diff --git a/Chinendar.xcodeproj/project.pbxproj b/Chinendar.xcodeproj/project.pbxproj index 534e0b4..e0b3439 100644 --- a/Chinendar.xcodeproj/project.pbxproj +++ b/Chinendar.xcodeproj/project.pbxproj @@ -99,6 +99,10 @@ B383A6ED2A4D1EA2002FADCF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = B383A6EC2A4D1EA2002FADCF /* Localizable.xcstrings */; }; B38B52A22B14C5770055569E /* StatusState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38B52A12B14C5770055569E /* StatusState.swift */; }; B38B52A32B14C5770055569E /* StatusState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38B52A12B14C5770055569E /* StatusState.swift */; }; + B38BC34C2C05562A00AB5BA5 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34DA20829FDC0B200562449 /* Utilities.swift */; }; + B38BC34D2C05562A00AB5BA5 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34DA20829FDC0B200562449 /* Utilities.swift */; }; + B38BC34E2C05562B00AB5BA5 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34DA20829FDC0B200562449 /* Utilities.swift */; }; + B38BC34F2C05562B00AB5BA5 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34DA20829FDC0B200562449 /* Utilities.swift */; }; B38CC0492A4F1F1600F4DB9F /* WatchFace.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38CC0482A4F1F1600F4DB9F /* WatchFace.swift */; }; B38E96B12A0D3A82002FD662 /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D245D60826FA886200A89044 /* Calendar.swift */; }; B38E96B32A0D3A8A002FD662 /* PlanetModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CFF74C270FF940000CECDA /* PlanetModel.swift */; }; @@ -1082,6 +1086,7 @@ files = ( B3E1D6E42A0ACD7800F2905A /* WatchFaceView.swift in Sources */, 9E6E10CE2AA6410A004CEDBE /* TaskGroup.swift in Sources */, + B38BC34C2C05562A00AB5BA5 /* Utilities.swift in Sources */, B3F85EB22A4A5F6900F8B40B /* DateTimeAdjust.swift in Sources */, B38CC0492A4F1F1600F4DB9F /* WatchFace.swift in Sources */, B36D2F7A2A0483F800005162 /* WatchFaceBasics.swift in Sources */, @@ -1112,6 +1117,7 @@ B395B5A82A0F22CF003206E7 /* IconView.swift in Sources */, B3C68B192B5DDC4B00FC08E3 /* Card.swift in Sources */, 9E5742812AA504D20052AE70 /* TaskGroup.swift in Sources */, + B38BC34E2C05562B00AB5BA5 /* Utilities.swift in Sources */, B3CC8BB02A0B31B70063DE44 /* Calendar.swift in Sources */, B3C68B1C2B5DE90800FC08E3 /* Protocols.swift in Sources */, B34009482A352FEA003F50F7 /* WatchFaceView.swift in Sources */, @@ -1158,6 +1164,7 @@ 9E5742822AA504D30052AE70 /* TaskGroup.swift in Sources */, B3E8A5172A4CF67700302473 /* Circular.swift in Sources */, B3CC8BF32A0C7E300063DE44 /* TextDesp.swift in Sources */, + B38BC34F2C05562B00AB5BA5 /* Utilities.swift in Sources */, 9E0438CD2A8FD5E0007217A8 /* Locale.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1176,6 +1183,7 @@ B3E1D6E52A0ACDD800F2905A /* Layout.swift in Sources */, B3E1D6DD2A0AC88B00F2905A /* WatchFaceBasics.swift in Sources */, 9E5742802AA504D20052AE70 /* TaskGroup.swift in Sources */, + B38BC34D2C05562A00AB5BA5 /* Utilities.swift in Sources */, B383A6D12A4D02E2002FADCF /* Dual.swift in Sources */, B3CC8BBD2A0B40E00063DE44 /* Full.swift in Sources */, B34009472A352FEA003F50F7 /* WatchFaceView.swift in Sources */, @@ -1697,8 +1705,8 @@ D2E4E0F326F7C73F002F3716 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - APP_BUILD = 132; - APP_VERSION = 5.4.1; + APP_BUILD = 137; + APP_VERSION = 5.5; ASSETCATALOG_COMPILER_APPICON_NAME = ""; ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOL_FRAMEWORKS = SwiftUI; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1761,11 +1769,13 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=400 -Xfrontend -warn-long-function-bodies=400"; PLIST_FILE_OUTPUT_FORMAT = binary; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; STRINGS_FILE_OUTPUT_ENCODING = binary; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; @@ -1777,8 +1787,8 @@ D2E4E0F426F7C73F002F3716 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - APP_BUILD = 132; - APP_VERSION = 5.4.1; + APP_BUILD = 137; + APP_VERSION = 5.5; ASSETCATALOG_COMPILER_APPICON_NAME = ""; ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOL_FRAMEWORKS = SwiftUI; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1859,7 +1869,7 @@ CODE_SIGN_ENTITLEMENTS = macOS/Chinendar.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 102; + CURRENT_PROJECT_VERSION = "$(APP_BUILD)"; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 28HU5A7B46; INFOPLIST_FILE = macOS/Info.plist; @@ -1888,7 +1898,7 @@ CODE_SIGN_ENTITLEMENTS = macOS/Chinendar.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 102; + CURRENT_PROJECT_VERSION = "$(APP_BUILD)"; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 28HU5A7B46; ENABLE_APP_SANDBOX = YES; diff --git a/Shared/DataModel/Calendar.swift b/Shared/DataModel/Calendar.swift index ccc938e..87df712 100644 --- a/Shared/DataModel/Calendar.swift +++ b/Shared/DataModel/Calendar.swift @@ -9,415 +9,24 @@ import Foundation import Observation import os.lock -infix operator %% -infix operator /% - -protocol NamedPoint { - var name: String { get } - var pos: Double { get } -} - -extension BinaryInteger { - static func %%(_ left: Self, _ right: Self) -> Self { - let mod = left % right - return mod >= 0 ? mod : mod + right - } -} - -extension FloatingPoint { - static func %%(_ left: Self, _ right: Self) -> Self { - let mod = left.truncatingRemainder(dividingBy: right) - return mod >= 0 ? mod : mod + right - } -} - -extension BinaryInteger { - static func /%(_ left: Self, _ right: Self) -> Self { - if left < 0 { - return (left - right + 1) / right - } else { - return left / right - } - } -} - -func +(lhs: CGPoint, rhs: CGPoint) -> CGPoint { - return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y) -} - -func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint { - return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y) -} - -func *(lhs: CGPoint, rhs: CGFloat) -> CGPoint { - return CGPoint(x: lhs.x * rhs, y: lhs.y * rhs) -} - -func /(lhs: CGPoint, rhs: CGFloat) -> CGPoint { - return CGPoint(x: lhs.x / rhs, y: lhs.y / rhs) -} - -extension Array { - func insertionIndex(of value: Element, comparison: (Element, Element) -> Bool) -> Index { - var slice: SubSequence = self[...] - - while !slice.isEmpty { - let middle = slice.index(slice.startIndex, offsetBy: slice.count / 2) - if comparison(value, slice[middle]) { - slice = slice[.. Date { - func convertToApparent(date: Date, location: CGPoint) -> Date { - var start = date - let timezoneDiff = Double(timeZone.secondsFromGMT(for: start)) - location.y / 360 * 86400 - start += timezoneDiff - start -= equationOfTime(D: fromJD2000(date: start)) / (2 * Double.pi) * 86400 - return start - } - let standardStartOfDay = startOfDay(for: day) - var startToday = standardStartOfDay + func startOfDay(for day: Date, apparent: Bool, location: GeoLocation?) -> Date { + let startToday = startOfDay(for: day) if let location = location, apparent { - startToday = convertToApparent(date: startToday, location: location) - if day < startToday { - var startYesterday = date(byAdding: .day, value: -1, to: standardStartOfDay)! - startYesterday = convertToApparent(date: startYesterday, location: location) - return startYesterday - } else { - var startTomorrow = date(byAdding: .day, value: 1, to: standardStartOfDay)! - startTomorrow = convertToApparent(date: startTomorrow, location: location) - if day >= startTomorrow { - return startTomorrow - } else { - return startToday - } - } + return dayStart(around: startToday, at: location) } else { return startToday } } } -private func getJD(yyyy: Int, mm: Int, dd: Int) -> Double { - var m1 = mm - var yy = yyyy - if m1 <= 2 { - m1 = m1 + 12 - yy = yy - 1 - } - // Gregorian calendar - let b = yy / 400 - yy / 100 + yy / 4 - let jd = Double(365 * yy - 679004 + b) + floor(30.6001 * Double(m1 + 1)) + Double(dd) + 2400000.5 - return jd -} - -private func DeltaT_spline_y(_ y: Double) -> Double { - func phase(x: Double) -> Double { - let t = x - 1825 - return 0.00314115 * t * t + 284.8435805251424 * cos(0.4487989505128276 * (0.01 * t + 0.75)) - } - if y < -720 { - let const = 1.007739546148514 - return phase(x: y) + const - } else if y > 2019 { - let const: Double = -150.263031657016 - return phase(x: y) + const - } - let n = [-720, -100, 400, 1000, 1150, 1300, 1500, 1600, 1650, 1720, 1800, 1810, 1820, 1830, 1840, 1850, 1855, 1860, 1865, 1870, 1875, 1880, 1885, 1890, 1895, 1900, 1905, 1910, 1915, 1920, 1925, 1930, 1935, 1940, 1945, 1950, 1953, 1956, 1959, 1962, 1965, 1968, 1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004, 2007, 2010, 2013, 2016] - - var l = n.count - 1 - while l >= 0 && !(y >= Double(n[l])) { - l -= 1 - } - - let year_splits = [-100, 400, 100, 1150, 1300, 1500, 1600, 1650, 1720, 1800, 1810, 1820, 1830, 1840, 1850, 1855, 1860, 1865, 1870, 1875, 1880, 1885, 1890, 1895, 1900, 1905, 1910, 1915, 1920, 1925, 1930, 1935, 1940, 1945, 1950, 1953, 1956, 1959, 1962, 1965, 1968, 1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004, 2007, 2010, 2013, 2016, 2019] - let r = (y - Double(n[l])) / Double(year_splits[l] - n[l]) - let coef1: [Double] = [20371.848, 11557.668, 6535.116, 1650.393, 1056.647, 681.149, 292.343, 109.127, 43.952, 12.068, 18.367, 15.678, 16.516, 10.804, 7.634, 9.338, 10.357, 9.04, 8.255, 2.371, -1.126, -3.21, -4.388, -3.884, -5.017, -1.977, 4.923, 11.142, 17.479, 21.617, 23.789, 24.418, 24.164, 24.426, 27.05, 28.932, 30.002, 30.76, 32.652, 33.621, 35.093, 37.956, 40.951, 44.244, 47.291, 50.361, 52.936, 54.984, 56.373, 58.453, 60.678, 62.898, 64.083, 64.553, 65.197, 66.061, 66.92, 68.109] - let coef2: [Double] = [-9999.586, -5822.27, -5671.519, -753.21, -459.628, -421.345, -192.841, -78.697, -68.089, 2.507, -3.481, 0.021, -2.157, -6.018, -0.416, 1.642, -0.486, -0.591, -3.456, -5.593, -2.314, -1.893, 0.101, -0.531, 0.134, 5.715, 6.828, 6.33, 5.518, 3.02, 1.333, 0.052, -0.419, 1.645, 2.499, 1.127, 0.737, 1.409, 1.577, 0.868, 2.275, 3.035, 3.157, 3.199, 3.069, 2.878, 2.354, 1.577, 1.648, 2.235, 2.324, 1.804, 0.674, 0.466, 0.804, 0.839, 1.007, 1.277] - let coef3: [Double] = [776.247, 1303.151, -298.291, 184.811, 108.771, 61.953, -6.572, 10.505, 38.333, 41.731, -1.126, 4.629, -6.806, 2.944, 2.658, 0.261, -2.389, 2.284, -5.148, 3.011, 0.269, 0.152, 1.842, -2.474, 3.138, 2.443, -1.329, 0.831, -1.643, -0.856, -0.831, -0.449, -0.022, 2.086, -1.232, 0.22, -0.61, 1.282, -1.115, 0.406, 1.002, -0.242, 0.364, -0.323, 0.193, -0.384, -0.14, -0.637, 0.708, -0.121, 0.21, -0.729, -0.402, 0.194, 0.144, -0.109, 0.277, -0.007] - let coef4: [Double] = [409.16, -503.433, 1085.087, -25.346, -24.641, -29.414, 16.197, 3.018, -2.127, -37.939, 1.918, -3.812, 3.25, -0.096, -0.539, -0.883, 1.558, -2.477, 2.72, -0.914, -0.039, 0.563, -1.438, 1.871, -0.232, -1.257, 0.72, -0.825, 0.262, 0.008, 0.127, 0.142, 0.702, -1.106, 0.614, -0.277, 0.631, -0.799, 0.507, 0.199, -0.414, 0.202, -0.229, 0.172, -0.192, 0.081, -0.165, 0.448, -0.276, 0.11, -0.313, 0.109, 0.199, -0.017, -0.084, 0.128, -0.095, -0.139] - return coef1[l] + r * (coef2[l] + r * (coef3[l] + r * coef4[l])) -} - -// UT -> TT -private func DeltaT(T: Double) -> Double { - let t = 36525 * T + 2451545 - if t > 2459580.5 || t < 2441317.5 { - return DeltaT_spline_y(t >= 2299160.5 ? (t - 2451544.5) / 365.2425 + 2000 : (t + 0.5) / 365.25 - 4712) / 86400.0 - } - let l: [Double] = [2457754.5, 2457204.5, 2456109.5, 2454832.5, 2453736.5, 2451179.5, 2450630.5, 2450083.5, 2449534.5, 2449169.5, 2448804.5, 2448257.5, 2447892.5, 2447161.5, 2446247.5, 2445516.5, 2445151.5, 2444786.5, 2444239.5, 2443874.5, 2443509.5, 2443144.5, 2442778.5, 2442413.5, 2442048.5, 2441683.5, 2441499.5, 2441133.5] - let n = l.count - var DT = 42.184 - for i in 0.. l[i] { - DT += Double(n - i - 1) - break - } - } - return DT / 86400.0 -} - -private func mod2pi_de(x: Double) -> Double { - return x - 2 * Double.pi * floor(0.5 * x / Double.pi + 0.5) -} - -private func decode_solar_terms(y: Int, istart: Int, offset_comp: Int, solar_comp: [Int8]) -> [Date] { - let jd0 = getJD(yyyy: y - 1, mm: 12, dd: 31) - 1.0 / 3 - let delta_T = DeltaT(T: (jd0 - 2451545 + 365.25 * 0.5) / 36525) - let offset = 2451545 - jd0 - delta_T - let w: [Double] = [2 * Double.pi, 6.282886, 12.565772, 0.337563, 83.99505, 77.712164, 5.7533, 3.9301] - let poly_coefs: [Double] - let amp: [Double] - let ph: [Double] - if y > 2500 { - poly_coefs = [-10.60617210417765, 365.2421759265393, -2.701502510496315e-08, 2.303900971263569e-12] - amp = [0.1736157870707964, 1.914572713893651, 0.0113716862045686, 0.004885711219368455, 0.0004032584498264633, 0.001736052092601642, 0.002035081600709588, 0.001360448706185977] - ph = [-2.012792258215681, 2.824063083728992, -0.4826844382278376, 0.9488391363261893, 2.646697770061209, -0.2675341497460084, 0.9646288791219602, -1.808852094435626] - } else if y > 1500 { - poly_coefs = [-10.6111079510509, 365.2421925947405, -3.888654930760874e-08, -5.434707919089998e-12] - amp = [0.1633918030382493, 1.95409759473169, 0.01184405584067255, 0.004842563463555804, 0.0004137082581449113, 0.001732513547029885, 0.002025850272284684, 0.001363226024948773] - ph = [-1.767045717746641, 2.832417615687159, -0.465176623256009, 0.9461667782644696, 2.713020913181211, -0.2031148059020781, 0.9980808019332812, -1.832536089597202] - } else { - poly_coefs = [] - amp = [] - ph = [] - } - - var sterm = [Date]() - for i in 0.. [Date] { - let w = [2 * Double.pi, 6.733776, 13.467552, 0.507989, 0.0273143, 0.507984, 20.201328, 6.225791, 7.24176, 5.32461, 12.058386, 0.901181, 5.832595, 12.56637061435917, 19.300146, 11.665189, 18.398965, 6.791174, 13.636974, 1.015968, 6.903198, 13.07437, 1.070354, 6.340578614359172] - let poly_coefs: [Double] - let amp: [Double] - let ph: [Double] - if y > 2500 { - poly_coefs = [5.093879710922470, 29.53058981687484, 2.670339910922144e-11, 1.807808217274283e-15] - amp = [0.00306380948959271, 6.08567588841838, 0.3023856209133756, 0.07481389897992345, 0.0001587661348338354, 0.1740759063081489, 0.0004131985233772993, 0.005796584475300004, 0.008268929076163079, 0.003256244384807976, 0.000520983165608148, 0.003742624708965854, 1.709506053530008, 28216.70389751519, 1.598844831045378, 0.314745599206173, 6.602993931108911, 0.0003387269181720862, 0.009226112317341887, 0.00196073145843697, 0.001457643607929487, 6.467401779992282e-05, 0.0007716739483064076, 0.001378880922256705] - ph = [-0.0001879456766404132, -2.745704167588171, -2.348884895288619, 1.420037528559222, -2.393586904955103, -0.3914194006325855, 1.183088056748942, -2.782692143601458, 0.4430565056744425, -0.4357413971405519, -3.081209195003025, 0.7945051912707899, -0.4010911170136437, 3.003035462639878e-10, 0.4040070684461441, 2.351831380989509, 2.748612213507844, 3.133002890683667, -0.6902922380876192, 0.09563473131477442, 2.056490394534053, 2.017507533465959, 2.394015964756036, -0.3466427504049927] - } else if y > 1500 { - poly_coefs = [5.097475813506625, 29.53058886049267, 1.095399949433705e-10, -6.926279905270773e-16] - amp = [0.003064332812182054, 0.8973816160666801, 0.03119866094731004, 0.07068988004978655, 0.0001583070735157395, 0.1762683983928151, 0.0004131592685474231, 0.005950873973350208, 0.008489324571543966, 0.00334306526160656, 0.00052946042568393, 0.003743585488835091, 0.2156913373736315, 44576.30467073629, 0.1050203948601217, 0.01883710371633125, 0.380047745859265, 0.0003472930592917774, 0.009225665415301823, 0.002061407071938891, 0.001454599562245767, 5.856419090840883e-05, 0.0007688706809666596, 0.001415547168551922] - ph = [-0.0003231124735555465, 0.380955331199635, 0.762645225819612, 1.4676293538949, -2.15595770830073, -0.3633370464549665, 1.134950591549256, -2.808169363709888, 0.422381840383887, -0.4226859182049138, -3.091797336860658, 0.7563140142610324, -0.3787677293480213, 1.863828515720658e-10, 0.3794794147818532, -0.7671105159156101, -0.3850942687637987, -3.098506117162865, -0.6738173539748421, 0.09011906278589261, 2.089832317302934, 2.160228985413543, -0.6734226930504117, -0.3333652792566645] - } else { - poly_coefs = [] - amp = [] - ph = [] - } - - let jd0 = getJD(yyyy: y - 1, mm: 12, dd: 31) - 1.0 / 3 - let delta_T = DeltaT(T: (jd0 - 2451545 + 365.25 * 0.5) / 36525) - let offset = 2451545 - jd0 - delta_T - let lsyn = 29.5306 - let p0 = lunar_comp[0] - let jdL0 = 2451550.259469 + 0.5 * Double(p0) * lsyn - - // Find the lunation number of the first moon phase in the year - var Lm0 = floor((jd0 + 1 - jdL0) / lsyn) - 1 - var Lm: Double = 0 - var s: Double = 0 - var s1 = 0 - for i in 0..<10 { - Lm = Lm0 + 0.5 * Double(p0) + Double(i) - s = poly_coefs[0] + offset + Lm * (poly_coefs[1] + Lm * (poly_coefs[2] + Lm * poly_coefs[3])) - for j in 0..<24 { - let ang = mod2pi_de(x: w[j] * Lm) + ph[j] - s += amp[j] * sin(ang) - } - s1 = Int((s - floor(s)) * 1440 + 0.5) - s = Double(s1) + 1441 * floor(s) + Double(lunar_comp[1]) - Double(offset_comp) - if s > 1440 { - break - } - } - Lm0 = Lm - var mphase = [Date]() - // Now decompress the remaining moon-phase times - for i in 1.. [Date] { - // year in [1900, 3000] - return decode_solar_terms(y: year, istart: 0, offset_comp: 5, solar_comp: sunData[year - 1900]) -} - -private func moon_phase_in_year(_ year: Int) -> ([Date], Int8) { - // year in [1900, 3000] - return (decode_moon_phases(y: year, offset_comp: 5, lunar_comp: moonData[year - 1900], dp: 0.5), moonData[year - 1900][0]) -} - -private func fromJD2000(date: Date) -> Double { - var dateComponents = utcCalendar.dateComponents([.year, .month, .day], from: date) - dateComponents.hour = 12 - let noon = utcCalendar.date(from: dateComponents)! - let j2000 = getJD(yyyy: dateComponents.year!, mm: dateComponents.month!, dd: dateComponents.day!) - let delta_j2000 = DeltaT(T: (j2000 - 2451545 + 365.25 * 0.5) / 36525) - var offset = j2000 + delta_j2000 - 2451544.5 - offset += noon.distance(to: date) / 86400 - return offset -} - -private func intraday_solar_times(chineseCalendar: ChineseCalendar, location: CGPoint) -> [Date?] { - let calendar = chineseCalendar.calendar - func timeOfDate(date: Date, hour: Int) -> Date { - var dateComponents = calendar.dateComponents([.year, .month, .day], from: date) - dateComponents.hour = hour - let newDate = calendar.date(from: dateComponents)! - var delta = TimeInterval(calendar.timeZone.secondsFromGMT(for: newDate)) - delta -= location.y / 360 * 86400 - return newDate + delta - } - - let approximateDate = chineseCalendar.startOfDay.addingTimeInterval(43200) - let localNoon = timeOfDate(date: approximateDate, hour: 12) - let noonTime = localNoon - equationOfTime(D: fromJD2000(date: localNoon)) / (2 * Double.pi) * 86400 - let priorMidNight = timeOfDate(date: approximateDate, hour: 0) - let nextMidNight = timeOfDate(date: approximateDate, hour: 24) - let priorMidNightTime = priorMidNight - equationOfTime(D: fromJD2000(date: priorMidNight)) / (2 * Double.pi) * 86400 - let nextMidNightTime = nextMidNight - equationOfTime(D: fromJD2000(date: nextMidNight)) / (2 * Double.pi) * 86400 - - let sunriseSunsetOffset = daytimeOffset(latitude: location.x / 180 * Double.pi, progressInYear: chineseCalendar.sunPosition(time: chineseCalendar.time) * 2 * Double.pi) / (2 * Double.pi) * 86400 - let results: [Date?] - if sunriseSunsetOffset == Double.infinity { // Extreme day - results = [nil, nil, noonTime, nil, nil] - } else if sunriseSunsetOffset == -Double.infinity { // Extreme night - results = [priorMidNightTime, nil, nil, nil, nextMidNightTime] - } else { - var sunriseTime = localNoon - sunriseSunsetOffset - var sunsetTime = localNoon + sunriseSunsetOffset - sunriseTime -= equationOfTime(D: fromJD2000(date: sunriseTime)) / (2 * Double.pi) * 86400 - sunsetTime -= equationOfTime(D: fromJD2000(date: sunsetTime)) / (2 * Double.pi) * 86400 - results = [priorMidNightTime, sunriseTime, noonTime, sunsetTime, nextMidNightTime] - } - return results -} - -private func intraday_lunar_times(chineseCalendar: ChineseCalendar, location: CGPoint) -> [Date?] { - func riseAndSet(meridianTime: Date, latitude: Double, light: Bool) -> ([Date?], Double) { - let offsetMeridian = lunarTimeOffset(latitude: location.x / 180 * Double.pi, jdTime: fromJD2000(date: meridianTime), light: light) - let moonrise = meridianTime - offsetMeridian / (2 * Double.pi) * 360 / (earthSpeed - moonSpeed) - let moonset = meridianTime + offsetMeridian / (2 * Double.pi) * 360 / (earthSpeed - moonSpeed) - if offsetMeridian == Double.infinity { - return ([nil, meridianTime, nil], offsetMeridian) - } else if offsetMeridian == -Double.infinity { - return ([nil, nil, nil], offsetMeridian) - } else { - return ([moonrise, meridianTime, moonset], offsetMeridian) - } - } - func roundHalf(_ num: Double) -> Double { - return num - 1 - floor(num - 0.5) - } - - func calDiff(time: Date) -> Double { - let (ra, _, _) = moonEquatorPosition(D: fromJD2000(date: time)) - let dayStart = chineseCalendar.calendar.startOfDay(for: time, apparent: true, location: location) - let nextDay = chineseCalendar.calendar.startOfDay(for: dayStart + 86400 * 1.5, apparent: true, location: location) - return roundHalf(-chineseCalendar.sunPosition(time: time) - 1 / 4 - dayStart.distance(to: time) / dayStart.distance(to: nextDay) + ra / (2 * Double.pi)) - } - - let longitudeDiff = calDiff(time: chineseCalendar.time) - var timeUnderMeridianNext: Date, timeUnderMeridianPrevious: Date - if longitudeDiff >= 0 { - timeUnderMeridianNext = chineseCalendar.time + longitudeDiff * 360 / (earthSpeed - moonSpeed) - timeUnderMeridianPrevious = chineseCalendar.time + (longitudeDiff - 1) * 360 / (earthSpeed - moonSpeed) - } else { - timeUnderMeridianPrevious = chineseCalendar.time + longitudeDiff * 360 / (earthSpeed - moonSpeed) - timeUnderMeridianNext = chineseCalendar.time + (longitudeDiff + 1) * 360 / (earthSpeed - moonSpeed) - } - let beginOfToday = chineseCalendar.startOfDay - let endOfToday = chineseCalendar.startOfNextDay - if timeUnderMeridianPrevious.advanced(by: 43200) < beginOfToday { - timeUnderMeridianPrevious += 360 / (earthSpeed - moonSpeed) - timeUnderMeridianNext += 360 / (earthSpeed - moonSpeed) - } else if timeUnderMeridianNext.advanced(by: -43200) >= endOfToday { - timeUnderMeridianPrevious -= 360 / (earthSpeed - moonSpeed) - timeUnderMeridianNext -= 360 / (earthSpeed - moonSpeed) - } - timeUnderMeridianPrevious += calDiff(time: timeUnderMeridianPrevious) * 360 / (earthSpeed - moonSpeed) - timeUnderMeridianNext += calDiff(time: timeUnderMeridianNext) * 360 / (earthSpeed - moonSpeed) - - let (previousTimes, offset1) = riseAndSet(meridianTime: timeUnderMeridianPrevious, latitude: location.x, light: true) - let (nextTimes, offset2) = riseAndSet(meridianTime: timeUnderMeridianNext, latitude: location.x, light: true) - let midtime = timeUnderMeridianPrevious + timeUnderMeridianPrevious.distance(to: timeUnderMeridianNext) / 2 - let (midTimes, offset) = riseAndSet(meridianTime: midtime, latitude: location.x, light: false) - - var results = [previousTimes[0], previousTimes[1]] - if let set1 = previousTimes[2], let set2 = midTimes[0] { - results.append(set2 + set2.distance(to: set1) * (1 + (offset - offset1) / Double.pi) / 2) - } else { - if offset == -Double.infinity { - results.append(nil) - } else { - results.append(previousTimes[2] ?? midTimes[0]) - } - } - if let set1 = midTimes[2], let set2 = nextTimes[0] { - results.append(set2 + set2.distance(to: set1) * (1 + (offset2 - offset) / Double.pi) / 2) - } else { - if offset == -Double.infinity { - results.append(nil) - } else { - results.append(nextTimes[0] ?? midTimes[2]) - } - } - results.append(contentsOf: [nextTimes[1], nextTimes[2]]) - return results -} - extension Date { static func from(year: Int, month: Int, day: Int, hour: Int, minute: Int, timezone: TimeZone?) -> Date? { var dateComponents = DateComponents() @@ -433,77 +42,9 @@ extension Date { } } -extension Int { - func quotient(rhs: Int) -> Int { - if self < 0 { - return (self - (rhs - 1)) / rhs - } else { - return self / rhs - } - } -} - -extension Array { - func slice(from: Int = 0, to: Int? = nil, step: Int = 1) -> Self { - var sliced = Self() - var i = from - let limit = to ?? count - while i < limit { - sliced.append(self[i]) - i += step - } - return sliced - } -} - @Observable final class ChineseCalendar { - - struct ChineseDate: Hashable { - var month: Int - var day: Int - var leap: Bool = false - - static func == (lhs: ChineseDate, rhs: ChineseDate) -> Bool { - lhs.month == rhs.month && lhs.day == rhs.day && lhs.leap == rhs.leap - } - } - struct Hour { - enum HourFormat { - case full - case partial(index: Int) - } - var hour: Int - var format: HourFormat - var string: String { - guard (0.. 0 { - str += ChineseCalendar.chinese_numbers[minorTick] - } - return str - } - } - - static let updateInterval: CGFloat = 14.4 //Seconds - static let month_chinese = ["正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月", "臘月", ] + static let updateInterval: CGFloat = 14.4 // Seconds + static let month_chinese = ["正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月", "臘月" ] static let month_chinese_compact = ["㋀", "㋁", "㋂", "㋃", "㋄", "㋅", "㋆", "㋇", "㋈", "㋉", "㋊", "㋋"] static let day_chinese = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"] static let day_chinese_compact = ["㏠", "㏡", "㏢", "㏣", "㏤", "㏥", "㏦", "㏧", "㏨", "㏩", "㏪", "㏫", "㏬", "㏭", "㏮", "㏯", "㏰", "㏱", "㏲", "㏳", "㏴", "㏵", "㏶", "㏷", "㏸", "㏹", "㏺", "㏻", "㏼", "㏽"] @@ -514,9 +55,10 @@ extension Array { static let oddSolarTermChinese = ["小 寒", "立 春", "驚 蟄", "清 明", "立 夏", "芒 種", "小 暑", "立 秋", "白 露", "寒 露", "立 冬", "大 雪"] static let leapLabel = "閏" static let alternativeMonthName = ["閏正月": "閏一月"] - static let dayTimeName = ["夜中", "日出", "日中", "日入"] - static let moonTimeName = ["月出", "月中", "月入"] - static let moonPhases = ["朔", "望"] + static let dayTimeName = (midnight: "夜中", sunrise: "日出", noon: "日中", sunset: "日入") + static let moonTimeName = (moonrise: "月出", highMoon: "月中", moonset: "月入") + static let moonPhases = (newmoon: "朔", fullmoon: "望") + static let planetNames = (mercury: "辰", venus: "太白", mars: "熒惑", jupiter: "歲", saturn: "填", moon: "月") static let holidays = [ChineseDate(month: 1, day: 1): "元旦", ChineseDate(month: 1, day: 15): "上元", ChineseDate(month: 2, day: 2): "春社", ChineseDate(month: 3, day: 3): "上巳", ChineseDate(month: 5, day: 5): "端午", ChineseDate(month: 7, day: 7): "七夕", ChineseDate(month: 7, day: 15): "中元", ChineseDate(month: 9, day: 9): "重陽", ChineseDate(month: 8, day: 15): "中秋", @@ -544,7 +86,7 @@ extension Array { private var _largeHour: Bool = false private var _time: Date = .distantPast private var _calendar: Calendar = .utcCalendar - private var _location: CGPoint? = nil + private var _location: GeoLocation? @ObservationIgnored private var _year: Int = 0 @ObservationIgnored private var _numberOfMonths: Int = 0 @ObservationIgnored private var _year_length: Double = 0 @@ -557,8 +99,9 @@ extension Array { @ObservationIgnored private var _precise_month: Int = -1 @ObservationIgnored private var _leap_month: Int = -1 @ObservationIgnored private var _day: Int = -1 - @ObservationIgnored private var _sunTimes: [Date?] = [] - @ObservationIgnored private var _moonTimes: [Date?] = [] + @ObservationIgnored private var _planets: Planets? + @ObservationIgnored private var _sunTimes: [DateType: Solar] = [:] + @ObservationIgnored private var _moonTimes: [DateType: Lunar] = [:] @ObservationIgnored private var _startHour: Date = .distantPast @ObservationIgnored private var _endHour: Date = .distantFuture @ObservationIgnored private var _hourNames: [NamedHour] = [] @@ -569,47 +112,7 @@ extension Array { @ObservationIgnored private var _quarter: SubHour = SubHour(majorTick: -1, minorTick: -1) @ObservationIgnored private let _lock = OSAllocatedUnfairLock() - struct NamedHour { - let hour: Date - let shortName: String - let longName: String - } - - struct NamedPosition: NamedPoint { - let name: String - let pos: Double - } - - struct NamedDate { - let name: String - let date: Date - } - - struct CelestialEvent { - var eclipse = [NamedPosition]() - var fullMoon = [NamedPosition]() - var oddSolarTerm = [NamedPosition]() - var evenSolarTerm = [NamedPosition]() - } - - struct DailyEvent { - var solar = [NamedPosition?]() - var lunar = [NamedPosition?]() - } - - struct Ticks { - struct TickName: NamedPoint { - var pos: Double = 0.0 - var name: String = "" - var active: Bool = false - } - - var majorTicks = [Double]() - var majorTickNames = [TickName]() - var minorTicks = [Double]() - } - - init(time: Date = .now, timezone: TimeZone? = nil, location: CGPoint? = nil, compact: Bool = false, globalMonth: Bool = false, apparentTime: Bool = false, largeHour: Bool = false) { + init(time: Date = .now, timezone: TimeZone? = nil, location: GeoLocation? = nil, compact: Bool = false, globalMonth: Bool = false, apparentTime: Bool = false, largeHour: Bool = false) { self._compact = compact self._time = time var calendar = Calendar.current @@ -624,8 +127,40 @@ extension Array { updateHour() updateSubHour() } + + func update(time: Date = .now, timezone: TimeZone? = nil, location: GeoLocation?? = Optional(nil), globalMonth: Bool? = nil, apparentTime: Bool? = nil, largeHour: Bool? = nil) { + _lock.withLock { + let oldTimezone = _calendar.timeZone + let oldLocation = _location + let oldGlobalMonth = _globalMonth + let oldApparentTime = _apparentTime + _time = time + _calendar.timeZone = timezone ?? _calendar.timeZone + _location = location ?? _location + _globalMonth = globalMonth ?? _globalMonth + _apparentTime = apparentTime ?? _apparentTime + _largeHour = largeHour ?? _largeHour + + if (_location == nil && oldLocation != nil) || (_location != nil && oldLocation == nil) { + updateYear() + } else if let newLocation = _location, let oldLocation = oldLocation, + sqrt(pow(newLocation.lat - oldLocation.lat, 2) + pow(newLocation.lon - oldLocation.lon, 2)) > 1 { + updateYear() + } else if timezone != oldTimezone || oldGlobalMonth != _globalMonth || oldApparentTime != _apparentTime { + updateYear() + } else { + let year = _calendar.component(.year, from: time) + if !(((year == _year) && (_solarTerms[24] > time)) || ((year == _year - 1) && (_solarTerms[0] <= time))) { + updateYear() + } + } + updateDate() + updateHour() + updateSubHour() + } + } - private init(compact: Bool, time: Date, calendar: Calendar, location: CGPoint?, globalMonth: Bool, apparentTime: Bool, largeHour: Bool, year: Int, year_length: Double, numberOfMonths: Int, solarTerms: [Date], evenSolarTerms: [Date], oddSolarTerms: [Date], moonEclipses: [Date], fullMoons: [Date], month: Int, precise_month: Int, leap_month: Int, day: Int, sunTimes: [Date?], moonTimes: [Date?], startHour: Date, endHour: Date, subhours: [Date], subhourMinors: [Date], hourNames: [NamedHour], hourNamesInCurrentHour: [NamedHour], hour: Hour, quarter: SubHour) { + private init(compact: Bool, time: Date, calendar: Calendar, location: GeoLocation?, globalMonth: Bool, apparentTime: Bool, largeHour: Bool, year: Int, year_length: Double, numberOfMonths: Int, solarTerms: [Date], evenSolarTerms: [Date], oddSolarTerms: [Date], moonEclipses: [Date], fullMoons: [Date], month: Int, precise_month: Int, leap_month: Int, day: Int, planets: Planets?, sunTimes: [DateType: Solar], moonTimes: [DateType: Lunar], startHour: Date, endHour: Date, subhours: [Date], subhourMinors: [Date], hourNames: [NamedHour], hourNamesInCurrentHour: [NamedHour], hour: Hour, quarter: SubHour) { self._compact = compact self._time = time self._calendar = calendar @@ -645,6 +180,7 @@ extension Array { self._precise_month = precise_month self._leap_month = leap_month self._day = day + self._planets = planets self._sunTimes = sunTimes self._moonTimes = moonTimes self._startHour = startHour @@ -656,281 +192,44 @@ extension Array { self._hour = hour self._quarter = quarter } - + var copy: ChineseCalendar { - ChineseCalendar(compact: _compact, time: _time, calendar: _calendar, location: _location, globalMonth: _globalMonth, apparentTime: _apparentTime, largeHour: _largeHour, year: _year, year_length: _year_length, numberOfMonths: _numberOfMonths, solarTerms: _solarTerms, evenSolarTerms: _evenSolarTerms, oddSolarTerms: _oddSolarTerms, moonEclipses: _moonEclipses, fullMoons: _fullMoons, month: _month, precise_month: _precise_month, leap_month: _leap_month, day: _day, sunTimes: _sunTimes, moonTimes: _moonTimes, startHour: _startHour, endHour: _endHour, subhours: _subhours, subhourMinors: _subhourMinors, hourNames: _hourNames, hourNamesInCurrentHour: _hourNamesInCurrentHour, hour: _hour, quarter: _quarter) + ChineseCalendar(compact: _compact, time: _time, calendar: _calendar, location: _location, globalMonth: _globalMonth, apparentTime: _apparentTime, largeHour: _largeHour, year: _year, year_length: _year_length, numberOfMonths: _numberOfMonths, solarTerms: _solarTerms, evenSolarTerms: _evenSolarTerms, oddSolarTerms: _oddSolarTerms, moonEclipses: _moonEclipses, fullMoons: _fullMoons, month: _month, precise_month: _precise_month, leap_month: _leap_month, day: _day, planets: _planets, sunTimes: _sunTimes, moonTimes: _moonTimes, startHour: _startHour, endHour: _endHour, subhours: _subhours, subhourMinors: _subhourMinors, hourNames: _hourNames, hourNamesInCurrentHour: _hourNamesInCurrentHour, hour: _hour, quarter: _quarter) } +} - private func updateYear() { - var year = calendar.component(.year, from: time) - var solar_terms = solar_terms_in_year(year + 1) - if solar_terms[0] <= time { - year += 1 - solar_terms += solar_terms_in_year(year + 1)[0...4] +// Basic properties +extension ChineseCalendar { + var currentDayInYear: Double { + _solarTerms[0].distance(to: _time) / _year_length + } + + var currentDayInMonth: Double { + if _globalMonth { + let monthLength = _moonEclipses[_precise_month].distance(to: _moonEclipses[_precise_month + 1]) + return _moonEclipses[_precise_month].distance(to: _time) / monthLength } else { - var solar_terms_current_year = solar_terms_in_year(year) - solar_terms_current_year += solar_terms[0...4] - solar_terms = solar_terms_current_year + let monthStart = calendar.startOfDay(for: _moonEclipses[_month], apparent: apparentTime, location: location) + let monthEnd = calendar.startOfDay(for: _moonEclipses[_month + 1], apparent: apparentTime, location: location) + return monthStart.distance(to: _time) / monthStart.distance(to: monthEnd) } - let solar_terms_previous_year = solar_terms_in_year(year - 1) + } - let (moon_phase_previous_year, first_event) = moon_phase_in_year(year - 1) - var (moon_phase, _) = moon_phase_in_year(year) - let (moon_phase_next_year, _) = moon_phase_in_year(year + 1) - moon_phase = moon_phase_previous_year + moon_phase + moon_phase_next_year - var eclipse = moon_phase.slice(from: Int(first_event), step: 2) - var fullMoon = moon_phase.slice(from: Int(1 - first_event), step: 2) - var start: Int?, end: Int? - for i in 0..= solar_terms[0] { - start = i - 1 - } - if end == nil, eclipseDate > solar_terms[24] { - end = i - } - } - eclipse = eclipse.slice(from: start!, to: end! + 2) - fullMoon = fullMoon.filter { $0 < eclipse.last! && $0 > eclipse[0] } - let evenSolarTerms = solar_terms.slice(step: 2) + var currentHourInDay: Double { + startOfDay.distance(to: _time) / startOfDay.distance(to: startOfNextDay) + } - var i = 0 - var j = 0 - var count = 0 - var solatice_in_month = [Int]() - var monthCount = Set() - while i + 1 < eclipse.count, j < evenSolarTerms.count { - let thisEclipse: Date - let nextEclipse: Date - if _globalMonth { - thisEclipse = eclipse[i] - nextEclipse = eclipse[i + 1] - } else { - thisEclipse = calendar.startOfDay(for: eclipse[i], apparent: apparentTime, location: location) - nextEclipse = calendar.startOfDay(for: eclipse[i + 1], apparent: apparentTime, location: location) - } - if thisEclipse <= evenSolarTerms[j], nextEclipse > evenSolarTerms[j] { - count += 1 - j += 1 - } else { - solatice_in_month.append(count) - count = 0 - i += 1 - } - if thisEclipse > solar_terms[0], thisEclipse <= solar_terms[24] { - monthCount.insert(thisEclipse) - } - } - - var leap_month = -1 - if monthCount.count > 12 { - for i in 0.. startOfDate { - break - } - i += 1 - } - var j = 0 - while j < _moonEclipses.count - 1 { - if _moonEclipses[j] > _time { - break - } - j += 1 - } - let previousEclipse = _calendar.startOfDay(for: _moonEclipses[i - 1], apparent: apparentTime, location: location) - let startOfDate = _calendar.startOfDay(for: _time, apparent: apparentTime, location: location) - let date_diff = Int(round(previousEclipse.distance(to: startOfDate) / 86400)) - _month = i - 1 - _precise_month = j - 1 - _day = date_diff - } - - private func updateHour() { - let startOfDay = startOfDay - let startOfNextDay = startOfNextDay - var tempStartHour: Date? - var tempEndHour: Date? - var hour = if apparentTime { - startOfDay - 2 * startOfDay.distance(to: startOfNextDay) / 24 - } else { - _calendar.date(byAdding: .hour, value: -2, to: startOfDay)! - } - let end = if apparentTime { - startOfNextDay + 2 * startOfDay.distance(to: startOfNextDay) / 24 - } else { - _calendar.date(byAdding: .hour, value: 2, to: startOfNextDay)! - } - _hourNames = [] - var prevHourName = "" - var prevOffsetHourName = "" - var prevLongName = "" - while hour < end { - let hourIndex = if apparentTime { - Int(round(startOfDay.distance(to: hour) / startOfDay.distance(to: startOfNextDay) * 24)) - } else { - _calendar.component(.hour, from: hour) - } - let hourName = Self.terrestrial_branches[(hourIndex /% 2) %% 12] - let offsetHourName = Self.terrestrial_branches[((hourIndex + 1) /% 2) %% 12] - if !_largeHour || hourName != prevHourName { - let shortName = if hourName != prevHourName { - ChineseCalendar.terrestrial_branches[(hourIndex /% 2) %% 12] - } else { - "" - } - let longName: String - if _largeHour { - if hourName != prevHourName { - longName = Self.terrestrial_branches[(hourIndex /% 2) %% 12] - } else { - longName = "" - } - } else { - let name = Self.terrestrial_branches[((hourIndex + 1) /% 2) %% 12] + Self.sub_hour_name[(hourIndex + 1) %% 2] - if name != prevLongName { - prevLongName = name - longName = name - } else { - longName = "" - } - } - _hourNames.append(NamedHour(hour: hour, shortName: shortName, longName: longName)) - } - if hour <= _time { - if _largeHour { - _hour = Hour(hour: (hourIndex /% 2) %% 12, format: .full) - } else { - _hour = Hour(hour: ((hourIndex + 1) /% 2) %% 12, format: .partial(index: (hourIndex + 1) %% 2)) - } - } - let changeOfHour = if _largeHour { - hourName != prevHourName - } else { - offsetHourName != prevOffsetHourName - } - if changeOfHour, hour <= _time { - tempStartHour = hour - } - if changeOfHour, hour > _time, tempEndHour == nil { - tempEndHour = hour - } - if apparentTime { - hour += startOfDay.distance(to: startOfNextDay) / 24 - } else { - hour = _calendar.date(byAdding: .hour, value: 1, to: hour)! - } - prevHourName = hourName - prevOffsetHourName = offsetHourName - } - _startHour = tempStartHour! - _endHour = tempEndHour! + var subhourInHour: Double { + startHour.distance(to: _time) / startHour.distance(to: endHour) } - - private func updateSubHour() { - _hourNamesInCurrentHour = [] - _subhours = [] - _subhourMinors = [] - - var currentSmallHour = startHour - for namedHour in _hourNames { - if !namedHour.longName.isEmpty && namedHour.hour >= startHour && namedHour.hour < endHour { - _hourNamesInCurrentHour.append(namedHour) - if namedHour.hour <= _time { - currentSmallHour = namedHour.hour - } - } - } - - var majorTickCount = 0 - var tickTime = startOfDay - 864 * 6 - var currentSubhour = currentSmallHour - while tickTime < endHour - 16 { - if tickTime > startHour + 16 { - _subhours.append(tickTime) - } - if tickTime > currentSmallHour && time >= tickTime { - currentSubhour = tickTime - majorTickCount += 1 - } - tickTime += 864 - } - var minorTickCount = 0 - tickTime = startOfDay - 864 * 6 - while tickTime < endHour { - if tickTime > startHour { - _subhourMinors.append(tickTime) - } - if tickTime > currentSubhour && time >= tickTime { - minorTickCount += 1 - } - tickTime += 144 - } - _quarter = SubHour(majorTick: majorTickCount, minorTick: minorTickCount) + var startOfDay: Date { + _calendar.startOfDay(for: _time, apparent: apparentTime, location: location) } - func update(time: Date = .now, timezone: TimeZone? = nil, location: CGPoint?? = Optional(nil), globalMonth: Bool? = nil, apparentTime: Bool? = nil, largeHour: Bool? = nil) { - _lock.withLock { - let oldTimezone = _calendar.timeZone - let oldLocation = _location - let oldGlobalMonth = _globalMonth - let oldApparentTime = _apparentTime - _time = time - _calendar.timeZone = timezone ?? _calendar.timeZone - _location = location ?? _location - _globalMonth = globalMonth ?? _globalMonth - _apparentTime = apparentTime ?? _apparentTime - _largeHour = largeHour ?? _largeHour - - if (_location == nil && oldLocation != nil) || (_location != nil && oldLocation == nil) { - updateYear() - } else if let newLocation = _location, let oldLocation = oldLocation, - sqrt(pow(newLocation.x - oldLocation.x, 2) + pow(newLocation.y - oldLocation.y, 2)) > 1 { - updateYear() - } else if timezone != oldTimezone || oldGlobalMonth != _globalMonth || oldApparentTime != _apparentTime { - updateYear() - } else { - let year = _calendar.component(.year, from: time) - if !(((year == _year) && (_solarTerms[24] > time)) || ((year == _year - 1) && (_solarTerms[0] <= time))) { - updateYear() - } - } - updateDate() - updateHour() - updateSubHour() - } + var startOfNextDay: Date { + let nextDay = startOfDay + 86400 * 1.5 + return _calendar.startOfDay(for: nextDay, apparent: apparentTime, location: location) } var apparentTime: Bool { @@ -1016,15 +315,15 @@ extension Array { var phases = [NamedDate]() for i in 0.. 0 && $0 <= 1 } - guard months.count == monthDivides.count else { return ticks } - var previousMonthDivide = 0.0 - var monthNames = [Ticks.TickName]() - let minMonthLength: Double = (_compact ? 0.009 : 0.006) - for i in 0.. minMonthLength * Double(months[i].count) { - monthNames.append(Ticks.TickName( - pos: position, - name: months[i], - active: previousMonthDivide <= currentDayInYear - )) - } - previousMonthDivide = monthDivides[i] - } - if let lastDivide = monthDivides.last, lastDivide < 1 { - let position = (1 + previousMonthDivide) / 2 - if position - previousMonthDivide > minMonthLength * Double(months[0].count) { - monthNames.append(Ticks.TickName( - pos: position, - name: months[0], - active: previousMonthDivide <= currentDayInYear - )) - } - } else { - let _ = monthDivides.popLast() + var location: GeoLocation? { + get { + _location } + } - ticks.majorTicks = [0] + monthDivides - ticks.majorTickNames = monthNames - ticks.minorTicks = _fullMoons.map { _solarTerms[0].distance(to: $0) / _year_length }.filter { ($0 < 1) && ($0 > 0) } - return ticks + var timezone: Int { + _calendar.timeZone.secondsFromGMT(for: _time) } - var dayTicks: Ticks { - var ticks = Ticks() + var year: Int { + _year + } - let monthStart: Date - let monthEnd: Date - var date: Date - if _globalMonth { - monthStart = _moonEclipses[_precise_month] - monthEnd = _moonEclipses[_precise_month + 1] - date = _calendar.startOfDay(for: monthStart, apparent: apparentTime, location: location) - } else { - monthStart = _calendar.startOfDay(for: _moonEclipses[_month], apparent: apparentTime, location: location) - monthEnd = _calendar.startOfDay(for: _moonEclipses[_month + 1], apparent: apparentTime, location: location) - date = monthStart - } + var month: Int { + _month + } - var dayDivides = [Date]() - while date < monthEnd { - if apparentTime { - date += 86400 * 1.5 - date = _calendar.startOfDay(for: date, apparent: apparentTime, location: location) - } else { - date = _calendar.date(byAdding: .day, value: 1, to: date)! - } - dayDivides.append(date) - } - let majorTicks: [Double] = dayDivides.map { monthStart.distance(to: $0) / monthStart.distance(to: monthEnd) }.filter { $0 > 0 && $0 < 1 } + var preciseMonth: Int { + _globalMonth ? _precise_month : _month + } - let allDayNames: [String] - if _compact { - allDayNames = Self.day_chinese_compact.slice(to: numberOfDaysInMonth) + [Self.day_chinese_compact[0]] - } else { - allDayNames = Self.day_chinese.slice(to: numberOfDaysInMonth) + [Self.day_chinese[0]] - } + var nominalMonth: Int { + let inLeapMonth = _leap_month >= 0 && _month >= _leap_month + return ((_month + (inLeapMonth ? 0 : 1) - 3) %% 12) + 1 + } - var dayNames = [Ticks.TickName]() - var previousDayDivide = 0.0 - let minDayLength = (_compact ? 0.009 : 0.006) - for i in 0.. minDayLength * Double(allDayNames[i].count) { - dayNames.append(Ticks.TickName( - pos: position, - name: allDayNames[i], - active: previousDayDivide <= currentDayInMonth - )) - } - previousDayDivide = majorTicks[i] - } - let position = (1 + previousDayDivide) / 2 - if position - previousDayDivide > minDayLength * Double(allDayNames[majorTicks.count].count) { - dayNames.append(Ticks.TickName( - pos: position, - name: allDayNames[majorTicks.count], - active: previousDayDivide <= currentDayInMonth - )) - } - ticks.majorTicks = [0] + majorTicks - ticks.majorTickNames = dayNames - return ticks + var isLeapMonth: Bool { + _leap_month >= 0 && _month == _leap_month } - var hourTicks: Ticks { - let startOfDay = startOfDay - let startOfNextDay = startOfNextDay - var ticks = Ticks() - var hourDivides = [Double]() - var quarterTick = [Double]() - var quarter = 0.0 - while quarter < 1.0 { - quarterTick.append(quarter) - quarter += 864 / startOfDay.distance(to: startOfNextDay) - } - quarterTick = Array(Set(quarterTick).subtracting(hourDivides)).sorted() - var hourNames = [Ticks.TickName]() - var hourStart = startOfDay - - for namedHour in _hourNames { - if namedHour.hour >= startOfDay && namedHour.hour < startOfNextDay { - let dividePos = startOfDay.distance(to: namedHour.hour) / startOfDay.distance(to: startOfNextDay) - if !namedHour.longName.isEmpty { - hourDivides.append(dividePos) - } - if _largeHour || !namedHour.shortName.isEmpty { - if _largeHour { - hourStart = namedHour.hour - } - hourNames.append(Ticks.TickName( - pos: dividePos, - name: namedHour.shortName, - active: hourStart <= _time - )) - } else { - if !namedHour.longName.isEmpty { - hourStart = namedHour.hour - } - } - } + var day: Int { + _day + 1 + } + + var time: Date { + _time + } + + var numberOfMonths: Int { + _numberOfMonths + } + + var numberOfDaysInMonth: Int { + let month = _globalMonth ? _precise_month : _month + let monthStartDate = _calendar.startOfDay(for: _moonEclipses[month], apparent: apparentTime, location: location) + let monthEndDate = _calendar.startOfDay(for: _moonEclipses[month + 1], apparent: apparentTime, location: location) + return Int(round(monthStartDate.distance(to: monthEndDate) / 86400)) + } + + var startHour: Date { + _startHour + } + + var endHour: Date { + _endHour + } + + var lunarHoliday: String? { + for holiday in Self.holidays.keys where self.equals(date: holiday) { + return Self.holidays[holiday] } - ticks.majorTicks = hourDivides - ticks.majorTickNames = hourNames - ticks.minorTicks = quarterTick - return ticks + return nil } - var subhourTicks: Ticks { - let startHour = startHour - let endHour = endHour - var ticks = Ticks() - var subHourTicks = Set() - var majorTickNames = [String]() - for namedHour in _hourNamesInCurrentHour { - majorTickNames.append(namedHour.longName) - let distPos = startHour.distance(to: namedHour.hour) / startHour.distance(to: endHour) - if distPos >= 0.0 && distPos < 1.0 { - subHourTicks.insert(distPos) - } + var holidays: [String] { + var holidays: [String] = [] + if let holiday = self.lunarHoliday { + holidays.append(holiday) } - - let majorTicks = subHourTicks - for tickTime in _subhours { - let distPos = startHour.distance(to: tickTime) / startHour.distance(to: endHour) - if distPos >= 0.0 && distPos < 1.0 { - subHourTicks.insert(distPos) - } + for solarTerm in self.eventInDay.oddSolarTerm { + holidays.append(solarTerm.name) } - - let minimumSubhourLength = _compact ? 0.045 : 0.03 - var subHourNames = [Ticks.TickName]() - var count = 1 - var j = 0 - let subHourTick = Array(subHourTicks).sorted() - for i in 0.. minimumSubhourLength { - subHourNames.append(Ticks.TickName( - pos: subHourTick[i], - name: Self.chinese_numbers[count], - active: subHourTick[i] <= subhourInHour - )) - } - count += 1 - } + for solarTerm in self.eventInDay.evenSolarTerm { + holidays.append(solarTerm.name) } - - var subQuarterTicks = Set() - for tickTime in _subhourMinors { - subQuarterTicks.insert(startHour.distance(to: tickTime) / startHour.distance(to: endHour)) + for moon in self.eventInDay.eclipse { + holidays.append(moon.name) } - subQuarterTicks = subQuarterTicks.subtracting(subHourTicks) - let subQuarterTick = Array(subQuarterTicks).sorted() - - ticks.majorTicks = subHourTick - ticks.majorTickNames = subHourNames - ticks.minorTicks = subQuarterTick - return ticks + for moon in self.eventInDay.fullMoon { + holidays.append(moon.name) + } + return holidays } - +} + +// Celestial Events +extension ChineseCalendar { func nextHours(count: Int) -> [Date] { var tickTime = startOfDay var i = 0 @@ -1268,7 +445,7 @@ extension Array { } return hours } - + func nextQuarters(count: Int) -> [Date] { var tickTime = startOfDay - 864 * 6 var i = 0 @@ -1293,150 +470,53 @@ extension Array { return quarters } - var location: CGPoint? { - get { - _location + var planetPosition: Planets { + if let existing = _planets { + return existing } + let solarSystem = SolarSystem(time: _time, loc: location, targets: .all) + let offset = currentDayInYear - solarSystem.planets.sun.loc.ra / Double.pi / 2 + let planets = Planets( + moon: .init(name: Self.planetNames.moon, pos: ((solarSystem.planets.moon.loc.ra) / Double.pi / 2 + offset) %% 1.0), + mercury: .init(name: Self.planetNames.mercury, pos: ((solarSystem.planets.mercury.loc.ra) / Double.pi / 2 + offset) %% 1.0), + venus: .init(name: Self.planetNames.venus, pos: ((solarSystem.planets.venus.loc.ra) / Double.pi / 2 + offset) %% 1.0), + mars: .init(name: Self.planetNames.mars, pos: ((solarSystem.planets.mars.loc.ra) / Double.pi / 2 + offset) %% 1.0), + jupiter: .init(name: Self.planetNames.jupiter, pos: ((solarSystem.planets.jupiter.loc.ra) / Double.pi / 2 + offset) %% 1.0), + saturn: .init(name: Self.planetNames.saturn, pos: ((solarSystem.planets.saturn.loc.ra) / Double.pi / 2 + offset) %% 1.0) + ) + _planets = planets + return planets } - var timezone: Int { - _calendar.timeZone.secondsFromGMT(for: _time) - } - - var year: Int { - _year - } - - var month: Int { - _month - } - - var preciseMonth: Int { - _globalMonth ? _precise_month : _month - } - - var nominalMonth: Int { - let inLeapMonth = _leap_month >= 0 && _month >= _leap_month - return ((_month + (inLeapMonth ? 0 : 1) - 3) %% 12) + 1 - } - - var isLeapMonth: Bool { - _leap_month >= 0 && _month == _leap_month - } - - var day: Int { - _day + 1 - } - - var time: Date { - _time - } - - var numberOfMonths: Int { - _numberOfMonths - } - - var numberOfDaysInMonth: Int { - let month = _globalMonth ? _precise_month : _month - let monthStartDate = _calendar.startOfDay(for: _moonEclipses[month], apparent: apparentTime, location: location) - let monthEndDate = _calendar.startOfDay(for: _moonEclipses[month + 1], apparent: apparentTime, location: location) - return Int(round(monthStartDate.distance(to: monthEndDate) / 86400)) - } - - var startHour: Date { - _startHour - } - - var endHour: Date { - _endHour - } - - func sunPosition(time: Date) -> Double { - func interpolate(f1: Double, f2: Double, f3: Double, y: Double) -> Double { - let a = f2 - f1 - let b = f3 - f2 - a - let ba = b - 2 * a - return (ba + sqrt(pow(ba, 2) + 8 * b * (y - f1))) / (4 * b) - } - var i = 0 - while (i + 1 < _solarTerms.count) && (time > _solarTerms[i + 1]) { - i += 1 - } - if i <= _solarTerms.count / 2 { - return (Double(i) + interpolate(f1: 0, f2: _solarTerms[i].distance(to: _solarTerms[i + 1]), f3: _solarTerms[i].distance(to: _solarTerms[i + 2]), y: _solarTerms[i].distance(to: time)) * 2) / 24 - } else { - return (Double(i) + (interpolate(f1: 0, f2: _solarTerms[i - 2].distance(to: _solarTerms[i - 1]), f3: _solarTerms[i - 2].distance(to: _solarTerms[i]), y: _solarTerms[i - 2].distance(to: time)) - 1) * 2) / 24 - } - } - - var currentDayInYear: Double { - _solarTerms[0].distance(to: _time) / _year_length - } - - var currentDayInMonth: Double { - if _globalMonth { - let monthLength = _moonEclipses[_precise_month].distance(to: _moonEclipses[_precise_month + 1]) - return _moonEclipses[_precise_month].distance(to: _time) / monthLength - } else { - let monthStart = calendar.startOfDay(for: _moonEclipses[_month], apparent: apparentTime, location: location) - let monthEnd = calendar.startOfDay(for: _moonEclipses[_month + 1], apparent: apparentTime, location: location) - return monthStart.distance(to: _time) / monthStart.distance(to: monthEnd) - } - } - - var currentHourInDay: Double { - startOfDay.distance(to: _time) / startOfDay.distance(to: startOfNextDay) - } - - var subhourInHour: Double { - startHour.distance(to: _time) / startHour.distance(to: endHour) - } - - var startOfDay: Date { - _calendar.startOfDay(for: _time, apparent: apparentTime, location: location) - } - - var startOfNextDay: Date { - let nextDay = startOfDay + 86400 * 1.5 - return _calendar.startOfDay(for: nextDay, apparent: apparentTime, location: location) - } - - var planetPosition: [NamedPosition] { - var planetPosition = planetPos(T: fromJD2000(date: _time) / 36525).enumerated().map { NamedPosition(name: planetNames[$0.offset], pos: $0.element) } - let moonPosition = NamedPosition(name: planetNames[planetNames.count-1], pos: moonElipticPosition(D: fromJD2000(date: _time))) - planetPosition.append(moonPosition) - return planetPosition.map { NamedPosition(name: $0.name, pos: ($0.pos / Double.pi / 2 + 0.25) % 1.0) } - } - - var eventInMonth: CelestialEvent { - let monthStart: Date - let monthLength: Double - if _globalMonth { - monthStart = _moonEclipses[_precise_month] - monthLength = _moonEclipses[_precise_month].distance(to: _moonEclipses[_precise_month + 1]) - } else { - monthStart = _calendar.startOfDay(for: _moonEclipses[_month], apparent: apparentTime, location: location) - let monthEnd = _calendar.startOfDay(for: _moonEclipses[_month + 1], apparent: apparentTime, location: location) - monthLength = monthStart.distance(to: monthEnd) - } - var event = CelestialEvent() - if !_globalMonth { - event.eclipse = _moonEclipses.map { date in - NamedPosition(name: Self.moonPhases[0], pos: monthStart.distance(to: date) / monthLength) - }.filter { $0.pos >= 0 && $0.pos < 1 } - } - event.fullMoon = _fullMoons.map { date in - NamedPosition(name: Self.moonPhases[1], pos: monthStart.distance(to: date) / monthLength) - }.filter { $0.pos >= 0 && $0.pos < 1 } - event.evenSolarTerm = _evenSolarTerms.enumerated().map { offset, date in - let name = String(Self.evenSolarTermChinese[(offset - 1) %% Self.evenSolarTermChinese.count].replacingOccurrences(of: " ", with: "")) - return NamedPosition(name: name, pos: monthStart.distance(to: date) / monthLength) - }.filter { $0.pos >= 0 && $0.pos < 1 } - event.oddSolarTerm = _oddSolarTerms.enumerated().map { offset, date in - let name = String(Self.oddSolarTermChinese[(offset - 1) %% Self.oddSolarTermChinese.count].replacingOccurrences(of: " ", with: "")) - return NamedPosition(name: name, pos: monthStart.distance(to: date) / monthLength) - }.filter { $0.pos >= 0 && $0.pos < 1 } - return event + var eventInMonth: CelestialEvent { + let monthStart: Date + let monthLength: Double + if _globalMonth { + monthStart = _moonEclipses[_precise_month] + monthLength = _moonEclipses[_precise_month].distance(to: _moonEclipses[_precise_month + 1]) + } else { + monthStart = _calendar.startOfDay(for: _moonEclipses[_month], apparent: apparentTime, location: location) + let monthEnd = _calendar.startOfDay(for: _moonEclipses[_month + 1], apparent: apparentTime, location: location) + monthLength = monthStart.distance(to: monthEnd) + } + var event = CelestialEvent() + if !_globalMonth { + event.eclipse = _moonEclipses.map { date in + NamedPosition(name: Self.moonPhases.newmoon, pos: monthStart.distance(to: date) / monthLength) + }.filter { $0.pos >= 0 && $0.pos < 1 } + } + event.fullMoon = _fullMoons.map { date in + NamedPosition(name: Self.moonPhases.fullmoon, pos: monthStart.distance(to: date) / monthLength) + }.filter { $0.pos >= 0 && $0.pos < 1 } + event.evenSolarTerm = _evenSolarTerms.enumerated().map { offset, date in + let name = String(Self.evenSolarTermChinese[(offset - 1) %% Self.evenSolarTermChinese.count].replacingOccurrences(of: " ", with: "")) + return NamedPosition(name: name, pos: monthStart.distance(to: date) / monthLength) + }.filter { $0.pos >= 0 && $0.pos < 1 } + event.oddSolarTerm = _oddSolarTerms.enumerated().map { offset, date in + let name = String(Self.oddSolarTermChinese[(offset - 1) %% Self.oddSolarTermChinese.count].replacingOccurrences(of: " ", with: "")) + return NamedPosition(name: name, pos: monthStart.distance(to: date) / monthLength) + }.filter { $0.pos >= 0 && $0.pos < 1 } + return event } var eventInDay: CelestialEvent { @@ -1444,10 +524,10 @@ extension Array { let lengthOfDay = startOfDay.distance(to: startOfNextDay) var event = CelestialEvent() event.eclipse = _moonEclipses.map { date in - NamedPosition(name: Self.moonPhases[0], pos: startOfDay.distance(to: date) / lengthOfDay) + NamedPosition(name: Self.moonPhases.newmoon, pos: startOfDay.distance(to: date) / lengthOfDay) }.filter { $0.pos >= 0 && $0.pos < 1 } event.fullMoon = _fullMoons.map { date in - NamedPosition(name: Self.moonPhases[1], pos: startOfDay.distance(to: date) / lengthOfDay) + NamedPosition(name: Self.moonPhases.fullmoon, pos: startOfDay.distance(to: date) / lengthOfDay) }.filter { $0.pos >= 0 && $0.pos < 1 } event.evenSolarTerm = _evenSolarTerms.enumerated().map { offset, date in let name = String(Self.evenSolarTermChinese[(offset - 1) %% Self.evenSolarTermChinese.count].replacingOccurrences(of: " ", with: "")) @@ -1464,10 +544,10 @@ extension Array { var event = CelestialEvent() let hourLength = startHour.distance(to: endHour) event.eclipse = _moonEclipses.map { date in - NamedPosition(name: Self.moonPhases[0], pos: startHour.distance(to: date) / hourLength) + NamedPosition(name: Self.moonPhases.newmoon, pos: startHour.distance(to: date) / hourLength) }.filter { $0.pos >= 0 && $0.pos < 1 } event.fullMoon = _fullMoons.map { date in - NamedPosition(name: Self.moonPhases[1], pos: startHour.distance(to: date) / hourLength) + NamedPosition(name: Self.moonPhases.fullmoon, pos: startHour.distance(to: date) / hourLength) }.filter { $0.pos >= 0 && $0.pos < 1 } event.evenSolarTerm = _evenSolarTerms.enumerated().map { offset, date in let name = String(Self.evenSolarTermChinese[(offset - 1) %% Self.evenSolarTermChinese.count].replacingOccurrences(of: " ", with: "")) @@ -1480,163 +560,869 @@ extension Array { return event } - private func datesToNamedDates(dates: [Date?], names: [String]) -> [NamedDate?] { - return dates.enumerated().map { offset, element in - if let date = element { - return NamedDate(name: names[offset %% names.count], date: date) - } else { - return nil - } - } - } - - var sunTimes: [NamedDate] { - let chineseCalendar = copy - let startOfDay = startOfDay - let startOfNextDay = startOfNextDay - if let location = location { - let today = datesToNamedDates(dates: intraday_solar_times(chineseCalendar: chineseCalendar, location: location), names: Self.dayTimeName) - chineseCalendar.update(time: startOfDay - 12 * 3600, timezone: _calendar.timeZone, location: location) - let previousDay = datesToNamedDates(dates: intraday_solar_times(chineseCalendar: chineseCalendar, location: location), names: Self.dayTimeName) - chineseCalendar.update(time: startOfNextDay + 12 * 3600, timezone: _calendar.timeZone, location: location) - let nextDay = datesToNamedDates(dates: intraday_solar_times(chineseCalendar: chineseCalendar, location: location), names: Self.dayTimeName) - var times = previousDay.filter { $0 != nil && $0!.date < startOfDay } - times += today.filter { $0 != nil && $0!.date >= startOfDay && $0!.date < startOfNextDay } - times += nextDay.filter { $0 != nil && $0!.date >= startOfNextDay } - return times.map { $0! } - } else { - return [] - } - } - - var moonTimes: [NamedDate] { - let chineseCalendar = copy - let startOfDay = startOfDay - let startOfNextDay = startOfNextDay - if let location = location { - let today = datesToNamedDates(dates: intraday_lunar_times(chineseCalendar: chineseCalendar, location: location), names: Self.moonTimeName) - chineseCalendar.update(time: startOfDay - 12 * 3600, timezone: _calendar.timeZone, location: location) - let previousDay = datesToNamedDates(dates: intraday_lunar_times(chineseCalendar: chineseCalendar, location: location), names: Self.moonTimeName) - chineseCalendar.update(time: startOfNextDay + 12 * 3600, timezone: _calendar.timeZone, location: location) - let nextDay = datesToNamedDates(dates: intraday_lunar_times(chineseCalendar: chineseCalendar, location: location), names: Self.moonTimeName) - var times = previousDay.filter { $0 != nil && $0!.date < startOfDay } - times += today.filter { $0 != nil && $0!.date >= startOfDay && $0!.date < startOfNextDay } - times += nextDay.filter { $0 != nil && $0!.date >= startOfNextDay } - return times.map { $0! } - } else { - return [] + func getSunTimes(for dateType: DateType) -> Solar { + if let existing = _sunTimes[dateType] { + return existing } - } - - var sunMoonPositions: DailyEvent { - var dailyEvent = DailyEvent() + var event = Solar(midnight: nil, sunrise: nil, noon: nil, sunset: nil) if let location = location { - _sunTimes = intraday_solar_times(chineseCalendar: self, location: location) - _moonTimes = intraday_lunar_times(chineseCalendar: self, location: location) - let startOfDay = startOfDay - let startOfNextDay = startOfNextDay - let lengthOfDay = startOfDay.distance(to: startOfNextDay) - func dayEventMapping(date: Date?) -> Double? { - if let date = date, date >= startOfDay && date < startOfNextDay { - return startOfDay.distance(to: date) / lengthOfDay - } else { - return nil + let (start, end) = getStartEnd(type: dateType) + let mid = start + start.distance(to: end) / 2 + if !apparentTime { + if let midnight = meridianTime(around: start, at: location, type: .midnight), midnight >= start && midnight < end { + event.midnight = .init(name: Self.dayTimeName.midnight, date: midnight) + } else if let midnight = meridianTime(around: end, at: location, type: .midnight), midnight >= start && midnight < end { + event.midnight = .init(name: Self.dayTimeName.midnight, date: midnight) } - } - dailyEvent.solar = _sunTimes.enumerated().map { offset, date in - if let pos = dayEventMapping(date: date) { - return NamedPosition(name: Self.dayTimeName[offset %% Self.dayTimeName.count], pos: pos) - } else { - return nil + if let noon = meridianTime(around: mid, at: location, type: .noon), noon >= start && noon < end { + event.noon = .init(name: Self.dayTimeName.noon, date: noon) } } - dailyEvent.lunar = _moonTimes.enumerated().map { offset, date in - if let pos = dayEventMapping(date: date) { - return NamedPosition(name: Self.moonTimeName[offset %% Self.moonTimeName.count], pos: pos) - } else { - return nil - } + if let sunrise = riseSetTime(around: mid, at: location, type: .sunrise), sunrise >= start && sunrise < end { + event.sunrise = .init(name: Self.dayTimeName.sunrise, date: sunrise) } - if apparentTime { - dailyEvent.solar[0] = nil - dailyEvent.solar[2] = nil - dailyEvent.solar[dailyEvent.solar.count - 1] = nil + if let sunset = riseSetTime(around: mid, at: location, type: .sunset), sunset >= start && sunset < end { + event.sunset = .init(name: Self.dayTimeName.sunset, date: sunset) } } - return dailyEvent + _sunTimes[dateType] = event + return event } - var sunMoonSubhourPositions: DailyEvent { - var dailyEvent = DailyEvent() - func hourEventMapping(date: Date?) -> Double? { - if let date = date, date >= startHour && date < endHour { - return startHour.distance(to: date) / startHour.distance(to: endHour) - } else { - return nil - } + func getMoonTimes(for dateType: DateType) -> Lunar { + if let existing = _moonTimes[dateType] { + return existing } + var event = Lunar(moonrise: nil, highMoon: nil, moonset: nil) if let location = location { - if _sunTimes.count == 0 || _moonTimes.count == 0 { - _sunTimes = intraday_solar_times(chineseCalendar: self, location: location) - _moonTimes = intraday_lunar_times(chineseCalendar: self, location: location) + let (start, end) = getStartEnd(type: dateType) + if let moonrise = riseSetTime(around: start, at: location, type: .moonrise), moonrise >= start && moonrise < end { + event.moonrise = .init(name: Self.moonTimeName.moonrise, date: moonrise) + } else if let moonrise = riseSetTime(around: end, at: location, type: .moonrise), moonrise >= start && moonrise < end { + event.moonrise = .init(name: Self.moonTimeName.moonrise, date: moonrise) } - dailyEvent.solar = _sunTimes.enumerated().map { offset, date in - if let pos = hourEventMapping(date: date) { - return NamedPosition(name: Self.dayTimeName[offset %% Self.dayTimeName.count], pos: pos) - } else { - return nil - } - } - dailyEvent.lunar = _moonTimes.enumerated().map { offset, date in - if let pos = hourEventMapping(date: date) { - return NamedPosition(name: Self.moonTimeName[offset %% Self.moonTimeName.count], pos: pos) - } else { - return nil - } + if let highMoon = meridianTime(around: start, at: location, type: .highMoon), highMoon >= start && highMoon < end { + event.highMoon = .init(name: Self.moonTimeName.highMoon, date: highMoon) + } else if let highMoon = meridianTime(around: end, at: location, type: .highMoon), highMoon >= start && highMoon < end { + event.highMoon = .init(name: Self.moonTimeName.highMoon, date: highMoon) } - if apparentTime { - dailyEvent.solar[0] = nil - dailyEvent.solar[2] = nil - dailyEvent.solar[dailyEvent.solar.count - 1] = nil + if let moonset = riseSetTime(around: start, at: location, type: .moonset), moonset >= start && moonset < end { + event.moonset = .init(name: Self.moonTimeName.moonset, date: moonset) + } else if let moonset = riseSetTime(around: end, at: location, type: .moonset), moonset >= start && moonset < end { + event.moonset = .init(name: Self.moonTimeName.moonset, date: moonset) } } + _moonTimes[dateType] = event + return event + } + + var sunMoonPositions: DailyEvent { + var dailyEvent = DailyEvent() + if location != nil { + let start = startOfDay + let end = startOfNextDay + // sun + let sunEvent = getSunTimes(for: .current) + dailyEvent.solar = Solar(midnight: nil, sunrise: nil, noon: nil, sunset: nil) + dailyEvent.solar.midnight = sunEvent.midnight?.toPositionBetween(start: start, end: end) + dailyEvent.solar.sunrise = sunEvent.sunrise?.toPositionBetween(start: start, end: end) + dailyEvent.solar.noon = sunEvent.noon?.toPositionBetween(start: start, end: end) + dailyEvent.solar.sunset = sunEvent.sunset?.toPositionBetween(start: start, end: end) + // moon + let moonEvent = getMoonTimes(for: .current) + dailyEvent.lunar = Lunar(moonrise: nil, highMoon: nil, moonset: nil) + dailyEvent.lunar.moonrise = moonEvent.moonrise?.toPositionBetween(start: start, end: end) + dailyEvent.lunar.highMoon = moonEvent.highMoon?.toPositionBetween(start: start, end: end) + dailyEvent.lunar.moonset = moonEvent.moonset?.toPositionBetween(start: start, end: end) + } return dailyEvent } - - var lunarHoliday: String? { - for holiday in Self.holidays.keys { - if self.equals(date: holiday) { - return Self.holidays[holiday] - } + + var sunMoonSubhourPositions: DailyEvent { + var dailyEvent = DailyEvent() + if location != nil { + let start = startHour + let end = endHour + // sun + let sunEvent = getSunTimes(for: .current) + dailyEvent.solar = Solar(midnight: nil, sunrise: nil, noon: nil, sunset: nil) + dailyEvent.solar.midnight = sunEvent.midnight?.toPositionBetween(start: start, end: end) + dailyEvent.solar.sunrise = sunEvent.sunrise?.toPositionBetween(start: start, end: end) + dailyEvent.solar.noon = sunEvent.noon?.toPositionBetween(start: start, end: end) + dailyEvent.solar.sunset = sunEvent.sunset?.toPositionBetween(start: start, end: end) + // moon + let moonEvent = getMoonTimes(for: .current) + dailyEvent.lunar = Lunar(moonrise: nil, highMoon: nil, moonset: nil) + dailyEvent.lunar.moonrise = moonEvent.moonrise?.toPositionBetween(start: start, end: end) + dailyEvent.lunar.highMoon = moonEvent.highMoon?.toPositionBetween(start: start, end: end) + dailyEvent.lunar.moonset = moonEvent.moonset?.toPositionBetween(start: start, end: end) } - return nil + return dailyEvent } - - var holidays: [String] { - var holidays: [String] = [] - if let holiday = self.lunarHoliday { - holidays.append(holiday) +} + +// Ticks +extension ChineseCalendar { + var monthTicks: Ticks { + let months = self.monthNames + var ticks = Ticks() + var monthDivides: [Double] + if _globalMonth { + monthDivides = _moonEclipses.map { _solarTerms[0].distance(to: $0) / _year_length } + } else { + monthDivides = _moonEclipses.map { _solarTerms[0].distance(to: _calendar.startOfDay(for: $0, apparent: apparentTime, location: location)) / _year_length } } - for solarTerm in self.eventInDay.oddSolarTerm { - holidays.append(solarTerm.name) + monthDivides = monthDivides.filter { $0 > 0 && $0 <= 1 } + guard months.count == monthDivides.count else { return ticks } + var previousMonthDivide = 0.0 + var monthNames = [Ticks.TickName]() + let minMonthLength: Double = (_compact ? 0.009 : 0.006) + for i in 0.. minMonthLength * Double(months[i].count) { + monthNames.append(Ticks.TickName( + pos: position, + name: months[i], + active: previousMonthDivide <= currentDayInYear + )) + } + previousMonthDivide = monthDivides[i] } - for solarTerm in self.eventInDay.evenSolarTerm { - holidays.append(solarTerm.name) + if let lastDivide = monthDivides.last, lastDivide < 1 { + let position = (1 + previousMonthDivide) / 2 + if position - previousMonthDivide > minMonthLength * Double(months[0].count) { + monthNames.append(Ticks.TickName( + pos: position, + name: months[0], + active: previousMonthDivide <= currentDayInYear + )) + } + } else { + _ = monthDivides.popLast() } - for moon in self.eventInDay.eclipse { - holidays.append(moon.name) + + ticks.majorTicks = [0] + monthDivides + ticks.majorTickNames = monthNames + ticks.minorTicks = _fullMoons.map { _solarTerms[0].distance(to: $0) / _year_length }.filter { ($0 < 1) && ($0 > 0) } + return ticks + } + + var dayTicks: Ticks { + var ticks = Ticks() + + let monthStart: Date + let monthEnd: Date + var date: Date + if _globalMonth { + monthStart = _moonEclipses[_precise_month] + monthEnd = _moonEclipses[_precise_month + 1] + date = _calendar.startOfDay(for: monthStart, apparent: apparentTime, location: location) + } else { + monthStart = _calendar.startOfDay(for: _moonEclipses[_month], apparent: apparentTime, location: location) + monthEnd = _calendar.startOfDay(for: _moonEclipses[_month + 1], apparent: apparentTime, location: location) + date = monthStart } - for moon in self.eventInDay.fullMoon { - holidays.append(moon.name) + + var dayDivides = [Date]() + while date < monthEnd { + if apparentTime { + date += 86400 * 1.5 + date = _calendar.startOfDay(for: date, apparent: apparentTime, location: location) + } else { + date = _calendar.date(byAdding: .day, value: 1, to: date)! + } + dayDivides.append(date) } - return holidays - } - - func equals(date: ChineseDate) -> Bool { - if date.day > 0 { - return date.leap == isLeapMonth && date.month == nominalMonth && date.day == day + let majorTicks: [Double] = dayDivides.map { monthStart.distance(to: $0) / monthStart.distance(to: monthEnd) }.filter { $0 > 0 && $0 < 1 } + + let allDayNames: [String] + if _compact { + allDayNames = Self.day_chinese_compact.slice(to: numberOfDaysInMonth) + [Self.day_chinese_compact[0]] } else { - return date.leap == isLeapMonth && date.month == nominalMonth && date.day == day - numberOfDaysInMonth - 1 + allDayNames = Self.day_chinese.slice(to: numberOfDaysInMonth) + [Self.day_chinese[0]] } + + var dayNames = [Ticks.TickName]() + var previousDayDivide = 0.0 + let minDayLength = (_compact ? 0.009 : 0.006) + for i in 0.. minDayLength * Double(allDayNames[i].count) { + dayNames.append(Ticks.TickName( + pos: position, + name: allDayNames[i], + active: previousDayDivide <= currentDayInMonth + )) + } + previousDayDivide = majorTicks[i] + } + let position = (1 + previousDayDivide) / 2 + if position - previousDayDivide > minDayLength * Double(allDayNames[majorTicks.count].count) { + dayNames.append(Ticks.TickName( + pos: position, + name: allDayNames[majorTicks.count], + active: previousDayDivide <= currentDayInMonth + )) + } + ticks.majorTicks = [0] + majorTicks + ticks.majorTickNames = dayNames + return ticks + } + + var hourTicks: Ticks { + let startOfDay = startOfDay + let startOfNextDay = startOfNextDay + var ticks = Ticks() + var hourDivides = [Double]() + var quarterTick = [Double]() + var quarter = 0.0 + while quarter < 1.0 { + quarterTick.append(quarter) + quarter += 864 / startOfDay.distance(to: startOfNextDay) + } + quarterTick = Array(Set(quarterTick).subtracting(hourDivides)).sorted() + var hourNames = [Ticks.TickName]() + var hourStart = startOfDay + + for namedHour in _hourNames { + if namedHour.hour >= startOfDay && namedHour.hour < startOfNextDay { + let dividePos = startOfDay.distance(to: namedHour.hour) / startOfDay.distance(to: startOfNextDay) + if !namedHour.longName.isEmpty { + hourDivides.append(dividePos) + } + if _largeHour || !namedHour.shortName.isEmpty { + if _largeHour { + hourStart = namedHour.hour + } + hourNames.append(Ticks.TickName( + pos: dividePos, + name: namedHour.shortName, + active: hourStart <= _time + )) + } else { + if !namedHour.longName.isEmpty { + hourStart = namedHour.hour + } + } + } + } + ticks.majorTicks = hourDivides + ticks.majorTickNames = hourNames + ticks.minorTicks = quarterTick + return ticks + } + + var subhourTicks: Ticks { + let startHour = startHour + let endHour = endHour + var ticks = Ticks() + var subHourTicks = Set() + var majorTickNames = [String]() + for namedHour in _hourNamesInCurrentHour { + majorTickNames.append(namedHour.longName) + let distPos = startHour.distance(to: namedHour.hour) / startHour.distance(to: endHour) + if distPos >= 0.0 && distPos < 1.0 { + subHourTicks.insert(distPos) + } + } + + let majorTicks = subHourTicks + for tickTime in _subhours { + let distPos = startHour.distance(to: tickTime) / startHour.distance(to: endHour) + if distPos >= 0.0 && distPos < 1.0 { + subHourTicks.insert(distPos) + } + } + + let minimumSubhourLength = _compact ? 0.045 : 0.03 + var subHourNames = [Ticks.TickName]() + var count = 1 + var j = 0 + let subHourTick = Array(subHourTicks).sorted() + for i in 0.. minimumSubhourLength { + subHourNames.append(Ticks.TickName( + pos: subHourTick[i], + name: Self.chinese_numbers[count], + active: subHourTick[i] <= subhourInHour + )) + } + count += 1 + } + } + + var subQuarterTicks = Set() + for tickTime in _subhourMinors { + subQuarterTicks.insert(startHour.distance(to: tickTime) / startHour.distance(to: endHour)) + } + subQuarterTicks = subQuarterTicks.subtracting(subHourTicks) + let subQuarterTick = Array(subQuarterTicks).sorted() + + ticks.majorTicks = subHourTick + ticks.majorTickNames = subHourNames + ticks.minorTicks = subQuarterTick + return ticks + } +} + +// Structs +extension ChineseCalendar { + struct ChineseDate: Hashable { + var month: Int + var day: Int + var leap: Bool = false + + static func == (lhs: ChineseDate, rhs: ChineseDate) -> Bool { + lhs.month == rhs.month && lhs.day == rhs.day && lhs.leap == rhs.leap + } + } + struct Hour { + enum HourFormat { + case full + case partial(index: Int) + } + var hour: Int + var format: HourFormat + var string: String { + guard (0.. 0 { + str += ChineseCalendar.chinese_numbers[minorTick] + } + return str + } + } + + struct NamedHour { + let hour: Date + let shortName: String + let longName: String + } + + struct NamedPosition: NamedPoint { + let name: String + let pos: Double + } + + struct NamedDate { + let name: String + let date: Date + func toPositionBetween(start: Date, end: Date) -> NamedPosition? { + guard date >= start && date < end else { return nil } + let position = start.distance(to: date) / start.distance(to: end) + return NamedPosition(name: name, pos: position) + } + } + + struct CelestialEvent { + var eclipse = [NamedPosition]() + var fullMoon = [NamedPosition]() + var oddSolarTerm = [NamedPosition]() + var evenSolarTerm = [NamedPosition]() + } + + struct DailyEvent { + var solar = Solar(midnight: nil, sunrise: nil, noon: nil, sunset: nil) + var lunar = Lunar(moonrise: nil, highMoon: nil, moonset: nil) + } + + enum DateType { + case current, previous, next + } + + struct Ticks { + struct TickName: NamedPoint { + var pos: Double = 0.0 + var name: String = "" + var active: Bool = false + } + + var majorTicks = [Double]() + var majorTickNames = [TickName]() + var minorTicks = [Double]() + } +} + +fileprivate extension ChineseCalendar { + func updateYear() { + var year = calendar.component(.year, from: time) + var solar_terms = solar_terms_in_year(year + 1) + if solar_terms[0] <= time { + year += 1 + solar_terms += solar_terms_in_year(year + 1)[0...4] + } else { + var solar_terms_current_year = solar_terms_in_year(year) + solar_terms_current_year += solar_terms[0...4] + solar_terms = solar_terms_current_year + } + let solar_terms_previous_year = solar_terms_in_year(year - 1) + + let (moon_phase_previous_year, first_event) = moon_phase_in_year(year - 1) + var (moon_phase, _) = moon_phase_in_year(year) + let (moon_phase_next_year, _) = moon_phase_in_year(year + 1) + moon_phase = moon_phase_previous_year + moon_phase + moon_phase_next_year + var eclipse = moon_phase.slice(from: Int(first_event), step: 2) + var fullMoon = moon_phase.slice(from: Int(1 - first_event), step: 2) + var start: Int?, end: Int? + for i in 0..= solar_terms[0] { + start = i - 1 + } + if end == nil, eclipseDate > solar_terms[24] { + end = i + } + } + eclipse = eclipse.slice(from: start!, to: end! + 2) + fullMoon = fullMoon.filter { $0 < eclipse.last! && $0 > eclipse[0] } + let evenSolarTerms = solar_terms.slice(step: 2) + + var i = 0 + var j = 0 + var count = 0 + var solatice_in_month = [Int]() + var monthCount = Set() + while i + 1 < eclipse.count, j < evenSolarTerms.count { + let thisEclipse: Date + let nextEclipse: Date + if _globalMonth { + thisEclipse = eclipse[i] + nextEclipse = eclipse[i + 1] + } else { + thisEclipse = calendar.startOfDay(for: eclipse[i], apparent: apparentTime, location: location) + nextEclipse = calendar.startOfDay(for: eclipse[i + 1], apparent: apparentTime, location: location) + } + if thisEclipse <= evenSolarTerms[j], nextEclipse > evenSolarTerms[j] { + count += 1 + j += 1 + } else { + solatice_in_month.append(count) + count = 0 + i += 1 + } + if thisEclipse > solar_terms[0], thisEclipse <= solar_terms[24] { + monthCount.insert(thisEclipse) + } + } + + var leap_month = -1 + if monthCount.count > 12 { + for i in 0.. startOfDate { + break + } + i += 1 + } + var j = 0 + while j < _moonEclipses.count - 1 { + if _moonEclipses[j] > _time { + break + } + j += 1 + } + let previousEclipse = _calendar.startOfDay(for: _moonEclipses[i - 1], apparent: apparentTime, location: location) + let startOfDate = _calendar.startOfDay(for: _time, apparent: apparentTime, location: location) + let date_diff = Int(round(previousEclipse.distance(to: startOfDate) / 86400)) + _month = i - 1 + _precise_month = j - 1 + _day = date_diff + } + + func updateHour() { + let startOfDay = startOfDay + let startOfNextDay = startOfNextDay + var tempStartHour: Date? + var tempEndHour: Date? + var hour = if apparentTime { + startOfDay - 2 * startOfDay.distance(to: startOfNextDay) / 24 + } else { + _calendar.date(byAdding: .hour, value: -2, to: startOfDay)! + } + let end = if apparentTime { + startOfNextDay + 2 * startOfDay.distance(to: startOfNextDay) / 24 + } else { + _calendar.date(byAdding: .hour, value: 2, to: startOfNextDay)! + } + _hourNames = [] + var prevHourName = "" + var prevOffsetHourName = "" + var prevLongName = "" + while hour < end { + let hourIndex = if apparentTime { + Int(round(startOfDay.distance(to: hour) / startOfDay.distance(to: startOfNextDay) * 24)) + } else { + _calendar.component(.hour, from: hour) + } + let hourName = Self.terrestrial_branches[(hourIndex /% 2) %% 12] + let offsetHourName = Self.terrestrial_branches[((hourIndex + 1) /% 2) %% 12] + if !_largeHour || hourName != prevHourName { + let shortName = if hourName != prevHourName { + ChineseCalendar.terrestrial_branches[(hourIndex /% 2) %% 12] + } else { + "" + } + let longName: String + if _largeHour { + if hourName != prevHourName { + longName = Self.terrestrial_branches[(hourIndex /% 2) %% 12] + } else { + longName = "" + } + } else { + let name = Self.terrestrial_branches[((hourIndex + 1) /% 2) %% 12] + Self.sub_hour_name[(hourIndex + 1) %% 2] + if name != prevLongName { + prevLongName = name + longName = name + } else { + longName = "" + } + } + _hourNames.append(NamedHour(hour: hour, shortName: shortName, longName: longName)) + } + if hour <= _time { + if _largeHour { + _hour = Hour(hour: (hourIndex /% 2) %% 12, format: .full) + } else { + _hour = Hour(hour: ((hourIndex + 1) /% 2) %% 12, format: .partial(index: (hourIndex + 1) %% 2)) + } + } + let changeOfHour = if _largeHour { + hourName != prevHourName + } else { + offsetHourName != prevOffsetHourName + } + if changeOfHour, hour <= _time { + tempStartHour = hour + } + if changeOfHour, hour > _time, tempEndHour == nil { + tempEndHour = hour + } + if apparentTime { + hour += startOfDay.distance(to: startOfNextDay) / 24 + } else { + hour = _calendar.date(byAdding: .hour, value: 1, to: hour)! + } + prevHourName = hourName + prevOffsetHourName = offsetHourName + } + _startHour = tempStartHour! + _endHour = tempEndHour! + _sunTimes = [:] + _moonTimes = [:] + _planets = nil + } + + func updateSubHour() { + _hourNamesInCurrentHour = [] + _subhours = [] + _subhourMinors = [] + + var currentSmallHour = startHour + for namedHour in _hourNames { + if !namedHour.longName.isEmpty && namedHour.hour >= startHour && namedHour.hour < endHour { + _hourNamesInCurrentHour.append(namedHour) + if namedHour.hour <= _time { + currentSmallHour = namedHour.hour + } + } + } + + var majorTickCount = 0 + var tickTime = startOfDay - 864 * 6 + var currentSubhour = currentSmallHour + while tickTime < endHour - 16 { + if tickTime > startHour + 16 { + _subhours.append(tickTime) + } + if tickTime > currentSmallHour && time >= tickTime { + currentSubhour = tickTime + majorTickCount += 1 + } + tickTime += 864 + } + + var minorTickCount = 0 + tickTime = startOfDay - 864 * 6 + while tickTime < endHour { + if tickTime > startHour { + _subhourMinors.append(tickTime) + } + if tickTime > currentSubhour && time >= tickTime { + minorTickCount += 1 + } + tickTime += 144 + } + _quarter = SubHour(majorTick: majorTickCount, minorTick: minorTickCount) + } + + func getStartEnd(type: DateType) -> (start: Date, end: Date) { + let start: Date + let end: Date + switch type { + case .current: + start = startOfDay + end = startOfNextDay + case .previous: + end = startOfDay + start = _calendar.startOfDay(for: end - 3600, apparent: apparentTime, location: location) + case .next: + start = startOfNextDay + end = _calendar.startOfDay(for: start + 90000, apparent: apparentTime, location: location) + } + return (start: start, end: end) + } + + func equals(date: ChineseDate) -> Bool { + if date.day > 0 { + return date.leap == isLeapMonth && date.month == nominalMonth && date.day == day + } else { + return date.leap == isLeapMonth && date.month == nominalMonth && date.day == day - numberOfDaysInMonth - 1 + } + } +} + +fileprivate extension ChineseCalendar { + func getJD(yyyy: Int, mm: Int, dd: Int) -> Double { + var m1 = mm + var yy = yyyy + if m1 <= 2 { + m1 = m1 + 12 + yy = yy - 1 + } + // Gregorian calendar + let b = yy / 400 - yy / 100 + yy / 4 + let jd = Double(365 * yy - 679004 + b) + floor(30.6001 * Double(m1 + 1)) + Double(dd) + 2400000.5 + return jd + } + + func DeltaT_spline_y(_ y: Double) -> Double { + func phase(x: Double) -> Double { + let t = x - 1825 + return 0.00314115 * t * t + 284.8435805251424 * cos(0.4487989505128276 * (0.01 * t + 0.75)) + } + if y < -720 { + let const = 1.007739546148514 + return phase(x: y) + const + } else if y > 2019 { + let const: Double = -150.263031657016 + return phase(x: y) + const + } + let n = [-720, -100, 400, 1000, 1150, 1300, 1500, 1600, 1650, 1720, 1800, 1810, 1820, 1830, 1840, 1850, 1855, 1860, 1865, 1870, 1875, 1880, 1885, 1890, 1895, 1900, 1905, 1910, 1915, 1920, 1925, 1930, 1935, 1940, 1945, 1950, 1953, 1956, 1959, 1962, 1965, 1968, 1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004, 2007, 2010, 2013, 2016] + + var l = n.count - 1 + while l >= 0 && !(y >= Double(n[l])) { + l -= 1 + } + + let year_splits = [-100, 400, 100, 1150, 1300, 1500, 1600, 1650, 1720, 1800, 1810, 1820, 1830, 1840, 1850, 1855, 1860, 1865, 1870, 1875, 1880, 1885, 1890, 1895, 1900, 1905, 1910, 1915, 1920, 1925, 1930, 1935, 1940, 1945, 1950, 1953, 1956, 1959, 1962, 1965, 1968, 1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004, 2007, 2010, 2013, 2016, 2019] + let r = (y - Double(n[l])) / Double(year_splits[l] - n[l]) + let coef1: [Double] = [20371.848, 11557.668, 6535.116, 1650.393, 1056.647, 681.149, 292.343, 109.127, 43.952, 12.068, 18.367, 15.678, 16.516, 10.804, 7.634, 9.338, 10.357, 9.04, 8.255, 2.371, -1.126, -3.21, -4.388, -3.884, -5.017, -1.977, 4.923, 11.142, 17.479, 21.617, 23.789, 24.418, 24.164, 24.426, 27.05, 28.932, 30.002, 30.76, 32.652, 33.621, 35.093, 37.956, 40.951, 44.244, 47.291, 50.361, 52.936, 54.984, 56.373, 58.453, 60.678, 62.898, 64.083, 64.553, 65.197, 66.061, 66.92, 68.109] + let coef2: [Double] = [-9999.586, -5822.27, -5671.519, -753.21, -459.628, -421.345, -192.841, -78.697, -68.089, 2.507, -3.481, 0.021, -2.157, -6.018, -0.416, 1.642, -0.486, -0.591, -3.456, -5.593, -2.314, -1.893, 0.101, -0.531, 0.134, 5.715, 6.828, 6.33, 5.518, 3.02, 1.333, 0.052, -0.419, 1.645, 2.499, 1.127, 0.737, 1.409, 1.577, 0.868, 2.275, 3.035, 3.157, 3.199, 3.069, 2.878, 2.354, 1.577, 1.648, 2.235, 2.324, 1.804, 0.674, 0.466, 0.804, 0.839, 1.007, 1.277] + let coef3: [Double] = [776.247, 1303.151, -298.291, 184.811, 108.771, 61.953, -6.572, 10.505, 38.333, 41.731, -1.126, 4.629, -6.806, 2.944, 2.658, 0.261, -2.389, 2.284, -5.148, 3.011, 0.269, 0.152, 1.842, -2.474, 3.138, 2.443, -1.329, 0.831, -1.643, -0.856, -0.831, -0.449, -0.022, 2.086, -1.232, 0.22, -0.61, 1.282, -1.115, 0.406, 1.002, -0.242, 0.364, -0.323, 0.193, -0.384, -0.14, -0.637, 0.708, -0.121, 0.21, -0.729, -0.402, 0.194, 0.144, -0.109, 0.277, -0.007] + let coef4: [Double] = [409.16, -503.433, 1085.087, -25.346, -24.641, -29.414, 16.197, 3.018, -2.127, -37.939, 1.918, -3.812, 3.25, -0.096, -0.539, -0.883, 1.558, -2.477, 2.72, -0.914, -0.039, 0.563, -1.438, 1.871, -0.232, -1.257, 0.72, -0.825, 0.262, 0.008, 0.127, 0.142, 0.702, -1.106, 0.614, -0.277, 0.631, -0.799, 0.507, 0.199, -0.414, 0.202, -0.229, 0.172, -0.192, 0.081, -0.165, 0.448, -0.276, 0.11, -0.313, 0.109, 0.199, -0.017, -0.084, 0.128, -0.095, -0.139] + return coef1[l] + r * (coef2[l] + r * (coef3[l] + r * coef4[l])) + } + + // UT -> TT + func DeltaT(T: Double) -> Double { + let t = 36525 * T + 2451545 + if t > 2459580.5 || t < 2441317.5 { + return DeltaT_spline_y(t >= 2299160.5 ? (t - 2451544.5) / 365.2425 + 2000 : (t + 0.5) / 365.25 - 4712) / 86400.0 + } + let l: [Double] = [2457754.5, 2457204.5, 2456109.5, 2454832.5, 2453736.5, 2451179.5, 2450630.5, 2450083.5, 2449534.5, 2449169.5, 2448804.5, 2448257.5, 2447892.5, 2447161.5, 2446247.5, 2445516.5, 2445151.5, 2444786.5, 2444239.5, 2443874.5, 2443509.5, 2443144.5, 2442778.5, 2442413.5, 2442048.5, 2441683.5, 2441499.5, 2441133.5] + let n = l.count + var DT = 42.184 + for i in 0.. l[i] { + DT += Double(n - i - 1) + break + } + } + return DT / 86400.0 + } + + func mod2pi_de(x: Double) -> Double { + return x - 2 * Double.pi * floor(0.5 * x / Double.pi + 0.5) + } + + func decode_solar_terms(y: Int, istart: Int, offset_comp: Int, solar_comp: [Int8]) -> [Date] { + let jd0 = getJD(yyyy: y - 1, mm: 12, dd: 31) - 1.0 / 3 + let delta_T = DeltaT(T: (jd0 - 2451545 + 365.25 * 0.5) / 36525) + let offset = 2451545 - jd0 - delta_T + let w: [Double] = [2 * Double.pi, 6.282886, 12.565772, 0.337563, 83.99505, 77.712164, 5.7533, 3.9301] + let poly_coefs: [Double] + let amp: [Double] + let ph: [Double] + if y > 2500 { + poly_coefs = [-10.60617210417765, 365.2421759265393, -2.701502510496315e-08, 2.303900971263569e-12] + amp = [0.1736157870707964, 1.914572713893651, 0.0113716862045686, 0.004885711219368455, 0.0004032584498264633, 0.001736052092601642, 0.002035081600709588, 0.001360448706185977] + ph = [-2.012792258215681, 2.824063083728992, -0.4826844382278376, 0.9488391363261893, 2.646697770061209, -0.2675341497460084, 0.9646288791219602, -1.808852094435626] + } else if y > 1500 { + poly_coefs = [-10.6111079510509, 365.2421925947405, -3.888654930760874e-08, -5.434707919089998e-12] + amp = [0.1633918030382493, 1.95409759473169, 0.01184405584067255, 0.004842563463555804, 0.0004137082581449113, 0.001732513547029885, 0.002025850272284684, 0.001363226024948773] + ph = [-1.767045717746641, 2.832417615687159, -0.465176623256009, 0.9461667782644696, 2.713020913181211, -0.2031148059020781, 0.9980808019332812, -1.832536089597202] + } else { + poly_coefs = [] + amp = [] + ph = [] + } + + var sterm = [Date]() + for i in 0.. [Date] { + let w = [2 * Double.pi, 6.733776, 13.467552, 0.507989, 0.0273143, 0.507984, 20.201328, 6.225791, 7.24176, 5.32461, 12.058386, 0.901181, 5.832595, 12.56637061435917, 19.300146, 11.665189, 18.398965, 6.791174, 13.636974, 1.015968, 6.903198, 13.07437, 1.070354, 6.340578614359172] + let poly_coefs: [Double] + let amp: [Double] + let ph: [Double] + if y > 2500 { + poly_coefs = [5.093879710922470, 29.53058981687484, 2.670339910922144e-11, 1.807808217274283e-15] + amp = [0.00306380948959271, 6.08567588841838, 0.3023856209133756, 0.07481389897992345, 0.0001587661348338354, 0.1740759063081489, 0.0004131985233772993, 0.005796584475300004, 0.008268929076163079, 0.003256244384807976, 0.000520983165608148, 0.003742624708965854, 1.709506053530008, 28216.70389751519, 1.598844831045378, 0.314745599206173, 6.602993931108911, 0.0003387269181720862, 0.009226112317341887, 0.00196073145843697, 0.001457643607929487, 6.467401779992282e-05, 0.0007716739483064076, 0.001378880922256705] + ph = [-0.0001879456766404132, -2.745704167588171, -2.348884895288619, 1.420037528559222, -2.393586904955103, -0.3914194006325855, 1.183088056748942, -2.782692143601458, 0.4430565056744425, -0.4357413971405519, -3.081209195003025, 0.7945051912707899, -0.4010911170136437, 3.003035462639878e-10, 0.4040070684461441, 2.351831380989509, 2.748612213507844, 3.133002890683667, -0.6902922380876192, 0.09563473131477442, 2.056490394534053, 2.017507533465959, 2.394015964756036, -0.3466427504049927] + } else if y > 1500 { + poly_coefs = [5.097475813506625, 29.53058886049267, 1.095399949433705e-10, -6.926279905270773e-16] + amp = [0.003064332812182054, 0.8973816160666801, 0.03119866094731004, 0.07068988004978655, 0.0001583070735157395, 0.1762683983928151, 0.0004131592685474231, 0.005950873973350208, 0.008489324571543966, 0.00334306526160656, 0.00052946042568393, 0.003743585488835091, 0.2156913373736315, 44576.30467073629, 0.1050203948601217, 0.01883710371633125, 0.380047745859265, 0.0003472930592917774, 0.009225665415301823, 0.002061407071938891, 0.001454599562245767, 5.856419090840883e-05, 0.0007688706809666596, 0.001415547168551922] + ph = [-0.0003231124735555465, 0.380955331199635, 0.762645225819612, 1.4676293538949, -2.15595770830073, -0.3633370464549665, 1.134950591549256, -2.808169363709888, 0.422381840383887, -0.4226859182049138, -3.091797336860658, 0.7563140142610324, -0.3787677293480213, 1.863828515720658e-10, 0.3794794147818532, -0.7671105159156101, -0.3850942687637987, -3.098506117162865, -0.6738173539748421, 0.09011906278589261, 2.089832317302934, 2.160228985413543, -0.6734226930504117, -0.3333652792566645] + } else { + poly_coefs = [] + amp = [] + ph = [] + } + + let jd0 = getJD(yyyy: y - 1, mm: 12, dd: 31) - 1.0 / 3 + let delta_T = DeltaT(T: (jd0 - 2451545 + 365.25 * 0.5) / 36525) + let offset = 2451545 - jd0 - delta_T + let lsyn = 29.5306 + let p0 = lunar_comp[0] + let jdL0 = 2451550.259469 + 0.5 * Double(p0) * lsyn + + // Find the lunation number of the first moon phase in the year + var Lm0 = floor((jd0 + 1 - jdL0) / lsyn) - 1 + var Lm: Double = 0 + var s: Double = 0 + var s1 = 0 + for i in 0..<10 { + Lm = Lm0 + 0.5 * Double(p0) + Double(i) + s = poly_coefs[0] + offset + Lm * (poly_coefs[1] + Lm * (poly_coefs[2] + Lm * poly_coefs[3])) + for j in 0..<24 { + let ang = mod2pi_de(x: w[j] * Lm) + ph[j] + s += amp[j] * sin(ang) + } + s1 = Int((s - floor(s)) * 1440 + 0.5) + s = Double(s1) + 1441 * floor(s) + Double(lunar_comp[1]) - Double(offset_comp) + if s > 1440 { + break + } + } + Lm0 = Lm + var mphase = [Date]() + // Now decompress the remaining moon-phase times + for i in 1.. [Date] { + // year in [1900, 3000] + return decode_solar_terms(y: year, istart: 0, offset_comp: 5, solar_comp: sunData[year - 1900]) + } + + func moon_phase_in_year(_ year: Int) -> ([Date], Int8) { + // year in [1900, 3000] + return (decode_moon_phases(y: year, offset_comp: 5, lunar_comp: moonData[year - 1900], dp: 0.5), moonData[year - 1900][0]) } } diff --git a/Shared/DataModel/Data.swift b/Shared/DataModel/Data.swift index d108884..855b89f 100644 --- a/Shared/DataModel/Data.swift +++ b/Shared/DataModel/Data.swift @@ -5,2212 +5,2206 @@ // Created by Leo Liu on 9/21/21. // -let earthSpeed = 360 / 86164.0989 -let moonSpeed = 360 / (27.321582 * 86400) -let eps = 0.409092610296857 // obliquity @ J2000 in rad -let aeroAdj = 50 / 60 / 180 * Double.pi +let moonData: [[Int8]] = [[0, 6, 6, 6, 6, 6, 5, 6, 3, 5, 4, 4, 5, 4, 6, 6, 6, 6, 6, 2, 6, 1, 6, 5, 6, 7], +[1, 7, 7, 7, 6, 4, 8, 4, 8, 5, 7, 5, 4, 5, 4, 6, 6, 6, 4, 5, 0, 3, 2, 5, 6, 6], +[0, 6, 6, 4, 4, 5, 4, 7, 5, 8, 7, 6, 7, 5, 5, 6, 4, 5, 4, 4, 4, 4, 3, 4, 4, 5], +[1, 6, 3, 7, 3, 6, 6, 5, 6, 7, 7, 7, 7, 5, 7, 2, 5, 2, 4, 5, 4, 5, 6, 6, 5], +[1, 5, 3, 7, 4, 8, 7, 7, 7, 6, 6, 7, 6, 6, 7, 4, 6, 2, 4, 3, 4, 6, 6, 6, 6, 4], +[0, 3, 4, 2, 6, 5, 6, 7, 6, 6, 5, 3, 5, 5, 6, 6, 4, 5, 5, 4, 5, 6, 5, 7, 3, 6], +[1, 3, 4, 5, 4, 4, 5, 4, 4, 5, 3, 6, 2, 5, 4, 6, 6, 7, 7, 8, 8, 6, 6, 2, 6, 3], +[0, 6, 5, 5, 5, 4, 2, 4, 4, 3, 7, 3, 7, 4, 5, 5, 6, 8, 9, 8, 9, 7, 4, 5, 2], +[0, 5, 5, 5, 7, 5, 3, 4, 1, 3, 3, 2, 5, 4, 5, 5, 5, 6, 6, 5, 8, 5, 7, 6, 5, 6], +[1, 5, 6, 6, 6, 6, 6, 3, 6, 3, 4, 3, 3, 5, 5, 6, 5, 6, 3, 6, 1, 6, 3, 6, 6, 7], +[0, 7, 6, 5, 5, 5, 4, 8, 3, 8, 5, 5, 6, 5, 6, 7, 7, 7, 6, 3, 4, 1, 4, 4, 6], +[0, 7, 7, 5, 5, 4, 3, 6, 4, 8, 6, 7, 6, 5, 5, 6, 4, 6, 4, 4, 4, 3, 4, 4, 5, 6], +[1, 6, 6, 8, 5, 7, 5, 6, 7, 6, 6, 7, 6, 6, 7, 3, 5, 1, 4, 2, 3, 5, 6, 6, 5, 5], +[0, 4, 6, 4, 8, 6, 8, 7, 6, 6, 6, 6, 6, 7, 5, 7, 3, 5, 2, 4, 4, 5, 6, 7, 5, 4], +[1, 4, 3, 5, 4, 7, 8, 7, 7, 5, 4, 6, 4, 5, 6, 5, 6, 5, 5, 6, 5, 5, 6, 3, 6], +[1, 3, 5, 4, 4, 4, 5, 5, 6, 6, 6, 8, 4, 7, 3, 6, 6, 6, 7, 8, 8, 7, 7, 3, 5, 1], +[0, 5, 4, 5, 5, 4, 3, 4, 3, 4, 5, 3, 7, 3, 6, 4, 4, 6, 6, 8, 9, 8, 7, 6, 2, 6], +[1, 4, 6, 7, 6, 6, 4, 1, 3, 2, 2, 4, 3, 5, 4, 5, 5, 5, 5, 7, 5, 8, 5, 5, 5, 4], +[0, 5, 6, 5, 5, 5, 3, 6, 2, 4, 3, 3, 5, 5, 5, 6, 6, 5, 7, 3, 6, 1, 6, 5, 6], +[0, 7, 6, 6, 5, 4, 3, 6, 3, 7, 4, 6, 5, 4, 5, 6, 6, 7, 6, 5, 5, 1, 4, 2, 4, 6], +[1, 7, 7, 6, 4, 4, 4, 3, 7, 5, 7, 6, 5, 5, 5, 4, 5, 3, 5, 4, 3, 4, 3, 4, 5, 5], +[0, 5, 6, 3, 7, 4, 5, 5, 5, 6, 6, 5, 6, 6, 4, 6, 1, 5, 2, 4, 4, 5, 6, 6, 5, 5], +[1, 5, 3, 6, 3, 8, 6, 6, 5, 5, 5, 6, 5, 5, 7, 3, 6, 1, 3, 3, 4, 6, 6, 6, 6], +[1, 4, 3, 4, 3, 6, 6, 8, 8, 6, 6, 6, 4, 6, 5, 5, 6, 4, 5, 5, 4, 5, 5, 5, 6, 3], +[0, 6, 4, 4, 5, 5, 5, 6, 5, 6, 6, 4, 6, 3, 6, 4, 5, 6, 7, 7, 8, 7, 6, 6, 2, 7], +[1, 3, 7, 6, 6, 5, 5, 3, 4, 3, 3, 6, 3, 6, 3, 4, 5, 5, 6, 8, 8, 7, 7, 4, 6, 2], +[0, 6, 6, 6, 7, 5, 4, 4, 1, 3, 3, 3, 6, 4, 5, 5, 5, 6, 7, 5, 8, 4, 6, 4, 4], +[0, 5, 5, 5, 6, 6, 5, 6, 2, 6, 3, 5, 4, 4, 5, 6, 6, 6, 7, 4, 7, 1, 6, 3, 6, 6], +[1, 6, 6, 6, 5, 4, 5, 3, 8, 4, 8, 5, 5, 5, 4, 5, 6, 6, 5, 5, 2, 4, 0, 3, 4, 6], +[0, 6, 6, 4, 4, 3, 3, 5, 3, 7, 6, 6, 6, 5, 5, 6, 4, 6, 5, 5, 5, 3, 4, 4, 4, 6], +[1, 6, 4, 6, 3, 5, 3, 4, 5, 5, 5, 7, 6, 6, 7, 4, 6, 2, 4, 2, 5, 5, 5, 6, 5], +[1, 5, 3, 6, 3, 8, 5, 7, 7, 6, 6, 6, 6, 6, 7, 5, 7, 2, 4, 2, 3, 4, 4, 6, 6, 4], +[0, 4, 3, 2, 5, 3, 6, 7, 6, 6, 6, 4, 5, 4, 5, 6, 4, 6, 4, 5, 5, 5, 5, 6, 4, 6], +[1, 4, 5, 4, 4, 5, 4, 5, 5, 4, 4, 6, 2, 5, 2, 4, 5, 5, 7, 8, 7, 7, 7, 3, 7], +[1, 2, 6, 4, 5, 6, 4, 3, 3, 2, 3, 5, 2, 6, 2, 4, 4, 5, 6, 7, 8, 9, 8, 6, 6, 2], +[0, 6, 4, 6, 7, 5, 5, 4, 2, 3, 2, 3, 4, 3, 5, 3, 3, 5, 4, 4, 7, 4, 7, 5, 5, 6], +[1, 6, 6, 7, 6, 7, 6, 4, 6, 2, 5, 3, 3, 4, 4, 5, 6, 5, 4, 6, 1, 6, 1, 5, 5, 6], +[0, 7, 6, 5, 5, 5, 3, 7, 4, 7, 4, 6, 5, 4, 4, 5, 6, 6, 6, 4, 4, 1, 4, 3, 4], +[0, 6, 6, 6, 5, 4, 4, 4, 4, 7, 5, 8, 6, 5, 6, 4, 4, 6, 4, 6, 4, 3, 4, 3, 4, 5], +[1, 5, 5, 6, 4, 6, 4, 6, 6, 6, 7, 7, 7, 7, 7, 5, 6, 2, 5, 1, 3, 4, 4, 5, 4, 4], +[0, 4, 4, 2, 6, 4, 8, 6, 7, 7, 6, 6, 7, 7, 6, 7, 3, 5, 1, 3, 3, 4, 5, 6, 6, 5], +[1, 3, 3, 3, 2, 6, 5, 6, 6, 5, 5, 5, 4, 6, 5, 5, 6, 4, 5, 4, 4, 5, 5, 4, 6], +[1, 3, 5, 2, 3, 4, 4, 4, 4, 4, 5, 6, 4, 6, 2, 6, 4, 6, 7, 7, 7, 8, 7, 5, 6, 1], +[0, 6, 3, 6, 5, 5, 4, 3, 2, 3, 3, 3, 6, 3, 6, 2, 4, 4, 6, 7, 9, 7, 8, 6, 3, 6], +[1, 2, 6, 6, 7, 7, 5, 4, 3, 1, 2, 3, 3, 5, 3, 4, 4, 4, 5, 6, 5, 7, 4, 7, 5, 5], +[0, 6, 5, 5, 6, 5, 4, 6, 2, 5, 2, 4, 3, 3, 4, 5, 6, 7, 7, 4, 7, 2, 6, 4, 6], +[0, 7, 7, 6, 5, 4, 3, 5, 2, 7, 2, 6, 4, 4, 5, 4, 5, 6, 6, 6, 5, 2, 4, 1, 5, 5], +[1, 6, 7, 6, 5, 5, 3, 3, 6, 4, 8, 6, 6, 6, 4, 5, 5, 3, 6, 4, 4, 4, 3, 4, 3, 4], +[0, 6, 5, 5, 7, 4, 6, 5, 5, 6, 6, 6, 6, 6, 6, 6, 3, 5, 0, 4, 2, 4, 4, 4, 5, 5], +[1, 4, 3, 5, 3, 8, 5, 7, 6, 6, 6, 5, 5, 6, 6, 4, 6, 1, 4, 1, 3, 4, 4, 5, 6], +[1, 4, 4, 3, 2, 5, 4, 7, 6, 6, 6, 6, 5, 6, 4, 7, 5, 5, 6, 4, 5, 4, 4, 4, 6, 3], +[0, 5, 2, 4, 3, 4, 4, 5, 4, 6, 5, 4, 6, 3, 6, 2, 5, 5, 5, 7, 7, 7, 6, 6, 2, 6], +[1, 2, 6, 4, 6, 5, 5, 3, 3, 3, 3, 5, 3, 6, 2, 4, 2, 3, 5, 6, 7, 8, 7, 5, 5, 3], +[0, 6, 4, 6, 7, 5, 5, 4, 1, 3, 2, 3, 4, 3, 5, 4, 4, 5, 5, 5, 7, 5, 7, 5, 5], +[0, 5, 5, 5, 5, 5, 5, 5, 2, 5, 1, 5, 2, 3, 4, 4, 5, 6, 5, 5, 6, 2, 5, 1, 6, 4], +[1, 6, 7, 6, 4, 4, 4, 3, 6, 3, 8, 3, 6, 5, 4, 5, 5, 6, 7, 5, 4, 5, 1, 4, 2, 5], +[0, 6, 5, 6, 6, 3, 4, 4, 4, 6, 5, 7, 6, 5, 5, 4, 4, 6, 3, 6, 4, 4, 5, 4, 4], +[0, 6, 4, 6, 6, 3, 7, 3, 5, 5, 5, 6, 6, 5, 6, 6, 4, 6, 1, 4, 1, 3, 4, 4, 6, 5], +[1, 4, 4, 4, 2, 6, 4, 8, 5, 6, 6, 5, 5, 6, 6, 7, 7, 3, 5, 1, 4, 3, 4, 6, 5, 5], +[0, 5, 3, 2, 4, 2, 5, 5, 6, 6, 6, 5, 6, 4, 6, 5, 6, 6, 5, 5, 5, 4, 5, 5, 5, 6], +[1, 4, 6, 4, 4, 5, 4, 4, 5, 4, 5, 6, 3, 7, 2, 5, 3, 5, 5, 6, 6, 7, 6, 4, 6], +[1, 2, 7, 4, 7, 6, 6, 4, 3, 2, 3, 3, 3, 6, 2, 5, 2, 4, 5, 5, 6, 7, 7, 8, 6, 4], +[0, 5, 2, 7, 6, 6, 6, 5, 3, 4, 1, 3, 3, 3, 5, 3, 4, 4, 4, 5, 6, 5, 7, 3, 5, 5], +[1, 4, 6, 5, 6, 7, 6, 5, 7, 3, 7, 3, 5, 3, 4, 5, 6, 6, 6, 6, 4, 5, 0, 5, 2, 6], +[0, 5, 6, 5, 4, 4, 3, 4, 3, 8, 3, 6, 4, 4, 5, 4, 5, 6, 6, 6, 5, 2, 4, 1, 4], +[0, 5, 5, 7, 6, 4, 4, 3, 3, 5, 3, 7, 4, 5, 5, 4, 4, 5, 3, 6, 4, 4, 3, 3, 4, 4], +[1, 4, 5, 5, 4, 6, 2, 6, 3, 4, 5, 5, 6, 6, 6, 6, 7, 4, 6, 1, 5, 2, 3, 4, 4, 4], +[0, 4, 3, 2, 4, 2, 7, 4, 7, 5, 5, 5, 5, 6, 6, 6, 6, 7, 2, 5, 1, 3, 5, 5, 5, 5], +[1, 3, 3, 3, 2, 5, 4, 7, 6, 6, 6, 5, 3, 6, 3, 5, 5, 4, 5, 4, 4, 5, 5, 4, 6], +[1, 4, 6, 3, 4, 3, 3, 4, 4, 4, 5, 4, 4, 6, 1, 5, 1, 4, 5, 6, 7, 7, 7, 7, 6, 3], +[0, 6, 2, 7, 5, 6, 5, 4, 2, 3, 3, 3, 4, 2, 5, 1, 3, 2, 3, 5, 6, 7, 8, 6, 5, 6], +[1, 3, 7, 5, 8, 8, 6, 6, 5, 3, 4, 3, 3, 5, 3, 4, 3, 3, 4, 4, 4, 6, 4, 6, 4], +[1, 6, 5, 5, 6, 6, 6, 6, 6, 3, 6, 2, 5, 2, 4, 5, 4, 5, 5, 6, 5, 5, 1, 6, 1, 6], +[0, 5, 6, 7, 6, 4, 4, 4, 3, 7, 3, 7, 4, 5, 4, 3, 4, 5, 5, 7, 5, 4, 4, 0, 4, 3], +[1, 5, 6, 5, 5, 5, 3, 4, 4, 4, 7, 6, 8, 6, 5, 6, 6, 5, 6, 4, 6, 4, 3, 4, 3, 4], +[0, 4, 3, 4, 5, 2, 6, 3, 6, 5, 6, 7, 6, 7, 7, 6, 5, 7, 1, 5, 1, 4, 4, 4, 5], +[0, 5, 4, 3, 3, 2, 6, 3, 8, 5, 7, 6, 6, 6, 6, 7, 6, 7, 4, 5, 0, 4, 3, 4, 6, 5], +[1, 4, 4, 2, 2, 3, 2, 5, 4, 6, 5, 5, 5, 5, 3, 6, 5, 6, 6, 5, 6, 4, 4, 5, 5, 4], +[0, 6, 3, 5, 2, 3, 3, 3, 4, 4, 4, 4, 5, 2, 6, 2, 5, 3, 5, 6, 7, 8, 7, 6, 5, 6], +[1, 2, 7, 3, 7, 5, 5, 4, 4, 3, 3, 3, 3, 5, 2, 5, 1, 4, 4, 4, 6, 7, 7, 7, 5], +[1, 3, 5, 3, 7, 6, 7, 7, 5, 3, 3, 2, 3, 2, 3, 4, 2, 3, 3, 4, 5, 6, 5, 7, 4, 6], +[0, 5, 5, 6, 5, 6, 5, 4, 4, 5, 2, 5, 0, 3, 2, 3, 4, 4, 5, 5, 5, 3, 5, 1, 6, 3], +[1, 7, 6, 6, 5, 5, 3, 3, 5, 3, 7, 1, 7, 4, 4, 5, 4, 5, 6, 6, 6, 5, 2, 4, 1, 5], +[0, 6, 6, 7, 5, 3, 5, 2, 4, 5, 4, 8, 5, 5, 5, 4, 4, 5, 3, 6, 3, 4, 3, 3, 4], +[0, 5, 5, 5, 5, 5, 7, 4, 7, 4, 6, 6, 6, 6, 7, 6, 5, 6, 2, 5, -1, 4, 2, 4, 4, 5], +[1, 4, 4, 4, 3, 5, 3, 7, 5, 8, 6, 5, 6, 5, 6, 7, 7, 6, 7, 2, 4, 2, 3, 4, 4, 5], +[0, 5, 3, 3, 2, 2, 5, 3, 6, 6, 6, 6, 5, 4, 6, 4, 6, 5, 6, 6, 5, 5, 5, 5, 4, 5], +[1, 2, 6, 2, 5, 4, 5, 5, 4, 5, 5, 6, 5, 7, 3, 6, 2, 5, 4, 5, 6, 7, 6, 6, 5], +[1, 2, 6, 1, 7, 4, 6, 5, 4, 4, 4, 3, 4, 5, 3, 5, 1, 4, 2, 3, 5, 6, 7, 7, 6, 5], +[0, 5, 3, 6, 5, 7, 7, 6, 4, 3, 1, 3, 1, 3, 4, 3, 5, 4, 4, 4, 4, 4, 6, 4, 7, 4], +[1, 5, 5, 5, 5, 5, 4, 5, 5, 3, 6, 2, 6, 2, 4, 4, 5, 6, 6, 6, 6, 5, 2, 6, 2], +[1, 6, 5, 6, 6, 6, 3, 3, 4, 2, 6, 3, 7, 3, 5, 4, 4, 5, 6, 6, 7, 5, 4, 4, 1, 4], +[0, 4, 5, 7, 6, 5, 5, 2, 3, 3, 4, 7, 5, 6, 5, 4, 5, 4, 4, 6, 3, 6, 3, 3, 5, 4], +[1, 4, 5, 4, 5, 5, 2, 6, 3, 6, 5, 5, 5, 6, 6, 7, 6, 5, 6, 2, 5, 2, 4, 5, 5, 5], +[0, 4, 4, 3, 3, 2, 6, 3, 7, 5, 6, 5, 5, 5, 6, 6, 7, 7, 5, 5, 1, 3, 3, 4, 6], +[0, 6, 4, 5, 2, 3, 4, 3, 6, 5, 7, 6, 5, 5, 5, 4, 7, 4, 6, 5, 4, 5, 3, 4, 5, 4], +[1, 4, 5, 3, 6, 3, 5, 4, 5, 4, 5, 5, 5, 5, 3, 6, 1, 5, 2, 5, 5, 6, 6, 7, 6, 4], +[0, 6, 3, 7, 4, 8, 6, 6, 4, 4, 2, 4, 4, 3, 5, 1, 4, 1, 3, 4, 5, 6, 7, 6, 6, 5], +[1, 3, 5, 3, 7, 6, 7, 6, 5, 3, 4, 2, 4, 4, 4, 5, 3, 4, 3, 4, 4, 5, 4, 6, 3], +[1, 6, 4, 5, 6, 4, 5, 6, 5, 5, 6, 3, 6, 2, 4, 4, 3, 5, 5, 5, 5, 5, 3, 6, 1, 6], +[0, 4, 6, 6, 6, 5, 4, 3, 4, 5, 3, 7, 3, 6, 3, 3, 4, 3, 5, 6, 5, 5, 5, 1, 4, 2], +[1, 5, 6, 6, 6, 5, 3, 4, 2, 4, 5, 3, 7, 5, 5, 6, 4, 5, 5, 4, 6, 3, 5, 4, 3, 5], +[0, 4, 4, 5, 5, 4, 6, 2, 6, 3, 5, 6, 5, 6, 7, 6, 6, 6, 3, 6, 1, 4, 3, 4, 5], +[0, 5, 5, 3, 3, 2, 5, 3, 8, 5, 8, 6, 6, 6, 5, 6, 7, 7, 6, 6, 2, 4, 1, 4, 5, 4], +[1, 5, 4, 3, 3, 2, 1, 5, 3, 6, 6, 6, 6, 5, 4, 6, 4, 6, 5, 5, 5, 4, 5, 5, 5, 5], +[0, 6, 3, 6, 3, 4, 4, 4, 4, 4, 4, 4, 5, 4, 5, 2, 5, 1, 5, 4, 6, 7, 7, 7, 7, 6], +[1, 3, 7, 2, 8, 4, 6, 5, 5, 4, 4, 3, 4, 5, 3, 6, 2, 4, 2, 4, 5, 6, 7, 7, 6], +[1, 4, 5, 3, 6, 5, 8, 7, 6, 5, 4, 3, 4, 3, 4, 5, 4, 4, 3, 3, 4, 5, 4, 6, 3, 7], +[0, 4, 6, 7, 6, 6, 7, 5, 6, 6, 3, 7, 1, 5, 2, 4, 3, 4, 5, 5, 5, 5, 4, 2, 5, 1], +[1, 7, 5, 7, 7, 6, 4, 4, 4, 3, 6, 3, 7, 2, 5, 4, 4, 6, 5, 6, 7, 6, 4, 4, 1], +[1, 5, 3, 6, 6, 6, 5, 4, 2, 3, 3, 4, 7, 4, 6, 6, 5, 6, 5, 4, 6, 4, 6, 3, 4, 4], +[0, 4, 4, 5, 4, 5, 5, 3, 7, 4, 7, 6, 6, 7, 7, 7, 8, 6, 5, 6, 1, 5, 1, 5, 4, 4], +[1, 5, 4, 3, 3, 2, 1, 6, 2, 7, 5, 7, 5, 5, 6, 6, 6, 7, 7, 5, 6, 1, 4, 3, 5, 6], +[0, 5, 4, 4, 1, 2, 2, 1, 5, 4, 6, 5, 4, 4, 5, 4, 7, 4, 6, 6, 5, 5, 5, 4, 5], +[0, 5, 4, 6, 2, 6, 2, 4, 3, 3, 4, 4, 4, 4, 5, 3, 6, 2, 5, 3, 6, 6, 6, 6, 7, 5], +[1, 4, 5, 2, 6, 3, 7, 6, 6, 4, 3, 3, 3, 4, 3, 5, 1, 4, 1, 4, 4, 5, 6, 7, 6, 6], +[0, 5, 4, 6, 4, 7, 7, 7, 7, 5, 3, 4, 1, 3, 3, 3, 4, 2, 3, 3, 3, 4, 5, 4, 7, 3], +[1, 6, 5, 5, 6, 6, 5, 6, 5, 4, 5, 2, 6, 2, 4, 3, 3, 5, 5, 6, 6, 6, 3, 6, 1], +[1, 7, 4, 7, 7, 6, 6, 5, 3, 3, 5, 3, 7, 2, 6, 2, 4, 4, 4, 5, 6, 5, 5, 4, 2, 5], +[0, 2, 6, 7, 7, 7, 6, 4, 5, 3, 4, 6, 5, 7, 5, 6, 5, 4, 5, 5, 3, 5, 2, 4, 3, 3], +[1, 4, 5, 4, 6, 5, 4, 6, 3, 7, 4, 6, 5, 5, 7, 7, 7, 6, 6, 3, 6, 0, 4, 3, 5, 5], +[0, 5, 4, 4, 2, 2, 4, 3, 8, 4, 7, 6, 6, 6, 6, 6, 8, 7, 7, 6, 3, 5, 1, 4, 5], +[0, 5, 5, 4, 3, 3, 2, 2, 5, 4, 7, 6, 6, 6, 6, 5, 7, 5, 7, 6, 6, 6, 4, 5, 5, 4], +[1, 5, 4, 3, 5, 1, 5, 3, 5, 5, 4, 5, 6, 6, 5, 6, 2, 6, 2, 6, 4, 6, 6, 6, 6, 5], +[0, 5, 3, 6, 2, 7, 5, 7, 5, 5, 4, 4, 4, 4, 5, 3, 5, 1, 3, 1, 3, 5, 6, 6, 7, 5], +[1, 5, 5, 3, 7, 5, 7, 6, 5, 5, 4, 2, 4, 3, 4, 4, 4, 5, 4, 5, 5, 4, 4, 6, 3], +[1, 7, 4, 5, 5, 5, 5, 5, 5, 5, 5, 3, 6, 2, 5, 2, 4, 5, 5, 6, 6, 6, 5, 6, 2, 6], +[0, 2, 7, 6, 7, 6, 6, 4, 4, 4, 4, 6, 3, 7, 3, 4, 4, 3, 6, 5, 6, 7, 5, 3, 5, 1], +[1, 5, 5, 7, 7, 6, 5, 5, 2, 4, 3, 4, 7, 4, 6, 5, 4, 5, 5, 4, 6, 3, 6, 4, 4], +[1, 6, 5, 5, 6, 4, 4, 5, 3, 6, 2, 6, 5, 4, 6, 6, 6, 7, 6, 5, 6, 2, 5, 2, 5, 5], +[0, 6, 5, 5, 3, 3, 2, 2, 6, 3, 8, 5, 6, 5, 5, 6, 7, 7, 8, 7, 5, 5, 1, 4, 3, 5], +[1, 6, 5, 4, 4, 2, 2, 3, 3, 6, 5, 7, 6, 5, 5, 6, 4, 7, 4, 6, 5, 5, 6, 4, 5, 6], +[0, 6, 5, 6, 3, 7, 3, 6, 5, 5, 5, 5, 5, 5, 5, 3, 6, 1, 5, 1, 5, 5, 6, 6, 6], +[0, 5, 4, 5, 2, 8, 4, 8, 6, 6, 5, 4, 3, 4, 5, 5, 6, 3, 5, 1, 3, 3, 5, 6, 6, 5], +[1, 5, 4, 3, 5, 3, 8, 6, 7, 7, 6, 4, 5, 3, 4, 4, 4, 4, 4, 5, 4, 5, 4, 5, 3, 7], +[0, 3, 6, 4, 5, 6, 6, 6, 7, 6, 6, 7, 4, 6, 2, 5, 3, 4, 6, 5, 6, 6, 5, 3, 5, 1], +[1, 6, 4, 7, 6, 7, 5, 5, 3, 4, 5, 4, 8, 2, 6, 3, 3, 5, 5, 6, 7, 5, 6, 5, 2], +[1, 5, 2, 6, 6, 6, 6, 5, 3, 4, 2, 4, 5, 4, 7, 5, 6, 5, 5, 5, 6, 4, 6, 3, 4, 4], +[0, 3, 5, 4, 4, 5, 5, 4, 6, 3, 7, 3, 6, 6, 6, 7, 8, 8, 7, 7, 4, 6, 1, 5, 2, 5], +[1, 6, 4, 3, 4, 2, 2, 4, 2, 7, 4, 7, 5, 6, 6, 6, 7, 8, 7, 7, 7, 3, 5, 3, 5, 6], +[0, 5, 6, 4, 3, 3, 2, 2, 5, 4, 6, 5, 5, 5, 5, 4, 6, 4, 7, 5, 6, 6, 5, 6, 6], +[0, 6, 5, 6, 3, 5, 2, 5, 3, 4, 4, 4, 5, 5, 5, 4, 6, 2, 6, 1, 6, 4, 7, 8, 7, 6], +[1, 6, 5, 4, 6, 3, 8, 5, 7, 6, 5, 4, 4, 3, 5, 5, 3, 5, 1, 3, 2, 4, 5, 6, 7, 7], +[0, 5, 6, 6, 4, 7, 6, 9, 8, 6, 6, 5, 4, 5, 3, 5, 4, 3, 4, 3, 4, 3, 4, 4, 6, 3], +[1, 7, 5, 7, 6, 6, 7, 6, 6, 6, 6, 4, 6, 2, 6, 2, 4, 4, 5, 6, 6, 6, 5, 5, 2], +[1, 7, 3, 8, 6, 8, 7, 6, 5, 4, 5, 4, 6, 3, 6, 2, 4, 3, 4, 6, 5, 6, 6, 5, 3, 4], +[0, 1, 5, 5, 6, 7, 6, 6, 5, 3, 5, 5, 5, 7, 5, 7, 5, 4, 5, 5, 4, 6, 3, 5, 4, 4], +[1, 4, 4, 4, 5, 4, 4, 5, 3, 7, 4, 7, 5, 6, 6, 7, 7, 7, 6, 5, 6, 1, 5, 1, 5], +[1, 5, 5, 5, 5, 2, 3, 2, 2, 6, 3, 7, 4, 6, 5, 5, 6, 7, 7, 8, 6, 4, 5, 2, 5, 4], +[0, 6, 6, 5, 3, 4, 0, 2, 3, 2, 6, 4, 6, 5, 5, 5, 6, 5, 7, 5, 7, 6, 5, 6, 5, 6], +[1, 6, 5, 5, 6, 2, 6, 2, 5, 4, 4, 5, 5, 5, 6, 6, 3, 6, 1, 6, 3, 6, 6, 7, 7, 7], +[0, 5, 4, 6, 2, 8, 4, 8, 6, 6, 5, 5, 4, 4, 4, 5, 5, 2, 5, 1, 3, 3, 5, 6, 6], +[0, 6, 6, 4, 4, 6, 4, 8, 6, 7, 7, 5, 4, 4, 2, 4, 4, 4, 5, 4, 5, 5, 5, 6, 6, 4], +[1, 7, 4, 7, 6, 6, 7, 6, 6, 6, 5, 5, 6, 2, 6, 1, 4, 3, 4, 5, 6, 6, 6, 6, 4, 5], +[0, 2, 7, 5, 8, 8, 7, 6, 5, 4, 5, 6, 5, 7, 3, 6, 3, 4, 4, 5, 6, 7, 5, 5, 4, 2], +[1, 5, 4, 7, 7, 7, 7, 6, 4, 5, 4, 5, 6, 5, 7, 6, 5, 6, 4, 4, 5, 3, 6, 2, 5], +[1, 4, 4, 5, 5, 5, 6, 5, 5, 6, 4, 7, 4, 6, 5, 6, 6, 7, 7, 7, 7, 3, 6, 1, 5, 3], +[0, 6, 5, 5, 4, 3, 2, 3, 5, 2, 8, 4, 7, 6, 6, 6, 7, 7, 9, 9, 7, 7, 3, 6, 3, 5], +[1, 6, 6, 6, 4, 2, 2, 2, 2, 5, 4, 7, 5, 6, 6, 5, 6, 7, 5, 8, 5, 7, 6, 6, 6, 6], +[0, 6, 6, 6, 3, 6, 2, 6, 4, 5, 5, 5, 6, 6, 5, 5, 6, 2, 6, 1, 6, 4, 6, 7, 7], +[0, 6, 5, 5, 3, 6, 3, 8, 5, 7, 6, 5, 5, 4, 4, 5, 6, 4, 5, 2, 5, 2, 4, 6, 6, 7], +[1, 7, 5, 5, 5, 4, 7, 5, 7, 6, 5, 5, 5, 3, 4, 3, 5, 4, 4, 5, 4, 4, 4, 5, 5, 6], +[0, 4, 7, 4, 6, 6, 6, 7, 6, 6, 6, 6, 4, 6, 2, 6, 2, 5, 5, 5, 6, 6, 6, 4, 5, 1], +[1, 6, 3, 7, 6, 8, 7, 6, 5, 5, 5, 4, 6, 3, 7, 3, 4, 3, 4, 5, 6, 6, 6, 5, 4], +[1, 5, 2, 7, 5, 7, 8, 7, 5, 6, 3, 5, 4, 4, 6, 5, 6, 5, 4, 5, 4, 4, 6, 3, 6, 4], +[0, 4, 5, 5, 5, 6, 5, 4, 6, 3, 7, 3, 7, 4, 6, 7, 7, 7, 8, 7, 6, 6, 2, 6, 3, 6], +[1, 6, 6, 5, 4, 2, 3, 3, 2, 6, 3, 7, 5, 6, 5, 5, 7, 8, 7, 8, 7, 5, 6, 3, 6, 5], +[0, 7, 7, 6, 5, 5, 2, 3, 4, 3, 7, 6, 6, 6, 5, 5, 6, 5, 7, 4, 6, 5, 5, 6, 5], +[0, 6, 7, 5, 5, 6, 4, 7, 3, 6, 5, 5, 6, 5, 5, 5, 6, 4, 6, 2, 5, 3, 6, 6, 7, 7], +[1, 7, 5, 4, 6, 3, 8, 5, 8, 6, 7, 5, 5, 5, 5, 5, 5, 6, 3, 5, 1, 4, 4, 5, 7, 6], +[0, 5, 5, 3, 4, 6, 5, 8, 7, 8, 7, 6, 6, 5, 4, 5, 5, 6, 5, 4, 5, 4, 4, 4, 5], +[0, 4, 6, 3, 6, 4, 5, 6, 6, 6, 7, 7, 6, 7, 3, 6, 2, 5, 3, 4, 5, 5, 6, 6, 5, 4], +[1, 6, 2, 7, 5, 8, 7, 7, 6, 5, 4, 5, 6, 4, 7, 2, 6, 2, 4, 4, 4, 6, 6, 5, 5, 4], +[0, 3, 5, 3, 7, 6, 7, 7, 5, 3, 4, 3, 5, 5, 5, 7, 6, 6, 6, 5, 6, 6, 4, 7, 3, 5], +[1, 4, 4, 5, 5, 4, 4, 4, 3, 6, 2, 7, 3, 6, 6, 7, 7, 8, 8, 7, 7, 4, 7, 2, 7], +[1, 4, 7, 7, 6, 4, 4, 2, 2, 4, 2, 7, 4, 6, 5, 5, 6, 6, 7, 9, 7, 7, 6, 3, 6, 4], +[0, 7, 7, 6, 6, 5, 2, 3, 2, 3, 4, 4, 6, 4, 5, 5, 5, 5, 6, 4, 8, 5, 6, 7, 6, 7], +[1, 7, 6, 6, 6, 4, 6, 3, 5, 3, 5, 5, 4, 5, 5, 5, 4, 5, 2, 6, 2, 5, 5, 7, 7, 7], +[0, 6, 6, 5, 3, 7, 3, 9, 6, 7, 7, 5, 5, 5, 5, 6, 6, 4, 5, 2, 4, 2, 4, 5, 6], +[0, 6, 7, 5, 5, 5, 5, 8, 6, 9, 7, 7, 7, 5, 4, 5, 3, 6, 4, 4, 5, 4, 4, 4, 4, 4], +[1, 6, 5, 8, 4, 8, 7, 7, 7, 7, 7, 7, 7, 4, 6, 2, 6, 2, 4, 4, 5, 6, 5, 5, 5, 4], +[0, 2, 6, 3, 8, 7, 9, 7, 6, 5, 5, 6, 6, 7, 5, 7, 3, 5, 4, 4, 6, 6, 6, 6, 4, 3], +[1, 4, 2, 6, 6, 7, 8, 7, 6, 6, 3, 6, 5, 6, 8, 6, 7, 6, 5, 6, 6, 5, 6, 3, 6], +[1, 4, 4, 5, 5, 5, 6, 5, 6, 6, 4, 7, 4, 7, 5, 6, 7, 7, 7, 8, 7, 6, 6, 1, 6, 3], +[0, 6, 6, 6, 6, 4, 3, 2, 3, 3, 6, 3, 7, 4, 6, 5, 6, 7, 8, 8, 9, 7, 5, 6, 3, 6], +[1, 6, 7, 8, 6, 4, 3, 0, 2, 2, 2, 5, 4, 6, 5, 5, 6, 5, 5, 8, 5, 8, 6, 6, 6, 6], +[0, 6, 6, 5, 5, 6, 3, 6, 3, 6, 5, 5, 6, 5, 6, 6, 6, 5, 6, 2, 6, 3, 6, 6, 6], +[0, 7, 6, 5, 4, 5, 2, 8, 4, 8, 6, 6, 6, 4, 5, 6, 5, 5, 6, 3, 5, 2, 4, 5, 6, 8], +[1, 7, 6, 6, 4, 4, 6, 5, 8, 6, 7, 7, 5, 5, 5, 3, 5, 3, 5, 4, 4, 5, 5, 4, 6, 6], +[0, 5, 7, 4, 7, 5, 6, 7, 6, 7, 6, 6, 5, 6, 3, 6, 2, 5, 4, 5, 6, 6, 7, 6, 5], +[0, 4, 5, 3, 8, 6, 8, 7, 7, 6, 5, 5, 5, 7, 5, 7, 3, 6, 3, 3, 4, 5, 6, 6, 6, 6], +[1, 4, 3, 6, 5, 9, 8, 8, 8, 6, 5, 6, 4, 6, 6, 6, 7, 6, 6, 5, 4, 5, 6, 3, 5, 3], +[0, 5, 5, 5, 6, 6, 5, 6, 6, 4, 6, 3, 7, 3, 6, 6, 7, 7, 8, 8, 8, 7, 4, 7, 2, 7], +[1, 5, 7, 7, 5, 4, 4, 2, 3, 4, 3, 7, 3, 6, 4, 5, 6, 6, 7, 9, 8, 7, 6, 3, 6], +[1, 4, 6, 7, 6, 6, 5, 2, 3, 2, 3, 6, 5, 7, 6, 5, 6, 5, 5, 7, 5, 7, 5, 6, 6, 5], +[0, 6, 6, 5, 6, 6, 3, 6, 3, 6, 4, 6, 5, 5, 6, 6, 6, 5, 6, 3, 6, 2, 5, 5, 7, 7], +[1, 7, 6, 5, 5, 4, 6, 4, 8, 5, 7, 6, 4, 5, 4, 5, 6, 6, 5, 5, 2, 5, 2, 5, 6, 6], +[0, 7, 6, 4, 4, 4, 4, 7, 6, 8, 7, 6, 6, 5, 4, 6, 4, 6, 5, 5, 6, 4, 5, 5, 5], +[0, 5, 5, 4, 7, 4, 7, 6, 6, 7, 7, 7, 7, 7, 5, 7, 3, 5, 3, 5, 5, 6, 7, 7, 5, 5], +[1, 5, 3, 6, 4, 8, 7, 9, 8, 6, 5, 6, 6, 6, 7, 4, 6, 3, 4, 3, 4, 6, 6, 6, 6, 4], +[0, 3, 4, 4, 6, 6, 8, 8, 6, 5, 5, 3, 5, 4, 5, 6, 5, 6, 6, 6, 7, 5, 5, 6, 4, 6], +[1, 5, 5, 6, 5, 5, 6, 4, 5, 5, 3, 6, 3, 6, 4, 6, 7, 7, 7, 9, 7, 6, 6, 2, 7], +[1, 3, 7, 7, 7, 7, 5, 3, 3, 3, 3, 7, 4, 7, 4, 6, 5, 6, 7, 8, 7, 8, 7, 5, 7, 3], +[0, 7, 6, 7, 7, 6, 5, 4, 2, 4, 4, 4, 6, 5, 6, 6, 4, 5, 6, 5, 7, 4, 7, 5, 6, 7], +[1, 7, 7, 8, 6, 6, 7, 4, 7, 3, 6, 5, 5, 5, 5, 5, 6, 6, 3, 6, 1, 6, 2, 6, 7], +[1, 7, 6, 6, 5, 4, 5, 3, 8, 5, 9, 6, 6, 7, 5, 6, 6, 6, 7, 6, 4, 6, 2, 4, 5, 6], +[0, 7, 6, 4, 4, 2, 4, 5, 5, 8, 7, 7, 8, 6, 5, 6, 4, 6, 4, 6, 5, 5, 5, 4, 5, 6], +[1, 6, 4, 6, 3, 7, 6, 7, 7, 6, 8, 7, 6, 6, 7, 4, 6, 1, 5, 3, 5, 6, 5, 6, 5, 5], +[0, 3, 5, 3, 8, 6, 9, 7, 7, 7, 6, 4, 5, 6, 6, 7, 4, 5, 3, 5, 5, 5, 7, 6, 5], +[0, 5, 4, 3, 5, 4, 7, 7, 6, 7, 5, 4, 5, 4, 6, 6, 6, 7, 6, 6, 7, 5, 6, 5, 4, 6], +[1, 3, 5, 5, 5, 6, 5, 5, 6, 5, 4, 6, 3, 6, 3, 6, 6, 7, 8, 9, 8, 8, 7, 4, 6, 2], +[0, 7, 5, 7, 7, 6, 4, 4, 2, 3, 5, 3, 7, 3, 6, 5, 4, 6, 6, 7, 9, 7, 7, 7, 4, 7], +[1, 5, 8, 9, 7, 6, 5, 2, 3, 1, 3, 4, 4, 5, 4, 4, 6, 5, 4, 6, 4, 7, 5, 7, 7], +[1, 6, 7, 7, 6, 6, 5, 4, 6, 3, 7, 4, 5, 6, 6, 6, 6, 6, 6, 6, 3, 6, 2, 6, 6, 7], +[0, 8, 7, 6, 5, 4, 3, 6, 4, 9, 5, 8, 7, 5, 6, 5, 6, 7, 6, 5, 6, 2, 4, 3, 5, 7], +[1, 7, 7, 7, 4, 5, 5, 5, 8, 7, 9, 8, 7, 7, 5, 5, 6, 4, 6, 4, 5, 5, 4, 5, 5, 5], +[0, 5, 6, 4, 8, 5, 7, 6, 7, 8, 7, 7, 8, 6, 5, 6, 2, 6, 3, 5, 5, 5, 7, 6, 6], +[0, 5, 4, 2, 7, 4, 9, 7, 8, 8, 7, 6, 6, 6, 6, 7, 5, 7, 3, 5, 4, 4, 6, 5, 6, 6], +[1, 4, 3, 4, 3, 7, 6, 7, 8, 6, 6, 6, 4, 7, 5, 7, 7, 6, 7, 7, 5, 6, 5, 5, 5, 3], +[0, 6, 3, 5, 4, 4, 5, 6, 4, 6, 5, 4, 7, 3, 7, 5, 7, 7, 7, 8, 8, 7, 6, 6, 3], +[0, 7, 4, 8, 7, 7, 6, 4, 2, 2, 2, 3, 6, 3, 6, 4, 5, 5, 5, 7, 8, 7, 8, 7, 5, 6], +[1, 4, 7, 6, 7, 7, 5, 4, 3, 0, 3, 2, 3, 6, 5, 5, 6, 5, 6, 6, 5, 8, 5, 7, 6, 6], +[0, 7, 6, 6, 6, 5, 5, 5, 2, 6, 3, 5, 4, 5, 6, 6, 6, 7, 6, 5, 6, 2, 6, 3, 7, 8], +[1, 7, 7, 6, 4, 4, 5, 3, 8, 4, 9, 5, 6, 5, 4, 6, 5, 5, 5, 6, 3, 5, 2, 5, 6], +[1, 7, 8, 6, 5, 5, 3, 4, 6, 5, 8, 7, 7, 7, 5, 5, 5, 4, 6, 4, 5, 5, 4, 6, 5, 5], +[0, 7, 6, 5, 7, 4, 7, 4, 7, 6, 7, 7, 7, 6, 5, 6, 3, 6, 2, 5, 3, 5, 7, 5, 6, 5], +[1, 4, 4, 5, 3, 8, 6, 10, 8, 8, 7, 6, 6, 6, 6, 6, 7, 3, 5, 3, 4, 4, 4, 6, 5, 4], +[0, 4, 4, 3, 6, 4, 8, 8, 7, 8, 6, 5, 6, 4, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 4], +[0, 6, 3, 6, 5, 6, 6, 6, 5, 7, 5, 5, 7, 3, 6, 3, 6, 5, 7, 7, 7, 8, 7, 6, 4, 6], +[1, 2, 6, 6, 8, 7, 6, 5, 4, 2, 3, 5, 3, 7, 3, 6, 4, 5, 6, 7, 8, 9, 7, 6, 6, 4], +[0, 6, 4, 7, 7, 6, 6, 4, 2, 4, 2, 4, 5, 5, 6, 5, 6, 7, 5, 5, 7, 5, 8, 4, 6, 7], +[1, 6, 7, 6, 6, 6, 6, 4, 7, 3, 6, 4, 5, 6, 5, 6, 6, 6, 6, 6, 3, 5, 2, 6, 5], +[1, 7, 7, 7, 5, 5, 4, 3, 6, 3, 8, 4, 6, 7, 5, 6, 6, 6, 7, 6, 6, 5, 3, 5, 4, 6], +[0, 7, 6, 7, 5, 3, 3, 3, 4, 6, 5, 8, 7, 6, 6, 5, 5, 5, 3, 6, 5, 6, 6, 5, 5, 5], +[1, 4, 6, 6, 4, 7, 4, 7, 6, 7, 7, 7, 7, 7, 6, 5, 6, 3, 5, 2, 5, 5, 6, 7, 6, 4], +[0, 4, 4, 3, 6, 3, 9, 7, 8, 7, 7, 6, 6, 5, 6, 7, 5, 6, 3, 4, 4, 4, 7, 6, 6], +[0, 5, 4, 4, 4, 4, 7, 6, 8, 8, 6, 6, 6, 3, 6, 4, 5, 6, 5, 6, 6, 5, 6, 5, 5, 6], +[1, 4, 6, 4, 5, 5, 5, 5, 6, 4, 5, 5, 4, 7, 3, 7, 5, 6, 7, 7, 8, 8, 7, 6, 6, 3], +[0, 7, 4, 8, 7, 7, 6, 5, 3, 4, 3, 3, 6, 3, 7, 3, 5, 5, 5, 7, 7, 7, 8, 6, 5], +[0, 6, 4, 8, 7, 8, 9, 6, 5, 5, 2, 4, 3, 4, 6, 4, 5, 5, 4, 5, 5, 4, 6, 3, 6, 5], +[1, 5, 7, 6, 6, 7, 6, 6, 6, 3, 7, 3, 5, 4, 5, 5, 6, 6, 7, 6, 5, 6, 2, 6, 3, 7], +[0, 7, 7, 7, 5, 4, 4, 4, 3, 7, 4, 8, 5, 6, 6, 4, 6, 6, 6, 7, 6, 4, 5, 2, 5, 6], +[1, 6, 7, 6, 4, 4, 2, 4, 5, 6, 9, 7, 8, 7, 6, 6, 5, 4, 5, 3, 6, 5, 4, 5, 4], +[1, 4, 6, 4, 5, 6, 3, 6, 4, 7, 7, 7, 7, 8, 6, 7, 7, 3, 6, 1, 4, 3, 5, 6, 6, 6], +[0, 5, 4, 3, 4, 2, 8, 6, 9, 7, 6, 7, 6, 5, 6, 6, 5, 6, 3, 6, 2, 4, 5, 5, 6, 5], +[1, 4, 4, 2, 2, 4, 4, 7, 7, 6, 7, 5, 5, 6, 4, 7, 6, 7, 7, 7, 7, 7, 5, 6, 5, 3], +[0, 6, 3, 5, 4, 5, 5, 5, 5, 6, 5, 5, 6, 3, 6, 3, 6, 6, 7, 8, 8, 8, 7, 6, 4], +[0, 6, 3, 7, 6, 7, 7, 5, 5, 4, 3, 3, 4, 4, 6, 2, 5, 3, 5, 6, 6, 8, 8, 7, 7, 6], +[1, 4, 7, 6, 8, 9, 6, 7, 4, 3, 4, 2, 3, 4, 4, 6, 5, 4, 6, 4, 6, 6, 5, 8, 5, 7], +[0, 7, 7, 7, 7, 5, 6, 5, 3, 6, 2, 6, 3, 5, 5, 5, 6, 7, 6, 6, 5, 2, 6, 3, 6, 6], +[1, 7, 8, 7, 6, 5, 5, 4, 7, 4, 9, 5, 8, 6, 5, 6, 5, 6, 7, 5, 5, 5, 2, 5, 4], +[1, 6, 7, 6, 6, 6, 4, 5, 4, 4, 7, 7, 8, 8, 6, 6, 5, 4, 5, 4, 6, 4, 4, 5, 4, 5], +[0, 6, 5, 6, 6, 4, 7, 4, 7, 6, 7, 8, 6, 7, 7, 6, 5, 6, 2, 5, 2, 4, 5, 5, 6, 5], +[1, 4, 3, 3, 2, 5, 3, 8, 7, 9, 8, 6, 6, 6, 6, 7, 7, 6, 6, 3, 5, 4, 5, 6, 5, 5], +[0, 4, 2, 2, 3, 2, 6, 5, 7, 8, 6, 6, 5, 4, 6, 5, 7, 7, 6, 7, 6, 5, 6, 5, 5], +[0, 5, 3, 6, 4, 5, 5, 5, 5, 5, 4, 5, 5, 3, 6, 2, 5, 4, 5, 6, 7, 8, 8, 6, 5, 6], +[1, 2, 6, 4, 8, 7, 7, 6, 4, 2, 3, 3, 3, 5, 3, 5, 3, 4, 5, 5, 7, 7, 8, 8, 6, 5], +[0, 6, 4, 7, 7, 7, 8, 5, 3, 3, 1, 3, 3, 3, 5, 4, 5, 5, 5, 6, 5, 5, 7, 4, 6], +[0, 6, 6, 7, 6, 7, 6, 5, 5, 5, 3, 6, 3, 6, 5, 5, 6, 6, 6, 7, 5, 5, 5, 2, 6, 3], +[1, 7, 8, 7, 7, 5, 3, 3, 5, 3, 8, 4, 7, 4, 5, 5, 4, 5, 6, 6, 6, 5, 4, 5, 3, 6], +[0, 7, 7, 8, 6, 5, 5, 2, 4, 5, 5, 8, 6, 7, 6, 4, 5, 4, 3, 5, 3, 5, 4, 5, 5, 5], +[1, 5, 6, 5, 5, 6, 4, 7, 5, 7, 7, 7, 8, 8, 7, 7, 7, 4, 6, 1, 5, 3, 4, 6, 5], +[1, 5, 4, 3, 3, 4, 2, 7, 5, 9, 8, 7, 8, 6, 7, 7, 7, 7, 7, 4, 5, 2, 4, 5, 4, 6], +[0, 5, 4, 4, 3, 3, 6, 5, 8, 8, 8, 7, 5, 6, 5, 4, 6, 6, 6, 7, 6, 6, 5, 5, 5, 5], +[1, 4, 5, 3, 5, 5, 5, 6, 5, 5, 6, 4, 5, 6, 3, 6, 3, 5, 5, 7, 8, 8, 8, 7, 6, 4], +[0, 6, 2, 8, 5, 8, 6, 5, 4, 4, 3, 4, 4, 3, 6, 3, 5, 4, 5, 6, 6, 7, 8, 7, 6], +[0, 5, 4, 7, 5, 7, 8, 7, 7, 4, 3, 4, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 7, 4], +[1, 6, 6, 6, 7, 6, 6, 6, 5, 4, 6, 2, 6, 3, 4, 5, 5, 6, 6, 6, 6, 5, 2, 5, 2, 7], +[0, 6, 7, 8, 7, 5, 4, 3, 3, 5, 3, 7, 3, 5, 5, 4, 5, 4, 6, 6, 5, 4, 4, 2, 5, 4], +[1, 6, 7, 6, 6, 5, 3, 4, 3, 4, 7, 6, 8, 7, 6, 6, 4, 5, 6, 4, 6, 5, 5, 5, 4], +[1, 5, 5, 4, 5, 4, 3, 6, 3, 6, 5, 6, 7, 7, 7, 7, 6, 5, 6, 2, 5, 2, 5, 5, 6, 6], +[0, 5, 4, 4, 3, 2, 6, 4, 9, 7, 9, 7, 6, 6, 6, 6, 6, 6, 4, 6, 2, 4, 4, 5, 6, 5], +[1, 5, 4, 3, 3, 3, 3, 6, 5, 7, 7, 6, 6, 4, 4, 6, 4, 6, 5, 6, 8, 6, 6, 6, 5, 5], +[0, 6, 3, 6, 4, 5, 5, 5, 5, 5, 5, 4, 4, 3, 5, 2, 5, 3, 6, 6, 7, 7, 7, 6, 6], +[0, 5, 3, 7, 5, 8, 8, 8, 6, 5, 3, 3, 4, 4, 5, 3, 5, 2, 4, 4, 4, 6, 6, 6, 6, 5], +[1, 4, 6, 4, 7, 8, 8, 9, 6, 5, 4, 3, 4, 3, 4, 5, 4, 4, 5, 4, 5, 4, 4, 6, 3, 6], +[0, 5, 6, 7, 7, 6, 7, 5, 5, 5, 3, 6, 2, 4, 3, 4, 5, 5, 5, 6, 5, 4, 5, 1, 5, 3], +[1, 7, 7, 6, 6, 5, 3, 3, 4, 3, 7, 4, 8, 5, 6, 6, 5, 6, 7, 6, 6, 5, 3, 4, 2], +[1, 5, 6, 6, 7, 5, 3, 4, 2, 4, 5, 5, 8, 7, 7, 7, 5, 6, 5, 4, 5, 4, 5, 4, 5, 5], +[0, 5, 5, 6, 4, 5, 5, 2, 7, 4, 6, 6, 6, 7, 7, 6, 7, 5, 4, 5, 1, 5, 3, 5, 6, 5], +[1, 5, 4, 2, 2, 3, 2, 6, 4, 8, 6, 6, 7, 5, 6, 7, 7, 7, 7, 4, 6, 3, 4, 5, 5], +[1, 7, 5, 3, 2, 2, 2, 4, 4, 6, 6, 6, 7, 5, 5, 5, 3, 7, 6, 6, 7, 7, 7, 6, 5, 5], +[0, 5, 4, 5, 2, 5, 4, 5, 6, 6, 5, 6, 5, 5, 5, 3, 6, 2, 5, 5, 6, 8, 7, 7, 6, 5], +[1, 3, 5, 2, 8, 6, 7, 7, 5, 5, 4, 2, 4, 3, 2, 5, 2, 4, 3, 4, 6, 6, 8, 7, 6, 6], +[0, 6, 4, 7, 6, 8, 8, 6, 6, 4, 2, 3, 1, 3, 4, 3, 5, 4, 3, 4, 4, 5, 5, 3, 6], +[0, 5, 6, 7, 6, 7, 7, 5, 6, 5, 4, 6, 2, 5, 3, 5, 5, 5, 6, 6, 6, 5, 5, 2, 5, 2], +[1, 6, 6, 7, 8, 6, 5, 4, 3, 3, 6, 4, 8, 5, 6, 5, 4, 6, 4, 6, 6, 5, 4, 4, 2, 5], +[0, 5, 6, 8, 6, 7, 5, 3, 5, 4, 5, 7, 6, 7, 6, 5, 5, 3, 4, 5, 3, 5, 3, 4, 5, 4], +[1, 4, 5, 4, 5, 5, 3, 6, 3, 7, 5, 6, 7, 6, 6, 7, 7, 6, 6, 3, 5, 2, 4, 5, 5], +[1, 6, 5, 3, 3, 2, 2, 4, 2, 7, 6, 7, 7, 5, 6, 6, 7, 7, 6, 6, 6, 2, 5, 4, 4, 6], +[0, 5, 4, 4, 2, 2, 2, 3, 5, 6, 7, 8, 6, 6, 5, 5, 6, 5, 6, 6, 6, 5, 6, 5, 6, 4], +[1, 5, 5, 2, 6, 3, 4, 5, 4, 5, 5, 4, 5, 4, 4, 5, 2, 5, 3, 5, 6, 6, 7, 7, 6, 5], +[0, 5, 3, 6, 4, 8, 6, 7, 5, 3, 2, 2, 2, 3, 5, 2, 5, 1, 3, 4, 5, 7, 7, 5, 6], +[0, 4, 3, 5, 4, 8, 7, 8, 8, 5, 5, 4, 2, 3, 3, 4, 5, 5, 5, 6, 5, 6, 5, 4, 6, 3], +[1, 6, 5, 5, 6, 6, 5, 6, 5, 4, 6, 3, 6, 3, 4, 4, 4, 6, 5, 6, 7, 5, 4, 4, 2, 6], +[0, 4, 8, 8, 8, 7, 6, 3, 4, 4, 3, 7, 3, 7, 4, 4, 5, 4, 6, 6, 5, 5, 4, 3, 5, 3], +[1, 6, 7, 6, 7, 5, 4, 4, 2, 4, 5, 4, 7, 6, 6, 6, 4, 5, 5, 3, 5, 3, 6, 5, 4], +[1, 6, 6, 5, 6, 4, 4, 5, 3, 6, 4, 6, 6, 6, 7, 7, 7, 8, 6, 4, 5, 1, 5, 3, 5, 6], +[0, 5, 6, 5, 3, 2, 4, 3, 7, 6, 8, 7, 7, 7, 6, 6, 7, 6, 6, 6, 3, 5, 2, 4, 5, 4], +[1, 5, 4, 3, 2, 1, 3, 5, 5, 7, 7, 6, 7, 4, 5, 5, 3, 6, 4, 6, 6, 6, 6, 6, 5], +[1, 6, 4, 3, 5, 3, 5, 4, 5, 5, 5, 5, 5, 4, 5, 5, 2, 5, 2, 5, 5, 6, 7, 7, 6, 6], +[0, 5, 3, 5, 2, 7, 5, 8, 6, 5, 4, 4, 3, 4, 4, 4, 6, 3, 4, 4, 4, 6, 5, 6, 6, 4], +[1, 4, 4, 2, 5, 5, 7, 7, 6, 6, 4, 3, 4, 2, 3, 4, 4, 5, 5, 5, 5, 4, 4, 5, 4, 6], +[0, 4, 6, 6, 6, 6, 6, 5, 6, 5, 3, 5, 2, 5, 2, 3, 5, 4, 6, 6, 5, 5, 4, 2, 4], +[0, 2, 6, 6, 7, 7, 5, 4, 3, 3, 3, 5, 3, 6, 3, 4, 4, 3, 6, 5, 6, 6, 5, 4, 4, 3], +[1, 5, 4, 6, 7, 6, 5, 4, 1, 3, 2, 3, 6, 5, 7, 6, 5, 5, 4, 5, 5, 3, 5, 3, 4, 5], +[0, 4, 5, 5, 4, 5, 4, 3, 6, 3, 7, 5, 6, 7, 6, 6, 8, 6, 5, 5, 2, 5, 1, 4, 5, 5], +[1, 7, 5, 3, 3, 2, 2, 4, 3, 7, 6, 7, 7, 5, 6, 6, 6, 7, 5, 5, 5, 3, 4, 4, 5], +[1, 8, 5, 5, 4, 1, 2, 2, 3, 5, 5, 7, 6, 5, 5, 4, 3, 5, 3, 6, 4, 5, 6, 5, 5, 6], +[0, 5, 5, 5, 2, 5, 3, 5, 5, 5, 6, 6, 5, 6, 5, 4, 5, 2, 5, 3, 5, 6, 6, 7, 6, 5], +[1, 4, 4, 3, 7, 5, 8, 7, 6, 6, 5, 4, 3, 4, 4, 5, 3, 5, 2, 4, 4, 4, 6, 6, 5, 6], +[0, 4, 3, 5, 5, 8, 7, 8, 8, 5, 5, 4, 2, 4, 3, 4, 5, 4, 4, 5, 3, 5, 3, 3, 5], +[0, 3, 6, 4, 5, 6, 6, 6, 6, 5, 5, 5, 3, 6, 2, 5, 3, 4, 6, 6, 7, 7, 5, 4, 4, 1], +[1, 5, 4, 7, 7, 6, 6, 4, 3, 3, 4, 4, 7, 4, 6, 5, 4, 5, 4, 6, 6, 6, 6, 4, 2, 5], +[0, 3, 5, 6, 6, 8, 5, 3, 4, 2, 4, 5, 5, 7, 6, 6, 6, 4, 5, 4, 3, 5, 2, 4, 3], +[0, 3, 5, 5, 4, 5, 4, 3, 5, 2, 5, 3, 5, 6, 6, 7, 7, 7, 7, 6, 3, 4, 1, 4, 4, 5], +[1, 7, 5, 4, 4, 1, 2, 2, 2, 5, 3, 6, 6, 4, 6, 5, 6, 7, 6, 6, 6, 4, 5, 3, 4, 6], +[0, 5, 6, 4, 2, 2, 0, 1, 3, 3, 6, 6, 6, 6, 4, 4, 5, 3, 6, 4, 7, 7, 6, 6, 6, 4], +[1, 5, 4, 3, 4, 2, 5, 3, 4, 4, 5, 4, 5, 4, 4, 5, 2, 4, 1, 4, 4, 6, 7, 7, 7], +[1, 6, 5, 3, 5, 3, 8, 5, 7, 7, 5, 5, 3, 3, 3, 3, 3, 4, 1, 3, 2, 3, 6, 5, 6, 6], +[0, 4, 5, 4, 4, 7, 5, 8, 8, 6, 6, 3, 2, 3, 1, 3, 3, 4, 4, 4, 4, 5, 4, 5, 5, 4], +[1, 6, 4, 6, 6, 6, 7, 6, 5, 5, 5, 3, 5, 2, 5, 2, 3, 4, 4, 6, 6, 5, 5, 3, 2, 4], +[0, 2, 7, 7, 8, 8, 6, 6, 5, 4, 4, 5, 4, 6, 4, 5, 5, 3, 6, 4, 5, 5, 3, 3, 3], +[0, 2, 5, 5, 6, 8, 6, 7, 4, 3, 4, 3, 4, 6, 5, 7, 6, 4, 5, 3, 4, 4, 2, 5, 3, 4], +[1, 4, 4, 4, 5, 3, 5, 4, 3, 6, 3, 6, 4, 5, 6, 6, 7, 7, 5, 5, 5, 1, 4, 2, 5, 4], +[0, 5, 5, 3, 2, 1, 1, 1, 4, 3, 7, 6, 7, 7, 5, 7, 6, 6, 8, 6, 6, 5, 3, 4, 4, 4], +[1, 7, 4, 3, 3, 0, 1, 1, 2, 5, 5, 7, 7, 5, 6, 4, 4, 5, 4, 7, 5, 6, 6, 6, 5], +[1, 6, 4, 5, 5, 2, 5, 2, 5, 4, 4, 5, 5, 4, 5, 4, 4, 5, 1, 5, 2, 4, 6, 6, 7, 6], +[0, 4, 4, 4, 2, 6, 3, 7, 7, 6, 5, 3, 4, 3, 4, 3, 5, 3, 5, 2, 3, 5, 4, 7, 6, 6], +[1, 5, 3, 3, 4, 4, 7, 7, 6, 7, 4, 4, 2, 2, 3, 3, 4, 5, 4, 5, 5, 4, 5, 4, 4, 5], +[0, 3, 6, 5, 6, 6, 6, 6, 7, 5, 5, 5, 3, 5, 2, 3, 3, 4, 6, 5, 6, 6, 5, 4, 4], +[0, 1, 6, 5, 8, 8, 7, 7, 5, 4, 3, 4, 3, 5, 3, 5, 3, 3, 5, 3, 5, 5, 5, 5, 4, 3], +[1, 5, 3, 7, 7, 6, 7, 5, 4, 3, 1, 3, 3, 4, 6, 5, 5, 5, 3, 5, 4, 3, 4, 3, 4, 5], +[0, 5, 6, 5, 5, 6, 3, 4, 4, 3, 6, 4, 6, 6, 6, 7, 8, 6, 7, 5, 3, 4, 1, 5, 3], +[0, 5, 6, 4, 5, 3, 1, 2, 2, 2, 6, 4, 7, 7, 5, 7, 5, 6, 7, 6, 6, 6, 3, 4, 3, 5], +[1, 6, 5, 7, 4, 2, 2, 1, 2, 4, 4, 7, 6, 6, 7, 4, 4, 4, 3, 6, 4, 6, 5, 5, 6, 5], +[0, 4, 6, 4, 2, 4, 2, 5, 3, 4, 4, 5, 5, 5, 4, 5, 4, 2, 5, 1, 5, 5, 6, 7, 6, 6], +[1, 5, 4, 2, 4, 2, 6, 5, 7, 6, 4, 4, 3, 3, 4, 4, 4, 4, 2, 4, 3, 3, 6, 5, 6], +[1, 6, 4, 4, 3, 3, 6, 5, 8, 8, 6, 7, 4, 3, 4, 2, 4, 4, 4, 4, 4, 3, 5, 3, 4, 4], +[0, 2, 5, 3, 6, 5, 6, 7, 6, 5, 5, 5, 3, 5, 2, 4, 2, 4, 4, 4, 6, 6, 5, 4, 3, 2], +[1, 5, 3, 7, 6, 7, 7, 6, 4, 4, 3, 3, 5, 3, 5, 2, 4, 4, 3, 6, 5, 6, 5, 4, 3, 3], +[0, 2, 5, 5, 6, 8, 6, 5, 4, 2, 3, 3, 4, 6, 5, 7, 7, 5, 6, 4, 4, 5, 2, 4, 2], +[0, 4, 4, 4, 5, 5, 3, 4, 3, 3, 5, 2, 6, 5, 5, 6, 6, 7, 7, 6, 5, 5, 2, 5, 2, 5], +[1, 6, 5, 7, 5, 3, 2, 1, 1, 4, 3, 6, 5, 6, 5, 4, 6, 5, 6, 7, 5, 5, 5, 3, 5, 5], +[0, 6, 7, 5, 4, 3, 1, 2, 1, 2, 5, 5, 6, 6, 4, 5, 4, 4, 6, 3, 6, 5, 6, 6, 6, 6], +[1, 7, 5, 5, 4, 2, 5, 3, 5, 4, 5, 5, 5, 4, 6, 4, 3, 4, 1, 4, 2, 4, 6, 5, 7], +[1, 6, 4, 4, 4, 3, 6, 4, 8, 7, 7, 6, 4, 4, 4, 4, 4, 4, 3, 4, 2, 3, 4, 4, 6, 5], +[0, 4, 4, 3, 3, 4, 5, 7, 8, 7, 8, 5, 5, 3, 2, 3, 2, 4, 4, 3, 4, 5, 3, 5, 4, 3], +[1, 5, 3, 5, 4, 6, 6, 6, 6, 6, 4, 5, 4, 2, 4, 1, 3, 2, 3, 5, 5, 6, 6, 4, 3, 4], +[0, 1, 5, 4, 7, 7, 7, 5, 4, 4, 4, 4, 4, 6, 4, 6, 4, 3, 5, 3, 6, 5, 4, 4, 3], +[0, 2, 4, 2, 5, 6, 5, 7, 5, 3, 3, 2, 3, 5, 4, 6, 6, 5, 7, 4, 5, 4, 3, 4, 2, 4], +[1, 4, 5, 5, 5, 4, 5, 2, 3, 4, 2, 6, 3, 5, 5, 5, 7, 7, 6, 7, 5, 4, 4, 1, 4, 3], +[0, 6, 7, 4, 4, 3, 0, 1, 1, 1, 4, 3, 6, 5, 5, 6, 5, 7, 7, 7, 7, 6, 3, 5, 4], +[0, 5, 7, 5, 6, 3, 2, 2, -1, 1, 2, 3, 5, 5, 4, 6, 3, 5, 4, 4, 5, 4, 6, 6, 6, 6], +[1, 6, 5, 6, 4, 4, 5, 2, 5, 3, 5, 5, 5, 5, 6, 4, 4, 4, 0, 4, 1, 4, 4, 5, 8, 7], +[0, 7, 5, 3, 3, 5, 3, 7, 5, 7, 7, 5, 5, 3, 3, 4, 3, 4, 3, 2, 3, 3, 3, 6, 5, 6], +[1, 6, 4, 4, 4, 3, 6, 6, 8, 8, 5, 6, 3, 3, 2, 2, 3, 3, 4, 4, 4, 4, 5, 4, 5], +[1, 3, 3, 5, 3, 6, 6, 6, 7, 7, 6, 6, 5, 5, 5, 2, 5, 2, 3, 5, 5, 6, 5, 4, 4, 3], +[0, 2, 4, 2, 7, 7, 8, 8, 6, 6, 5, 4, 4, 6, 4, 6, 3, 4, 4, 3, 6, 4, 5, 5, 3, 2], +[1, 3, 2, 5, 5, 7, 8, 6, 7, 5, 3, 4, 3, 4, 5, 6, 6, 6, 5, 6, 4, 4, 3, 2, 4, 2], +[0, 3, 5, 4, 5, 5, 3, 4, 4, 2, 5, 2, 6, 5, 6, 7, 7, 7, 8, 7, 7, 5, 2, 4, 2], +[0, 5, 6, 5, 6, 3, 1, 1, 0, 1, 4, 2, 6, 4, 6, 6, 4, 7, 6, 7, 7, 5, 5, 5, 3, 5], +[1, 5, 6, 8, 4, 4, 2, 0, 2, 1, 2, 5, 5, 5, 6, 4, 6, 4, 4, 5, 3, 5, 4, 5, 6, 5], +[0, 5, 6, 3, 4, 3, 1, 5, 2, 4, 3, 4, 5, 4, 4, 5, 4, 4, 4, 2, 4, 2, 5, 6, 6, 8], +[1, 6, 4, 3, 3, 1, 5, 3, 7, 5, 5, 5, 3, 4, 3, 4, 4, 4, 2, 4, 2, 3, 5, 4, 7], +[1, 5, 5, 4, 3, 2, 4, 4, 7, 7, 7, 8, 5, 5, 3, 2, 4, 2, 4, 4, 4, 5, 5, 4, 5, 3], +[0, 3, 5, 2, 5, 4, 6, 7, 6, 6, 6, 5, 5, 5, 2, 4, 1, 3, 3, 4, 5, 5, 6, 5, 4, 3], +[1, 4, 3, 6, 5, 8, 9, 7, 6, 5, 4, 4, 4, 4, 5, 3, 5, 3, 2, 4, 3, 5, 5, 4, 4], +[1, 3, 2, 4, 4, 6, 7, 6, 8, 5, 4, 4, 2, 4, 4, 4, 6, 6, 5, 6, 3, 6, 4, 3, 4, 2], +[0, 5, 4, 4, 5, 6, 4, 5, 3, 3, 4, 2, 5, 3, 5, 5, 5, 7, 7, 7, 7, 5, 3, 4, 1, 4], +[1, 4, 5, 7, 5, 5, 4, 2, 2, 3, 3, 5, 4, 6, 6, 5, 6, 5, 6, 6, 5, 5, 4, 3, 5, 3], +[0, 5, 7, 5, 6, 4, 2, 2, 1, 3, 3, 4, 6, 5, 4, 6, 3, 5, 5, 4, 5, 4, 6, 6, 6], +[0, 6, 6, 5, 6, 3, 3, 5, 2, 5, 3, 4, 5, 5, 5, 5, 4, 5, 3, 3, 4, 1, 4, 5, 6, 7], +[1, 6, 5, 5, 2, 2, 3, 2, 6, 6, 7, 7, 5, 6, 4, 5, 5, 4, 4, 4, 2, 4, 3, 3, 6, 4], +[0, 6, 5, 3, 2, 2, 3, 5, 6, 7, 8, 6, 7, 4, 4, 3, 3, 4, 3, 4, 5, 4, 5, 5, 4, 5], +[1, 4, 3, 5, 3, 6, 5, 6, 6, 7, 5, 6, 5, 4, 5, 2, 4, 2, 3, 4, 4, 6, 5, 5, 4], +[1, 3, 1, 4, 3, 6, 7, 8, 7, 6, 5, 4, 3, 4, 5, 4, 6, 4, 4, 5, 4, 6, 5, 6, 5, 3], +[0, 3, 3, 2, 5, 5, 6, 7, 6, 5, 3, 3, 4, 3, 4, 5, 6, 6, 7, 5, 7, 4, 5, 5, 3, 5], +[1, 3, 5, 5, 5, 5, 6, 4, 5, 3, 3, 5, 3, 6, 4, 5, 6, 6, 7, 8, 6, 6, 5, 2, 5, 3], +[0, 5, 7, 6, 7, 4, 2, 2, 1, 1, 4, 2, 6, 3, 4, 5, 4, 7, 5, 7, 7, 6, 5, 6, 4], +[0, 6, 7, 7, 8, 5, 4, 2, 0, 2, 1, 2, 5, 4, 5, 6, 3, 5, 3, 4, 5, 3, 5, 4, 6, 6], +[1, 6, 6, 7, 4, 5, 4, 3, 5, 3, 5, 4, 5, 6, 5, 6, 6, 4, 4, 4, 1, 4, 2, 4, 6, 5], +[0, 7, 6, 4, 4, 3, 3, 6, 4, 8, 7, 6, 7, 4, 5, 4, 4, 5, 4, 3, 4, 2, 3, 4, 4, 7], +[1, 5, 5, 4, 2, 3, 4, 5, 7, 7, 7, 8, 4, 5, 3, 2, 4, 2, 3, 3, 4, 4, 5, 4, 5], +[1, 3, 4, 4, 3, 5, 4, 6, 6, 7, 6, 6, 5, 6, 5, 4, 4, 2, 4, 3, 4, 6, 5, 6, 5, 3], +[0, 3, 2, 2, 5, 5, 7, 7, 6, 6, 4, 4, 4, 4, 5, 6, 4, 5, 4, 3, 5, 3, 6, 4, 4, 4], +[1, 3, 2, 4, 3, 6, 7, 6, 8, 4, 4, 4, 3, 5, 5, 6, 7, 6, 5, 6, 4, 6, 3, 3, 4, 2], +[0, 5, 4, 4, 5, 5, 3, 5, 3, 3, 4, 2, 5, 2, 4, 5, 5, 7, 8, 7, 8, 6, 5, 5, 2], +[0, 5, 5, 6, 8, 5, 4, 2, 0, 1, 2, 1, 4, 3, 4, 5, 4, 6, 5, 7, 6, 6, 7, 5, 4, 5], +[1, 5, 5, 8, 5, 7, 4, 2, 2, 0, 2, 4, 4, 5, 6, 5, 7, 4, 6, 5, 4, 6, 4, 6, 6, 6], +[0, 6, 6, 5, 6, 3, 4, 5, 2, 5, 4, 5, 5, 4, 5, 6, 5, 5, 4, 3, 4, 2, 5, 5, 6], +[0, 8, 7, 6, 5, 4, 3, 4, 3, 7, 6, 7, 7, 5, 6, 3, 4, 4, 4, 4, 4, 2, 3, 3, 4, 7], +[1, 5, 7, 5, 3, 3, 3, 4, 5, 5, 8, 8, 6, 7, 3, 4, 3, 2, 4, 4, 5, 4, 5, 5, 6, 3], +[0, 5, 4, 3, 5, 3, 6, 5, 6, 6, 7, 6, 6, 5, 5, 5, 3, 4, 2, 4, 5, 5, 7, 5, 5, 4], +[1, 3, 2, 4, 3, 7, 8, 8, 9, 6, 6, 5, 5, 5, 6, 5, 5, 3, 4, 4, 3, 6, 3, 5, 4], +[1, 3, 2, 2, 2, 5, 6, 7, 9, 6, 7, 4, 3, 4, 3, 5, 5, 5, 6, 7, 5, 7, 4, 5, 4, 2], +[0, 4, 3, 4, 5, 4, 5, 5, 3, 5, 3, 3, 4, 2, 5, 3, 5, 6, 6, 7, 8, 7, 6, 5, 2, 5], +[1, 3, 6, 7, 6, 6, 4, 2, 2, 0, 2, 4, 3, 6, 4, 5, 6, 5, 7, 6, 7, 7, 5, 4, 5, 3], +[0, 5, 6, 6, 8, 5, 4, 3, 0, 2, 1, 3, 5, 5, 6, 6, 3, 6, 4, 4, 5, 4, 6, 5, 5], +[0, 7, 6, 6, 7, 5, 5, 4, 2, 5, 3, 5, 4, 3, 5, 5, 5, 5, 4, 4, 4, 2, 4, 3, 5, 7], +[1, 6, 7, 6, 3, 3, 2, 2, 5, 3, 7, 5, 5, 6, 3, 5, 4, 5, 5, 5, 4, 4, 2, 3, 6, 5], +[0, 7, 5, 4, 4, 2, 2, 4, 4, 7, 6, 7, 8, 4, 5, 3, 3, 4, 3, 5, 4, 4, 5, 6, 4, 7], +[1, 3, 4, 5, 4, 6, 5, 6, 7, 7, 7, 7, 5, 6, 5, 3, 4, 2, 3, 3, 3, 6, 5, 6, 5], +[1, 3, 3, 3, 2, 5, 6, 8, 9, 7, 8, 5, 5, 5, 5, 5, 5, 4, 5, 3, 3, 5, 3, 6, 5, 4], +[0, 4, 3, 3, 4, 5, 7, 8, 7, 9, 4, 4, 4, 3, 4, 4, 5, 6, 6, 5, 7, 4, 6, 4, 4, 4], +[1, 3, 5, 4, 5, 6, 6, 4, 6, 4, 5, 4, 4, 6, 4, 6, 6, 6, 8, 8, 7, 7, 5, 4, 4], +[1, 2, 5, 5, 6, 8, 6, 5, 3, 2, 3, 2, 3, 5, 4, 5, 5, 4, 7, 5, 7, 6, 6, 6, 4, 3], +[0, 5, 4, 6, 9, 6, 7, 4, 3, 2, 1, 2, 3, 3, 5, 5, 4, 6, 3, 5, 4, 4, 5, 4, 5, 6], +[1, 6, 7, 6, 5, 5, 4, 4, 4, 2, 5, 3, 4, 6, 5, 6, 6, 6, 7, 5, 3, 4, 2, 5, 6, 6], +[0, 8, 6, 5, 4, 2, 2, 3, 2, 6, 5, 7, 7, 5, 6, 4, 6, 5, 5, 5, 5, 3, 4, 4, 4], +[0, 8, 5, 7, 5, 4, 4, 2, 4, 6, 6, 8, 8, 6, 8, 3, 4, 4, 3, 4, 4, 4, 5, 4, 5, 5], +[1, 4, 5, 4, 3, 4, 4, 6, 6, 6, 7, 6, 6, 7, 5, 5, 4, 3, 4, 2, 4, 5, 5, 7, 6, 5], +[0, 4, 3, 3, 4, 3, 7, 7, 8, 7, 6, 5, 4, 3, 4, 5, 4, 5, 4, 3, 5, 4, 7, 5, 6, 5], +[1, 3, 2, 3, 2, 5, 6, 7, 9, 6, 7, 5, 4, 4, 3, 5, 6, 6, 6, 7, 5, 7, 4, 5, 4], +[1, 3, 4, 4, 4, 6, 5, 5, 6, 3, 5, 4, 4, 4, 3, 5, 3, 4, 6, 6, 8, 8, 6, 6, 5, 3], +[0, 5, 5, 7, 8, 7, 7, 4, 3, 2, 1, 2, 4, 2, 5, 4, 4, 5, 3, 6, 5, 7, 7, 5, 4, 5], +[1, 4, 6, 7, 7, 9, 5, 5, 3, 2, 2, 2, 3, 4, 5, 5, 7, 4, 6, 4, 5, 5, 3, 6, 5, 5], +[0, 7, 7, 7, 7, 4, 6, 5, 3, 6, 3, 5, 4, 5, 6, 5, 6, 7, 5, 4, 3, 1, 4, 3, 6], +[0, 8, 7, 7, 6, 4, 4, 4, 3, 6, 6, 8, 7, 6, 8, 4, 6, 5, 5, 5, 4, 3, 3, 2, 3, 6], +[1, 4, 8, 5, 5, 4, 2, 3, 4, 5, 8, 8, 7, 9, 4, 7, 3, 4, 4, 3, 5, 5, 4, 5, 6, 4], +[0, 6, 3, 4, 4, 3, 5, 4, 6, 7, 7, 7, 7, 5, 7, 5, 4, 5, 2, 3, 4, 4, 6, 5, 7, 5], +[1, 3, 3, 2, 2, 6, 5, 7, 8, 7, 8, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 6, 3, 6, 4], +[1, 4, 3, 1, 1, 3, 4, 6, 8, 6, 9, 5, 6, 4, 3, 5, 5, 6, 6, 7, 7, 7, 5, 7, 4, 4], +[0, 5, 3, 4, 5, 5, 6, 5, 4, 5, 3, 4, 4, 3, 5, 3, 4, 5, 6, 8, 8, 7, 7, 5, 4, 5], +[1, 3, 6, 6, 7, 8, 6, 5, 3, 1, 2, 2, 2, 4, 3, 5, 5, 4, 7, 6, 8, 7, 6, 7, 5, 4], +[0, 6, 5, 6, 8, 6, 7, 4, 3, 2, 1, 3, 4, 4, 5, 6, 5, 6, 3, 6, 4, 4, 6, 5, 6], +[0, 6, 6, 8, 8, 6, 7, 4, 5, 5, 3, 6, 4, 5, 5, 4, 6, 6, 5, 6, 3, 3, 4, 2, 5, 6], +[1, 7, 9, 7, 6, 5, 3, 3, 4, 3, 7, 6, 7, 6, 4, 6, 4, 5, 5, 5, 5, 4, 3, 4, 5, 5], +[0, 8, 6, 8, 5, 3, 3, 3, 4, 6, 6, 7, 8, 6, 7, 3, 4, 4, 3, 4, 4, 4, 5, 5, 5], +[0, 6, 4, 6, 3, 4, 5, 4, 7, 7, 7, 8, 7, 7, 8, 6, 6, 4, 3, 3, 2, 4, 5, 4, 7, 5], +[1, 5, 3, 1, 2, 4, 3, 8, 8, 8, 9, 7, 7, 5, 6, 6, 5, 5, 5, 4, 4, 5, 4, 7, 4, 6], +[0, 4, 2, 3, 2, 2, 5, 6, 7, 9, 6, 7, 4, 4, 4, 4, 4, 5, 5, 6, 7, 5, 8, 4, 5, 4], +[1, 2, 5, 3, 4, 4, 5, 5, 6, 3, 5, 3, 4, 4, 3, 5, 5, 5, 7, 7, 9, 8, 7, 7, 5], +[1, 3, 5, 4, 7, 7, 6, 7, 4, 3, 2, 2, 2, 4, 3, 5, 4, 5, 7, 4, 8, 6, 7, 6, 6, 4], +[0, 5, 4, 7, 8, 7, 9, 5, 6, 3, 2, 3, 2, 3, 4, 5, 5, 6, 4, 6, 3, 5, 4, 3, 5, 5], +[1, 6, 7, 6, 7, 7, 4, 6, 4, 3, 4, 3, 5, 5, 4, 6, 6, 6, 7, 5, 5, 4, 2, 5, 4, 6], +[0, 8, 7, 8, 5, 3, 3, 3, 2, 5, 4, 6, 6, 5, 7, 3, 6, 5, 6, 5, 5, 4, 4, 4, 5], +[0, 7, 6, 9, 6, 5, 3, 2, 3, 4, 5, 8, 8, 7, 9, 5, 7, 3, 4, 4, 4, 5, 5, 5, 6, 5], +[1, 4, 7, 4, 5, 5, 4, 6, 5, 6, 7, 7, 8, 8, 7, 8, 5, 4, 4, 2, 4, 4, 5, 7, 5, 7], +[0, 5, 3, 4, 3, 3, 6, 6, 8, 9, 6, 8, 6, 6, 5, 5, 5, 5, 4, 5, 4, 3, 7, 4, 7, 4], +[1, 5, 3, 2, 3, 4, 4, 6, 8, 6, 9, 4, 6, 4, 4, 5, 5, 6, 6, 6, 6, 8, 5, 7, 4], +[1, 4, 4, 4, 5, 4, 6, 6, 6, 5, 7, 4, 5, 4, 4, 4, 3, 5, 6, 6, 9, 8, 8, 8, 5, 5], +[0, 4, 3, 6, 6, 8, 9, 7, 6, 5, 2, 3, 3, 3, 5, 4, 4, 5, 4, 7, 5, 7, 6, 6, 6, 5], +[1, 4, 5, 5, 7, 9, 6, 8, 4, 4, 3, 1, 3, 4, 5, 5, 6, 5, 8, 4, 6, 4, 5, 6, 5], +[1, 6, 7, 7, 7, 7, 5, 6, 4, 4, 4, 3, 5, 4, 4, 6, 5, 6, 6, 5, 7, 4, 3, 4, 3, 5], +[0, 7, 7, 9, 6, 5, 4, 3, 2, 4, 3, 7, 6, 7, 8, 5, 8, 4, 6, 6, 5, 5, 3, 3, 4, 4], +[1, 5, 9, 6, 8, 4, 3, 3, 3, 4, 6, 6, 8, 8, 6, 8, 4, 6, 4, 4, 4, 4, 5, 5, 6, 5], +[0, 6, 4, 6, 4, 4, 5, 4, 6, 5, 6, 7, 6, 6, 7, 5, 6, 4, 3, 4, 2, 4, 5, 5, 8], +[0, 6, 5, 4, 2, 2, 4, 3, 7, 8, 7, 8, 6, 7, 5, 5, 7, 5, 6, 5, 5, 5, 6, 4, 8, 4], +[1, 7, 4, 2, 2, 2, 3, 5, 6, 6, 9, 6, 7, 4, 4, 5, 4, 6, 5, 6, 7, 7, 6, 8, 5, 6], +[0, 5, 4, 6, 4, 5, 6, 6, 6, 7, 5, 6, 4, 5, 4, 3, 4, 3, 5, 7, 7, 8, 8, 7, 6, 4], +[1, 3, 6, 5, 7, 9, 7, 8, 5, 4, 3, 3, 3, 4, 3, 4, 4, 4, 6, 4, 8, 6, 8, 7, 5], +[1, 5, 6, 5, 7, 9, 8, 11, 5, 6, 3, 2, 2, 2, 3, 4, 5, 6, 7, 5, 7, 4, 5, 5, 4, 5], +[0, 5, 6, 7, 8, 7, 8, 5, 7, 5, 4, 6, 5, 5, 5, 5, 7, 6, 7, 7, 5, 5, 4, 2, 4, 4], +[1, 6, 8, 7, 9, 5, 4, 4, 4, 4, 6, 5, 7, 7, 5, 7, 4, 7, 5, 6, 6, 4, 4, 4, 4, 5], +[0, 7, 6, 10, 5, 5, 4, 2, 3, 4, 6, 8, 7, 7, 9, 4, 8, 4, 4, 4, 3, 4, 4, 4, 6], +[0, 6, 5, 6, 3, 5, 4, 4, 5, 5, 6, 7, 7, 8, 8, 7, 9, 6, 5, 4, 3, 4, 5, 5, 7, 5], +[1, 6, 5, 3, 2, 1, 2, 5, 6, 7, 8, 7, 8, 6, 7, 6, 6, 7, 7, 5, 5, 5, 4, 7, 4, 8], +[0, 4, 4, 3, 2, 2, 4, 5, 6, 8, 7, 9, 4, 6, 4, 4, 5, 5, 6, 6, 7, 7, 8, 5, 7, 4], +[1, 5, 5, 4, 5, 4, 5, 6, 6, 5, 6, 4, 5, 3, 3, 4, 3, 5, 6, 6, 9, 8, 8, 8, 6], +[1, 5, 5, 4, 6, 7, 7, 9, 6, 6, 3, 2, 2, 2, 3, 4, 3, 4, 5, 3, 8, 5, 8, 7, 7, 6], +[0, 5, 4, 6, 7, 8, 10, 7, 9, 5, 4, 3, 2, 3, 4, 5, 5, 6, 4, 7, 4, 6, 4, 4, 5, 5], +[1, 6, 7, 7, 8, 8, 6, 7, 4, 5, 5, 3, 5, 4, 4, 5, 5, 6, 6, 5, 7, 4, 3, 4, 3], +[1, 6, 7, 7, 10, 7, 6, 5, 3, 3, 4, 4, 7, 5, 6, 6, 4, 7, 3, 5, 5, 5, 4, 3, 3, 4], +[0, 6, 5, 9, 6, 8, 5, 4, 3, 2, 4, 6, 6, 8, 9, 6, 8, 4, 6, 4, 4, 5, 4, 4, 5, 5], +[1, 5, 6, 4, 6, 4, 5, 5, 5, 6, 7, 6, 8, 8, 8, 9, 7, 8, 5, 4, 4, 2, 4, 5, 5, 8], +[0, 6, 4, 3, 2, 3, 4, 5, 7, 8, 9, 10, 7, 8, 6, 7, 6, 6, 5, 5, 4, 5, 6, 4, 7], +[0, 4, 6, 4, 2, 2, 2, 3, 5, 7, 7, 9, 6, 8, 4, 5, 5, 4, 6, 6, 7, 8, 8, 7, 8, 5], +[1, 6, 4, 3, 4, 3, 5, 5, 5, 5, 6, 5, 6, 4, 4, 4, 3, 4, 5, 5, 7, 7, 9, 8, 7, 6], +[0, 4, 3, 5, 4, 8, 9, 7, 8, 5, 4, 3, 3, 4, 4, 4, 5, 4, 4, 6, 4, 9, 6, 7, 5, 5], +[1, 4, 5, 5, 7, 8, 7, 10, 6, 7, 4, 3, 3, 3, 4, 5, 5, 5, 7, 5, 7, 4, 6, 4, 5], +[1, 6, 6, 6, 8, 7, 7, 8, 5, 6, 4, 4, 4, 3, 3, 5, 3, 7, 6, 7, 7, 6, 5, 4, 3, 4], +[0, 5, 7, 10, 7, 8, 6, 4, 3, 2, 3, 5, 5, 6, 7, 5, 8, 4, 8, 5, 6, 6, 4, 4, 5, 4], +[1, 5, 8, 6, 9, 5, 5, 4, 3, 3, 4, 5, 7, 7, 7, 8, 4, 8, 4, 5, 4, 4, 4, 5, 5, 7], +[0, 7, 6, 7, 4, 6, 5, 4, 6, 5, 7, 7, 6, 8, 8, 7, 8, 5, 5, 3, 3, 4, 4, 5, 8], +[0, 6, 7, 6, 3, 3, 3, 3, 5, 6, 8, 9, 6, 8, 5, 7, 6, 6, 7, 6, 5, 5, 5, 4, 8, 5], +[1, 8, 5, 4, 3, 2, 2, 3, 5, 6, 8, 6, 8, 4, 6, 4, 4, 5, 5, 6, 6, 7, 7, 8, 5, 7], +[0, 4, 5, 4, 4, 6, 5, 6, 7, 7, 6, 7, 5, 6, 4, 4, 4, 3, 4, 6, 6, 8, 7, 8, 7, 5], +[1, 4, 4, 4, 6, 7, 8, 10, 6, 7, 4, 3, 4, 4, 4, 4, 3, 4, 5, 3, 8, 4, 8, 6, 6], +[1, 5, 4, 4, 6, 6, 7, 10, 7, 9, 4, 5, 2, 2, 3, 3, 4, 5, 6, 5, 7, 3, 6, 4, 4, 4], +[0, 4, 5, 7, 7, 7, 7, 5, 7, 4, 5, 4, 3, 4, 4, 4, 6, 6, 8, 8, 7, 7, 4, 4, 3, 3], +[1, 6, 7, 7, 10, 6, 6, 4, 3, 3, 4, 4, 7, 6, 6, 7, 4, 8, 4, 7, 5, 5, 5, 4, 3], +[1, 5, 6, 7, 10, 6, 9, 5, 4, 3, 3, 5, 6, 6, 7, 8, 6, 9, 4, 6, 4, 4, 4, 3, 4, 6], +[0, 5, 6, 7, 4, 6, 4, 4, 5, 4, 6, 6, 7, 8, 7, 8, 9, 7, 8, 5, 4, 5, 3, 5, 7, 6], +[1, 9, 6, 4, 4, 2, 2, 3, 3, 6, 8, 7, 8, 5, 8, 6, 7, 7, 6, 6, 5, 5, 5, 7, 5, 9], +[0, 5, 7, 4, 2, 2, 1, 3, 5, 7, 7, 9, 6, 8, 4, 5, 5, 4, 6, 6, 7, 7, 7, 7, 9], +[0, 5, 6, 4, 4, 5, 4, 5, 6, 6, 7, 7, 5, 6, 4, 4, 4, 3, 3, 3, 4, 7, 6, 9, 8, 7], +[1, 7, 5, 4, 6, 6, 8, 10, 8, 9, 4, 5, 3, 3, 3, 3, 4, 4, 4, 3, 6, 3, 8, 5, 7, 5], +[0, 5, 4, 5, 5, 7, 8, 8, 11, 5, 7, 3, 4, 3, 3, 4, 5, 5, 6, 7, 5, 8, 3, 5, 4, 4], +[1, 5, 6, 6, 7, 7, 7, 8, 5, 7, 4, 5, 5, 4, 5, 6, 4, 7, 6, 8, 7, 5, 5, 3, 2], +[1, 4, 5, 6, 10, 8, 9, 6, 4, 5, 4, 4, 6, 5, 6, 7, 4, 8, 3, 8, 5, 6, 6, 4, 3, 4], +[0, 4, 5, 8, 6, 10, 5, 5, 3, 3, 3, 4, 5, 7, 7, 6, 9, 5, 8, 4, 5, 4, 4, 5, 6, 5], +[1, 6, 6, 5, 7, 3, 5, 3, 3, 5, 5, 6, 7, 6, 8, 8, 7, 9, 5, 6, 4, 3, 4, 5, 5, 8], +[0, 6, 7, 4, 2, 2, 1, 2, 5, 6, 8, 9, 7, 9, 6, 8, 7, 6, 7, 6, 6, 4, 4, 4, 8], +[0, 4, 8, 4, 4, 2, 1, 2, 3, 4, 6, 8, 6, 8, 4, 6, 3, 5, 5, 4, 6, 7, 7, 7, 8, 5], +[1, 8, 4, 5, 4, 4, 6, 4, 5, 6, 6, 5, 6, 4, 5, 3, 3, 3, 2, 4, 5, 6, 9, 8, 8, 7], +[0, 5, 4, 4, 4, 6, 7, 7, 9, 6, 7, 3, 3, 3, 3, 4, 4, 3, 4, 5, 3, 8, 5, 9, 5, 6], +[1, 4, 4, 4, 5, 6, 7, 10, 6, 9, 5, 4, 3, 3, 3, 3, 4, 5, 6, 5, 7, 3, 7, 4, 5], +[1, 6, 5, 7, 8, 8, 9, 9, 6, 8, 5, 6, 4, 4, 4, 3, 4, 6, 4, 7, 7, 5, 6, 4, 3, 4], +[0, 3, 6, 9, 8, 10, 7, 7, 5, 3, 4, 4, 4, 6, 6, 6, 7, 3, 8, 5, 7, 5, 4, 5, 4, 3], +[1, 5, 6, 7, 11, 6, 9, 5, 4, 4, 3, 4, 6, 7, 8, 8, 6, 9, 4, 7, 3, 4, 4, 4, 4], +[1, 5, 5, 6, 7, 4, 7, 4, 5, 5, 5, 7, 7, 7, 9, 7, 9, 9, 7, 8, 5, 4, 3, 3, 4, 6], +[0, 5, 8, 5, 4, 3, 1, 2, 3, 4, 7, 8, 7, 10, 5, 8, 6, 7, 7, 6, 6, 5, 5, 5, 7, 5], +[1, 10, 4, 7, 3, 2, 1, 1, 3, 5, 6, 7, 9, 5, 9, 3, 5, 5, 4, 5, 6, 6, 7, 8, 7, 8], +[0, 4, 6, 4, 4, 4, 3, 4, 5, 6, 6, 6, 5, 7, 5, 5, 4, 3, 4, 5, 4, 8, 6, 9, 7], +[0, 6, 5, 3, 3, 5, 5, 7, 9, 6, 8, 5, 5, 4, 3, 4, 4, 5, 4, 4, 3, 7, 4, 8, 6, 7], +[1, 6, 5, 4, 5, 5, 7, 9, 7, 11, 5, 7, 3, 3, 3, 3, 4, 5, 5, 6, 7, 5, 7, 4, 6, 4], +[0, 5, 5, 6, 7, 8, 7, 7, 8, 5, 6, 3, 4, 3, 2, 3, 5, 3, 7, 6, 8, 8, 6, 6, 3, 4], +[1, 5, 6, 7, 10, 7, 9, 5, 4, 3, 3, 3, 5, 5, 5, 6, 4, 7, 3, 8, 5, 6, 5, 4, 4], +[1, 4, 4, 6, 9, 6, 11, 5, 7, 3, 3, 4, 4, 5, 7, 7, 6, 9, 4, 8, 3, 5, 4, 4, 4, 5], +[0, 5, 7, 7, 6, 8, 4, 6, 4, 4, 5, 5, 6, 7, 6, 8, 7, 6, 9, 5, 6, 4, 3, 4, 5, 5], +[1, 9, 6, 8, 5, 2, 3, 2, 2, 5, 6, 6, 8, 5, 8, 5, 7, 6, 6, 7, 5, 5, 4, 5, 4, 9], +[0, 5, 9, 4, 5, 2, 1, 3, 4, 5, 6, 8, 6, 9, 5, 8, 4, 5, 5, 5, 5, 7, 7, 6, 7], +[0, 5, 8, 4, 5, 4, 4, 5, 5, 6, 7, 6, 6, 7, 5, 6, 4, 5, 3, 3, 3, 6, 5, 9, 7, 7], +[1, 6, 4, 4, 3, 4, 7, 8, 8, 10, 7, 8, 4, 5, 4, 4, 4, 4, 4, 3, 4, 3, 8, 4, 8, 5], +[0, 5, 4, 3, 4, 5, 7, 8, 10, 6, 10, 4, 5, 3, 3, 3, 4, 5, 6, 7, 6, 8, 4, 7, 4, 5], +[1, 5, 5, 5, 6, 7, 7, 7, 5, 7, 4, 6, 4, 3, 4, 4, 3, 6, 4, 8, 7, 6, 7, 3, 3], +[1, 3, 3, 5, 9, 8, 10, 6, 7, 5, 3, 4, 4, 4, 6, 6, 5, 7, 4, 9, 4, 7, 5, 5, 4, 3], +[0, 3, 4, 6, 6, 10, 6, 8, 4, 4, 3, 3, 4, 5, 6, 7, 8, 5, 8, 3, 7, 3, 4, 4, 4, 5], +[1, 6, 5, 6, 7, 4, 6, 2, 4, 3, 4, 5, 5, 5, 8, 6, 8, 8, 6, 7, 5, 4, 4, 4, 4], +[1, 8, 6, 8, 5, 4, 3, 1, 2, 3, 3, 6, 7, 6, 8, 5, 9, 6, 8, 7, 7, 6, 5, 5, 5, 7], +[0, 5, 9, 4, 7, 3, 1, 1, 1, 2, 5, 6, 6, 8, 4, 8, 3, 5, 4, 5, 5, 5, 6, 7, 8, 6], +[1, 9, 5, 7, 4, 5, 5, 4, 6, 6, 5, 6, 6, 5, 6, 3, 5, 3, 3, 3, 4, 3, 8, 6, 9, 7], +[0, 6, 5, 3, 4, 5, 6, 7, 9, 7, 9, 5, 5, 4, 3, 5, 4, 4, 3, 4, 3, 6, 4, 9, 5], +[0, 8, 4, 4, 4, 4, 5, 7, 9, 8, 10, 5, 7, 3, 3, 3, 3, 4, 5, 5, 5, 7, 5, 7, 3, 5], +[1, 4, 4, 5, 6, 7, 8, 8, 8, 8, 6, 8, 4, 5, 4, 3, 3, 5, 3, 7, 6, 7, 7, 4, 4, 2], +[0, 3, 3, 5, 6, 10, 8, 9, 6, 5, 4, 3, 4, 5, 5, 5, 5, 3, 7, 3, 8, 5, 6, 5, 3, 3], +[1, 4, 4, 5, 9, 6, 10, 4, 6, 3, 2, 3, 4, 5, 6, 7, 6, 9, 4, 8, 3, 5, 3, 4, 4], +[1, 5, 4, 5, 5, 5, 6, 3, 5, 3, 3, 4, 4, 5, 7, 7, 8, 9, 8, 9, 5, 6, 3, 2, 4, 5], +[0, 4, 9, 5, 6, 3, 1, 2, 0, 3, 4, 5, 5, 8, 5, 9, 4, 8, 7, 6, 7, 5, 5, 4, 5, 5], +[1, 9, 6, 10, 4, 5, 2, 1, 2, 3, 5, 5, 7, 5, 9, 3, 7, 3, 4, 4, 4, 5, 6, 6, 7, 8], +[0, 6, 8, 3, 6, 4, 4, 5, 4, 5, 6, 5, 6, 7, 4, 7, 3, 4, 3, 4, 4, 6, 5, 10, 8], +[0, 8, 7, 3, 4, 3, 4, 6, 6, 7, 9, 5, 7, 3, 4, 4, 3, 5, 3, 4, 3, 5, 3, 9, 5, 9], +[1, 5, 6, 5, 3, 4, 6, 7, 8, 10, 6, 10, 4, 6, 3, 3, 3, 3, 4, 5, 6, 5, 7, 4, 7, 3], +[0, 5, 4, 5, 6, 7, 7, 8, 7, 6, 8, 5, 6, 4, 4, 3, 3, 2, 5, 4, 7, 6, 6, 6, 3, 4], +[1, 3, 4, 7, 9, 8, 11, 6, 7, 4, 3, 4, 3, 5, 5, 5, 4, 6, 2, 7, 3, 7, 4, 4, 3], +[1, 3, 3, 4, 6, 6, 10, 6, 9, 4, 4, 4, 3, 4, 5, 6, 7, 9, 6, 9, 4, 6, 3, 4, 3, 3], +[0, 4, 5, 5, 5, 7, 3, 7, 3, 4, 4, 4, 5, 6, 6, 8, 7, 8, 9, 6, 8, 4, 4, 3, 3, 4], +[1, 7, 5, 9, 5, 4, 3, 0, 2, 3, 4, 5, 7, 6, 9, 4, 9, 5, 7, 7, 5, 6, 5, 4, 4], +[1, 7, 5, 10, 4, 7, 2, 1, 1, 1, 2, 4, 5, 5, 8, 4, 9, 3, 6, 4, 4, 5, 6, 6, 7, 7], +[0, 7, 9, 4, 7, 3, 3, 3, 3, 4, 5, 4, 6, 6, 5, 7, 4, 6, 3, 3, 3, 4, 4, 8, 6, 9], +[1, 7, 6, 5, 3, 3, 4, 5, 7, 9, 6, 9, 5, 6, 3, 4, 4, 4, 4, 3, 3, 2, 6, 3, 9, 4], +[0, 7, 4, 3, 2, 3, 5, 6, 8, 7, 11, 4, 8, 2, 3, 2, 3, 3, 4, 5, 6, 7, 4, 7, 3], +[0, 6, 3, 4, 5, 5, 6, 8, 7, 7, 7, 5, 7, 3, 4, 2, 3, 2, 4, 2, 7, 5, 7, 7, 5, 4], +[1, 3, 3, 4, 5, 7, 9, 7, 9, 6, 5, 5, 4, 4, 5, 4, 5, 6, 3, 8, 3, 8, 5, 6, 4, 3], +[0, 2, 3, 4, 5, 9, 6, 10, 5, 7, 3, 4, 4, 5, 5, 7, 7, 6, 9, 4, 8, 3, 6, 3, 4, 4], +[1, 6, 5, 7, 6, 5, 7, 3, 6, 3, 4, 4, 5, 5, 6, 5, 9, 8, 7, 9, 4, 6, 3, 3, 3], +[1, 5, 5, 9, 6, 7, 4, 2, 2, 1, 3, 4, 5, 5, 8, 4, 9, 5, 9, 6, 6, 7, 5, 5, 4, 5], +[0, 5, 10, 5, 9, 4, 4, 2, 1, 1, 3, 3, 5, 7, 5, 8, 3, 8, 4, 5, 4, 5, 5, 6, 6, 6], +[1, 7, 4, 8, 3, 6, 3, 4, 5, 5, 5, 7, 6, 6, 7, 4, 7, 4, 4, 3, 3, 3, 5, 4, 8, 6], +[0, 7, 5, 3, 3, 2, 4, 6, 7, 7, 9, 5, 8, 4, 5, 4, 4, 4, 3, 4, 3, 5, 3, 9, 4], +[0, 9, 4, 4, 3, 2, 3, 4, 6, 6, 9, 5, 10, 3, 5, 2, 3, 2, 3, 3, 5, 6, 5, 7, 3, 7], +[1, 2, 4, 3, 4, 4, 6, 5, 7, 7, 6, 7, 5, 7, 3, 4, 3, 3, 3, 6, 4, 8, 6, 6, 6, 2], +[0, 3, 2, 3, 5, 8, 7, 10, 5, 6, 4, 3, 3, 3, 4, 5, 5, 4, 7, 2, 9, 3, 8, 4, 4, 3], +[1, 2, 3, 4, 6, 6, 10, 5, 9, 4, 5, 2, 3, 3, 4, 6, 6, 8, 5, 9, 3, 7, 2, 4, 4], +[1, 4, 4, 5, 5, 5, 6, 3, 6, 2, 4, 3, 3, 3, 5, 4, 8, 6, 8, 8, 7, 8, 4, 4, 3, 4], +[0, 5, 9, 6, 9, 5, 3, 2, 0, 1, 1, 3, 4, 6, 4, 8, 3, 8, 5, 7, 7, 6, 6, 5, 5, 5], +[1, 8, 6, 11, 5, 8, 3, 2, 2, 1, 3, 4, 6, 6, 8, 4, 8, 2, 6, 3, 4, 4, 4, 5, 7, 7], +[0, 6, 9, 4, 7, 3, 4, 4, 4, 5, 6, 4, 7, 5, 5, 6, 3, 5, 2, 2, 1, 3, 3, 8, 6], +[0, 9, 6, 6, 5, 2, 3, 4, 5, 6, 9, 6, 8, 3, 6, 2, 4, 4, 3, 3, 2, 3, 2, 6, 3, 9], +[1, 4, 7, 4, 3, 2, 3, 5, 7, 8, 7, 11, 5, 8, 3, 5, 2, 3, 3, 4, 5, 5, 7, 4, 7, 2], +[0, 5, 2, 3, 4, 5, 5, 7, 7, 7, 8, 6, 8, 4, 5, 3, 3, 2, 5, 3, 7, 5, 8, 6, 4], +[0, 4, 2, 3, 3, 6, 6, 10, 7, 10, 5, 5, 5, 4, 4, 4, 5, 4, 5, 2, 7, 3, 8, 3, 6, 3], +[1, 2, 2, 2, 4, 4, 8, 5, 9, 4, 6, 3, 3, 3, 4, 5, 7, 8, 6, 9, 4, 9, 3, 6, 2, 3], +[0, 3, 5, 4, 6, 5, 3, 6, 2, 5, 2, 4, 3, 4, 4, 7, 6, 8, 8, 8, 9, 5, 6, 3, 3, 3], +[1, 6, 5, 9, 5, 6, 4, 1, 2, 0, 3, 4, 5, 5, 8, 3, 8, 4, 8, 6, 7, 6, 5, 4, 4], +[1, 5, 5, 9, 5, 10, 4, 5, 1, 1, 1, 2, 3, 5, 6, 4, 8, 3, 7, 2, 5, 4, 4, 5, 6, 6], +[0, 8, 8, 5, 8, 2, 5, 3, 4, 3, 4, 3, 5, 4, 6, 6, 4, 6, 3, 3, 1, 3, 3, 6, 5, 10], +[1, 6, 7, 5, 2, 3, 2, 4, 5, 6, 7, 9, 5, 8, 3, 5, 4, 4, 4, 3, 3, 3, 5, 3, 9, 4], +[0, 9, 3, 4, 3, 2, 3, 4, 6, 7, 9, 5, 9, 3, 6, 2, 3, 2, 3, 3, 4, 5, 5, 7, 3], +[0, 7, 2, 6, 3, 4, 5, 6, 6, 7, 7, 6, 8, 4, 6, 3, 3, 2, 2, 2, 6, 3, 7, 5, 6, 5], +[1, 2, 3, 2, 4, 6, 9, 8, 10, 6, 7, 4, 4, 4, 4, 5, 4, 5, 3, 6, 2, 8, 3, 8, 3, 3], +[0, 2, 2, 2, 4, 6, 5, 10, 5, 9, 3, 4, 3, 3, 3, 5, 6, 6, 8, 5, 9, 3, 7, 2, 3, 3], +[1, 3, 3, 5, 5, 5, 6, 3, 6, 3, 5, 3, 4, 4, 6, 4, 8, 6, 8, 8, 6, 7, 3, 4, 2], +[1, 3, 4, 7, 5, 8, 3, 4, 2, 0, 2, 2, 4, 4, 6, 3, 8, 3, 9, 4, 8, 6, 5, 4, 4, 4], +[0, 5, 8, 5, 10, 3, 6, 1, 1, 0, 0, 2, 3, 5, 5, 7, 3, 7, 1, 5, 3, 4, 4, 4, 5, 7], +[1, 6, 6, 7, 3, 6, 2, 4, 3, 4, 3, 5, 4, 7, 5, 6, 8, 4, 6, 2, 3, 2, 3, 3, 8, 5], +[0, 9, 6, 4, 3, 2, 2, 3, 5, 6, 9, 5, 9, 3, 7, 3, 4, 5, 4, 4, 3, 4, 3, 7, 4], +[0, 10, 4, 7, 3, 3, 3, 3, 4, 6, 8, 6, 10, 4, 8, 1, 5, 1, 2, 2, 4, 4, 5, 7, 4, 8], +[1, 2, 6, 2, 4, 3, 5, 5, 7, 6, 6, 8, 5, 7, 4, 5, 2, 2, 2, 5, 3, 8, 5, 7, 7, 4], +[0, 4, 1, 2, 3, 6, 6, 9, 6, 9, 4, 5, 3, 4, 5, 4, 4, 4, 6, 2, 8, 3, 9, 4, 6], +[0, 4, 3, 2, 2, 5, 5, 9, 6, 10, 5, 7, 3, 3, 3, 4, 4, 6, 7, 6, 9, 4, 8, 2, 6, 2], +[1, 3, 3, 5, 4, 6, 6, 4, 7, 2, 6, 2, 3, 3, 4, 3, 6, 5, 8, 7, 7, 9, 5, 5, 3, 3], +[0, 4, 6, 6, 10, 5, 7, 3, 1, 1, 0, 2, 2, 3, 3, 7, 2, 8, 3, 8, 5, 6, 5, 4, 3, 4], +[1, 6, 5, 9, 5, 9, 3, 5, 1, 1, 2, 2, 4, 5, 7, 4, 9, 3, 8, 2, 5, 3, 4, 3, 6], +[1, 5, 6, 7, 4, 7, 2, 5, 2, 3, 3, 5, 3, 6, 5, 6, 6, 5, 7, 2, 4, 2, 2, 2, 6, 4], +[0, 10, 5, 7, 4, 2, 3, 2, 3, 5, 6, 6, 9, 4, 8, 3, 6, 4, 4, 4, 3, 2, 2, 4, 3, 8], +[1, 3, 8, 3, 3, 2, 1, 2, 4, 5, 6, 9, 5, 9, 2, 7, 2, 3, 2, 4, 3, 5, 5, 5, 8, 3], +[0, 7, 2, 4, 2, 4, 4, 6, 4, 7, 7, 6, 7, 4, 6, 3, 4, 2, 3, 2, 6, 3, 8, 5, 5], +[0, 5, 2, 2, 1, 3, 5, 9, 6, 11, 5, 8, 4, 4, 4, 4, 5, 4, 5, 3, 6, 2, 8, 3, 7, 2], +[1, 3, 2, 2, 2, 4, 7, 5, 10, 4, 9, 3, 4, 2, 2, 3, 4, 5, 6, 7, 5, 9, 3, 7, 3, 5], +[0, 2, 3, 4, 6, 4, 5, 6, 3, 6, 1, 4, 2, 3, 2, 4, 2, 6, 5, 8, 8, 6, 7, 4, 3, 2], +[1, 4, 5, 9, 5, 9, 4, 4, 2, 0, 2, 2, 3, 4, 6, 3, 8, 2, 9, 4, 8, 5, 5, 4, 4], +[1, 4, 4, 8, 6, 11, 4, 7, 1, 2, 1, 1, 2, 4, 5, 5, 8, 3, 8, 2, 6, 2, 4, 3, 5, 5], +[0, 7, 7, 6, 9, 4, 7, 2, 5, 3, 4, 4, 6, 3, 7, 5, 6, 6, 3, 6, 1, 2, 1, 4, 3, 8], +[1, 5, 9, 5, 5, 3, 1, 3, 3, 5, 6, 9, 4, 10, 3, 8, 4, 5, 5, 3, 4, 3, 4, 3, 7], +[1, 4, 10, 3, 7, 3, 2, 1, 3, 3, 6, 8, 7, 10, 4, 9, 2, 5, 2, 3, 3, 5, 4, 5, 6, 3], +[0, 8, 2, 6, 2, 5, 3, 5, 6, 8, 7, 8, 8, 6, 8, 3, 5, 2, 3, 1, 4, 2, 7, 4, 7, 4], +[1, 3, 3, 0, 2, 2, 6, 6, 10, 6, 10, 4, 6, 4, 4, 5, 4, 5, 3, 5, 2, 8, 2, 9, 3, 5], +[0, 3, 1, 1, 1, 4, 4, 8, 4, 9, 3, 6, 2, 3, 3, 3, 4, 5, 7, 6, 8, 4, 9, 2, 5], +[0, 2, 3, 3, 4, 4, 5, 5, 4, 6, 2, 6, 2, 3, 3, 4, 3, 7, 4, 9, 7, 8, 8, 4, 5, 2], +[1, 4, 2, 5, 3, 8, 4, 7, 3, 4, 3, 2, 3, 3, 3, 2, 4, 1, 7, 4, 9, 8, 9, 7, 5, 5], +[0, 3, 4, 4, 9, 4, 11, 3, 7, 2, 2, 1, 1, 1, 3, 4, 2, 7, 3, 8, 5, 6, 4, 4, 4, 4], +[1, 4, 5, 7, 4, 9, 3, 7, 3, 4, 3, 3, 1, 4, 2, 5, 7, 7, 9, 5, 6, 2, 2, 2, 4], +[1, 3, 9, 6, 8, 6, 4, 4, 3, 4, 4, 5, 3, 7, 2, 8, 4, 8, 7, 6, 6, 2, 2, 1, 3, 1], +[0, 8, 4, 11, 5, 7, 4, 4, 2, 4, 4, 5, 8, 5, 10, 4, 8, 4, 4, 3, 2, 2, 2, 3, 3, 7], +[1, 4, 9, 3, 8, 5, 6, 4, 6, 4, 7, 6, 8, 8, 7, 9, 5, 5, 2, 1, 0, 3, 2, 6, 6, 7], +[0, 6, 4, 5, 3, 5, 4, 8, 4, 9, 4, 8, 5, 6, 7, 5, 5, 4, 3, 1, 4, 1, 8, 3, 8], +[0, 5, 5, 3, 2, 1, 3, 5, 4, 9, 5, 11, 5, 8, 4, 6, 5, 4, 5, 4, 6, 4, 9, 3, 8, 4], +[1, 5, 3, 4, 2, 4, 2, 5, 6, 4, 8, 5, 8, 5, 4, 3, 4, 2, 5, 6, 8, 10, 8, 10, 5, 5], +[0, 3, 3, 3, 7, 4, 9, 3, 6, 3, 3, 4, 3, 4, 2, 3, 1, 6, 2, 8, 6, 9, 8, 6, 6], +[0, 4, 4, 3, 6, 4, 10, 3, 8, 3, 4, 1, 3, 2, 3, 4, 3, 6, 4, 9, 4, 8, 5, 5, 5, 4], +[1, 3, 5, 5, 5, 8, 4, 8, 3, 5, 3, 4, 2, 3, 0, 5, 5, 7, 9, 6, 9, 4, 4, 2, 2, 2], +[0, 7, 5, 9, 6, 7, 5, 4, 4, 4, 4, 4, 6, 3, 8, 3, 8, 6, 7, 7, 4, 4, 2, 2, 1, 5], +[1, 2, 10, 4, 9, 4, 5, 3, 3, 3, 4, 5, 4, 9, 4, 9, 4, 6, 4, 3, 3, 3, 3, 4, 6], +[1, 4, 8, 4, 9, 3, 6, 4, 5, 3, 5, 4, 6, 6, 6, 8, 5, 7, 3, 2, 1, 1, 1, 5, 4, 8], +[0, 6, 5, 5, 3, 4, 3, 5, 3, 8, 4, 9, 5, 8, 6, 7, 7, 5, 5, 2, 3, 1, 5, 3, 8, 5], +[1, 8, 5, 3, 2, 2, 3, 3, 7, 4, 10, 4, 9, 4, 6, 4, 4, 4, 4, 5, 3, 7, 4, 9, 4, 7], +[0, 4, 5, 4, 5, 3, 5, 4, 4, 7, 4, 8, 3, 5, 3, 3, 1, 3, 3, 6, 7, 7, 9, 6, 7], +[0, 3, 4, 2, 6, 4, 8, 4, 7, 3, 4, 4, 3, 4, 3, 3, 2, 4, 1, 7, 4, 9, 7, 7, 7, 5], +[1, 3, 3, 3, 4, 9, 4, 11, 4, 7, 2, 3, 2, 2, 2, 3, 4, 3, 7, 3, 9, 4, 5, 4, 3, 4], +[0, 5, 4, 5, 7, 5, 9, 5, 8, 4, 5, 4, 4, 2, 4, 3, 6, 7, 6, 9, 4, 6, 2, 2, 1, 4], +[1, 3, 9, 5, 7, 5, 4, 4, 3, 4, 4, 5, 3, 6, 1, 8, 4, 7, 7, 5, 6, 3, 2, 0, 3], +[1, 2, 8, 4, 10, 4, 6, 3, 3, 2, 3, 3, 5, 7, 4, 9, 3, 8, 4, 4, 4, 2, 2, 3, 3, 3], +[0, 6, 3, 8, 4, 7, 4, 5, 4, 5, 3, 7, 5, 7, 9, 7, 9, 6, 5, 3, 2, 1, 3, 2, 7, 5], +[1, 6, 5, 3, 3, 2, 3, 3, 6, 4, 9, 4, 8, 5, 7, 7, 7, 6, 4, 3, 1, 4, 1, 7, 4, 8], +[0, 5, 5, 3, 2, 2, 3, 5, 4, 8, 4, 9, 4, 7, 4, 5, 4, 4, 5, 4, 6, 5, 9, 5, 8], +[0, 5, 6, 3, 4, 2, 4, 2, 5, 5, 3, 7, 4, 6, 4, 4, 2, 3, 2, 6, 5, 8, 10, 8, 9, 5], +[1, 6, 3, 4, 3, 7, 4, 8, 4, 5, 3, 3, 4, 3, 3, 3, 3, 1, 5, 2, 8, 6, 9, 8, 7, 5], +[0, 4, 3, 4, 7, 5, 11, 5, 9, 4, 5, 3, 2, 2, 3, 3, 3, 6, 3, 8, 4, 7, 4, 5, 3], +[0, 4, 3, 6, 5, 6, 8, 5, 9, 5, 6, 3, 3, 2, 4, 2, 5, 5, 6, 9, 6, 8, 4, 3, 2, 2], +[1, 3, 7, 5, 10, 6, 7, 6, 4, 4, 4, 4, 4, 5, 2, 7, 2, 8, 5, 7, 7, 5, 4, 1, 1, 1], +[0, 6, 3, 10, 4, 9, 4, 4, 3, 4, 3, 5, 6, 5, 9, 5, 9, 4, 6, 4, 3, 3, 2, 2, 3, 5], +[1, 3, 7, 2, 7, 3, 6, 3, 5, 3, 6, 4, 7, 7, 7, 10, 6, 7, 4, 2, 2, 1, 1, 5, 4], +[1, 8, 6, 5, 4, 3, 3, 3, 4, 4, 8, 4, 8, 4, 7, 7, 7, 7, 4, 5, 2, 2, 0, 5, 2, 9], +[0, 5, 7, 4, 3, 1, 1, 1, 3, 5, 3, 8, 3, 8, 4, 6, 5, 4, 5, 4, 5, 4, 7, 5, 9, 4], +[1, 7, 4, 4, 2, 4, 2, 3, 2, 4, 5, 3, 7, 3, 5, 3, 3, 1, 3, 3, 7, 8, 8, 9, 6, 6], +[0, 4, 3, 4, 5, 4, 9, 3, 7, 4, 4, 4, 3, 4, 3, 2, 1, 2, 1, 6, 3, 9, 7, 8, 7], +[0, 4, 3, 4, 4, 4, 8, 5, 10, 4, 7, 3, 3, 1, 2, 2, 3, 3, 3, 7, 3, 8, 4, 7, 5, 4], +[1, 4, 6, 4, 6, 6, 5, 8, 4, 7, 4, 4, 2, 3, 1, 3, 2, 5, 7, 6, 9, 5, 6, 3, 2, 2], +[0, 5, 4, 9, 5, 7, 5, 5, 5, 4, 4, 5, 4, 4, 6, 2, 7, 4, 8, 7, 6, 6, 3, 2, 1, 3], +[1, 3, 8, 4, 10, 5, 7, 4, 4, 3, 4, 5, 5, 7, 4, 9, 4, 8, 5, 4, 4, 2, 2, 3, 4], +[1, 4, 7, 4, 8, 4, 8, 4, 5, 4, 5, 4, 6, 5, 7, 9, 7, 9, 6, 5, 2, 1, 0, 3, 2, 6], +[0, 5, 6, 5, 3, 4, 3, 3, 3, 6, 4, 8, 4, 9, 6, 8, 8, 7, 7, 5, 4, 2, 4, 1, 7, 3], +[1, 8, 4, 4, 3, 2, 1, 2, 4, 4, 8, 4, 9, 4, 8, 5, 5, 5, 5, 5, 5, 7, 5, 8, 4, 8], +[0, 4, 6, 4, 4, 3, 4, 3, 4, 5, 5, 7, 5, 7, 4, 4, 2, 2, 2, 4, 5, 8, 8, 7, 8], +[0, 4, 5, 3, 4, 4, 7, 4, 8, 3, 6, 4, 4, 4, 3, 3, 2, 3, 1, 4, 2, 8, 6, 9, 7, 6], +[1, 5, 4, 3, 4, 6, 5, 9, 4, 9, 3, 5, 2, 2, 1, 2, 2, 3, 6, 4, 8, 4, 7, 5, 5, 4], +[0, 4, 4, 5, 5, 6, 7, 5, 8, 4, 6, 4, 3, 3, 4, 2, 5, 5, 7, 9, 6, 8, 4, 3, 2, 2], +[1, 3, 7, 4, 9, 5, 6, 5, 4, 4, 5, 3, 4, 4, 2, 6, 3, 8, 6, 7, 7, 5, 5, 2, 2], +[1, 2, 6, 3, 10, 5, 9, 4, 4, 3, 3, 3, 4, 5, 4, 7, 4, 8, 4, 5, 4, 3, 3, 3, 2, 4], +[0, 5, 5, 7, 3, 7, 3, 5, 3, 5, 3, 5, 4, 6, 7, 7, 10, 7, 7, 4, 2, 2, 2, 2, 6, 4], +[1, 8, 6, 4, 4, 2, 3, 3, 4, 4, 7, 4, 8, 5, 8, 7, 7, 7, 6, 5, 2, 3, 1, 6, 3], +[1, 9, 5, 8, 4, 3, 2, 2, 2, 4, 6, 5, 10, 4, 8, 5, 6, 5, 4, 4, 4, 5, 4, 7, 4, 8], +[0, 4, 7, 4, 5, 4, 5, 3, 5, 4, 5, 7, 5, 7, 4, 5, 3, 2, 2, 3, 2, 7, 6, 8, 9, 6], +[1, 7, 4, 4, 4, 6, 5, 8, 4, 8, 4, 5, 5, 3, 4, 3, 3, 2, 2, 1, 6, 3, 8, 7, 8, 6], +[0, 5, 3, 4, 4, 5, 9, 5, 10, 4, 8, 4, 4, 4, 3, 3, 4, 4, 4, 8, 4, 8, 5, 6, 4], +[0, 3, 4, 4, 4, 5, 5, 5, 8, 5, 7, 5, 5, 4, 3, 2, 4, 2, 6, 7, 7, 9, 6, 6, 2, 2], +[1, 3, 5, 4, 9, 5, 8, 5, 4, 4, 4, 4, 4, 4, 3, 5, 2, 8, 4, 8, 7, 6, 5, 3, 2, 2], +[0, 3, 3, 8, 4, 9, 4, 6, 3, 4, 2, 4, 3, 5, 7, 5, 10, 5, 9, 5, 6, 4, 3, 3, 3, 3], +[1, 4, 6, 4, 7, 3, 6, 3, 4, 4, 4, 3, 6, 5, 7, 9, 8, 10, 6, 5, 3, 1, 2, 3, 2], +[1, 7, 5, 7, 5, 3, 3, 3, 4, 4, 6, 4, 8, 4, 8, 6, 8, 9, 6, 7, 4, 3, 1, 4, 2, 8], +[0, 4, 9, 5, 5, 2, 2, 2, 3, 3, 4, 7, 4, 8, 4, 7, 5, 5, 5, 4, 4, 5, 6, 5, 9, 5], +[1, 9, 5, 6, 4, 4, 3, 4, 2, 4, 4, 4, 7, 4, 6, 4, 3, 3, 2, 2, 4, 4, 8, 8, 8, 9], +[0, 6, 5, 4, 4, 5, 8, 4, 8, 4, 6, 4, 5, 5, 5, 4, 3, 3, 0, 4, 2, 8, 5, 9, 7], +[0, 6, 5, 4, 3, 5, 6, 6, 10, 5, 9, 4, 6, 4, 3, 3, 3, 3, 3, 5, 3, 8, 3, 7, 4, 5], +[1, 5, 5, 5, 7, 6, 6, 7, 6, 8, 5, 6, 4, 3, 2, 3, 2, 4, 4, 6, 8, 6, 7, 4, 3, 2], +[0, 3, 3, 7, 5, 9, 5, 7, 5, 4, 5, 5, 4, 4, 5, 3, 6, 3, 8, 6, 8, 7, 5, 4, 2, 1], +[1, 2, 5, 3, 9, 4, 8, 4, 4, 4, 4, 3, 5, 5, 5, 8, 5, 9, 5, 7, 5, 3, 3, 3, 2], +[1, 4, 4, 4, 7, 3, 7, 4, 6, 5, 5, 4, 6, 4, 7, 7, 7, 10, 7, 7, 5, 2, 2, 1, 1, 5], +[0, 4, 7, 5, 4, 4, 2, 3, 3, 4, 4, 7, 4, 8, 4, 8, 7, 8, 9, 5, 5, 3, 3, 2, 6, 4], +[1, 9, 5, 7, 3, 3, 1, 2, 2, 3, 5, 3, 8, 3, 8, 5, 5, 5, 4, 5, 4, 5, 4, 7, 5], +[1, 9, 5, 7, 5, 5, 3, 4, 3, 4, 4, 5, 6, 5, 7, 6, 6, 4, 2, 3, 3, 3, 7, 7, 8, 9], +[0, 6, 6, 4, 4, 4, 6, 5, 8, 4, 8, 4, 5, 5, 5, 4, 4, 1, 1, 3, 2, 6, 5, 9, 7, 8], +[1, 7, 5, 4, 4, 4, 5, 8, 5, 10, 4, 7, 4, 3, 2, 2, 2, 3, 3, 4, 7, 3, 8, 5, 7, 5], +[0, 5, 5, 5, 5, 6, 6, 5, 8, 5, 7, 5, 4, 4, 3, 1, 4, 3, 6, 7, 7, 9, 6, 6, 4], +[0, 3, 4, 5, 4, 9, 5, 8, 5, 5, 5, 5, 4, 5, 4, 3, 5, 2, 7, 5, 7, 7, 6, 6, 3, 3], +[1, 3, 4, 4, 9, 5, 10, 5, 8, 5, 5, 4, 5, 4, 5, 7, 5, 8, 4, 8, 5, 5, 4, 3, 3, 3], +[0, 3, 5, 7, 4, 8, 4, 7, 5, 5, 4, 5, 4, 6, 6, 7, 9, 8, 10, 6, 6, 3, 1, 2, 4, 3], +[1, 7, 5, 6, 5, 3, 3, 2, 3, 4, 5, 4, 7, 4, 8, 6, 8, 8, 7, 7, 4, 4, 3, 3, 2], +[1, 8, 4, 8, 4, 5, 3, 2, 1, 4, 4, 5, 8, 5, 9, 5, 8, 6, 5, 6, 4, 5, 5, 5, 5, 8], +[0, 4, 8, 4, 6, 4, 4, 3, 5, 2, 5, 5, 5, 7, 6, 7, 5, 3, 3, 2, 2, 4, 5, 7, 8, 8], +[1, 8, 5, 5, 4, 4, 5, 6, 4, 8, 3, 6, 4, 5, 5, 5, 3, 3, 2, 1, 3, 2, 8, 5, 8, 7], +[0, 6, 5, 4, 3, 4, 5, 5, 9, 4, 8, 4, 5, 4, 3, 3, 3, 3, 4, 6, 4, 8, 4, 8, 5], +[0, 5, 5, 5, 4, 6, 5, 6, 6, 5, 8, 5, 6, 4, 3, 3, 3, 2, 5, 5, 7, 9, 6, 8, 5, 3], +[1, 4, 4, 4, 7, 6, 9, 6, 6, 6, 5, 5, 5, 4, 4, 3, 2, 6, 2, 8, 6, 7, 7, 5, 4, 2], +[0, 3, 3, 6, 4, 10, 5, 9, 4, 5, 4, 4, 4, 5, 5, 5, 8, 4, 8, 5, 7, 5, 4, 5, 4, 3], +[1, 4, 5, 5, 7, 4, 7, 4, 5, 5, 4, 4, 5, 4, 6, 7, 8, 10, 7, 8, 5, 3, 3, 3, 3], +[1, 7, 5, 7, 5, 5, 5, 3, 4, 4, 5, 5, 7, 5, 9, 5, 9, 8, 8, 9, 6, 5, 3, 3, 2, 5], +[0, 3, 10, 5, 8, 4, 3, 2, 3, 3, 4, 5, 5, 8, 4, 9, 6, 6, 6, 4, 5, 4, 5, 5, 6, 5], +[1, 9, 5, 8, 6, 5, 4, 4, 4, 5, 4, 6, 7, 6, 8, 5, 5, 4, 2, 2, 3, 3, 6, 6, 8], +[1, 8, 6, 6, 5, 3, 5, 5, 5, 8, 4, 8, 4, 6, 6, 6, 6, 4, 4, 3, 3, 2, 6, 5, 9, 6], +[0, 7, 5, 4, 3, 4, 4, 5, 8, 5, 9, 5, 8, 5, 4, 4, 3, 3, 3, 4, 4, 7, 4, 8, 5, 6], +[1, 5, 4, 4, 5, 4, 7, 6, 6, 8, 6, 7, 6, 5, 5, 2, 2, 3, 3, 6, 7, 7, 8, 5, 5, 3], +[0, 2, 4, 6, 5, 9, 5, 7, 5, 4, 5, 5, 4, 5, 4, 3, 5, 3, 7, 5, 9, 8, 6, 6, 4], +[0, 2, 3, 4, 4, 9, 5, 9, 5, 6, 4, 4, 3, 4, 4, 5, 6, 5, 9, 5, 9, 6, 5, 5, 4, 3], +[1, 4, 4, 4, 5, 4, 7, 4, 6, 5, 4, 4, 5, 4, 6, 5, 7, 9, 8, 11, 7, 5, 4, 1, 2, 4], +[0, 3, 7, 4, 6, 5, 3, 3, 3, 3, 4, 5, 4, 7, 4, 7, 6, 8, 9, 7, 7, 5, 4, 3, 4, 3], +[1, 9, 5, 9, 5, 5, 3, 2, 2, 3, 3, 4, 6, 4, 8, 5, 7, 6, 5, 5, 3, 5, 4, 6, 6], +[1, 9, 5, 9, 5, 6, 5, 4, 4, 4, 3, 5, 4, 5, 7, 5, 7, 5, 3, 3, 1, 2, 5, 5, 8, 8], +[0, 8, 7, 5, 5, 5, 4, 5, 7, 5, 8, 4, 6, 5, 6, 6, 5, 5, 3, 2, 1, 4, 2, 7, 5, 8], +[1, 7, 6, 5, 6, 4, 6, 7, 6, 10, 6, 9, 5, 6, 4, 3, 3, 2, 3, 3, 5, 4, 7, 3, 6, 5], +[0, 5, 6, 5, 5, 7, 5, 7, 8, 6, 8, 6, 7, 5, 4, 3, 3, 2, 4, 5, 7, 8, 6, 7, 4], +[0, 3, 3, 4, 5, 8, 6, 9, 6, 7, 6, 6, 5, 5, 4, 4, 4, 2, 6, 3, 8, 6, 8, 7, 4, 3], +[1, 3, 2, 3, 6, 4, 10, 6, 9, 5, 5, 5, 5, 5, 6, 6, 6, 8, 6, 9, 5, 6, 6, 4, 4, 3], +[0, 3, 5, 4, 4, 7, 3, 7, 5, 6, 6, 5, 4, 6, 5, 7, 8, 9, 11, 8, 8, 6, 3, 3, 3], +[0, 3, 7, 4, 8, 5, 4, 3, 3, 3, 4, 3, 4, 6, 4, 7, 5, 8, 8, 8, 9, 6, 5, 3, 3, 3], +[1, 7, 4, 9, 5, 7, 3, 3, 2, 2, 2, 4, 5, 5, 8, 5, 9, 6, 7, 7, 5, 6, 5, 5, 5, 6], +[0, 6, 8, 5, 7, 5, 5, 5, 4, 3, 5, 3, 5, 6, 6, 8, 6, 6, 5, 2, 3, 2, 4, 7, 7, 8], +[1, 8, 6, 6, 5, 4, 6, 5, 6, 8, 4, 7, 4, 6, 6, 5, 6, 4, 3, 2, 2, 2, 6, 4, 8], +[1, 7, 8, 6, 5, 4, 4, 4, 6, 8, 5, 9, 5, 7, 4, 4, 4, 3, 3, 3, 4, 5, 7, 5, 8, 5], +[0, 7, 6, 5, 6, 6, 4, 6, 6, 5, 7, 5, 7, 6, 4, 4, 1, 2, 3, 3, 6, 7, 7, 8, 6, 5], +[1, 4, 3, 5, 6, 6, 10, 6, 8, 6, 6, 6, 6, 5, 6, 4, 3, 4, 2, 6, 4, 7, 7, 6, 6, 4], +[0, 3, 3, 4, 5, 9, 6, 10, 6, 8, 6, 5, 4, 5, 5, 5, 7, 5, 8, 5, 8, 5, 5, 5, 3], +[0, 3, 4, 4, 5, 6, 5, 8, 4, 7, 5, 4, 5, 4, 3, 6, 5, 8, 9, 8, 10, 7, 5, 4, 1, 2], +[1, 4, 3, 7, 5, 6, 5, 3, 3, 4, 3, 5, 5, 5, 7, 4, 8, 7, 9, 10, 8, 8, 6, 3, 3, 4], +[0, 3, 8, 5, 8, 4, 4, 3, 2, 2, 4, 4, 5, 7, 5, 10, 5, 7, 6, 4, 5, 4, 4, 5, 6, 6], +[1, 8, 6, 8, 5, 6, 5, 4, 4, 4, 3, 6, 5, 6, 8, 6, 7, 5, 3, 3, 1, 2, 4, 5, 8], +[1, 8, 8, 7, 5, 4, 5, 5, 5, 7, 5, 7, 4, 6, 5, 6, 7, 6, 5, 4, 3, 2, 4, 3, 8, 6], +[0, 9, 6, 6, 5, 4, 3, 5, 5, 5, 8, 5, 9, 5, 6, 5, 3, 4, 4, 4, 4, 6, 4, 8, 4, 7], +[1, 6, 5, 5, 5, 5, 6, 5, 7, 7, 6, 9, 7, 7, 6, 4, 3, 3, 3, 5, 5, 7, 8, 6, 7, 4], +[0, 4, 4, 4, 5, 8, 6, 9, 5, 7, 5, 6, 6, 6, 5, 5, 3, 3, 5, 3, 8, 6, 8, 7, 5], +[0, 5, 4, 4, 4, 6, 5, 10, 6, 9, 6, 5, 5, 5, 4, 5, 5, 5, 8, 5, 9, 5, 6, 6, 4, 5], +[1, 4, 4, 5, 4, 4, 7, 4, 7, 5, 5, 5, 4, 4, 5, 5, 7, 8, 9, 11, 8, 9, 6, 4, 4, 3], +[0, 4, 7, 5, 8, 5, 4, 4, 3, 4, 4, 4, 5, 5, 3, 7, 5, 8, 9, 9, 9, 6, 5, 4, 4], +[0, 4, 7, 5, 11, 6, 8, 4, 4, 3, 3, 3, 4, 5, 5, 8, 5, 8, 5, 6, 6, 4, 5, 4, 5, 5], +[1, 7, 6, 8, 6, 8, 6, 5, 5, 5, 4, 4, 4, 6, 6, 6, 8, 6, 6, 5, 2, 3, 3, 4, 7, 6], +[0, 8, 8, 6, 5, 5, 4, 6, 5, 6, 7, 5, 8, 4, 6, 6, 5, 6, 5, 3, 2, 3, 2, 6, 4, 8], +[1, 6, 7, 5, 4, 4, 5, 4, 6, 7, 6, 9, 6, 8, 6, 5, 5, 3, 4, 4, 4, 4, 6, 4, 7], +[1, 4, 6, 5, 4, 5, 5, 4, 6, 6, 6, 8, 7, 8, 7, 4, 5, 2, 3, 3, 3, 6, 7, 7, 8, 6], +[0, 5, 4, 3, 5, 6, 5, 8, 6, 7, 5, 5, 5, 6, 5, 6, 4, 3, 3, 2, 6, 4, 8, 6, 6, 5], +[1, 4, 2, 4, 4, 5, 8, 5, 8, 5, 6, 5, 4, 4, 5, 5, 6, 6, 6, 9, 5, 8, 6, 5, 5, 3], +[0, 3, 5, 3, 5, 5, 4, 6, 4, 6, 5, 4, 4, 4, 3, 6, 6, 8, 10, 9, 10, 8, 6, 5, 3], +[0, 4, 6, 5, 9, 5, 6, 5, 4, 3, 4, 4, 5, 4, 3, 6, 3, 8, 6, 8, 9, 7, 7, 5, 4, 4], +[1, 5, 5, 9, 6, 9, 5, 5, 4, 3, 2, 3, 3, 4, 6, 4, 8, 5, 7, 6, 5, 6, 5, 6, 6, 7], +[0, 7, 8, 6, 8, 5, 6, 6, 4, 4, 4, 3, 5, 5, 6, 7, 6, 7, 5, 3, 3, 2, 3, 4, 5, 8], +[1, 8, 8, 7, 6, 5, 6, 5, 7, 7, 5, 9, 4, 8, 6, 6, 7, 6, 6, 3, 2, 2, 4, 2, 8], +[1, 5, 9, 6, 6, 5, 5, 4, 7, 7, 7, 10, 6, 9, 6, 7, 5, 3, 4, 3, 4, 4, 5, 4, 7, 4], +[0, 7, 5, 6, 7, 6, 6, 7, 6, 7, 8, 7, 8, 7, 7, 6, 3, 3, 1, 2, 4, 5, 7, 8, 6, 6], +[1, 4, 3, 4, 4, 5, 8, 6, 9, 6, 8, 6, 7, 7, 7, 6, 5, 4, 4, 6, 4, 7, 7, 7, 6], +[1, 5, 3, 2, 2, 4, 5, 5, 9, 5, 8, 6, 6, 6, 5, 6, 6, 6, 6, 8, 6, 9, 5, 7, 6, 4], +[0, 5, 4, 3, 5, 5, 5, 6, 4, 7, 5, 5, 6, 4, 5, 5, 4, 7, 8, 9, 10, 8, 8, 6, 3, 4], +[1, 3, 4, 7, 5, 8, 4, 4, 3, 3, 3, 5, 3, 4, 4, 4, 7, 5, 8, 9, 9, 10, 6, 6, 4, 4], +[0, 4, 6, 5, 9, 5, 7, 4, 3, 2, 2, 2, 3, 4, 5, 7, 5, 8, 7, 6, 7, 5, 6, 5, 5], +[0, 6, 7, 6, 8, 6, 7, 6, 5, 6, 4, 4, 5, 4, 6, 6, 7, 9, 7, 6, 5, 2, 3, 2, 4, 7], +[1, 6, 8, 7, 6, 5, 5, 4, 7, 5, 6, 7, 5, 7, 4, 6, 6, 6, 6, 5, 3, 3, 2, 2, 6, 5], +[0, 9, 7, 8, 6, 5, 4, 5, 4, 6, 7, 5, 9, 5, 6, 5, 4, 4, 2, 3, 3, 4, 5, 7, 5, 8], +[1, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 8, 7, 8, 7, 5, 5, 2, 2, 3, 3, 7, 6, 8, 8], +[1, 5, 5, 4, 3, 5, 6, 7, 9, 6, 8, 6, 7, 7, 6, 6, 6, 4, 3, 4, 3, 6, 5, 8, 6, 6], +[0, 5, 4, 3, 4, 5, 6, 9, 6, 10, 6, 8, 6, 5, 5, 5, 5, 6, 6, 5, 8, 5, 7, 5, 4, 5], +[1, 3, 4, 4, 4, 5, 5, 5, 7, 5, 7, 6, 4, 6, 3, 4, 6, 6, 8, 10, 9, 11, 8, 6, 5, 3], +[0, 4, 5, 5, 8, 5, 6, 4, 3, 4, 4, 3, 5, 4, 4, 6, 4, 8, 7, 9, 10, 8, 8, 5, 3], +[0, 4, 5, 4, 9, 5, 9, 5, 5, 4, 3, 4, 5, 4, 6, 7, 5, 9, 5, 7, 6, 5, 6, 4, 5, 5], +[1, 5, 6, 7, 5, 8, 5, 6, 6, 4, 5, 4, 4, 5, 5, 6, 8, 7, 8, 5, 3, 4, 2, 4, 5, 5], +[0, 9, 8, 7, 6, 5, 5, 5, 4, 6, 6, 5, 6, 3, 7, 5, 7, 7, 6, 6, 4, 2, 3, 4, 4, 7], +[1, 5, 8, 7, 5, 5, 5, 3, 6, 5, 6, 9, 6, 8, 6, 6, 6, 4, 5, 4, 5, 4, 5, 5, 7], +[1, 5, 7, 5, 5, 6, 4, 5, 6, 5, 7, 7, 6, 9, 7, 7, 6, 3, 4, 2, 3, 4, 5, 7, 7, 7], +[0, 7, 5, 4, 5, 5, 6, 8, 6, 9, 6, 7, 6, 6, 6, 6, 5, 4, 3, 3, 4, 3, 7, 6, 7, 6], +[1, 5, 4, 3, 3, 5, 6, 5, 9, 6, 7, 5, 5, 6, 4, 4, 5, 5, 5, 7, 6, 9, 6, 7, 6], +[1, 4, 6, 5, 5, 5, 5, 4, 6, 4, 6, 5, 5, 5, 3, 4, 4, 4, 6, 8, 8, 10, 8, 8, 6, 3], +[0, 5, 4, 5, 8, 6, 8, 5, 5, 4, 3, 4, 5, 4, 5, 5, 4, 6, 4, 8, 8, 8, 9, 5, 5, 4], +[1, 3, 5, 7, 6, 9, 6, 7, 5, 4, 3, 3, 3, 4, 4, 5, 7, 5, 8, 5, 5, 6, 4, 5, 5, 5], +[0, 7, 7, 6, 8, 6, 7, 6, 5, 6, 4, 4, 4, 3, 6, 6, 7, 8, 6, 6, 5, 1, 3, 2, 4], +[0, 7, 6, 8, 7, 6, 5, 4, 4, 6, 5, 6, 7, 5, 8, 5, 7, 7, 7, 7, 5, 4, 3, 2, 2, 6], +[1, 4, 8, 6, 6, 5, 4, 3, 4, 4, 6, 7, 7, 9, 5, 8, 6, 4, 5, 3, 4, 4, 4, 5, 6, 4], +[0, 8, 5, 6, 6, 5, 6, 6, 5, 6, 6, 7, 8, 7, 8, 7, 5, 5, 1, 3, 2, 2, 5, 5, 7, 6], +[1, 5, 5, 4, 3, 5, 5, 5, 8, 6, 8, 6, 6, 6, 6, 7, 6, 4, 4, 4, 3, 7, 5, 8, 6], +[1, 6, 5, 3, 3, 4, 3, 5, 7, 5, 9, 5, 6, 6, 4, 5, 4, 5, 5, 6, 6, 9, 6, 8, 6, 5], +[0, 6, 4, 5, 5, 4, 5, 5, 5, 7, 5, 7, 6, 4, 6, 3, 3, 5, 6, 8, 9, 9, 9, 7, 6, 5], +[1, 3, 5, 6, 5, 9, 5, 6, 4, 3, 4, 4, 3, 5, 4, 3, 4, 3, 7, 6, 9, 9, 7, 8, 6, 5], +[0, 5, 5, 6, 9, 6, 9, 5, 4, 4, 3, 2, 3, 3, 4, 5, 4, 7, 5, 6, 6, 4, 6, 4, 6], +[0, 6, 6, 7, 8, 6, 7, 6, 6, 6, 4, 5, 4, 4, 6, 5, 7, 8, 8, 8, 6, 4, 4, 2, 3, 5], +[1, 6, 8, 7, 7, 7, 5, 5, 5, 5, 7, 6, 6, 7, 4, 8, 6, 7, 8, 6, 6, 4, 2, 2, 4, 4], +[0, 8, 6, 9, 6, 6, 5, 5, 4, 7, 6, 6, 8, 6, 8, 5, 6, 6, 3, 5, 3, 3, 4, 4, 4, 7], +[1, 5, 6, 6, 6, 6, 5, 6, 6, 5, 7, 7, 7, 9, 7, 7, 6, 3, 4, 2, 3, 5, 5, 8, 7], +[1, 6, 6, 4, 3, 4, 3, 6, 7, 6, 9, 5, 7, 6, 6, 7, 7, 6, 5, 4, 3, 5, 4, 7, 6, 7], +[0, 6, 4, 3, 3, 3, 4, 6, 5, 9, 5, 9, 6, 6, 6, 5, 5, 5, 5, 6, 7, 6, 8, 6, 6, 5], +[1, 4, 5, 4, 3, 5, 4, 4, 5, 4, 6, 5, 4, 5, 3, 4, 3, 4, 6, 8, 9, 10, 8, 8, 6, 3], +[0, 5, 4, 6, 7, 5, 6, 4, 4, 3, 3, 3, 4, 2, 4, 2, 2, 6, 5, 7, 8, 7, 9, 6, 5], +[0, 5, 4, 5, 6, 5, 9, 5, 6, 4, 3, 3, 3, 2, 5, 4, 5, 7, 5, 8, 6, 5, 7, 4, 5, 4], +[1, 5, 6, 6, 5, 7, 5, 6, 6, 4, 5, 3, 4, 4, 3, 5, 6, 7, 8, 6, 6, 5, 2, 4, 2, 5], +[0, 8, 7, 8, 7, 6, 5, 5, 4, 6, 5, 6, 6, 4, 6, 4, 6, 6, 6, 6, 4, 3, 3, 2, 3], +[0, 6, 5, 9, 7, 7, 6, 4, 4, 5, 4, 6, 7, 6, 8, 5, 7, 6, 4, 6, 3, 4, 4, 4, 5, 6], +[1, 5, 8, 5, 6, 6, 5, 6, 5, 5, 6, 6, 7, 7, 8, 8, 7, 5, 5, 1, 3, 2, 3, 6, 6, 7], +[0, 7, 5, 5, 5, 4, 6, 6, 7, 9, 7, 9, 7, 7, 7, 8, 7, 7, 4, 4, 3, 2, 5, 4, 7, 6], +[1, 6, 5, 4, 2, 4, 5, 5, 8, 6, 9, 6, 7, 6, 5, 6, 5, 5, 6, 6, 6, 7, 5, 7, 5], +[1, 5, 6, 4, 4, 5, 4, 6, 5, 4, 6, 5, 6, 6, 4, 5, 2, 3, 4, 5, 8, 9, 8, 9, 7, 5], +[0, 5, 3, 5, 5, 5, 7, 4, 5, 4, 4, 4, 5, 4, 6, 3, 4, 5, 4, 7, 7, 9, 9, 7, 6, 5], +[1, 3, 4, 4, 5, 8, 5, 8, 5, 5, 4, 2, 4, 4, 3, 5, 5, 5, 8, 5, 7, 6, 4, 6, 4, 5], +[0, 6, 6, 6, 7, 6, 7, 5, 5, 6, 3, 4, 3, 3, 4, 4, 6, 8, 7, 8, 5, 3, 4, 1, 3], +[0, 5, 5, 8, 7, 7, 6, 5, 4, 5, 4, 6, 5, 5, 5, 4, 7, 6, 7, 8, 6, 6, 4, 2, 3, 4], +[1, 4, 8, 6, 8, 6, 4, 4, 3, 3, 5, 4, 6, 7, 5, 8, 5, 6, 6, 4, 5, 3, 4, 4, 5, 5], +[0, 7, 5, 7, 5, 5, 6, 5, 6, 5, 6, 6, 6, 7, 9, 7, 7, 6, 2, 3, 1, 3, 4, 4, 6, 6], +[1, 6, 6, 4, 3, 5, 4, 6, 7, 6, 8, 6, 7, 7, 6, 7, 6, 5, 5, 3, 3, 4, 3, 7, 6], +[1, 8, 6, 4, 4, 4, 2, 4, 5, 5, 8, 5, 7, 5, 5, 5, 3, 5, 4, 4, 5, 7, 6, 8, 6, 7], +[0, 7, 4, 6, 5, 4, 5, 4, 5, 5, 4, 6, 5, 5, 6, 2, 4, 3, 4, 5, 7, 8, 10, 8, 7, 6], +[1, 3, 6, 4, 5, 8, 6, 7, 5, 5, 4, 4, 4, 5, 3, 4, 2, 3, 5, 4, 7, 7, 7, 7, 5, 4], +[0, 5, 4, 7, 8, 6, 10, 6, 7, 5, 3, 4, 3, 3, 4, 4, 4, 6, 5, 7, 6, 4, 5, 3, 4], +[0, 4, 4, 6, 6, 6, 7, 6, 7, 6, 4, 6, 3, 4, 4, 3, 6, 7, 7, 9, 7, 6, 5, 1, 3, 2], +[1, 5, 7, 6, 7, 5, 4, 4, 4, 3, 7, 5, 6, 6, 4, 7, 4, 8, 8, 6, 7, 5, 4, 3, 2, 4], +[0, 6, 5, 8, 6, 7, 5, 4, 4, 5, 4, 7, 7, 7, 9, 6, 8, 6, 4, 6, 2, 4, 3, 3, 4], +[0, 5, 4, 7, 4, 5, 6, 5, 6, 5, 5, 6, 6, 6, 8, 7, 8, 7, 5, 5, 1, 3, 2, 3, 6, 6], +[1, 7, 6, 5, 4, 4, 3, 5, 5, 5, 7, 4, 7, 6, 7, 7, 6, 7, 6, 4, 3, 3, 3, 5, 5, 8], +[0, 5, 5, 4, 2, 2, 4, 3, 4, 6, 5, 8, 5, 6, 6, 5, 6, 5, 6, 5, 7, 6, 8, 6, 7, 6], +[1, 4, 5, 4, 5, 4, 3, 5, 4, 4, 6, 5, 6, 6, 4, 5, 2, 4, 4, 5, 8, 9, 9, 9, 7], +[1, 5, 6, 3, 6, 6, 6, 7, 5, 5, 4, 4, 3, 4, 3, 4, 2, 2, 3, 2, 6, 6, 8, 8, 7, 7], +[0, 5, 4, 5, 5, 6, 8, 6, 8, 5, 4, 4, 3, 2, 3, 3, 4, 5, 5, 7, 5, 6, 7, 4, 7, 4], +[1, 6, 6, 5, 7, 7, 5, 6, 5, 5, 6, 3, 5, 2, 3, 5, 4, 6, 7, 7, 7, 5, 3, 4, 1, 4], +[0, 6, 6, 8, 7, 7, 6, 5, 5, 6, 5, 7, 4, 5, 6, 3, 7, 5, 7, 7, 5, 5, 3, 1, 2], +[0, 3, 3, 7, 6, 8, 6, 5, 5, 4, 4, 6, 5, 6, 7, 5, 7, 5, 6, 6, 3, 5, 2, 3, 4, 4], +[1, 4, 6, 4, 6, 5, 5, 6, 4, 6, 6, 5, 6, 7, 6, 8, 7, 6, 6, 2, 3, 1, 2, 4, 3, 6], +[0, 5, 5, 4, 3, 2, 5, 3, 6, 6, 6, 7, 5, 8, 7, 7, 8, 6, 5, 5, 2, 3, 4, 3, 6], +[0, 5, 6, 5, 3, 3, 2, 2, 4, 5, 5, 7, 6, 7, 6, 5, 6, 4, 5, 5, 5, 5, 6, 5, 8, 5], +[1, 5, 6, 3, 6, 4, 4, 4, 4, 4, 5, 4, 6, 5, 4, 5, 2, 3, 2, 4, 5, 6, 8, 9, 8, 7], +[0, 5, 3, 6, 3, 6, 7, 5, 7, 4, 3, 3, 3, 3, 4, 3, 4, 2, 2, 5, 5, 7, 8, 7, 8, 6], +[1, 5, 5, 4, 6, 6, 5, 8, 5, 5, 4, 2, 3, 2, 3, 3, 3, 5, 6, 5, 7, 6, 6, 7, 3], +[1, 6, 5, 5, 6, 6, 6, 7, 5, 6, 7, 4, 6, 3, 4, 3, 3, 5, 6, 6, 9, 6, 6, 4, 1, 4], +[0, 3, 5, 7, 6, 8, 6, 5, 5, 4, 3, 6, 3, 6, 4, 4, 5, 4, 7, 7, 6, 6, 5, 3, 4, 2], +[1, 4, 7, 5, 9, 6, 6, 5, 4, 3, 5, 3, 6, 5, 6, 7, 5, 6, 5, 3, 5, 2, 4, 3, 3, 4], +[0, 5, 5, 6, 5, 5, 6, 4, 6, 4, 6, 6, 5, 7, 8, 8, 9, 7, 5, 5, 1, 2, 1, 3, 5], +[0, 5, 6, 5, 4, 3, 4, 3, 6, 5, 6, 7, 5, 7, 6, 7, 8, 7, 7, 6, 3, 3, 2, 3, 5, 4], +[1, 7, 5, 5, 4, 4, 2, 4, 4, 5, 7, 6, 7, 6, 5, 6, 3, 6, 3, 5, 5, 5, 5, 7, 5, 6], +[0, 5, 4, 5, 3, 4, 4, 4, 5, 4, 4, 6, 5, 5, 5, 3, 5, 1, 3, 4, 5, 7, 9, 8, 8, 6], +[1, 5, 5, 3, 6, 5, 5, 7, 4, 5, 3, 3, 4, 4, 3, 4, 2, 3, 3, 3, 6, 5, 7, 8, 6], +[1, 6, 5, 4, 5, 5, 5, 8, 5, 8, 5, 4, 4, 2, 4, 3, 3, 4, 5, 4, 7, 5, 5, 6, 4, 6], +[0, 4, 4, 5, 5, 5, 6, 5, 6, 5, 4, 6, 2, 5, 2, 2, 3, 4, 6, 8, 7, 7, 6, 3, 4, 2], +[1, 4, 6, 6, 8, 6, 6, 5, 3, 3, 5, 3, 5, 3, 3, 4, 3, 6, 5, 6, 7, 5, 5, 3, 1, 2], +[0, 4, 4, 8, 5, 7, 5, 4, 4, 3, 3, 5, 4, 6, 6, 6, 7, 5, 5, 6, 3, 5, 2, 3, 4], +[0, 3, 4, 6, 4, 6, 5, 4, 6, 3, 5, 5, 4, 6, 6, 7, 8, 7, 6, 6, 2, 4, 0, 3, 4, 4], +[1, 7, 6, 5, 5, 4, 3, 5, 3, 6, 6, 6, 7, 5, 6, 6, 6, 7, 6, 4, 4, 2, 2, 4, 3, 7], +[0, 6, 7, 6, 3, 4, 3, 2, 4, 4, 5, 7, 5, 7, 6, 4, 6, 3, 5, 5, 5, 5, 6, 5, 7], +[0, 5, 6, 6, 4, 5, 3, 4, 4, 3, 4, 5, 5, 6, 6, 5, 6, 2, 4, 2, 4, 5, 6, 8, 8, 7], +[1, 7, 6, 4, 6, 4, 7, 8, 6, 7, 5, 5, 4, 4, 5, 5, 3, 4, 2, 2, 4, 4, 6, 6, 6, 7], +[0, 5, 4, 5, 3, 6, 7, 6, 9, 6, 6, 5, 4, 4, 3, 3, 4, 4, 4, 6, 4, 7, 6, 4, 6, 3], +[1, 5, 5, 5, 6, 6, 6, 7, 5, 6, 6, 4, 6, 2, 3, 3, 3, 5, 6, 7, 8, 7, 5, 5, 1], +[1, 3, 3, 5, 7, 5, 6, 5, 4, 4, 5, 4, 6, 4, 5, 5, 4, 6, 4, 7, 7, 6, 6, 4, 3, 2], +[0, 1, 3, 5, 4, 7, 5, 5, 5, 3, 3, 4, 4, 6, 6, 6, 7, 5, 7, 6, 4, 6, 2, 4, 3, 3], +[1, 5, 5, 5, 6, 4, 5, 5, 3, 5, 4, 5, 5, 4, 6, 7, 7, 8, 7, 4, 5, 0, 3, 2, 3, 5], +[0, 5, 5, 4, 3, 2, 3, 2, 5, 4, 5, 5, 5, 6, 5, 7, 7, 7, 7, 6, 4, 4, 3, 3, 5], +[0, 4, 7, 5, 4, 3, 1, 1, 3, 2, 4, 5, 4, 6, 5, 6, 5, 4, 6, 4, 6, 5, 5, 6, 7, 5], +[1, 6, 6, 5, 6, 4, 4, 4, 4, 4, 4, 4, 6, 5, 5, 5, 2, 4, 1, 3, 2, 4, 6, 7, 7, 8], +[0, 6, 5, 5, 3, 6, 5, 6, 7, 4, 4, 3, 3, 4, 4, 3, 4, 1, 2, 2, 2, 6, 5, 7, 8, 6], +[1, 6, 5, 4, 5, 5, 6, 8, 5, 7, 4, 3, 4, 1, 3, 2, 2, 3, 3, 3, 5, 4, 5, 5, 3], +[1, 6, 3, 5, 6, 5, 6, 7, 5, 6, 5, 5, 6, 3, 5, 3, 3, 4, 3, 6, 7, 6, 7, 4, 2, 4], +[0, 1, 4, 5, 6, 8, 6, 5, 5, 4, 4, 5, 4, 6, 4, 4, 4, 3, 6, 5, 6, 7, 4, 5, 3, 1], +[1, 2, 3, 4, 7, 5, 7, 6, 4, 5, 4, 5, 6, 4, 6, 6, 5, 7, 5, 5, 5, 2, 4, 1, 3, 3], +[0, 4, 4, 5, 4, 5, 5, 4, 6, 4, 5, 4, 5, 6, 6, 8, 9, 8, 8, 6, 3, 4, 1, 3, 3], +[0, 4, 6, 4, 4, 3, 2, 1, 4, 3, 5, 5, 5, 7, 5, 7, 7, 7, 8, 7, 6, 5, 2, 3, 4, 4], +[1, 6, 5, 5, 4, 3, 2, 3, 2, 4, 4, 5, 6, 5, 7, 5, 5, 7, 3, 5, 4, 5, 5, 6, 5, 6], +[0, 5, 5, 6, 4, 5, 3, 4, 4, 3, 4, 4, 4, 5, 5, 4, 5, 1, 4, 1, 3, 6, 6, 8, 8], +[0, 8, 5, 6, 3, 6, 4, 6, 6, 5, 5, 3, 3, 3, 4, 4, 4, 2, 3, 2, 2, 3, 4, 7, 7, 7], +[1, 6, 5, 3, 4, 3, 5, 6, 5, 7, 5, 5, 5, 3, 4, 2, 3, 3, 4, 4, 5, 4, 6, 5, 4, 6], +[0, 3, 5, 4, 5, 6, 5, 5, 6, 5, 6, 6, 3, 6, 2, 3, 2, 2, 4, 5, 6, 8, 6, 5, 5, 1], +[1, 5, 3, 5, 8, 6, 7, 5, 4, 4, 5, 3, 6, 3, 4, 3, 2, 4, 4, 5, 6, 6, 6, 3, 3], +[1, 4, 3, 4, 6, 5, 8, 5, 6, 5, 3, 4, 4, 4, 6, 5, 5, 7, 5, 6, 5, 4, 5, 2, 4, 3], +[0, 4, 5, 5, 4, 6, 4, 4, 5, 3, 5, 4, 5, 5, 5, 6, 8, 7, 8, 7, 4, 5, 0, 3, 1, 3], +[1, 6, 4, 5, 5, 3, 3, 4, 3, 6, 4, 6, 6, 5, 6, 5, 7, 7, 6, 7, 5, 3, 3, 2, 2, 5], +[0, 4, 6, 5, 3, 4, 2, 2, 4, 3, 5, 5, 5, 6, 5, 5, 5, 3, 6, 3, 5, 4, 4, 5, 7], +[0, 5, 6, 5, 4, 5, 3, 4, 3, 3, 4, 4, 4, 5, 4, 5, 5, 2, 4, 0, 3, 2, 4, 7, 7, 7], +[1, 7, 5, 3, 5, 2, 6, 5, 6, 7, 5, 5, 4, 4, 4, 5, 4, 5, 2, 2, 2, 2, 4, 5, 6, 6], +[0, 5, 5, 4, 3, 4, 4, 5, 7, 5, 7, 4, 4, 5, 2, 4, 3, 3, 3, 4, 4, 5, 4, 5, 5, 3], +[1, 5, 4, 6, 5, 5, 5, 5, 5, 5, 5, 4, 6, 2, 4, 1, 2, 3, 3, 6, 6, 6, 6, 5, 2], +[1, 4, 1, 4, 5, 6, 7, 5, 5, 4, 3, 4, 5, 3, 6, 3, 3, 5, 3, 6, 6, 6, 7, 5, 4, 4], +[0, 1, 3, 3, 4, 7, 5, 6, 5, 3, 4, 3, 4, 4, 4, 6, 6, 5, 7, 6, 5, 6, 3, 5, 2, 3], +[1, 4, 3, 4, 5, 4, 5, 5, 4, 6, 3, 6, 5, 4, 6, 6, 7, 8, 7, 7, 6, 2, 4, 0, 3, 4], +[0, 4, 7, 5, 4, 4, 2, 2, 4, 2, 6, 4, 4, 6, 4, 6, 6, 7, 7, 7, 5, 5, 3, 3, 4], +[0, 4, 7, 5, 6, 5, 3, 2, 2, 2, 4, 3, 4, 5, 4, 6, 5, 4, 5, 3, 5, 3, 5, 4, 6, 5], +[1, 6, 5, 5, 6, 4, 6, 3, 5, 4, 4, 4, 5, 5, 6, 5, 5, 5, 1, 3, 1, 3, 4, 5, 7, 6], +[0, 6, 5, 5, 2, 6, 4, 7, 7, 6, 6, 4, 4, 4, 4, 4, 5, 3, 3, 1, 2, 3, 3, 6, 6, 6], +[1, 6, 4, 4, 5, 3, 6, 6, 6, 8, 5, 6, 5, 2, 4, 2, 3, 3, 3, 3, 4, 3, 5, 5, 4], +[1, 5, 3, 5, 4, 4, 5, 4, 5, 6, 5, 5, 6, 3, 6, 1, 4, 2, 2, 5, 5, 7, 8, 6, 5, 4], +[0, 1, 5, 3, 5, 6, 5, 6, 4, 3, 3, 4, 4, 6, 3, 5, 3, 3, 5, 4, 6, 6, 6, 6, 4, 2], +[1, 3, 2, 4, 6, 5, 7, 5, 5, 5, 3, 4, 4, 4, 6, 5, 6, 6, 5, 5, 5, 3, 5, 2, 3], +[1, 3, 3, 4, 4, 3, 5, 3, 4, 5, 3, 5, 2, 4, 4, 4, 6, 8, 7, 9, 7, 5, 5, 0, 3, 2], +[0, 4, 5, 5, 5, 3, 2, 2, 2, 1, 4, 3, 5, 4, 4, 5, 4, 6, 8, 6, 8, 5, 4, 4, 2, 3], +[1, 6, 5, 6, 4, 4, 4, 1, 2, 2, 3, 5, 5, 5, 6, 4, 5, 6, 3, 6, 3, 4, 5, 5, 5, 5], +[0, 5, 6, 5, 3, 5, 3, 5, 3, 4, 4, 4, 5, 5, 5, 5, 5, 2, 4, 0, 3, 2, 4, 6, 7], +[0, 7, 6, 5, 4, 5, 3, 7, 6, 6, 7, 4, 5, 4, 4, 4, 4, 3, 3, 1, 1, 1, 2, 4, 5, 6], +[1, 7, 5, 5, 5, 3, 5, 5, 6, 7, 5, 7, 5, 4, 5, 2, 4, 3, 3, 4, 4, 4, 6, 5, 5, 5], +[0, 4, 6, 3, 6, 5, 5, 5, 6, 5, 6, 6, 5, 6, 2, 5, 1, 3, 3, 3, 6, 7, 6, 6, 5, 2], +[1, 4, 2, 6, 6, 7, 8, 6, 6, 5, 4, 5, 6, 3, 6, 3, 3, 4, 3, 5, 5, 5, 6, 3, 3], +[1, 3, 1, 3, 4, 5, 7, 6, 7, 5, 4, 5, 4, 4, 5, 4, 5, 6, 5, 6, 5, 4, 6, 2, 4, 2], +[0, 4, 4, 4, 3, 4, 3, 4, 4, 3, 6, 2, 5, 4, 4, 5, 6, 7, 8, 7, 7, 6, 2, 4, 0, 3], +[1, 4, 4, 6, 4, 3, 2, 2, 1, 4, 2, 6, 4, 5, 6, 5, 7, 7, 7, 9, 6, 5, 4, 2, 3, 3], +[0, 4, 7, 4, 5, 4, 2, 2, 2, 2, 3, 3, 5, 6, 4, 6, 5, 4, 6, 2, 5, 3, 4, 5, 5], +[0, 5, 6, 5, 5, 5, 3, 6, 3, 4, 3, 3, 3, 4, 4, 5, 5, 3, 5, 1, 3, 0, 3, 4, 5, 7], +[1, 7, 6, 5, 4, 2, 6, 3, 6, 5, 5, 5, 4, 4, 4, 4, 4, 4, 3, 4, 1, 3, 4, 4, 6, 6], +[0, 5, 5, 4, 3, 4, 3, 5, 5, 5, 6, 5, 5, 4, 2, 4, 1, 3, 3, 3, 4, 5, 5, 5, 5, 4], +[1, 6, 3, 6, 5, 5, 6, 5, 6, 6, 6, 6, 6, 3, 5, 1, 3, 1, 2, 4, 4, 6, 7, 6, 4], +[1, 4, 2, 5, 3, 6, 7, 6, 6, 4, 4, 4, 4, 3, 6, 3, 4, 2, 2, 4, 4, 6, 6, 5, 5, 4], +[0, 3, 4, 3, 5, 7, 5, 7, 5, 5, 5, 3, 4, 3, 3, 5, 5, 4, 6, 5, 6, 5, 3, 5, 1, 3], +[1, 3, 4, 5, 4, 4, 5, 4, 4, 6, 3, 7, 4, 5, 5, 5, 6, 8, 8, 9, 7, 4, 5, -1, 3], +[1, 2, 3, 5, 4, 4, 3, 2, 2, 4, 3, 6, 4, 5, 5, 4, 6, 5, 6, 8, 7, 7, 5, 3, 4, 2], +[0, 4, 6, 5, 6, 5, 4, 4, 2, 2, 3, 3, 4, 5, 5, 6, 5, 4, 6, 2, 5, 3, 5, 5, 4, 5], +[1, 6, 5, 5, 4, 3, 5, 2, 5, 3, 4, 4, 4, 5, 6, 6, 6, 6, 3, 5, 0, 3, 3, 4, 7, 6], +[0, 6, 6, 4, 3, 4, 2, 6, 4, 5, 6, 5, 5, 5, 4, 6, 5, 5, 4, 2, 2, 1, 2, 5, 5], +[0, 7, 7, 4, 5, 4, 3, 5, 4, 6, 7, 6, 6, 5, 4, 5, 2, 4, 3, 3, 4, 4, 4, 5, 4, 4], +[1, 6, 3, 6, 3, 6, 5, 4, 5, 5, 5, 5, 5, 5, 6, 2, 4, 1, 3, 3, 4, 6, 7, 6, 6, 5], +[0, 3, 5, 2, 5, 6, 6, 7, 4, 4, 4, 3, 3, 5, 3, 5, 2, 3, 3, 3, 6, 5, 6, 7, 5, 4], +[1, 3, 2, 4, 4, 4, 7, 5, 6, 5, 4, 6, 3, 4, 5, 5, 5, 6, 5, 6, 5, 4, 6, 1, 5], +[1, 2, 3, 4, 4, 3, 4, 4, 4, 4, 3, 6, 3, 5, 3, 4, 5, 5, 6, 9, 8, 7, 6, 2, 4, 1], +[0, 5, 5, 5, 7, 5, 4, 3, 2, 1, 4, 2, 5, 3, 3, 4, 4, 5, 6, 6, 8, 6, 5, 5, 2, 4], +[1, 4, 5, 7, 5, 5, 5, 2, 3, 1, 2, 4, 3, 5, 5, 4, 5, 5, 4, 6, 3, 6, 4, 5, 5, 6], +[0, 5, 7, 5, 5, 6, 3, 6, 3, 4, 3, 4, 4, 4, 5, 6, 6, 5, 5, 1, 4, 0, 3, 4, 5], +[0, 7, 6, 5, 5, 5, 3, 7, 4, 7, 7, 6, 6, 4, 5, 5, 5, 5, 4, 3, 2, 0, 2, 3, 3, 5], +[1, 6, 5, 5, 3, 3, 4, 4, 6, 6, 6, 7, 6, 6, 5, 2, 4, 2, 3, 3, 4, 4, 5, 4, 5, 4], +[0, 4, 5, 3, 6, 4, 4, 5, 4, 5, 5, 5, 6, 6, 3, 6, 1, 3, 2, 3, 5, 5, 6, 6, 5, 4], +[1, 4, 1, 5, 3, 6, 6, 5, 6, 5, 4, 5, 5, 4, 7, 4, 5, 3, 3, 4, 4, 6, 6, 4, 5], +[1, 3, 2, 3, 2, 4, 6, 4, 7, 5, 4, 6, 3, 5, 4, 4, 5, 5, 5, 7, 5, 6, 5, 3, 6, 2], +[0, 4, 4, 3, 5, 4, 3, 4, 4, 3, 5, 3, 6, 3, 4, 4, 4, 6, 7, 7, 9, 7, 4, 6, 1, 4], +[1, 3, 4, 6, 4, 4, 3, 2, 2, 3, 2, 5, 2, 5, 4, 4, 5, 5, 7, 9, 7, 8, 5, 4, 5], +[1, 3, 5, 6, 5, 6, 4, 3, 3, 1, 2, 3, 3, 4, 4, 4, 6, 5, 5, 6, 4, 6, 4, 5, 5, 5], +[0, 6, 6, 6, 6, 6, 4, 6, 3, 6, 4, 4, 4, 4, 4, 5, 5, 6, 5, 2, 4, -1, 3, 3, 4, 6], +[1, 6, 7, 6, 5, 3, 5, 3, 6, 5, 6, 6, 4, 5, 4, 4, 6, 5, 4, 3, 2, 3, 2, 3, 5, 5], +[0, 7, 7, 5, 5, 4, 4, 5, 4, 5, 6, 5, 6, 4, 3, 5, 1, 4, 2, 3, 3, 4, 4, 5, 5], +[0, 5, 5, 3, 6, 4, 6, 5, 5, 6, 6, 6, 6, 7, 5, 6, 2, 5, 0, 2, 3, 4, 6, 6, 5, 5], +[1, 4, 2, 5, 2, 6, 6, 6, 7, 6, 6, 5, 5, 5, 6, 4, 5, 3, 3, 3, 2, 5, 4, 5, 6, 3], +[0, 4, 3, 2, 4, 4, 5, 7, 5, 6, 6, 4, 5, 3, 4, 4, 4, 6, 5, 5, 6, 5, 5, 5, 2, 5], +[1, 2, 4, 4, 3, 3, 4, 3, 4, 5, 3, 6, 2, 5, 3, 5, 6, 7, 7, 9, 8, 7, 6, 2, 4], +[1, 1, 5, 5, 5, 5, 3, 2, 2, 1, 2, 4, 2, 5, 3, 4, 5, 4, 6, 7, 7, 9, 5, 5, 4, 2], +[0, 5, 4, 5, 7, 5, 5, 4, 1, 3, 2, 2, 4, 3, 4, 5, 4, 5, 5, 4, 7, 2, 6, 3, 4, 5], +[1, 5, 5, 6, 5, 4, 6, 3, 6, 3, 4, 3, 3, 3, 4, 5, 6, 5, 5, 5, 1, 4, 1, 4, 5, 5], +[0, 7, 6, 5, 4, 4, 2, 6, 3, 7, 5, 4, 5, 3, 4, 4, 5, 5, 4, 3, 3, 1, 2, 4, 4], +[0, 7, 6, 5, 5, 3, 4, 4, 4, 7, 5, 6, 7, 5, 5, 5, 3, 5, 2, 4, 3, 3, 4, 5, 4, 5], +[1, 5, 4, 6, 3, 6, 5, 5, 5, 5, 6, 6, 6, 7, 7, 3, 6, 0, 3, 1, 2, 5, 5, 7, 7, 5], +[0, 4, 5, 3, 6, 5, 7, 7, 6, 6, 5, 5, 5, 5, 5, 5, 3, 4, 2, 3, 3, 4, 6, 5, 5, 5], +[1, 4, 3, 4, 3, 5, 6, 5, 7, 5, 5, 6, 4, 5, 5, 5, 6, 5, 6, 6, 5, 6, 5, 3, 5], +[1, 2, 4, 4, 4, 4, 4, 4, 5, 4, 4, 6, 3, 7, 3, 5, 4, 5, 7, 8, 8, 9, 7, 4, 5, 1], +[0, 5, 4, 5, 7, 6, 5, 4, 2, 3, 3, 2, 6, 3, 5, 4, 4, 6, 5, 7, 8, 7, 7, 5, 4, 5], +[1, 2, 5, 6, 5, 7, 5, 4, 4, 2, 3, 4, 3, 4, 4, 4, 6, 5, 5, 7, 3, 6, 3, 5, 5, 5], +[0, 6, 5, 5, 5, 5, 4, 6, 3, 6, 2, 3, 4, 3, 4, 6, 6, 6, 6, 3, 5, 0, 4, 3, 5], +[0, 6, 6, 6, 5, 4, 3, 5, 3, 7, 4, 6, 6, 4, 5, 4, 5, 6, 5, 5, 4, 1, 3, 1, 3, 4], +[1, 5, 6, 6, 4, 5, 4, 3, 5, 5, 6, 6, 6, 7, 6, 4, 5, 3, 5, 2, 4, 4, 4, 5, 5, 5], +[0, 5, 6, 3, 7, 4, 6, 6, 5, 6, 5, 5, 6, 5, 5, 6, 2, 4, 0, 3, 3, 4, 6, 6, 6], +[0, 5, 4, 2, 5, 2, 6, 6, 6, 6, 5, 5, 5, 5, 6, 6, 4, 6, 3, 4, 3, 4, 5, 5, 6, 6], +[1, 4, 4, 3, 2, 4, 4, 5, 7, 5, 6, 6, 3, 5, 4, 5, 4, 4, 5, 6, 6, 7, 6, 5, 6, 3], +[0, 6, 3, 5, 5, 4, 4, 4, 4, 5, 5, 4, 6, 2, 5, 2, 4, 4, 6, 6, 8, 8, 7, 6, 2, 5], +[1, 2, 6, 6, 5, 6, 5, 4, 3, 1, 2, 5, 2, 5, 2, 3, 4, 3, 5, 7, 7, 8, 6, 6, 6], +[1, 3, 6, 6, 5, 7, 5, 6, 5, 2, 3, 2, 2, 3, 3, 5, 5, 5, 5, 5, 4, 6, 3, 6, 3, 4], +[0, 5, 5, 5, 6, 5, 6, 6, 4, 8, 4, 6, 5, 4, 5, 6, 6, 7, 7, 5, 5, 0, 4, 0, 4, 5], +[1, 5, 6, 6, 5, 5, 5, 3, 7, 5, 8, 6, 6, 7, 4, 5, 6, 5, 6, 5, 4, 4, 1, 3, 3, 4], +[0, 6, 6, 5, 6, 4, 5, 4, 5, 6, 6, 7, 7, 5, 6, 6, 3, 5, 2, 4, 3, 4, 4, 4, 4], +[0, 6, 5, 4, 5, 3, 6, 4, 6, 6, 5, 5, 6, 7, 7, 7, 4, 6, 1, 5, 1, 3, 4, 6, 6, 6], +[1, 4, 3, 4, 1, 6, 4, 7, 6, 5, 6, 5, 5, 6, 6, 6, 7, 5, 5, 2, 4, 5, 4, 6, 6, 5], +[0, 6, 3, 3, 4, 3, 6, 6, 5, 7, 6, 5, 6, 4, 6, 4, 5, 6, 5, 6, 7, 6, 6, 6, 3, 6], +[1, 2, 5, 4, 5, 5, 4, 3, 4, 4, 4, 5, 2, 6, 2, 4, 4, 5, 7, 8, 8, 10, 8, 5, 6], +[1, 2, 6, 4, 6, 6, 5, 4, 3, 2, 2, 3, 2, 5, 2, 4, 3, 3, 5, 6, 7, 9, 7, 8, 6, 4], +[0, 5, 4, 5, 7, 6, 7, 5, 3, 5, 2, 3, 3, 3, 4, 4, 5, 6, 5, 5, 6, 3, 6, 3, 5, 5], +[1, 5, 6, 7, 5, 6, 6, 4, 7, 3, 7, 4, 4, 4, 3, 5, 5, 6, 6, 6, 2, 5, 0, 4, 4, 6], +[0, 7, 7, 7, 6, 5, 4, 5, 3, 7, 4, 6, 5, 4, 5, 4, 4, 6, 4, 5, 4, 2, 3, 2, 3], +[0, 6, 6, 7, 7, 4, 5, 3, 4, 6, 5, 7, 7, 6, 6, 6, 5, 6, 2, 5, 2, 3, 4, 4, 4, 4], +[1, 4, 5, 6, 4, 7, 4, 7, 6, 6, 6, 6, 6, 7, 7, 6, 7, 2, 5, 1, 3, 3, 4, 5, 6, 5], +[0, 5, 4, 3, 5, 3, 8, 7, 8, 8, 6, 6, 6, 6, 6, 7, 5, 5, 2, 3, 3, 3, 5, 5, 4], +[0, 6, 4, 3, 3, 2, 4, 4, 5, 7, 5, 6, 6, 4, 6, 3, 5, 4, 5, 6, 6, 6, 6, 6, 5, 6], +[1, 3, 5, 2, 4, 4, 3, 3, 4, 3, 4, 5, 3, 6, 2, 5, 3, 4, 5, 6, 8, 9, 8, 7, 6, 2], +[0, 5, 2, 6, 6, 6, 6, 5, 3, 3, 2, 3, 5, 3, 6, 3, 4, 4, 4, 7, 7, 6, 8, 6, 5, 4], +[1, 3, 5, 5, 6, 7, 5, 4, 5, 2, 3, 2, 3, 4, 3, 5, 5, 5, 6, 6, 4, 7, 2, 7, 4], +[1, 6, 6, 6, 6, 6, 5, 5, 6, 3, 7, 2, 5, 3, 4, 5, 5, 6, 6, 6, 5, 6, 1, 4, 2, 5], +[0, 6, 6, 7, 6, 4, 4, 5, 3, 6, 3, 7, 5, 5, 5, 4, 5, 7, 6, 7, 6, 5, 4, 2, 4, 5], +[1, 5, 7, 5, 5, 6, 3, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 4, 6, 2, 5, 4, 4, 5, 5, 5], +[0, 6, 5, 4, 7, 4, 7, 5, 7, 7, 6, 7, 6, 6, 7, 7, 4, 6, 1, 3, 1, 3, 4, 5, 7], +[0, 7, 5, 4, 5, 3, 7, 5, 7, 8, 7, 7, 5, 5, 6, 6, 6, 6, 4, 5, 3, 3, 4, 5, 6, 6], +[1, 5, 6, 3, 3, 4, 4, 5, 6, 5, 6, 6, 4, 6, 4, 6, 4, 6, 5, 6, 6, 7, 5, 6, 6, 3], +[0, 7, 3, 6, 4, 5, 5, 4, 5, 5, 5, 5, 6, 3, 7, 3, 5, 4, 5, 6, 7, 8, 9, 7, 4, 6], +[1, 2, 6, 4, 6, 7, 5, 5, 4, 3, 4, 4, 4, 6, 3, 5, 3, 3, 5, 6, 7, 8, 7, 7, 5], +[1, 4, 6, 4, 6, 7, 6, 6, 5, 3, 5, 2, 4, 3, 3, 4, 4, 4, 6, 5, 5, 6, 3, 6, 3, 5], +[0, 5, 6, 6, 5, 5, 5, 5, 3, 7, 2, 7, 3, 5, 5, 5, 6, 7, 7, 7, 6, 3, 5, 0, 4, 3], +[1, 6, 7, 6, 6, 5, 3, 3, 5, 2, 8, 4, 6, 6, 4, 6, 5, 6, 7, 6, 6, 4, 2, 4, 2], +[1, 5, 6, 6, 7, 7, 4, 5, 4, 4, 6, 5, 6, 6, 6, 7, 6, 4, 6, 2, 5, 2, 4, 4, 4, 5], +[0, 5, 4, 5, 6, 3, 7, 4, 7, 5, 5, 6, 5, 6, 7, 7, 6, 7, 2, 5, 1, 4, 4, 5, 6, 6], +[1, 6, 5, 4, 3, 5, 3, 7, 6, 7, 7, 6, 5, 5, 5, 6, 6, 5, 6, 2, 4, 4, 4, 6, 6, 5], +[0, 6, 4, 4, 3, 3, 5, 5, 6, 7, 6, 7, 6, 4, 7, 4, 6, 4, 5, 6, 6, 5, 6, 6, 5], +[0, 7, 3, 6, 4, 6, 5, 5, 4, 5, 5, 5, 5, 4, 6, 2, 6, 2, 4, 4, 6, 8, 8, 8, 7, 7], +[1, 3, 7, 4, 8, 7, 7, 7, 5, 3, 3, 2, 3, 5, 2, 5, 2, 4, 3, 4, 6, 7, 7, 8, 6, 6], +[0, 6, 4, 7, 6, 6, 8, 6, 6, 6, 3, 4, 3, 4, 5, 5, 5, 6, 6, 6, 6, 4, 6, 3, 6, 4], +[1, 6, 6, 6, 6, 6, 6, 5, 7, 4, 7, 3, 7, 4, 4, 5, 6, 6, 8, 7, 6, 6, 1, 5, 1], +[1, 5, 6, 7, 8, 6, 5, 4, 5, 4, 8, 4, 8, 6, 6, 6, 5, 5, 6, 5, 7, 5, 4, 4, 2, 3], +[0, 4, 5, 7, 6, 5, 6, 3, 5, 5, 5, 7, 6, 7, 8, 6, 6, 6, 4, 6, 3, 5, 4, 4, 6, 5], +[1, 5, 6, 5, 4, 6, 3, 7, 4, 6, 5, 5, 7, 7, 7, 7, 8, 5, 6, 1, 5, 2, 4, 5, 5, 6], +[0, 6, 4, 3, 4, 2, 6, 5, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 5, 5, 3, 4, 4, 5, 6], +[0, 6, 4, 5, 3, 3, 4, 4, 5, 6, 5, 7, 6, 5, 6, 3, 7, 4, 5, 6, 6, 6, 7, 6, 6, 6], +[1, 4, 7, 3, 6, 5, 5, 4, 4, 4, 4, 4, 4, 6, 2, 5, 1, 4, 3, 5, 7, 7, 9, 9, 8, 5], +[0, 6, 2, 7, 5, 7, 7, 5, 5, 4, 2, 4, 4, 4, 6, 3, 4, 3, 4, 5, 6, 7, 9, 7, 7, 6], +[1, 5, 6, 5, 7, 7, 6, 6, 5, 3, 5, 2, 4, 4, 3, 5, 4, 5, 6, 6, 5, 6, 3, 7, 4], +[1, 7, 7, 7, 7, 7, 6, 7, 5, 5, 7, 3, 7, 3, 5, 4, 3, 5, 6, 6, 7, 6, 3, 5, 1, 5], +[0, 5, 6, 8, 7, 6, 6, 4, 4, 6, 3, 8, 4, 7, 5, 4, 5, 5, 6, 7, 6, 5, 5, 2, 4, 3], +[1, 5, 7, 6, 7, 6, 4, 5, 4, 5, 6, 5, 7, 6, 7, 6, 6, 5, 7, 3, 5, 3, 4, 4, 4], +[1, 5, 5, 5, 5, 5, 4, 8, 5, 9, 7, 7, 7, 7, 7, 9, 8, 7, 7, 3, 6, 1, 3, 3, 4, 5], +[0, 5, 5, 4, 3, 2, 5, 3, 8, 7, 7, 8, 7, 6, 7, 6, 7, 6, 6, 7, 3, 4, 3, 4, 5, 6], +[1, 6, 5, 4, 4, 4, 3, 5, 5, 6, 7, 6, 6, 7, 4, 7, 3, 6, 4, 6, 6, 6, 6, 7, 6, 5], +[0, 6, 3, 7, 3, 5, 4, 4, 4, 4, 4, 5, 5, 4, 7, 3, 6, 3, 5, 6, 7, 9, 9, 7, 7], +[0, 7, 3, 7, 3, 7, 6, 6, 6, 4, 3, 4, 3, 3, 6, 3, 6, 3, 4, 4, 5, 7, 7, 7, 9, 6], +[1, 6, 6, 4, 7, 6, 6, 8, 6, 5, 6, 3, 5, 3, 3, 4, 4, 5, 6, 6, 6, 6, 5, 7, 3, 7], +[0, 5, 6, 7, 6, 6, 6, 5, 5, 7, 3, 7, 2, 5, 3, 3, 5, 6, 7, 8, 7, 6, 6, 2, 6, 2], +[1, 6, 6, 6, 7, 6, 4, 4, 4, 3, 6, 3, 7, 4, 4, 5, 4, 6, 7, 6, 7, 6, 4, 5, 3], +[1, 5, 6, 5, 7, 6, 5, 7, 4, 5, 5, 5, 7, 6, 7, 7, 6, 6, 6, 4, 7, 2, 5, 3, 4, 5], +[0, 5, 5, 5, 5, 5, 7, 4, 8, 5, 7, 6, 6, 7, 7, 7, 7, 7, 4, 6, 0, 4, 1, 4, 6, 6], +[1, 7, 6, 5, 4, 5, 3, 7, 5, 7, 7, 6, 6, 6, 6, 7, 6, 7, 6, 4, 5, 3, 3, 4, 5, 6], +[0, 6, 5, 5, 3, 4, 4, 4, 6, 6, 6, 7, 6, 6, 7, 4, 7, 4, 6, 6, 6, 6, 6, 6, 5], +[0, 6, 3, 7, 3, 6, 4, 5, 5, 5, 5, 5, 5, 6, 7, 3, 7, 2, 5, 4, 5, 7, 7, 7, 8, 6], +[1, 5, 7, 3, 7, 5, 7, 8, 7, 6, 5, 4, 4, 5, 4, 6, 2, 4, 3, 3, 5, 5, 6, 8, 6, 7], +[0, 5, 4, 6, 4, 7, 7, 6, 7, 6, 3, 5, 3, 5, 4, 4, 5, 5, 5, 6, 5, 5, 6, 4, 7], +[0, 3, 6, 6, 6, 6, 6, 5, 5, 5, 4, 7, 2, 7, 3, 5, 4, 5, 7, 7, 7, 7, 7, 4, 6, 1], +[1, 5, 4, 7, 7, 6, 5, 5, 4, 4, 6, 4, 8, 5, 6, 5, 5, 6, 5, 6, 8, 5, 6, 4, 3, 4], +[0, 3, 4, 7, 6, 6, 6, 4, 6, 4, 5, 6, 6, 7, 7, 7, 7, 6, 5, 7, 3, 6, 3, 5, 5, 5], +[1, 5, 5, 5, 5, 6, 4, 7, 4, 7, 5, 6, 6, 6, 6, 8, 8, 6, 7, 2, 6, 1, 4, 3, 5], +[1, 7, 6, 5, 5, 3, 3, 5, 3, 8, 5, 7, 7, 6, 6, 7, 7, 8, 8, 7, 7, 4, 5, 4, 5, 7], +[0, 6, 6, 6, 4, 4, 3, 3, 5, 5, 6, 6, 6, 6, 7, 5, 7, 4, 6, 5, 6, 7, 7, 6, 7, 7], +[1, 5, 8, 4, 8, 5, 7, 6, 5, 5, 5, 5, 5, 6, 5, 6, 2, 5, 2, 4, 5, 6, 7, 8, 7, 7], +[0, 6, 4, 8, 5, 8, 7, 7, 7, 5, 4, 4, 4, 4, 6, 4, 6, 3, 4, 4, 5, 6, 7, 7, 9], +[0, 6, 6, 6, 4, 7, 6, 7, 8, 6, 5, 5, 3, 5, 3, 4, 5, 4, 6, 6, 5, 6, 6, 4, 7, 3], +[1, 7, 5, 6, 7, 7, 6, 7, 7, 6, 8, 4, 8, 3, 7, 4, 4, 5, 6, 7, 8, 6, 5, 6, 2, 5], +[0, 2, 6, 6, 7, 7, 6, 5, 5, 5, 4, 7, 4, 7, 5, 6, 5, 4, 5, 7, 6, 7, 5, 4, 4, 3], +[1, 5, 5, 6, 7, 6, 5, 6, 3, 6, 5, 5, 7, 6, 7, 7, 6, 6, 6, 3, 7, 2, 5, 3, 5], +[1, 6, 5, 5, 5, 4, 4, 6, 3, 8, 4, 7, 6, 6, 8, 8, 8, 9, 9, 5, 7, 2, 5, 2, 4, 5], +[0, 5, 6, 5, 3, 3, 3, 2, 7, 4, 8, 6, 6, 7, 6, 6, 7, 7, 8, 7, 5, 5, 3, 4, 5, 5], +[1, 7, 6, 5, 6, 4, 4, 4, 4, 6, 5, 6, 6, 6, 5, 6, 3, 7, 3, 6, 6, 6, 7, 6, 6, 6], +[0, 6, 4, 7, 4, 7, 5, 5, 5, 4, 4, 5, 4, 5, 6, 3, 6, 1, 5, 3, 6, 7, 8, 8, 8], +[0, 7, 5, 7, 3, 7, 5, 7, 7, 6, 5, 4, 3, 4, 4, 4, 6, 3, 4, 3, 4, 5, 6, 6, 8, 6], +[1, 7, 6, 6, 7, 6, 8, 8, 7, 7, 7, 4, 6, 3, 5, 4, 5, 5, 5, 5, 5, 5, 5, 6, 3, 7], +[0, 4, 7, 6, 7, 7, 6, 6, 6, 6, 5, 8, 3, 7, 2, 4, 4, 4, 6, 6, 7, 7, 7, 3, 5, 2], +[1, 7, 5, 8, 9, 8, 6, 6, 4, 4, 6, 4, 8, 4, 6, 4, 4, 5, 6, 6, 7, 6, 5, 5, 2], +[1, 5, 3, 6, 7, 6, 6, 6, 4, 7, 4, 6, 7, 6, 8, 7, 7, 8, 7, 5, 7, 2, 6, 2, 5, 5], +[0, 4, 5, 5, 4, 5, 5, 4, 8, 4, 8, 6, 7, 7, 7, 8, 9, 8, 8, 8, 4, 5, 0, 5, 4, 4], +[1, 6, 6, 4, 4, 4, 2, 6, 3, 8, 6, 8, 7, 6, 6, 7, 7, 8, 7, 6, 7, 3, 5, 3, 5], +[1, 5, 6, 5, 6, 2, 4, 2, 3, 5, 4, 5, 6, 5, 6, 6, 5, 7, 4, 7, 5, 6, 6, 7, 7, 7], +[0, 6, 5, 7, 3, 7, 4, 6, 4, 4, 4, 4, 4, 5, 6, 4, 7, 2, 6, 2, 5, 5, 6, 8, 8, 7], +[1, 6, 6, 3, 7, 5, 8, 7, 7, 7, 5, 4, 4, 4, 5, 6, 4, 6, 2, 4, 4, 4, 6, 6, 6, 8], +[0, 5, 5, 5, 4, 7, 7, 7, 8, 6, 5, 5, 3, 5, 2, 4, 4, 4, 5, 6, 5, 7, 6, 4, 7], +[0, 3, 8, 5, 7, 7, 7, 6, 5, 5, 5, 7, 3, 6, 2, 5, 2, 3, 5, 5, 7, 8, 7, 6, 6, 2], +[1, 6, 4, 7, 7, 7, 7, 6, 4, 5, 4, 4, 7, 4, 8, 4, 5, 5, 4, 6, 7, 5, 7, 5, 5, 5], +[0, 3, 5, 6, 5, 7, 6, 5, 6, 3, 5, 5, 6, 6, 6, 6, 7, 6, 6, 7, 3, 7, 2, 5, 4, 4], +[1, 6, 5, 6, 6, 5, 5, 7, 4, 8, 5, 7, 6, 6, 6, 7, 7, 8, 8, 5, 6, 0, 4, 2, 5], +[1, 6, 6, 6, 5, 4, 4, 4, 3, 7, 4, 7, 6, 6, 6, 6, 7, 7, 7, 8, 7, 5, 6, 3, 5, 5], +[0, 6, 7, 7, 5, 6, 3, 4, 5, 4, 5, 5, 6, 7, 6, 5, 7, 4, 7, 4, 7, 6, 6, 7, 7, 6], +[1, 6, 6, 4, 7, 4, 8, 5, 6, 6, 5, 6, 6, 6, 6, 7, 4, 6, 2, 5, 3, 5, 6, 7, 7, 7], +[0, 5, 4, 6, 3, 8, 6, 8, 8, 7, 6, 5, 4, 5, 4, 4, 6, 3, 4, 3, 4, 5, 5, 7, 7], +[0, 6, 7, 5, 5, 6, 5, 7, 7, 7, 6, 6, 4, 6, 2, 5, 4, 4, 5, 5, 5, 6, 6, 5, 7, 3], +[1, 7, 4, 7, 6, 7, 6, 6, 5, 6, 6, 4, 8, 3, 7, 3, 5, 5, 5, 6, 8, 7, 7, 6, 3, 6], +[0, 2, 7, 5, 7, 8, 6, 5, 5, 4, 5, 6, 4, 8, 4, 6, 5, 5, 6, 6, 6, 7, 5, 6, 5], +[0, 4, 5, 4, 6, 7, 6, 7, 6, 3, 6, 4, 6, 6, 6, 6, 6, 7, 6, 6, 5, 7, 3, 6, 2, 5], +[1, 5, 5, 6, 5, 5, 4, 5, 4, 7, 4, 8, 4, 6, 6, 6, 7, 8, 8, 8, 8, 4, 7, 2, 5, 5], +[0, 5, 7, 5, 5, 4, 3, 2, 5, 3, 7, 4, 6, 6, 6, 6, 7, 7, 8, 7, 7, 7, 4, 6, 4, 5], +[1, 6, 6, 6, 6, 3, 5, 3, 4, 5, 5, 7, 6, 5, 6, 6, 4, 7, 3, 6, 5, 6, 6, 7, 6], +[1, 7, 6, 5, 7, 3, 8, 5, 7, 5, 5, 5, 5, 5, 5, 6, 4, 6, 1, 5, 1, 4, 5, 6, 8, 8], +[0, 8, 7, 7, 4, 8, 5, 8, 7, 7, 7, 5, 4, 4, 4, 4, 5, 3, 4, 2, 3, 3, 4, 5, 6, 6], +[1, 7, 5, 5, 6, 5, 7, 7, 8, 8, 6, 6, 6, 4, 6, 3, 4, 5, 4, 5, 6, 5, 5, 6, 4, 6], +[0, 3, 7, 4, 6, 7, 6, 6, 6, 6, 6, 7, 4, 8, 3, 6, 3, 4, 6, 5, 6, 7, 6, 5, 5], +[0, 1, 6, 3, 7, 8, 7, 7, 6, 4, 5, 5, 4, 7, 4, 7, 4, 5, 5, 4, 5, 6, 5, 7, 4, 4], +[1, 4, 3, 6, 5, 6, 7, 6, 5, 5, 3, 6, 5, 6, 7, 6, 7, 7, 6, 7, 7, 4, 7, 2, 6, 4], +[0, 5, 5, 5, 5, 5, 3, 3, 6, 3, 7, 4, 7, 6, 6, 7, 7, 8, 9, 8, 6, 6, 1, 5, 2, 5], +[1, 6, 6, 6, 4, 3, 3, 4, 3, 7, 5, 8, 6, 6, 6, 6, 6, 9, 7, 9, 6, 5, 5, 3, 5], +[1, 5, 5, 6, 6, 4, 5, 3, 4, 3, 4, 6, 5, 5, 6, 6, 5, 6, 3, 7, 4, 7, 6, 7, 7, 7], +[0, 6, 6, 6, 4, 7, 3, 8, 4, 6, 4, 4, 5, 4, 5, 4, 5, 3, 6, 1, 5, 3, 5, 7, 8, 8], +[1, 7, 6, 4, 6, 3, 8, 5, 8, 7, 6, 5, 4, 4, 5, 5, 4, 6, 3, 4, 3, 4, 5, 5, 7, 8], +[0, 5, 7, 5, 5, 6, 6, 7, 7, 7, 7, 6, 4, 6, 2, 5, 3, 5, 4, 5, 6, 5, 6, 5, 7], +[0, 4, 8, 4, 8, 7, 7, 7, 7, 6, 6, 6, 5, 7, 2, 6, 2, 4, 3, 4, 6, 6, 6, 6, 6, 3], +[1, 6, 2, 7, 6, 8, 9, 6, 5, 5, 4, 4, 6, 4, 8, 4, 5, 4, 4, 6, 5, 6, 7, 5, 5, 4], +[0, 3, 5, 4, 5, 7, 6, 7, 7, 4, 6, 4, 6, 6, 6, 7, 7, 6, 7, 6, 5, 7, 2, 6, 3, 5], +[1, 4, 5, 5, 5, 4, 5, 5, 4, 8, 4, 8, 5, 7, 7, 6, 7, 8, 8, 7, 7, 3, 5, 1, 5], +[1, 4, 6, 6, 4, 4, 3, 2, 2, 5, 3, 7, 5, 7, 6, 5, 6, 7, 6, 9, 6, 7, 6, 4, 6, 4], +[0, 6, 6, 6, 5, 5, 2, 4, 2, 3, 4, 4, 6, 6, 5, 5, 6, 4, 7, 2, 7, 4, 5, 6, 6, 6], +[1, 7, 6, 5, 6, 3, 8, 3, 7, 5, 5, 5, 5, 6, 6, 7, 5, 6, 2, 5, 2, 4, 4, 6, 7], +[1, 7, 6, 6, 6, 3, 7, 4, 8, 6, 7, 6, 5, 5, 5, 4, 5, 5, 3, 5, 2, 4, 3, 5, 6, 7], +[0, 5, 7, 5, 5, 6, 5, 7, 6, 7, 7, 6, 5, 6, 2, 5, 2, 4, 4, 4, 4, 5, 5, 5, 5, 4], +[1, 6, 3, 7, 5, 7, 6, 6, 6, 5, 5, 6, 6, 4, 7, 2, 5, 2, 4, 5, 5, 7, 7, 7, 5, 6], +[0, 2, 6, 3, 7, 7, 7, 6, 5, 4, 5, 5, 5, 7, 4, 6, 4, 4, 5, 5, 6, 6, 6, 6, 5], +[0, 4, 5, 4, 6, 6, 7, 8, 7, 5, 6, 3, 6, 5, 5, 7, 6, 7, 7, 6, 5, 6, 3, 6, 1, 6], +[1, 4, 5, 5, 5, 5, 5, 5, 4, 7, 3, 7, 4, 7, 5, 5, 6, 7, 7, 9, 8, 6, 7, 1, 5, 3], +[0, 6, 6, 6, 6, 5, 3, 3, 3, 2, 6, 4, 7, 5, 5, 5, 6, 6, 8, 6, 8, 6, 5, 6, 4, 5], +[1, 5, 6, 6, 5, 4, 5, 2, 4, 4, 4, 6, 6, 6, 7, 5, 6, 7, 4, 7, 3, 7, 5, 5, 6], +[1, 6, 5, 5, 6, 3, 6, 3, 8, 4, 6, 6, 5, 5, 6, 6, 6, 7, 3, 6, 1, 4, 2, 5, 6, 7], +[0, 7, 6, 5, 4, 5, 3, 8, 5, 8, 7, 6, 5, 5, 4, 5, 5, 5, 6, 3, 4, 2, 3, 5, 5, 6], +[1, 7, 5, 7, 4, 4, 6, 4, 7, 6, 6, 6, 6, 4, 5, 2, 5, 3, 5, 5, 5, 6, 5, 5, 4, 6], +[0, 3, 7, 3, 7, 5, 6, 6, 5, 5, 4, 6, 4, 7, 2, 7, 2, 4, 4, 4, 6, 6, 7, 6, 5], +[0, 3, 5, 2, 7, 6, 8, 7, 6, 5, 5, 4, 4, 5, 5, 7, 3, 6, 3, 4, 5, 5, 5, 6, 5, 5], +[1, 4, 3, 5, 4, 6, 7, 6, 6, 6, 3, 6, 3, 5, 5, 5, 6, 5, 6, 7, 6, 5, 6, 3, 6, 3], +[0, 6, 6, 5, 5, 5, 3, 4, 5, 3, 6, 2, 7, 4, 5, 5, 6, 7, 9, 7, 7, 7, 3, 6, 1, 6], +[1, 5, 6, 6, 5, 3, 3, 2, 2, 4, 3, 8, 4, 6, 6, 5, 6, 6, 6, 8, 7, 6, 6, 4, 6], +[1, 4, 6, 7, 5, 5, 5, 3, 4, 3, 4, 5, 4, 6, 6, 5, 5, 6, 4, 6, 3, 7, 4, 6, 6, 6], +[0, 7, 6, 6, 5, 6, 4, 8, 4, 7, 5, 5, 5, 4, 5, 5, 5, 4, 5, 1, 4, 0, 4, 4, 6, 7], +[1, 7, 6, 5, 5, 4, 8, 4, 9, 6, 7, 6, 5, 4, 4, 5, 5, 5, 4, 5, 2, 4, 3, 4, 5], +[1, 6, 5, 7, 4, 5, 5, 4, 7, 6, 8, 7, 6, 6, 5, 3, 6, 2, 5, 4, 5, 5, 5, 5, 5, 5], +[0, 3, 6, 2, 7, 5, 7, 7, 7, 7, 6, 6, 7, 7, 4, 7, 2, 5, 2, 4, 5, 5, 7, 7, 5, 4], +[1, 4, 1, 6, 3, 8, 7, 7, 7, 5, 4, 5, 4, 5, 7, 4, 6, 3, 4, 4, 4, 5, 6, 5, 7, 4], +[0, 4, 5, 3, 5, 5, 5, 6, 5, 4, 6, 2, 5, 4, 5, 6, 5, 6, 6, 6, 6, 6, 3, 6, 2], +[0, 5, 4, 5, 5, 5, 4, 4, 3, 3, 6, 3, 7, 3, 7, 5, 6, 7, 8, 8, 9, 8, 6, 6, 1, 5], +[1, 3, 6, 6, 5, 4, 4, 2, 3, 2, 2, 6, 4, 6, 4, 5, 5, 5, 6, 8, 7, 8, 6, 5, 5, 4], +[0, 6, 6, 6, 7, 6, 3, 5, 1, 4, 3, 4, 5, 4, 4, 5, 5, 4, 5, 2, 6, 2, 7, 5, 6, 6], +[1, 6, 6, 6, 5, 4, 7, 3, 8, 4, 5, 4, 4, 4, 5, 5, 5, 6, 3, 5, 1, 5, 3, 5, 7], +[1, 7, 7, 7, 5, 4, 5, 2, 8, 5, 8, 6, 5, 5, 4, 4, 5, 5, 4, 5, 3, 4, 2, 4, 5, 6], +[0, 6, 7, 4, 7, 4, 5, 6, 5, 8, 7, 7, 7, 5, 4, 6, 2, 5, 2, 3, 4, 3, 5, 4, 5, 4], +[1, 5, 3, 7, 4, 8, 6, 7, 7, 6, 5, 5, 6, 5, 7, 2, 6, 1, 4, 3, 4, 6, 6, 6, 6, 5], +[0, 3, 6, 2, 7, 6, 8, 7, 6, 5, 4, 4, 4, 6, 4, 6, 3, 5, 3, 3, 4, 5, 5, 5, 3], +[0, 4, 4, 3, 5, 4, 6, 6, 6, 6, 6, 4, 6, 4, 6, 5, 6, 7, 6, 6, 6, 5, 4, 6, 2, 6], +[1, 2, 4, 4, 4, 4, 4, 3, 4, 5, 3, 7, 3, 7, 4, 5, 5, 6, 7, 8, 8, 7, 6, 3, 6, 1], +[0, 5, 5, 6, 6, 5, 3, 3, 1, 2, 4, 3, 7, 4, 6, 4, 4, 6, 6, 6, 8, 5, 6, 5, 3, 5], +[1, 4, 5, 6, 5, 5, 5, 1, 3, 2, 3, 4, 4, 5, 6, 6, 6, 6, 4, 7, 2, 7, 4, 6, 6], +[1, 6, 6, 5, 4, 4, 6, 2, 7, 2, 6, 4, 5, 5, 5, 5, 5, 6, 5, 6, 2, 5, 1, 4, 5, 6], +[0, 7, 6, 5, 5, 5, 3, 6, 4, 8, 7, 6, 6, 4, 5, 4, 4, 5, 5, 3, 4, 2, 4, 3, 4, 6], +[1, 6, 5, 6, 3, 5, 4, 4, 7, 6, 6, 6, 6, 5, 5, 3, 5, 2, 5, 4, 4, 6, 5, 5, 5]] -let moonData: [[Int8]] = [[0,6,6,6,6,6,5,6,3,5,4,4,5,4,6,6,6,6,6,2,6,1,6,5,6,7], -[1,7,7,7,6,4,8,4,8,5,7,5,4,5,4,6,6,6,4,5,0,3,2,5,6,6], -[0,6,6,4,4,5,4,7,5,8,7,6,7,5,5,6,4,5,4,4,4,4,3,4,4,5], -[1,6,3,7,3,6,6,5,6,7,7,7,7,5,7,2,5,2,4,5,4,5,6,6,5], -[1,5,3,7,4,8,7,7,7,6,6,7,6,6,7,4,6,2,4,3,4,6,6,6,6,4], -[0,3,4,2,6,5,6,7,6,6,5,3,5,5,6,6,4,5,5,4,5,6,5,7,3,6], -[1,3,4,5,4,4,5,4,4,5,3,6,2,5,4,6,6,7,7,8,8,6,6,2,6,3], -[0,6,5,5,5,4,2,4,4,3,7,3,7,4,5,5,6,8,9,8,9,7,4,5,2], -[0,5,5,5,7,5,3,4,1,3,3,2,5,4,5,5,5,6,6,5,8,5,7,6,5,6], -[1,5,6,6,6,6,6,3,6,3,4,3,3,5,5,6,5,6,3,6,1,6,3,6,6,7], -[0,7,6,5,5,5,4,8,3,8,5,5,6,5,6,7,7,7,6,3,4,1,4,4,6], -[0,7,7,5,5,4,3,6,4,8,6,7,6,5,5,6,4,6,4,4,4,3,4,4,5,6], -[1,6,6,8,5,7,5,6,7,6,6,7,6,6,7,3,5,1,4,2,3,5,6,6,5,5], -[0,4,6,4,8,6,8,7,6,6,6,6,6,7,5,7,3,5,2,4,4,5,6,7,5,4], -[1,4,3,5,4,7,8,7,7,5,4,6,4,5,6,5,6,5,5,6,5,5,6,3,6], -[1,3,5,4,4,4,5,5,6,6,6,8,4,7,3,6,6,6,7,8,8,7,7,3,5,1], -[0,5,4,5,5,4,3,4,3,4,5,3,7,3,6,4,4,6,6,8,9,8,7,6,2,6], -[1,4,6,7,6,6,4,1,3,2,2,4,3,5,4,5,5,5,5,7,5,8,5,5,5,4], -[0,5,6,5,5,5,3,6,2,4,3,3,5,5,5,6,6,5,7,3,6,1,6,5,6], -[0,7,6,6,5,4,3,6,3,7,4,6,5,4,5,6,6,7,6,5,5,1,4,2,4,6], -[1,7,7,6,4,4,4,3,7,5,7,6,5,5,5,4,5,3,5,4,3,4,3,4,5,5], -[0,5,6,3,7,4,5,5,5,6,6,5,6,6,4,6,1,5,2,4,4,5,6,6,5,5], -[1,5,3,6,3,8,6,6,5,5,5,6,5,5,7,3,6,1,3,3,4,6,6,6,6], -[1,4,3,4,3,6,6,8,8,6,6,6,4,6,5,5,6,4,5,5,4,5,5,5,6,3], -[0,6,4,4,5,5,5,6,5,6,6,4,6,3,6,4,5,6,7,7,8,7,6,6,2,7], -[1,3,7,6,6,5,5,3,4,3,3,6,3,6,3,4,5,5,6,8,8,7,7,4,6,2], -[0,6,6,6,7,5,4,4,1,3,3,3,6,4,5,5,5,6,7,5,8,4,6,4,4], -[0,5,5,5,6,6,5,6,2,6,3,5,4,4,5,6,6,6,7,4,7,1,6,3,6,6], -[1,6,6,6,5,4,5,3,8,4,8,5,5,5,4,5,6,6,5,5,2,4,0,3,4,6], -[0,6,6,4,4,3,3,5,3,7,6,6,6,5,5,6,4,6,5,5,5,3,4,4,4,6], -[1,6,4,6,3,5,3,4,5,5,5,7,6,6,7,4,6,2,4,2,5,5,5,6,5], -[1,5,3,6,3,8,5,7,7,6,6,6,6,6,7,5,7,2,4,2,3,4,4,6,6,4], -[0,4,3,2,5,3,6,7,6,6,6,4,5,4,5,6,4,6,4,5,5,5,5,6,4,6], -[1,4,5,4,4,5,4,5,5,4,4,6,2,5,2,4,5,5,7,8,7,7,7,3,7], -[1,2,6,4,5,6,4,3,3,2,3,5,2,6,2,4,4,5,6,7,8,9,8,6,6,2], -[0,6,4,6,7,5,5,4,2,3,2,3,4,3,5,3,3,5,4,4,7,4,7,5,5,6], -[1,6,6,7,6,7,6,4,6,2,5,3,3,4,4,5,6,5,4,6,1,6,1,5,5,6], -[0,7,6,5,5,5,3,7,4,7,4,6,5,4,4,5,6,6,6,4,4,1,4,3,4], -[0,6,6,6,5,4,4,4,4,7,5,8,6,5,6,4,4,6,4,6,4,3,4,3,4,5], -[1,5,5,6,4,6,4,6,6,6,7,7,7,7,7,5,6,2,5,1,3,4,4,5,4,4], -[0,4,4,2,6,4,8,6,7,7,6,6,7,7,6,7,3,5,1,3,3,4,5,6,6,5], -[1,3,3,3,2,6,5,6,6,5,5,5,4,6,5,5,6,4,5,4,4,5,5,4,6], -[1,3,5,2,3,4,4,4,4,4,5,6,4,6,2,6,4,6,7,7,7,8,7,5,6,1], -[0,6,3,6,5,5,4,3,2,3,3,3,6,3,6,2,4,4,6,7,9,7,8,6,3,6], -[1,2,6,6,7,7,5,4,3,1,2,3,3,5,3,4,4,4,5,6,5,7,4,7,5,5], -[0,6,5,5,6,5,4,6,2,5,2,4,3,3,4,5,6,7,7,4,7,2,6,4,6], -[0,7,7,6,5,4,3,5,2,7,2,6,4,4,5,4,5,6,6,6,5,2,4,1,5,5], -[1,6,7,6,5,5,3,3,6,4,8,6,6,6,4,5,5,3,6,4,4,4,3,4,3,4], -[0,6,5,5,7,4,6,5,5,6,6,6,6,6,6,6,3,5,0,4,2,4,4,4,5,5], -[1,4,3,5,3,8,5,7,6,6,6,5,5,6,6,4,6,1,4,1,3,4,4,5,6], -[1,4,4,3,2,5,4,7,6,6,6,6,5,6,4,7,5,5,6,4,5,4,4,4,6,3], -[0,5,2,4,3,4,4,5,4,6,5,4,6,3,6,2,5,5,5,7,7,7,6,6,2,6], -[1,2,6,4,6,5,5,3,3,3,3,5,3,6,2,4,2,3,5,6,7,8,7,5,5,3], -[0,6,4,6,7,5,5,4,1,3,2,3,4,3,5,4,4,5,5,5,7,5,7,5,5], -[0,5,5,5,5,5,5,5,2,5,1,5,2,3,4,4,5,6,5,5,6,2,5,1,6,4], -[1,6,7,6,4,4,4,3,6,3,8,3,6,5,4,5,5,6,7,5,4,5,1,4,2,5], -[0,6,5,6,6,3,4,4,4,6,5,7,6,5,5,4,4,6,3,6,4,4,5,4,4], -[0,6,4,6,6,3,7,3,5,5,5,6,6,5,6,6,4,6,1,4,1,3,4,4,6,5], -[1,4,4,4,2,6,4,8,5,6,6,5,5,6,6,7,7,3,5,1,4,3,4,6,5,5], -[0,5,3,2,4,2,5,5,6,6,6,5,6,4,6,5,6,6,5,5,5,4,5,5,5,6], -[1,4,6,4,4,5,4,4,5,4,5,6,3,7,2,5,3,5,5,6,6,7,6,4,6], -[1,2,7,4,7,6,6,4,3,2,3,3,3,6,2,5,2,4,5,5,6,7,7,8,6,4], -[0,5,2,7,6,6,6,5,3,4,1,3,3,3,5,3,4,4,4,5,6,5,7,3,5,5], -[1,4,6,5,6,7,6,5,7,3,7,3,5,3,4,5,6,6,6,6,4,5,0,5,2,6], -[0,5,6,5,4,4,3,4,3,8,3,6,4,4,5,4,5,6,6,6,5,2,4,1,4], -[0,5,5,7,6,4,4,3,3,5,3,7,4,5,5,4,4,5,3,6,4,4,3,3,4,4], -[1,4,5,5,4,6,2,6,3,4,5,5,6,6,6,6,7,4,6,1,5,2,3,4,4,4], -[0,4,3,2,4,2,7,4,7,5,5,5,5,6,6,6,6,7,2,5,1,3,5,5,5,5], -[1,3,3,3,2,5,4,7,6,6,6,5,3,6,3,5,5,4,5,4,4,5,5,4,6], -[1,4,6,3,4,3,3,4,4,4,5,4,4,6,1,5,1,4,5,6,7,7,7,7,6,3], -[0,6,2,7,5,6,5,4,2,3,3,3,4,2,5,1,3,2,3,5,6,7,8,6,5,6], -[1,3,7,5,8,8,6,6,5,3,4,3,3,5,3,4,3,3,4,4,4,6,4,6,4], -[1,6,5,5,6,6,6,6,6,3,6,2,5,2,4,5,4,5,5,6,5,5,1,6,1,6], -[0,5,6,7,6,4,4,4,3,7,3,7,4,5,4,3,4,5,5,7,5,4,4,0,4,3], -[1,5,6,5,5,5,3,4,4,4,7,6,8,6,5,6,6,5,6,4,6,4,3,4,3,4], -[0,4,3,4,5,2,6,3,6,5,6,7,6,7,7,6,5,7,1,5,1,4,4,4,5], -[0,5,4,3,3,2,6,3,8,5,7,6,6,6,6,7,6,7,4,5,0,4,3,4,6,5], -[1,4,4,2,2,3,2,5,4,6,5,5,5,5,3,6,5,6,6,5,6,4,4,5,5,4], -[0,6,3,5,2,3,3,3,4,4,4,4,5,2,6,2,5,3,5,6,7,8,7,6,5,6], -[1,2,7,3,7,5,5,4,4,3,3,3,3,5,2,5,1,4,4,4,6,7,7,7,5], -[1,3,5,3,7,6,7,7,5,3,3,2,3,2,3,4,2,3,3,4,5,6,5,7,4,6], -[0,5,5,6,5,6,5,4,4,5,2,5,0,3,2,3,4,4,5,5,5,3,5,1,6,3], -[1,7,6,6,5,5,3,3,5,3,7,1,7,4,4,5,4,5,6,6,6,5,2,4,1,5], -[0,6,6,7,5,3,5,2,4,5,4,8,5,5,5,4,4,5,3,6,3,4,3,3,4], -[0,5,5,5,5,5,7,4,7,4,6,6,6,6,7,6,5,6,2,5,-1,4,2,4,4,5], -[1,4,4,4,3,5,3,7,5,8,6,5,6,5,6,7,7,6,7,2,4,2,3,4,4,5], -[0,5,3,3,2,2,5,3,6,6,6,6,5,4,6,4,6,5,6,6,5,5,5,5,4,5], -[1,2,6,2,5,4,5,5,4,5,5,6,5,7,3,6,2,5,4,5,6,7,6,6,5], -[1,2,6,1,7,4,6,5,4,4,4,3,4,5,3,5,1,4,2,3,5,6,7,7,6,5], -[0,5,3,6,5,7,7,6,4,3,1,3,1,3,4,3,5,4,4,4,4,4,6,4,7,4], -[1,5,5,5,5,5,4,5,5,3,6,2,6,2,4,4,5,6,6,6,6,5,2,6,2], -[1,6,5,6,6,6,3,3,4,2,6,3,7,3,5,4,4,5,6,6,7,5,4,4,1,4], -[0,4,5,7,6,5,5,2,3,3,4,7,5,6,5,4,5,4,4,6,3,6,3,3,5,4], -[1,4,5,4,5,5,2,6,3,6,5,5,5,6,6,7,6,5,6,2,5,2,4,5,5,5], -[0,4,4,3,3,2,6,3,7,5,6,5,5,5,6,6,7,7,5,5,1,3,3,4,6], -[0,6,4,5,2,3,4,3,6,5,7,6,5,5,5,4,7,4,6,5,4,5,3,4,5,4], -[1,4,5,3,6,3,5,4,5,4,5,5,5,5,3,6,1,5,2,5,5,6,6,7,6,4], -[0,6,3,7,4,8,6,6,4,4,2,4,4,3,5,1,4,1,3,4,5,6,7,6,6,5], -[1,3,5,3,7,6,7,6,5,3,4,2,4,4,4,5,3,4,3,4,4,5,4,6,3], -[1,6,4,5,6,4,5,6,5,5,6,3,6,2,4,4,3,5,5,5,5,5,3,6,1,6], -[0,4,6,6,6,5,4,3,4,5,3,7,3,6,3,3,4,3,5,6,5,5,5,1,4,2], -[1,5,6,6,6,5,3,4,2,4,5,3,7,5,5,6,4,5,5,4,6,3,5,4,3,5], -[0,4,4,5,5,4,6,2,6,3,5,6,5,6,7,6,6,6,3,6,1,4,3,4,5], -[0,5,5,3,3,2,5,3,8,5,8,6,6,6,5,6,7,7,6,6,2,4,1,4,5,4], -[1,5,4,3,3,2,1,5,3,6,6,6,6,5,4,6,4,6,5,5,5,4,5,5,5,5], -[0,6,3,6,3,4,4,4,4,4,4,4,5,4,5,2,5,1,5,4,6,7,7,7,7,6], -[1,3,7,2,8,4,6,5,5,4,4,3,4,5,3,6,2,4,2,4,5,6,7,7,6], -[1,4,5,3,6,5,8,7,6,5,4,3,4,3,4,5,4,4,3,3,4,5,4,6,3,7], -[0,4,6,7,6,6,7,5,6,6,3,7,1,5,2,4,3,4,5,5,5,5,4,2,5,1], -[1,7,5,7,7,6,4,4,4,3,6,3,7,2,5,4,4,6,5,6,7,6,4,4,1], -[1,5,3,6,6,6,5,4,2,3,3,4,7,4,6,6,5,6,5,4,6,4,6,3,4,4], -[0,4,4,5,4,5,5,3,7,4,7,6,6,7,7,7,8,6,5,6,1,5,1,5,4,4], -[1,5,4,3,3,2,1,6,2,7,5,7,5,5,6,6,6,7,7,5,6,1,4,3,5,6], -[0,5,4,4,1,2,2,1,5,4,6,5,4,4,5,4,7,4,6,6,5,5,5,4,5], -[0,5,4,6,2,6,2,4,3,3,4,4,4,4,5,3,6,2,5,3,6,6,6,6,7,5], -[1,4,5,2,6,3,7,6,6,4,3,3,3,4,3,5,1,4,1,4,4,5,6,7,6,6], -[0,5,4,6,4,7,7,7,7,5,3,4,1,3,3,3,4,2,3,3,3,4,5,4,7,3], -[1,6,5,5,6,6,5,6,5,4,5,2,6,2,4,3,3,5,5,6,6,6,3,6,1], -[1,7,4,7,7,6,6,5,3,3,5,3,7,2,6,2,4,4,4,5,6,5,5,4,2,5], -[0,2,6,7,7,7,6,4,5,3,4,6,5,7,5,6,5,4,5,5,3,5,2,4,3,3], -[1,4,5,4,6,5,4,6,3,7,4,6,5,5,7,7,7,6,6,3,6,0,4,3,5,5], -[0,5,4,4,2,2,4,3,8,4,7,6,6,6,6,6,8,7,7,6,3,5,1,4,5], -[0,5,5,4,3,3,2,2,5,4,7,6,6,6,6,5,7,5,7,6,6,6,4,5,5,4], -[1,5,4,3,5,1,5,3,5,5,4,5,6,6,5,6,2,6,2,6,4,6,6,6,6,5], -[0,5,3,6,2,7,5,7,5,5,4,4,4,4,5,3,5,1,3,1,3,5,6,6,7,5], -[1,5,5,3,7,5,7,6,5,5,4,2,4,3,4,4,4,5,4,5,5,4,4,6,3], -[1,7,4,5,5,5,5,5,5,5,5,3,6,2,5,2,4,5,5,6,6,6,5,6,2,6], -[0,2,7,6,7,6,6,4,4,4,4,6,3,7,3,4,4,3,6,5,6,7,5,3,5,1], -[1,5,5,7,7,6,5,5,2,4,3,4,7,4,6,5,4,5,5,4,6,3,6,4,4], -[1,6,5,5,6,4,4,5,3,6,2,6,5,4,6,6,6,7,6,5,6,2,5,2,5,5], -[0,6,5,5,3,3,2,2,6,3,8,5,6,5,5,6,7,7,8,7,5,5,1,4,3,5], -[1,6,5,4,4,2,2,3,3,6,5,7,6,5,5,6,4,7,4,6,5,5,6,4,5,6], -[0,6,5,6,3,7,3,6,5,5,5,5,5,5,5,3,6,1,5,1,5,5,6,6,6], -[0,5,4,5,2,8,4,8,6,6,5,4,3,4,5,5,6,3,5,1,3,3,5,6,6,5], -[1,5,4,3,5,3,8,6,7,7,6,4,5,3,4,4,4,4,4,5,4,5,4,5,3,7], -[0,3,6,4,5,6,6,6,7,6,6,7,4,6,2,5,3,4,6,5,6,6,5,3,5,1], -[1,6,4,7,6,7,5,5,3,4,5,4,8,2,6,3,3,5,5,6,7,5,6,5,2], -[1,5,2,6,6,6,6,5,3,4,2,4,5,4,7,5,6,5,5,5,6,4,6,3,4,4], -[0,3,5,4,4,5,5,4,6,3,7,3,6,6,6,7,8,8,7,7,4,6,1,5,2,5], -[1,6,4,3,4,2,2,4,2,7,4,7,5,6,6,6,7,8,7,7,7,3,5,3,5,6], -[0,5,6,4,3,3,2,2,5,4,6,5,5,5,5,4,6,4,7,5,6,6,5,6,6], -[0,6,5,6,3,5,2,5,3,4,4,4,5,5,5,4,6,2,6,1,6,4,7,8,7,6], -[1,6,5,4,6,3,8,5,7,6,5,4,4,3,5,5,3,5,1,3,2,4,5,6,7,7], -[0,5,6,6,4,7,6,9,8,6,6,5,4,5,3,5,4,3,4,3,4,3,4,4,6,3], -[1,7,5,7,6,6,7,6,6,6,6,4,6,2,6,2,4,4,5,6,6,6,5,5,2], -[1,7,3,8,6,8,7,6,5,4,5,4,6,3,6,2,4,3,4,6,5,6,6,5,3,4], -[0,1,5,5,6,7,6,6,5,3,5,5,5,7,5,7,5,4,5,5,4,6,3,5,4,4], -[1,4,4,4,5,4,4,5,3,7,4,7,5,6,6,7,7,7,6,5,6,1,5,1,5], -[1,5,5,5,5,2,3,2,2,6,3,7,4,6,5,5,6,7,7,8,6,4,5,2,5,4], -[0,6,6,5,3,4,0,2,3,2,6,4,6,5,5,5,6,5,7,5,7,6,5,6,5,6], -[1,6,5,5,6,2,6,2,5,4,4,5,5,5,6,6,3,6,1,6,3,6,6,7,7,7], -[0,5,4,6,2,8,4,8,6,6,5,5,4,4,4,5,5,2,5,1,3,3,5,6,6], -[0,6,6,4,4,6,4,8,6,7,7,5,4,4,2,4,4,4,5,4,5,5,5,6,6,4], -[1,7,4,7,6,6,7,6,6,6,5,5,6,2,6,1,4,3,4,5,6,6,6,6,4,5], -[0,2,7,5,8,8,7,6,5,4,5,6,5,7,3,6,3,4,4,5,6,7,5,5,4,2], -[1,5,4,7,7,7,7,6,4,5,4,5,6,5,7,6,5,6,4,4,5,3,6,2,5], -[1,4,4,5,5,5,6,5,5,6,4,7,4,6,5,6,6,7,7,7,7,3,6,1,5,3], -[0,6,5,5,4,3,2,3,5,2,8,4,7,6,6,6,7,7,9,9,7,7,3,6,3,5], -[1,6,6,6,4,2,2,2,2,5,4,7,5,6,6,5,6,7,5,8,5,7,6,6,6,6], -[0,6,6,6,3,6,2,6,4,5,5,5,6,6,5,5,6,2,6,1,6,4,6,7,7], -[0,6,5,5,3,6,3,8,5,7,6,5,5,4,4,5,6,4,5,2,5,2,4,6,6,7], -[1,7,5,5,5,4,7,5,7,6,5,5,5,3,4,3,5,4,4,5,4,4,4,5,5,6], -[0,4,7,4,6,6,6,7,6,6,6,6,4,6,2,6,2,5,5,5,6,6,6,4,5,1], -[1,6,3,7,6,8,7,6,5,5,5,4,6,3,7,3,4,3,4,5,6,6,6,5,4], -[1,5,2,7,5,7,8,7,5,6,3,5,4,4,6,5,6,5,4,5,4,4,6,3,6,4], -[0,4,5,5,5,6,5,4,6,3,7,3,7,4,6,7,7,7,8,7,6,6,2,6,3,6], -[1,6,6,5,4,2,3,3,2,6,3,7,5,6,5,5,7,8,7,8,7,5,6,3,6,5], -[0,7,7,6,5,5,2,3,4,3,7,6,6,6,5,5,6,5,7,4,6,5,5,6,5], -[0,6,7,5,5,6,4,7,3,6,5,5,6,5,5,5,6,4,6,2,5,3,6,6,7,7], -[1,7,5,4,6,3,8,5,8,6,7,5,5,5,5,5,5,6,3,5,1,4,4,5,7,6], -[0,5,5,3,4,6,5,8,7,8,7,6,6,5,4,5,5,6,5,4,5,4,4,4,5], -[0,4,6,3,6,4,5,6,6,6,7,7,6,7,3,6,2,5,3,4,5,5,6,6,5,4], -[1,6,2,7,5,8,7,7,6,5,4,5,6,4,7,2,6,2,4,4,4,6,6,5,5,4], -[0,3,5,3,7,6,7,7,5,3,4,3,5,5,5,7,6,6,6,5,6,6,4,7,3,5], -[1,4,4,5,5,4,4,4,3,6,2,7,3,6,6,7,7,8,8,7,7,4,7,2,7], -[1,4,7,7,6,4,4,2,2,4,2,7,4,6,5,5,6,6,7,9,7,7,6,3,6,4], -[0,7,7,6,6,5,2,3,2,3,4,4,6,4,5,5,5,5,6,4,8,5,6,7,6,7], -[1,7,6,6,6,4,6,3,5,3,5,5,4,5,5,5,4,5,2,6,2,5,5,7,7,7], -[0,6,6,5,3,7,3,9,6,7,7,5,5,5,5,6,6,4,5,2,4,2,4,5,6], -[0,6,7,5,5,5,5,8,6,9,7,7,7,5,4,5,3,6,4,4,5,4,4,4,4,4], -[1,6,5,8,4,8,7,7,7,7,7,7,7,4,6,2,6,2,4,4,5,6,5,5,5,4], -[0,2,6,3,8,7,9,7,6,5,5,6,6,7,5,7,3,5,4,4,6,6,6,6,4,3], -[1,4,2,6,6,7,8,7,6,6,3,6,5,6,8,6,7,6,5,6,6,5,6,3,6], -[1,4,4,5,5,5,6,5,6,6,4,7,4,7,5,6,7,7,7,8,7,6,6,1,6,3], -[0,6,6,6,6,4,3,2,3,3,6,3,7,4,6,5,6,7,8,8,9,7,5,6,3,6], -[1,6,7,8,6,4,3,0,2,2,2,5,4,6,5,5,6,5,5,8,5,8,6,6,6,6], -[0,6,6,5,5,6,3,6,3,6,5,5,6,5,6,6,6,5,6,2,6,3,6,6,6], -[0,7,6,5,4,5,2,8,4,8,6,6,6,4,5,6,5,5,6,3,5,2,4,5,6,8], -[1,7,6,6,4,4,6,5,8,6,7,7,5,5,5,3,5,3,5,4,4,5,5,4,6,6], -[0,5,7,4,7,5,6,7,6,7,6,6,5,6,3,6,2,5,4,5,6,6,7,6,5], -[0,4,5,3,8,6,8,7,7,6,5,5,5,7,5,7,3,6,3,3,4,5,6,6,6,6], -[1,4,3,6,5,9,8,8,8,6,5,6,4,6,6,6,7,6,6,5,4,5,6,3,5,3], -[0,5,5,5,6,6,5,6,6,4,6,3,7,3,6,6,7,7,8,8,8,7,4,7,2,7], -[1,5,7,7,5,4,4,2,3,4,3,7,3,6,4,5,6,6,7,9,8,7,6,3,6], -[1,4,6,7,6,6,5,2,3,2,3,6,5,7,6,5,6,5,5,7,5,7,5,6,6,5], -[0,6,6,5,6,6,3,6,3,6,4,6,5,5,6,6,6,5,6,3,6,2,5,5,7,7], -[1,7,6,5,5,4,6,4,8,5,7,6,4,5,4,5,6,6,5,5,2,5,2,5,6,6], -[0,7,6,4,4,4,4,7,6,8,7,6,6,5,4,6,4,6,5,5,6,4,5,5,5], -[0,5,5,4,7,4,7,6,6,7,7,7,7,7,5,7,3,5,3,5,5,6,7,7,5,5], -[1,5,3,6,4,8,7,9,8,6,5,6,6,6,7,4,6,3,4,3,4,6,6,6,6,4], -[0,3,4,4,6,6,8,8,6,5,5,3,5,4,5,6,5,6,6,6,7,5,5,6,4,6], -[1,5,5,6,5,5,6,4,5,5,3,6,3,6,4,6,7,7,7,9,7,6,6,2,7], -[1,3,7,7,7,7,5,3,3,3,3,7,4,7,4,6,5,6,7,8,7,8,7,5,7,3], -[0,7,6,7,7,6,5,4,2,4,4,4,6,5,6,6,4,5,6,5,7,4,7,5,6,7], -[1,7,7,8,6,6,7,4,7,3,6,5,5,5,5,5,6,6,3,6,1,6,2,6,7], -[1,7,6,6,5,4,5,3,8,5,9,6,6,7,5,6,6,6,7,6,4,6,2,4,5,6], -[0,7,6,4,4,2,4,5,5,8,7,7,8,6,5,6,4,6,4,6,5,5,5,4,5,6], -[1,6,4,6,3,7,6,7,7,6,8,7,6,6,7,4,6,1,5,3,5,6,5,6,5,5], -[0,3,5,3,8,6,9,7,7,7,6,4,5,6,6,7,4,5,3,5,5,5,7,6,5], -[0,5,4,3,5,4,7,7,6,7,5,4,5,4,6,6,6,7,6,6,7,5,6,5,4,6], -[1,3,5,5,5,6,5,5,6,5,4,6,3,6,3,6,6,7,8,9,8,8,7,4,6,2], -[0,7,5,7,7,6,4,4,2,3,5,3,7,3,6,5,4,6,6,7,9,7,7,7,4,7], -[1,5,8,9,7,6,5,2,3,1,3,4,4,5,4,4,6,5,4,6,4,7,5,7,7], -[1,6,7,7,6,6,5,4,6,3,7,4,5,6,6,6,6,6,6,6,3,6,2,6,6,7], -[0,8,7,6,5,4,3,6,4,9,5,8,7,5,6,5,6,7,6,5,6,2,4,3,5,7], -[1,7,7,7,4,5,5,5,8,7,9,8,7,7,5,5,6,4,6,4,5,5,4,5,5,5], -[0,5,6,4,8,5,7,6,7,8,7,7,8,6,5,6,2,6,3,5,5,5,7,6,6], -[0,5,4,2,7,4,9,7,8,8,7,6,6,6,6,7,5,7,3,5,4,4,6,5,6,6], -[1,4,3,4,3,7,6,7,8,6,6,6,4,7,5,7,7,6,7,7,5,6,5,5,5,3], -[0,6,3,5,4,4,5,6,4,6,5,4,7,3,7,5,7,7,7,8,8,7,6,6,3], -[0,7,4,8,7,7,6,4,2,2,2,3,6,3,6,4,5,5,5,7,8,7,8,7,5,6], -[1,4,7,6,7,7,5,4,3,0,3,2,3,6,5,5,6,5,6,6,5,8,5,7,6,6], -[0,7,6,6,6,5,5,5,2,6,3,5,4,5,6,6,6,7,6,5,6,2,6,3,7,8], -[1,7,7,6,4,4,5,3,8,4,9,5,6,5,4,6,5,5,5,6,3,5,2,5,6], -[1,7,8,6,5,5,3,4,6,5,8,7,7,7,5,5,5,4,6,4,5,5,4,6,5,5], -[0,7,6,5,7,4,7,4,7,6,7,7,7,6,5,6,3,6,2,5,3,5,7,5,6,5], -[1,4,4,5,3,8,6,10,8,8,7,6,6,6,6,6,7,3,5,3,4,4,4,6,5,4], -[0,4,4,3,6,4,8,8,7,8,6,5,6,4,6,6,6,6,6,6,6,5,6,6,4], -[0,6,3,6,5,6,6,6,5,7,5,5,7,3,6,3,6,5,7,7,7,8,7,6,4,6], -[1,2,6,6,8,7,6,5,4,2,3,5,3,7,3,6,4,5,6,7,8,9,7,6,6,4], -[0,6,4,7,7,6,6,4,2,4,2,4,5,5,6,5,6,7,5,5,7,5,8,4,6,7], -[1,6,7,6,6,6,6,4,7,3,6,4,5,6,5,6,6,6,6,6,3,5,2,6,5], -[1,7,7,7,5,5,4,3,6,3,8,4,6,7,5,6,6,6,7,6,6,5,3,5,4,6], -[0,7,6,7,5,3,3,3,4,6,5,8,7,6,6,5,5,5,3,6,5,6,6,5,5,5], -[1,4,6,6,4,7,4,7,6,7,7,7,7,7,6,5,6,3,5,2,5,5,6,7,6,4], -[0,4,4,3,6,3,9,7,8,7,7,6,6,5,6,7,5,6,3,4,4,4,7,6,6], -[0,5,4,4,4,4,7,6,8,8,6,6,6,3,6,4,5,6,5,6,6,5,6,5,5,6], -[1,4,6,4,5,5,5,5,6,4,5,5,4,7,3,7,5,6,7,7,8,8,7,6,6,3], -[0,7,4,8,7,7,6,5,3,4,3,3,6,3,7,3,5,5,5,7,7,7,8,6,5], -[0,6,4,8,7,8,9,6,5,5,2,4,3,4,6,4,5,5,4,5,5,4,6,3,6,5], -[1,5,7,6,6,7,6,6,6,3,7,3,5,4,5,5,6,6,7,6,5,6,2,6,3,7], -[0,7,7,7,5,4,4,4,3,7,4,8,5,6,6,4,6,6,6,7,6,4,5,2,5,6], -[1,6,7,6,4,4,2,4,5,6,9,7,8,7,6,6,5,4,5,3,6,5,4,5,4], -[1,4,6,4,5,6,3,6,4,7,7,7,7,8,6,7,7,3,6,1,4,3,5,6,6,6], -[0,5,4,3,4,2,8,6,9,7,6,7,6,5,6,6,5,6,3,6,2,4,5,5,6,5], -[1,4,4,2,2,4,4,7,7,6,7,5,5,6,4,7,6,7,7,7,7,7,5,6,5,3], -[0,6,3,5,4,5,5,5,5,6,5,5,6,3,6,3,6,6,7,8,8,8,7,6,4], -[0,6,3,7,6,7,7,5,5,4,3,3,4,4,6,2,5,3,5,6,6,8,8,7,7,6], -[1,4,7,6,8,9,6,7,4,3,4,2,3,4,4,6,5,4,6,4,6,6,5,8,5,7], -[0,7,7,7,7,5,6,5,3,6,2,6,3,5,5,5,6,7,6,6,5,2,6,3,6,6], -[1,7,8,7,6,5,5,4,7,4,9,5,8,6,5,6,5,6,7,5,5,5,2,5,4], -[1,6,7,6,6,6,4,5,4,4,7,7,8,8,6,6,5,4,5,4,6,4,4,5,4,5], -[0,6,5,6,6,4,7,4,7,6,7,8,6,7,7,6,5,6,2,5,2,4,5,5,6,5], -[1,4,3,3,2,5,3,8,7,9,8,6,6,6,6,7,7,6,6,3,5,4,5,6,5,5], -[0,4,2,2,3,2,6,5,7,8,6,6,5,4,6,5,7,7,6,7,6,5,6,5,5], -[0,5,3,6,4,5,5,5,5,5,4,5,5,3,6,2,5,4,5,6,7,8,8,6,5,6], -[1,2,6,4,8,7,7,6,4,2,3,3,3,5,3,5,3,4,5,5,7,7,8,8,6,5], -[0,6,4,7,7,7,8,5,3,3,1,3,3,3,5,4,5,5,5,6,5,5,7,4,6], -[0,6,6,7,6,7,6,5,5,5,3,6,3,6,5,5,6,6,6,7,5,5,5,2,6,3], -[1,7,8,7,7,5,3,3,5,3,8,4,7,4,5,5,4,5,6,6,6,5,4,5,3,6], -[0,7,7,8,6,5,5,2,4,5,5,8,6,7,6,4,5,4,3,5,3,5,4,5,5,5], -[1,5,6,5,5,6,4,7,5,7,7,7,8,8,7,7,7,4,6,1,5,3,4,6,5], -[1,5,4,3,3,4,2,7,5,9,8,7,8,6,7,7,7,7,7,4,5,2,4,5,4,6], -[0,5,4,4,3,3,6,5,8,8,8,7,5,6,5,4,6,6,6,7,6,6,5,5,5,5], -[1,4,5,3,5,5,5,6,5,5,6,4,5,6,3,6,3,5,5,7,8,8,8,7,6,4], -[0,6,2,8,5,8,6,5,4,4,3,4,4,3,6,3,5,4,5,6,6,7,8,7,6], -[0,5,4,7,5,7,8,7,7,4,3,4,3,4,5,5,5,5,5,5,5,5,5,4,7,4], -[1,6,6,6,7,6,6,6,5,4,6,2,6,3,4,5,5,6,6,6,6,5,2,5,2,7], -[0,6,7,8,7,5,4,3,3,5,3,7,3,5,5,4,5,4,6,6,5,4,4,2,5,4], -[1,6,7,6,6,5,3,4,3,4,7,6,8,7,6,6,4,5,6,4,6,5,5,5,4], -[1,5,5,4,5,4,3,6,3,6,5,6,7,7,7,7,6,5,6,2,5,2,5,5,6,6], -[0,5,4,4,3,2,6,4,9,7,9,7,6,6,6,6,6,6,4,6,2,4,4,5,6,5], -[1,5,4,3,3,3,3,6,5,7,7,6,6,4,4,6,4,6,5,6,8,6,6,6,5,5], -[0,6,3,6,4,5,5,5,5,5,5,4,4,3,5,2,5,3,6,6,7,7,7,6,6], -[0,5,3,7,5,8,8,8,6,5,3,3,4,4,5,3,5,2,4,4,4,6,6,6,6,5], -[1,4,6,4,7,8,8,9,6,5,4,3,4,3,4,5,4,4,5,4,5,4,4,6,3,6], -[0,5,6,7,7,6,7,5,5,5,3,6,2,4,3,4,5,5,5,6,5,4,5,1,5,3], -[1,7,7,6,6,5,3,3,4,3,7,4,8,5,6,6,5,6,7,6,6,5,3,4,2], -[1,5,6,6,7,5,3,4,2,4,5,5,8,7,7,7,5,6,5,4,5,4,5,4,5,5], -[0,5,5,6,4,5,5,2,7,4,6,6,6,7,7,6,7,5,4,5,1,5,3,5,6,5], -[1,5,4,2,2,3,2,6,4,8,6,6,7,5,6,7,7,7,7,4,6,3,4,5,5], -[1,7,5,3,2,2,2,4,4,6,6,6,7,5,5,5,3,7,6,6,7,7,7,6,5,5], -[0,5,4,5,2,5,4,5,6,6,5,6,5,5,5,3,6,2,5,5,6,8,7,7,6,5], -[1,3,5,2,8,6,7,7,5,5,4,2,4,3,2,5,2,4,3,4,6,6,8,7,6,6], -[0,6,4,7,6,8,8,6,6,4,2,3,1,3,4,3,5,4,3,4,4,5,5,3,6], -[0,5,6,7,6,7,7,5,6,5,4,6,2,5,3,5,5,5,6,6,6,5,5,2,5,2], -[1,6,6,7,8,6,5,4,3,3,6,4,8,5,6,5,4,6,4,6,6,5,4,4,2,5], -[0,5,6,8,6,7,5,3,5,4,5,7,6,7,6,5,5,3,4,5,3,5,3,4,5,4], -[1,4,5,4,5,5,3,6,3,7,5,6,7,6,6,7,7,6,6,3,5,2,4,5,5], -[1,6,5,3,3,2,2,4,2,7,6,7,7,5,6,6,7,7,6,6,6,2,5,4,4,6], -[0,5,4,4,2,2,2,3,5,6,7,8,6,6,5,5,6,5,6,6,6,5,6,5,6,4], -[1,5,5,2,6,3,4,5,4,5,5,4,5,4,4,5,2,5,3,5,6,6,7,7,6,5], -[0,5,3,6,4,8,6,7,5,3,2,2,2,3,5,2,5,1,3,4,5,7,7,5,6], -[0,4,3,5,4,8,7,8,8,5,5,4,2,3,3,4,5,5,5,6,5,6,5,4,6,3], -[1,6,5,5,6,6,5,6,5,4,6,3,6,3,4,4,4,6,5,6,7,5,4,4,2,6], -[0,4,8,8,8,7,6,3,4,4,3,7,3,7,4,4,5,4,6,6,5,5,4,3,5,3], -[1,6,7,6,7,5,4,4,2,4,5,4,7,6,6,6,4,5,5,3,5,3,6,5,4], -[1,6,6,5,6,4,4,5,3,6,4,6,6,6,7,7,7,8,6,4,5,1,5,3,5,6], -[0,5,6,5,3,2,4,3,7,6,8,7,7,7,6,6,7,6,6,6,3,5,2,4,5,4], -[1,5,4,3,2,1,3,5,5,7,7,6,7,4,5,5,3,6,4,6,6,6,6,6,5], -[1,6,4,3,5,3,5,4,5,5,5,5,5,4,5,5,2,5,2,5,5,6,7,7,6,6], -[0,5,3,5,2,7,5,8,6,5,4,4,3,4,4,4,6,3,4,4,4,6,5,6,6,4], -[1,4,4,2,5,5,7,7,6,6,4,3,4,2,3,4,4,5,5,5,5,4,4,5,4,6], -[0,4,6,6,6,6,6,5,6,5,3,5,2,5,2,3,5,4,6,6,5,5,4,2,4], -[0,2,6,6,7,7,5,4,3,3,3,5,3,6,3,4,4,3,6,5,6,6,5,4,4,3], -[1,5,4,6,7,6,5,4,1,3,2,3,6,5,7,6,5,5,4,5,5,3,5,3,4,5], -[0,4,5,5,4,5,4,3,6,3,7,5,6,7,6,6,8,6,5,5,2,5,1,4,5,5], -[1,7,5,3,3,2,2,4,3,7,6,7,7,5,6,6,6,7,5,5,5,3,4,4,5], -[1,8,5,5,4,1,2,2,3,5,5,7,6,5,5,4,3,5,3,6,4,5,6,5,5,6], -[0,5,5,5,2,5,3,5,5,5,6,6,5,6,5,4,5,2,5,3,5,6,6,7,6,5], -[1,4,4,3,7,5,8,7,6,6,5,4,3,4,4,5,3,5,2,4,4,4,6,6,5,6], -[0,4,3,5,5,8,7,8,8,5,5,4,2,4,3,4,5,4,4,5,3,5,3,3,5], -[0,3,6,4,5,6,6,6,6,5,5,5,3,6,2,5,3,4,6,6,7,7,5,4,4,1], -[1,5,4,7,7,6,6,4,3,3,4,4,7,4,6,5,4,5,4,6,6,6,6,4,2,5], -[0,3,5,6,6,8,5,3,4,2,4,5,5,7,6,6,6,4,5,4,3,5,2,4,3], -[0,3,5,5,4,5,4,3,5,2,5,3,5,6,6,7,7,7,7,6,3,4,1,4,4,5], -[1,7,5,4,4,1,2,2,2,5,3,6,6,4,6,5,6,7,6,6,6,4,5,3,4,6], -[0,5,6,4,2,2,0,1,3,3,6,6,6,6,4,4,5,3,6,4,7,7,6,6,6,4], -[1,5,4,3,4,2,5,3,4,4,5,4,5,4,4,5,2,4,1,4,4,6,7,7,7], -[1,6,5,3,5,3,8,5,7,7,5,5,3,3,3,3,3,4,1,3,2,3,6,5,6,6], -[0,4,5,4,4,7,5,8,8,6,6,3,2,3,1,3,3,4,4,4,4,5,4,5,5,4], -[1,6,4,6,6,6,7,6,5,5,5,3,5,2,5,2,3,4,4,6,6,5,5,3,2,4], -[0,2,7,7,8,8,6,6,5,4,4,5,4,6,4,5,5,3,6,4,5,5,3,3,3], -[0,2,5,5,6,8,6,7,4,3,4,3,4,6,5,7,6,4,5,3,4,4,2,5,3,4], -[1,4,4,4,5,3,5,4,3,6,3,6,4,5,6,6,7,7,5,5,5,1,4,2,5,4], -[0,5,5,3,2,1,1,1,4,3,7,6,7,7,5,7,6,6,8,6,6,5,3,4,4,4], -[1,7,4,3,3,0,1,1,2,5,5,7,7,5,6,4,4,5,4,7,5,6,6,6,5], -[1,6,4,5,5,2,5,2,5,4,4,5,5,4,5,4,4,5,1,5,2,4,6,6,7,6], -[0,4,4,4,2,6,3,7,7,6,5,3,4,3,4,3,5,3,5,2,3,5,4,7,6,6], -[1,5,3,3,4,4,7,7,6,7,4,4,2,2,3,3,4,5,4,5,5,4,5,4,4,5], -[0,3,6,5,6,6,6,6,7,5,5,5,3,5,2,3,3,4,6,5,6,6,5,4,4], -[0,1,6,5,8,8,7,7,5,4,3,4,3,5,3,5,3,3,5,3,5,5,5,5,4,3], -[1,5,3,7,7,6,7,5,4,3,1,3,3,4,6,5,5,5,3,5,4,3,4,3,4,5], -[0,5,6,5,5,6,3,4,4,3,6,4,6,6,6,7,8,6,7,5,3,4,1,5,3], -[0,5,6,4,5,3,1,2,2,2,6,4,7,7,5,7,5,6,7,6,6,6,3,4,3,5], -[1,6,5,7,4,2,2,1,2,4,4,7,6,6,7,4,4,4,3,6,4,6,5,5,6,5], -[0,4,6,4,2,4,2,5,3,4,4,5,5,5,4,5,4,2,5,1,5,5,6,7,6,6], -[1,5,4,2,4,2,6,5,7,6,4,4,3,3,4,4,4,4,2,4,3,3,6,5,6], -[1,6,4,4,3,3,6,5,8,8,6,7,4,3,4,2,4,4,4,4,4,3,5,3,4,4], -[0,2,5,3,6,5,6,7,6,5,5,5,3,5,2,4,2,4,4,4,6,6,5,4,3,2], -[1,5,3,7,6,7,7,6,4,4,3,3,5,3,5,2,4,4,3,6,5,6,5,4,3,3], -[0,2,5,5,6,8,6,5,4,2,3,3,4,6,5,7,7,5,6,4,4,5,2,4,2], -[0,4,4,4,5,5,3,4,3,3,5,2,6,5,5,6,6,7,7,6,5,5,2,5,2,5], -[1,6,5,7,5,3,2,1,1,4,3,6,5,6,5,4,6,5,6,7,5,5,5,3,5,5], -[0,6,7,5,4,3,1,2,1,2,5,5,6,6,4,5,4,4,6,3,6,5,6,6,6,6], -[1,7,5,5,4,2,5,3,5,4,5,5,5,4,6,4,3,4,1,4,2,4,6,5,7], -[1,6,4,4,4,3,6,4,8,7,7,6,4,4,4,4,4,4,3,4,2,3,4,4,6,5], -[0,4,4,3,3,4,5,7,8,7,8,5,5,3,2,3,2,4,4,3,4,5,3,5,4,3], -[1,5,3,5,4,6,6,6,6,6,4,5,4,2,4,1,3,2,3,5,5,6,6,4,3,4], -[0,1,5,4,7,7,7,5,4,4,4,4,4,6,4,6,4,3,5,3,6,5,4,4,3], -[0,2,4,2,5,6,5,7,5,3,3,2,3,5,4,6,6,5,7,4,5,4,3,4,2,4], -[1,4,5,5,5,4,5,2,3,4,2,6,3,5,5,5,7,7,6,7,5,4,4,1,4,3], -[0,6,7,4,4,3,0,1,1,1,4,3,6,5,5,6,5,7,7,7,7,6,3,5,4], -[0,5,7,5,6,3,2,2,-1,1,2,3,5,5,4,6,3,5,4,4,5,4,6,6,6,6], -[1,6,5,6,4,4,5,2,5,3,5,5,5,5,6,4,4,4,0,4,1,4,4,5,8,7], -[0,7,5,3,3,5,3,7,5,7,7,5,5,3,3,4,3,4,3,2,3,3,3,6,5,6], -[1,6,4,4,4,3,6,6,8,8,5,6,3,3,2,2,3,3,4,4,4,4,5,4,5], -[1,3,3,5,3,6,6,6,7,7,6,6,5,5,5,2,5,2,3,5,5,6,5,4,4,3], -[0,2,4,2,7,7,8,8,6,6,5,4,4,6,4,6,3,4,4,3,6,4,5,5,3,2], -[1,3,2,5,5,7,8,6,7,5,3,4,3,4,5,6,6,6,5,6,4,4,3,2,4,2], -[0,3,5,4,5,5,3,4,4,2,5,2,6,5,6,7,7,7,8,7,7,5,2,4,2], -[0,5,6,5,6,3,1,1,0,1,4,2,6,4,6,6,4,7,6,7,7,5,5,5,3,5], -[1,5,6,8,4,4,2,0,2,1,2,5,5,5,6,4,6,4,4,5,3,5,4,5,6,5], -[0,5,6,3,4,3,1,5,2,4,3,4,5,4,4,5,4,4,4,2,4,2,5,6,6,8], -[1,6,4,3,3,1,5,3,7,5,5,5,3,4,3,4,4,4,2,4,2,3,5,4,7], -[1,5,5,4,3,2,4,4,7,7,7,8,5,5,3,2,4,2,4,4,4,5,5,4,5,3], -[0,3,5,2,5,4,6,7,6,6,6,5,5,5,2,4,1,3,3,4,5,5,6,5,4,3], -[1,4,3,6,5,8,9,7,6,5,4,4,4,4,5,3,5,3,2,4,3,5,5,4,4], -[1,3,2,4,4,6,7,6,8,5,4,4,2,4,4,4,6,6,5,6,3,6,4,3,4,2], -[0,5,4,4,5,6,4,5,3,3,4,2,5,3,5,5,5,7,7,7,7,5,3,4,1,4], -[1,4,5,7,5,5,4,2,2,3,3,5,4,6,6,5,6,5,6,6,5,5,4,3,5,3], -[0,5,7,5,6,4,2,2,1,3,3,4,6,5,4,6,3,5,5,4,5,4,6,6,6], -[0,6,6,5,6,3,3,5,2,5,3,4,5,5,5,5,4,5,3,3,4,1,4,5,6,7], -[1,6,5,5,2,2,3,2,6,6,7,7,5,6,4,5,5,4,4,4,2,4,3,3,6,4], -[0,6,5,3,2,2,3,5,6,7,8,6,7,4,4,3,3,4,3,4,5,4,5,5,4,5], -[1,4,3,5,3,6,5,6,6,7,5,6,5,4,5,2,4,2,3,4,4,6,5,5,4], -[1,3,1,4,3,6,7,8,7,6,5,4,3,4,5,4,6,4,4,5,4,6,5,6,5,3], -[0,3,3,2,5,5,6,7,6,5,3,3,4,3,4,5,6,6,7,5,7,4,5,5,3,5], -[1,3,5,5,5,5,6,4,5,3,3,5,3,6,4,5,6,6,7,8,6,6,5,2,5,3], -[0,5,7,6,7,4,2,2,1,1,4,2,6,3,4,5,4,7,5,7,7,6,5,6,4], -[0,6,7,7,8,5,4,2,0,2,1,2,5,4,5,6,3,5,3,4,5,3,5,4,6,6], -[1,6,6,7,4,5,4,3,5,3,5,4,5,6,5,6,6,4,4,4,1,4,2,4,6,5], -[0,7,6,4,4,3,3,6,4,8,7,6,7,4,5,4,4,5,4,3,4,2,3,4,4,7], -[1,5,5,4,2,3,4,5,7,7,7,8,4,5,3,2,4,2,3,3,4,4,5,4,5], -[1,3,4,4,3,5,4,6,6,7,6,6,5,6,5,4,4,2,4,3,4,6,5,6,5,3], -[0,3,2,2,5,5,7,7,6,6,4,4,4,4,5,6,4,5,4,3,5,3,6,4,4,4], -[1,3,2,4,3,6,7,6,8,4,4,4,3,5,5,6,7,6,5,6,4,6,3,3,4,2], -[0,5,4,4,5,5,3,5,3,3,4,2,5,2,4,5,5,7,8,7,8,6,5,5,2], -[0,5,5,6,8,5,4,2,0,1,2,1,4,3,4,5,4,6,5,7,6,6,7,5,4,5], -[1,5,5,8,5,7,4,2,2,0,2,4,4,5,6,5,7,4,6,5,4,6,4,6,6,6], -[0,6,6,5,6,3,4,5,2,5,4,5,5,4,5,6,5,5,4,3,4,2,5,5,6], -[0,8,7,6,5,4,3,4,3,7,6,7,7,5,6,3,4,4,4,4,4,2,3,3,4,7], -[1,5,7,5,3,3,3,4,5,5,8,8,6,7,3,4,3,2,4,4,5,4,5,5,6,3], -[0,5,4,3,5,3,6,5,6,6,7,6,6,5,5,5,3,4,2,4,5,5,7,5,5,4], -[1,3,2,4,3,7,8,8,9,6,6,5,5,5,6,5,5,3,4,4,3,6,3,5,4], -[1,3,2,2,2,5,6,7,9,6,7,4,3,4,3,5,5,5,6,7,5,7,4,5,4,2], -[0,4,3,4,5,4,5,5,3,5,3,3,4,2,5,3,5,6,6,7,8,7,6,5,2,5], -[1,3,6,7,6,6,4,2,2,0,2,4,3,6,4,5,6,5,7,6,7,7,5,4,5,3], -[0,5,6,6,8,5,4,3,0,2,1,3,5,5,6,6,3,6,4,4,5,4,6,5,5], -[0,7,6,6,7,5,5,4,2,5,3,5,4,3,5,5,5,5,4,4,4,2,4,3,5,7], -[1,6,7,6,3,3,2,2,5,3,7,5,5,6,3,5,4,5,5,5,4,4,2,3,6,5], -[0,7,5,4,4,2,2,4,4,7,6,7,8,4,5,3,3,4,3,5,4,4,5,6,4,7], -[1,3,4,5,4,6,5,6,7,7,7,7,5,6,5,3,4,2,3,3,3,6,5,6,5], -[1,3,3,3,2,5,6,8,9,7,8,5,5,5,5,5,5,4,5,3,3,5,3,6,5,4], -[0,4,3,3,4,5,7,8,7,9,4,4,4,3,4,4,5,6,6,5,7,4,6,4,4,4], -[1,3,5,4,5,6,6,4,6,4,5,4,4,6,4,6,6,6,8,8,7,7,5,4,4], -[1,2,5,5,6,8,6,5,3,2,3,2,3,5,4,5,5,4,7,5,7,6,6,6,4,3], -[0,5,4,6,9,6,7,4,3,2,1,2,3,3,5,5,4,6,3,5,4,4,5,4,5,6], -[1,6,7,6,5,5,4,4,4,2,5,3,4,6,5,6,6,6,7,5,3,4,2,5,6,6], -[0,8,6,5,4,2,2,3,2,6,5,7,7,5,6,4,6,5,5,5,5,3,4,4,4], -[0,8,5,7,5,4,4,2,4,6,6,8,8,6,8,3,4,4,3,4,4,4,5,4,5,5], -[1,4,5,4,3,4,4,6,6,6,7,6,6,7,5,5,4,3,4,2,4,5,5,7,6,5], -[0,4,3,3,4,3,7,7,8,7,6,5,4,3,4,5,4,5,4,3,5,4,7,5,6,5], -[1,3,2,3,2,5,6,7,9,6,7,5,4,4,3,5,6,6,6,7,5,7,4,5,4], -[1,3,4,4,4,6,5,5,6,3,5,4,4,4,3,5,3,4,6,6,8,8,6,6,5,3], -[0,5,5,7,8,7,7,4,3,2,1,2,4,2,5,4,4,5,3,6,5,7,7,5,4,5], -[1,4,6,7,7,9,5,5,3,2,2,2,3,4,5,5,7,4,6,4,5,5,3,6,5,5], -[0,7,7,7,7,4,6,5,3,6,3,5,4,5,6,5,6,7,5,4,3,1,4,3,6], -[0,8,7,7,6,4,4,4,3,6,6,8,7,6,8,4,6,5,5,5,4,3,3,2,3,6], -[1,4,8,5,5,4,2,3,4,5,8,8,7,9,4,7,3,4,4,3,5,5,4,5,6,4], -[0,6,3,4,4,3,5,4,6,7,7,7,7,5,7,5,4,5,2,3,4,4,6,5,7,5], -[1,3,3,2,2,6,5,7,8,7,8,6,6,6,6,6,6,5,5,4,4,6,3,6,4], -[1,4,3,1,1,3,4,6,8,6,9,5,6,4,3,5,5,6,6,7,7,7,5,7,4,4], -[0,5,3,4,5,5,6,5,4,5,3,4,4,3,5,3,4,5,6,8,8,7,7,5,4,5], -[1,3,6,6,7,8,6,5,3,1,2,2,2,4,3,5,5,4,7,6,8,7,6,7,5,4], -[0,6,5,6,8,6,7,4,3,2,1,3,4,4,5,6,5,6,3,6,4,4,6,5,6], -[0,6,6,8,8,6,7,4,5,5,3,6,4,5,5,4,6,6,5,6,3,3,4,2,5,6], -[1,7,9,7,6,5,3,3,4,3,7,6,7,6,4,6,4,5,5,5,5,4,3,4,5,5], -[0,8,6,8,5,3,3,3,4,6,6,7,8,6,7,3,4,4,3,4,4,4,5,5,5], -[0,6,4,6,3,4,5,4,7,7,7,8,7,7,8,6,6,4,3,3,2,4,5,4,7,5], -[1,5,3,1,2,4,3,8,8,8,9,7,7,5,6,6,5,5,5,4,4,5,4,7,4,6], -[0,4,2,3,2,2,5,6,7,9,6,7,4,4,4,4,4,5,5,6,7,5,8,4,5,4], -[1,2,5,3,4,4,5,5,6,3,5,3,4,4,3,5,5,5,7,7,9,8,7,7,5], -[1,3,5,4,7,7,6,7,4,3,2,2,2,4,3,5,4,5,7,4,8,6,7,6,6,4], -[0,5,4,7,8,7,9,5,6,3,2,3,2,3,4,5,5,6,4,6,3,5,4,3,5,5], -[1,6,7,6,7,7,4,6,4,3,4,3,5,5,4,6,6,6,7,5,5,4,2,5,4,6], -[0,8,7,8,5,3,3,3,2,5,4,6,6,5,7,3,6,5,6,5,5,4,4,4,5], -[0,7,6,9,6,5,3,2,3,4,5,8,8,7,9,5,7,3,4,4,4,5,5,5,6,5], -[1,4,7,4,5,5,4,6,5,6,7,7,8,8,7,8,5,4,4,2,4,4,5,7,5,7], -[0,5,3,4,3,3,6,6,8,9,6,8,6,6,5,5,5,5,4,5,4,3,7,4,7,4], -[1,5,3,2,3,4,4,6,8,6,9,4,6,4,4,5,5,6,6,6,6,8,5,7,4], -[1,4,4,4,5,4,6,6,6,5,7,4,5,4,4,4,3,5,6,6,9,8,8,8,5,5], -[0,4,3,6,6,8,9,7,6,5,2,3,3,3,5,4,4,5,4,7,5,7,6,6,6,5], -[1,4,5,5,7,9,6,8,4,4,3,1,3,4,5,5,6,5,8,4,6,4,5,6,5], -[1,6,7,7,7,7,5,6,4,4,4,3,5,4,4,6,5,6,6,5,7,4,3,4,3,5], -[0,7,7,9,6,5,4,3,2,4,3,7,6,7,8,5,8,4,6,6,5,5,3,3,4,4], -[1,5,9,6,8,4,3,3,3,4,6,6,8,8,6,8,4,6,4,4,4,4,5,5,6,5], -[0,6,4,6,4,4,5,4,6,5,6,7,6,6,7,5,6,4,3,4,2,4,5,5,8], -[0,6,5,4,2,2,4,3,7,8,7,8,6,7,5,5,7,5,6,5,5,5,6,4,8,4], -[1,7,4,2,2,2,3,5,6,6,9,6,7,4,4,5,4,6,5,6,7,7,6,8,5,6], -[0,5,4,6,4,5,6,6,6,7,5,6,4,5,4,3,4,3,5,7,7,8,8,7,6,4], -[1,3,6,5,7,9,7,8,5,4,3,3,3,4,3,4,4,4,6,4,8,6,8,7,5], -[1,5,6,5,7,9,8,11,5,6,3,2,2,2,3,4,5,6,7,5,7,4,5,5,4,5], -[0,5,6,7,8,7,8,5,7,5,4,6,5,5,5,5,7,6,7,7,5,5,4,2,4,4], -[1,6,8,7,9,5,4,4,4,4,6,5,7,7,5,7,4,7,5,6,6,4,4,4,4,5], -[0,7,6,10,5,5,4,2,3,4,6,8,7,7,9,4,8,4,4,4,3,4,4,4,6], -[0,6,5,6,3,5,4,4,5,5,6,7,7,8,8,7,9,6,5,4,3,4,5,5,7,5], -[1,6,5,3,2,1,2,5,6,7,8,7,8,6,7,6,6,7,7,5,5,5,4,7,4,8], -[0,4,4,3,2,2,4,5,6,8,7,9,4,6,4,4,5,5,6,6,7,7,8,5,7,4], -[1,5,5,4,5,4,5,6,6,5,6,4,5,3,3,4,3,5,6,6,9,8,8,8,6], -[1,5,5,4,6,7,7,9,6,6,3,2,2,2,3,4,3,4,5,3,8,5,8,7,7,6], -[0,5,4,6,7,8,10,7,9,5,4,3,2,3,4,5,5,6,4,7,4,6,4,4,5,5], -[1,6,7,7,8,8,6,7,4,5,5,3,5,4,4,5,5,6,6,5,7,4,3,4,3], -[1,6,7,7,10,7,6,5,3,3,4,4,7,5,6,6,4,7,3,5,5,5,4,3,3,4], -[0,6,5,9,6,8,5,4,3,2,4,6,6,8,9,6,8,4,6,4,4,5,4,4,5,5], -[1,5,6,4,6,4,5,5,5,6,7,6,8,8,8,9,7,8,5,4,4,2,4,5,5,8], -[0,6,4,3,2,3,4,5,7,8,9,10,7,8,6,7,6,6,5,5,4,5,6,4,7], -[0,4,6,4,2,2,2,3,5,7,7,9,6,8,4,5,5,4,6,6,7,8,8,7,8,5], -[1,6,4,3,4,3,5,5,5,5,6,5,6,4,4,4,3,4,5,5,7,7,9,8,7,6], -[0,4,3,5,4,8,9,7,8,5,4,3,3,4,4,4,5,4,4,6,4,9,6,7,5,5], -[1,4,5,5,7,8,7,10,6,7,4,3,3,3,4,5,5,5,7,5,7,4,6,4,5], -[1,6,6,6,8,7,7,8,5,6,4,4,4,3,3,5,3,7,6,7,7,6,5,4,3,4], -[0,5,7,10,7,8,6,4,3,2,3,5,5,6,7,5,8,4,8,5,6,6,4,4,5,4], -[1,5,8,6,9,5,5,4,3,3,4,5,7,7,7,8,4,8,4,5,4,4,4,5,5,7], -[0,7,6,7,4,6,5,4,6,5,7,7,6,8,8,7,8,5,5,3,3,4,4,5,8], -[0,6,7,6,3,3,3,3,5,6,8,9,6,8,5,7,6,6,7,6,5,5,5,4,8,5], -[1,8,5,4,3,2,2,3,5,6,8,6,8,4,6,4,4,5,5,6,6,7,7,8,5,7], -[0,4,5,4,4,6,5,6,7,7,6,7,5,6,4,4,4,3,4,6,6,8,7,8,7,5], -[1,4,4,4,6,7,8,10,6,7,4,3,4,4,4,4,3,4,5,3,8,4,8,6,6], -[1,5,4,4,6,6,7,10,7,9,4,5,2,2,3,3,4,5,6,5,7,3,6,4,4,4], -[0,4,5,7,7,7,7,5,7,4,5,4,3,4,4,4,6,6,8,8,7,7,4,4,3,3], -[1,6,7,7,10,6,6,4,3,3,4,4,7,6,6,7,4,8,4,7,5,5,5,4,3], -[1,5,6,7,10,6,9,5,4,3,3,5,6,6,7,8,6,9,4,6,4,4,4,3,4,6], -[0,5,6,7,4,6,4,4,5,4,6,6,7,8,7,8,9,7,8,5,4,5,3,5,7,6], -[1,9,6,4,4,2,2,3,3,6,8,7,8,5,8,6,7,7,6,6,5,5,5,7,5,9], -[0,5,7,4,2,2,1,3,5,7,7,9,6,8,4,5,5,4,6,6,7,7,7,7,9], -[0,5,6,4,4,5,4,5,6,6,7,7,5,6,4,4,4,3,3,3,4,7,6,9,8,7], -[1,7,5,4,6,6,8,10,8,9,4,5,3,3,3,3,4,4,4,3,6,3,8,5,7,5], -[0,5,4,5,5,7,8,8,11,5,7,3,4,3,3,4,5,5,6,7,5,8,3,5,4,4], -[1,5,6,6,7,7,7,8,5,7,4,5,5,4,5,6,4,7,6,8,7,5,5,3,2], -[1,4,5,6,10,8,9,6,4,5,4,4,6,5,6,7,4,8,3,8,5,6,6,4,3,4], -[0,4,5,8,6,10,5,5,3,3,3,4,5,7,7,6,9,5,8,4,5,4,4,5,6,5], -[1,6,6,5,7,3,5,3,3,5,5,6,7,6,8,8,7,9,5,6,4,3,4,5,5,8], -[0,6,7,4,2,2,1,2,5,6,8,9,7,9,6,8,7,6,7,6,6,4,4,4,8], -[0,4,8,4,4,2,1,2,3,4,6,8,6,8,4,6,3,5,5,4,6,7,7,7,8,5], -[1,8,4,5,4,4,6,4,5,6,6,5,6,4,5,3,3,3,2,4,5,6,9,8,8,7], -[0,5,4,4,4,6,7,7,9,6,7,3,3,3,3,4,4,3,4,5,3,8,5,9,5,6], -[1,4,4,4,5,6,7,10,6,9,5,4,3,3,3,3,4,5,6,5,7,3,7,4,5], -[1,6,5,7,8,8,9,9,6,8,5,6,4,4,4,3,4,6,4,7,7,5,6,4,3,4], -[0,3,6,9,8,10,7,7,5,3,4,4,4,6,6,6,7,3,8,5,7,5,4,5,4,3], -[1,5,6,7,11,6,9,5,4,4,3,4,6,7,8,8,6,9,4,7,3,4,4,4,4], -[1,5,5,6,7,4,7,4,5,5,5,7,7,7,9,7,9,9,7,8,5,4,3,3,4,6], -[0,5,8,5,4,3,1,2,3,4,7,8,7,10,5,8,6,7,7,6,6,5,5,5,7,5], -[1,10,4,7,3,2,1,1,3,5,6,7,9,5,9,3,5,5,4,5,6,6,7,8,7,8], -[0,4,6,4,4,4,3,4,5,6,6,6,5,7,5,5,4,3,4,5,4,8,6,9,7], -[0,6,5,3,3,5,5,7,9,6,8,5,5,4,3,4,4,5,4,4,3,7,4,8,6,7], -[1,6,5,4,5,5,7,9,7,11,5,7,3,3,3,3,4,5,5,6,7,5,7,4,6,4], -[0,5,5,6,7,8,7,7,8,5,6,3,4,3,2,3,5,3,7,6,8,8,6,6,3,4], -[1,5,6,7,10,7,9,5,4,3,3,3,5,5,5,6,4,7,3,8,5,6,5,4,4], -[1,4,4,6,9,6,11,5,7,3,3,4,4,5,7,7,6,9,4,8,3,5,4,4,4,5], -[0,5,7,7,6,8,4,6,4,4,5,5,6,7,6,8,7,6,9,5,6,4,3,4,5,5], -[1,9,6,8,5,2,3,2,2,5,6,6,8,5,8,5,7,6,6,7,5,5,4,5,4,9], -[0,5,9,4,5,2,1,3,4,5,6,8,6,9,5,8,4,5,5,5,5,7,7,6,7], -[0,5,8,4,5,4,4,5,5,6,7,6,6,7,5,6,4,5,3,3,3,6,5,9,7,7], -[1,6,4,4,3,4,7,8,8,10,7,8,4,5,4,4,4,4,4,3,4,3,8,4,8,5], -[0,5,4,3,4,5,7,8,10,6,10,4,5,3,3,3,4,5,6,7,6,8,4,7,4,5], -[1,5,5,5,6,7,7,7,5,7,4,6,4,3,4,4,3,6,4,8,7,6,7,3,3], -[1,3,3,5,9,8,10,6,7,5,3,4,4,4,6,6,5,7,4,9,4,7,5,5,4,3], -[0,3,4,6,6,10,6,8,4,4,3,3,4,5,6,7,8,5,8,3,7,3,4,4,4,5], -[1,6,5,6,7,4,6,2,4,3,4,5,5,5,8,6,8,8,6,7,5,4,4,4,4], -[1,8,6,8,5,4,3,1,2,3,3,6,7,6,8,5,9,6,8,7,7,6,5,5,5,7], -[0,5,9,4,7,3,1,1,1,2,5,6,6,8,4,8,3,5,4,5,5,5,6,7,8,6], -[1,9,5,7,4,5,5,4,6,6,5,6,6,5,6,3,5,3,3,3,4,3,8,6,9,7], -[0,6,5,3,4,5,6,7,9,7,9,5,5,4,3,5,4,4,3,4,3,6,4,9,5], -[0,8,4,4,4,4,5,7,9,8,10,5,7,3,3,3,3,4,5,5,5,7,5,7,3,5], -[1,4,4,5,6,7,8,8,8,8,6,8,4,5,4,3,3,5,3,7,6,7,7,4,4,2], -[0,3,3,5,6,10,8,9,6,5,4,3,4,5,5,5,5,3,7,3,8,5,6,5,3,3], -[1,4,4,5,9,6,10,4,6,3,2,3,4,5,6,7,6,9,4,8,3,5,3,4,4], -[1,5,4,5,5,5,6,3,5,3,3,4,4,5,7,7,8,9,8,9,5,6,3,2,4,5], -[0,4,9,5,6,3,1,2,0,3,4,5,5,8,5,9,4,8,7,6,7,5,5,4,5,5], -[1,9,6,10,4,5,2,1,2,3,5,5,7,5,9,3,7,3,4,4,4,5,6,6,7,8], -[0,6,8,3,6,4,4,5,4,5,6,5,6,7,4,7,3,4,3,4,4,6,5,10,8], -[0,8,7,3,4,3,4,6,6,7,9,5,7,3,4,4,3,5,3,4,3,5,3,9,5,9], -[1,5,6,5,3,4,6,7,8,10,6,10,4,6,3,3,3,3,4,5,6,5,7,4,7,3], -[0,5,4,5,6,7,7,8,7,6,8,5,6,4,4,3,3,2,5,4,7,6,6,6,3,4], -[1,3,4,7,9,8,11,6,7,4,3,4,3,5,5,5,4,6,2,7,3,7,4,4,3], -[1,3,3,4,6,6,10,6,9,4,4,4,3,4,5,6,7,9,6,9,4,6,3,4,3,3], -[0,4,5,5,5,7,3,7,3,4,4,4,5,6,6,8,7,8,9,6,8,4,4,3,3,4], -[1,7,5,9,5,4,3,0,2,3,4,5,7,6,9,4,9,5,7,7,5,6,5,4,4], -[1,7,5,10,4,7,2,1,1,1,2,4,5,5,8,4,9,3,6,4,4,5,6,6,7,7], -[0,7,9,4,7,3,3,3,3,4,5,4,6,6,5,7,4,6,3,3,3,4,4,8,6,9], -[1,7,6,5,3,3,4,5,7,9,6,9,5,6,3,4,4,4,4,3,3,2,6,3,9,4], -[0,7,4,3,2,3,5,6,8,7,11,4,8,2,3,2,3,3,4,5,6,7,4,7,3], -[0,6,3,4,5,5,6,8,7,7,7,5,7,3,4,2,3,2,4,2,7,5,7,7,5,4], -[1,3,3,4,5,7,9,7,9,6,5,5,4,4,5,4,5,6,3,8,3,8,5,6,4,3], -[0,2,3,4,5,9,6,10,5,7,3,4,4,5,5,7,7,6,9,4,8,3,6,3,4,4], -[1,6,5,7,6,5,7,3,6,3,4,4,5,5,6,5,9,8,7,9,4,6,3,3,3], -[1,5,5,9,6,7,4,2,2,1,3,4,5,5,8,4,9,5,9,6,6,7,5,5,4,5], -[0,5,10,5,9,4,4,2,1,1,3,3,5,7,5,8,3,8,4,5,4,5,5,6,6,6], -[1,7,4,8,3,6,3,4,5,5,5,7,6,6,7,4,7,4,4,3,3,3,5,4,8,6], -[0,7,5,3,3,2,4,6,7,7,9,5,8,4,5,4,4,4,3,4,3,5,3,9,4], -[0,9,4,4,3,2,3,4,6,6,9,5,10,3,5,2,3,2,3,3,5,6,5,7,3,7], -[1,2,4,3,4,4,6,5,7,7,6,7,5,7,3,4,3,3,3,6,4,8,6,6,6,2], -[0,3,2,3,5,8,7,10,5,6,4,3,3,3,4,5,5,4,7,2,9,3,8,4,4,3], -[1,2,3,4,6,6,10,5,9,4,5,2,3,3,4,6,6,8,5,9,3,7,2,4,4], -[1,4,4,5,5,5,6,3,6,2,4,3,3,3,5,4,8,6,8,8,7,8,4,4,3,4], -[0,5,9,6,9,5,3,2,0,1,1,3,4,6,4,8,3,8,5,7,7,6,6,5,5,5], -[1,8,6,11,5,8,3,2,2,1,3,4,6,6,8,4,8,2,6,3,4,4,4,5,7,7], -[0,6,9,4,7,3,4,4,4,5,6,4,7,5,5,6,3,5,2,2,1,3,3,8,6], -[0,9,6,6,5,2,3,4,5,6,9,6,8,3,6,2,4,4,3,3,2,3,2,6,3,9], -[1,4,7,4,3,2,3,5,7,8,7,11,5,8,3,5,2,3,3,4,5,5,7,4,7,2], -[0,5,2,3,4,5,5,7,7,7,8,6,8,4,5,3,3,2,5,3,7,5,8,6,4], -[0,4,2,3,3,6,6,10,7,10,5,5,5,4,4,4,5,4,5,2,7,3,8,3,6,3], -[1,2,2,2,4,4,8,5,9,4,6,3,3,3,4,5,7,8,6,9,4,9,3,6,2,3], -[0,3,5,4,6,5,3,6,2,5,2,4,3,4,4,7,6,8,8,8,9,5,6,3,3,3], -[1,6,5,9,5,6,4,1,2,0,3,4,5,5,8,3,8,4,8,6,7,6,5,4,4], -[1,5,5,9,5,10,4,5,1,1,1,2,3,5,6,4,8,3,7,2,5,4,4,5,6,6], -[0,8,8,5,8,2,5,3,4,3,4,3,5,4,6,6,4,6,3,3,1,3,3,6,5,10], -[1,6,7,5,2,3,2,4,5,6,7,9,5,8,3,5,4,4,4,3,3,3,5,3,9,4], -[0,9,3,4,3,2,3,4,6,7,9,5,9,3,6,2,3,2,3,3,4,5,5,7,3], -[0,7,2,6,3,4,5,6,6,7,7,6,8,4,6,3,3,2,2,2,6,3,7,5,6,5], -[1,2,3,2,4,6,9,8,10,6,7,4,4,4,4,5,4,5,3,6,2,8,3,8,3,3], -[0,2,2,2,4,6,5,10,5,9,3,4,3,3,3,5,6,6,8,5,9,3,7,2,3,3], -[1,3,3,5,5,5,6,3,6,3,5,3,4,4,6,4,8,6,8,8,6,7,3,4,2], -[1,3,4,7,5,8,3,4,2,0,2,2,4,4,6,3,8,3,9,4,8,6,5,4,4,4], -[0,5,8,5,10,3,6,1,1,0,0,2,3,5,5,7,3,7,1,5,3,4,4,4,5,7], -[1,6,6,7,3,6,2,4,3,4,3,5,4,7,5,6,8,4,6,2,3,2,3,3,8,5], -[0,9,6,4,3,2,2,3,5,6,9,5,9,3,7,3,4,5,4,4,3,4,3,7,4], -[0,10,4,7,3,3,3,3,4,6,8,6,10,4,8,1,5,1,2,2,4,4,5,7,4,8], -[1,2,6,2,4,3,5,5,7,6,6,8,5,7,4,5,2,2,2,5,3,8,5,7,7,4], -[0,4,1,2,3,6,6,9,6,9,4,5,3,4,5,4,4,4,6,2,8,3,9,4,6], -[0,4,3,2,2,5,5,9,6,10,5,7,3,3,3,4,4,6,7,6,9,4,8,2,6,2], -[1,3,3,5,4,6,6,4,7,2,6,2,3,3,4,3,6,5,8,7,7,9,5,5,3,3], -[0,4,6,6,10,5,7,3,1,1,0,2,2,3,3,7,2,8,3,8,5,6,5,4,3,4], -[1,6,5,9,5,9,3,5,1,1,2,2,4,5,7,4,9,3,8,2,5,3,4,3,6], -[1,5,6,7,4,7,2,5,2,3,3,5,3,6,5,6,6,5,7,2,4,2,2,2,6,4], -[0,10,5,7,4,2,3,2,3,5,6,6,9,4,8,3,6,4,4,4,3,2,2,4,3,8], -[1,3,8,3,3,2,1,2,4,5,6,9,5,9,2,7,2,3,2,4,3,5,5,5,8,3], -[0,7,2,4,2,4,4,6,4,7,7,6,7,4,6,3,4,2,3,2,6,3,8,5,5], -[0,5,2,2,1,3,5,9,6,11,5,8,4,4,4,4,5,4,5,3,6,2,8,3,7,2], -[1,3,2,2,2,4,7,5,10,4,9,3,4,2,2,3,4,5,6,7,5,9,3,7,3,5], -[0,2,3,4,6,4,5,6,3,6,1,4,2,3,2,4,2,6,5,8,8,6,7,4,3,2], -[1,4,5,9,5,9,4,4,2,0,2,2,3,4,6,3,8,2,9,4,8,5,5,4,4], -[1,4,4,8,6,11,4,7,1,2,1,1,2,4,5,5,8,3,8,2,6,2,4,3,5,5], -[0,7,7,6,9,4,7,2,5,3,4,4,6,3,7,5,6,6,3,6,1,2,1,4,3,8], -[1,5,9,5,5,3,1,3,3,5,6,9,4,10,3,8,4,5,5,3,4,3,4,3,7], -[1,4,10,3,7,3,2,1,3,3,6,8,7,10,4,9,2,5,2,3,3,5,4,5,6,3], -[0,8,2,6,2,5,3,5,6,8,7,8,8,6,8,3,5,2,3,1,4,2,7,4,7,4], -[1,3,3,0,2,2,6,6,10,6,10,4,6,4,4,5,4,5,3,5,2,8,2,9,3,5], -[0,3,1,1,1,4,4,8,4,9,3,6,2,3,3,3,4,5,7,6,8,4,9,2,5], -[0,2,3,3,4,4,5,5,4,6,2,6,2,3,3,4,3,7,4,9,7,8,8,4,5,2], -[1,4,2,5,3,8,4,7,3,4,3,2,3,3,3,2,4,1,7,4,9,8,9,7,5,5], -[0,3,4,4,9,4,11,3,7,2,2,1,1,1,3,4,2,7,3,8,5,6,4,4,4,4], -[1,4,5,7,4,9,3,7,3,4,3,3,1,4,2,5,7,7,9,5,6,2,2,2,4], -[1,3,9,6,8,6,4,4,3,4,4,5,3,7,2,8,4,8,7,6,6,2,2,1,3,1], -[0,8,4,11,5,7,4,4,2,4,4,5,8,5,10,4,8,4,4,3,2,2,2,3,3,7], -[1,4,9,3,8,5,6,4,6,4,7,6,8,8,7,9,5,5,2,1,0,3,2,6,6,7], -[0,6,4,5,3,5,4,8,4,9,4,8,5,6,7,5,5,4,3,1,4,1,8,3,8], -[0,5,5,3,2,1,3,5,4,9,5,11,5,8,4,6,5,4,5,4,6,4,9,3,8,4], -[1,5,3,4,2,4,2,5,6,4,8,5,8,5,4,3,4,2,5,6,8,10,8,10,5,5], -[0,3,3,3,7,4,9,3,6,3,3,4,3,4,2,3,1,6,2,8,6,9,8,6,6], -[0,4,4,3,6,4,10,3,8,3,4,1,3,2,3,4,3,6,4,9,4,8,5,5,5,4], -[1,3,5,5,5,8,4,8,3,5,3,4,2,3,0,5,5,7,9,6,9,4,4,2,2,2], -[0,7,5,9,6,7,5,4,4,4,4,4,6,3,8,3,8,6,7,7,4,4,2,2,1,5], -[1,2,10,4,9,4,5,3,3,3,4,5,4,9,4,9,4,6,4,3,3,3,3,4,6], -[1,4,8,4,9,3,6,4,5,3,5,4,6,6,6,8,5,7,3,2,1,1,1,5,4,8], -[0,6,5,5,3,4,3,5,3,8,4,9,5,8,6,7,7,5,5,2,3,1,5,3,8,5], -[1,8,5,3,2,2,3,3,7,4,10,4,9,4,6,4,4,4,4,5,3,7,4,9,4,7], -[0,4,5,4,5,3,5,4,4,7,4,8,3,5,3,3,1,3,3,6,7,7,9,6,7], -[0,3,4,2,6,4,8,4,7,3,4,4,3,4,3,3,2,4,1,7,4,9,7,7,7,5], -[1,3,3,3,4,9,4,11,4,7,2,3,2,2,2,3,4,3,7,3,9,4,5,4,3,4], -[0,5,4,5,7,5,9,5,8,4,5,4,4,2,4,3,6,7,6,9,4,6,2,2,1,4], -[1,3,9,5,7,5,4,4,3,4,4,5,3,6,1,8,4,7,7,5,6,3,2,0,3], -[1,2,8,4,10,4,6,3,3,2,3,3,5,7,4,9,3,8,4,4,4,2,2,3,3,3], -[0,6,3,8,4,7,4,5,4,5,3,7,5,7,9,7,9,6,5,3,2,1,3,2,7,5], -[1,6,5,3,3,2,3,3,6,4,9,4,8,5,7,7,7,6,4,3,1,4,1,7,4,8], -[0,5,5,3,2,2,3,5,4,8,4,9,4,7,4,5,4,4,5,4,6,5,9,5,8], -[0,5,6,3,4,2,4,2,5,5,3,7,4,6,4,4,2,3,2,6,5,8,10,8,9,5], -[1,6,3,4,3,7,4,8,4,5,3,3,4,3,3,3,3,1,5,2,8,6,9,8,7,5], -[0,4,3,4,7,5,11,5,9,4,5,3,2,2,3,3,3,6,3,8,4,7,4,5,3], -[0,4,3,6,5,6,8,5,9,5,6,3,3,2,4,2,5,5,6,9,6,8,4,3,2,2], -[1,3,7,5,10,6,7,6,4,4,4,4,4,5,2,7,2,8,5,7,7,5,4,1,1,1], -[0,6,3,10,4,9,4,4,3,4,3,5,6,5,9,5,9,4,6,4,3,3,2,2,3,5], -[1,3,7,2,7,3,6,3,5,3,6,4,7,7,7,10,6,7,4,2,2,1,1,5,4], -[1,8,6,5,4,3,3,3,4,4,8,4,8,4,7,7,7,7,4,5,2,2,0,5,2,9], -[0,5,7,4,3,1,1,1,3,5,3,8,3,8,4,6,5,4,5,4,5,4,7,5,9,4], -[1,7,4,4,2,4,2,3,2,4,5,3,7,3,5,3,3,1,3,3,7,8,8,9,6,6], -[0,4,3,4,5,4,9,3,7,4,4,4,3,4,3,2,1,2,1,6,3,9,7,8,7], -[0,4,3,4,4,4,8,5,10,4,7,3,3,1,2,2,3,3,3,7,3,8,4,7,5,4], -[1,4,6,4,6,6,5,8,4,7,4,4,2,3,1,3,2,5,7,6,9,5,6,3,2,2], -[0,5,4,9,5,7,5,5,5,4,4,5,4,4,6,2,7,4,8,7,6,6,3,2,1,3], -[1,3,8,4,10,5,7,4,4,3,4,5,5,7,4,9,4,8,5,4,4,2,2,3,4], -[1,4,7,4,8,4,8,4,5,4,5,4,6,5,7,9,7,9,6,5,2,1,0,3,2,6], -[0,5,6,5,3,4,3,3,3,6,4,8,4,9,6,8,8,7,7,5,4,2,4,1,7,3], -[1,8,4,4,3,2,1,2,4,4,8,4,9,4,8,5,5,5,5,5,5,7,5,8,4,8], -[0,4,6,4,4,3,4,3,4,5,5,7,5,7,4,4,2,2,2,4,5,8,8,7,8], -[0,4,5,3,4,4,7,4,8,3,6,4,4,4,3,3,2,3,1,4,2,8,6,9,7,6], -[1,5,4,3,4,6,5,9,4,9,3,5,2,2,1,2,2,3,6,4,8,4,7,5,5,4], -[0,4,4,5,5,6,7,5,8,4,6,4,3,3,4,2,5,5,7,9,6,8,4,3,2,2], -[1,3,7,4,9,5,6,5,4,4,5,3,4,4,2,6,3,8,6,7,7,5,5,2,2], -[1,2,6,3,10,5,9,4,4,3,3,3,4,5,4,7,4,8,4,5,4,3,3,3,2,4], -[0,5,5,7,3,7,3,5,3,5,3,5,4,6,7,7,10,7,7,4,2,2,2,2,6,4], -[1,8,6,4,4,2,3,3,4,4,7,4,8,5,8,7,7,7,6,5,2,3,1,6,3], -[1,9,5,8,4,3,2,2,2,4,6,5,10,4,8,5,6,5,4,4,4,5,4,7,4,8], -[0,4,7,4,5,4,5,3,5,4,5,7,5,7,4,5,3,2,2,3,2,7,6,8,9,6], -[1,7,4,4,4,6,5,8,4,8,4,5,5,3,4,3,3,2,2,1,6,3,8,7,8,6], -[0,5,3,4,4,5,9,5,10,4,8,4,4,4,3,3,4,4,4,8,4,8,5,6,4], -[0,3,4,4,4,5,5,5,8,5,7,5,5,4,3,2,4,2,6,7,7,9,6,6,2,2], -[1,3,5,4,9,5,8,5,4,4,4,4,4,4,3,5,2,8,4,8,7,6,5,3,2,2], -[0,3,3,8,4,9,4,6,3,4,2,4,3,5,7,5,10,5,9,5,6,4,3,3,3,3], -[1,4,6,4,7,3,6,3,4,4,4,3,6,5,7,9,8,10,6,5,3,1,2,3,2], -[1,7,5,7,5,3,3,3,4,4,6,4,8,4,8,6,8,9,6,7,4,3,1,4,2,8], -[0,4,9,5,5,2,2,2,3,3,4,7,4,8,4,7,5,5,5,4,4,5,6,5,9,5], -[1,9,5,6,4,4,3,4,2,4,4,4,7,4,6,4,3,3,2,2,4,4,8,8,8,9], -[0,6,5,4,4,5,8,4,8,4,6,4,5,5,5,4,3,3,0,4,2,8,5,9,7], -[0,6,5,4,3,5,6,6,10,5,9,4,6,4,3,3,3,3,3,5,3,8,3,7,4,5], -[1,5,5,5,7,6,6,7,6,8,5,6,4,3,2,3,2,4,4,6,8,6,7,4,3,2], -[0,3,3,7,5,9,5,7,5,4,5,5,4,4,5,3,6,3,8,6,8,7,5,4,2,1], -[1,2,5,3,9,4,8,4,4,4,4,3,5,5,5,8,5,9,5,7,5,3,3,3,2], -[1,4,4,4,7,3,7,4,6,5,5,4,6,4,7,7,7,10,7,7,5,2,2,1,1,5], -[0,4,7,5,4,4,2,3,3,4,4,7,4,8,4,8,7,8,9,5,5,3,3,2,6,4], -[1,9,5,7,3,3,1,2,2,3,5,3,8,3,8,5,5,5,4,5,4,5,4,7,5], -[1,9,5,7,5,5,3,4,3,4,4,5,6,5,7,6,6,4,2,3,3,3,7,7,8,9], -[0,6,6,4,4,4,6,5,8,4,8,4,5,5,5,4,4,1,1,3,2,6,5,9,7,8], -[1,7,5,4,4,4,5,8,5,10,4,7,4,3,2,2,2,3,3,4,7,3,8,5,7,5], -[0,5,5,5,5,6,6,5,8,5,7,5,4,4,3,1,4,3,6,7,7,9,6,6,4], -[0,3,4,5,4,9,5,8,5,5,5,5,4,5,4,3,5,2,7,5,7,7,6,6,3,3], -[1,3,4,4,9,5,10,5,8,5,5,4,5,4,5,7,5,8,4,8,5,5,4,3,3,3], -[0,3,5,7,4,8,4,7,5,5,4,5,4,6,6,7,9,8,10,6,6,3,1,2,4,3], -[1,7,5,6,5,3,3,2,3,4,5,4,7,4,8,6,8,8,7,7,4,4,3,3,2], -[1,8,4,8,4,5,3,2,1,4,4,5,8,5,9,5,8,6,5,6,4,5,5,5,5,8], -[0,4,8,4,6,4,4,3,5,2,5,5,5,7,6,7,5,3,3,2,2,4,5,7,8,8], -[1,8,5,5,4,4,5,6,4,8,3,6,4,5,5,5,3,3,2,1,3,2,8,5,8,7], -[0,6,5,4,3,4,5,5,9,4,8,4,5,4,3,3,3,3,4,6,4,8,4,8,5], -[0,5,5,5,4,6,5,6,6,5,8,5,6,4,3,3,3,2,5,5,7,9,6,8,5,3], -[1,4,4,4,7,6,9,6,6,6,5,5,5,4,4,3,2,6,2,8,6,7,7,5,4,2], -[0,3,3,6,4,10,5,9,4,5,4,4,4,5,5,5,8,4,8,5,7,5,4,5,4,3], -[1,4,5,5,7,4,7,4,5,5,4,4,5,4,6,7,8,10,7,8,5,3,3,3,3], -[1,7,5,7,5,5,5,3,4,4,5,5,7,5,9,5,9,8,8,9,6,5,3,3,2,5], -[0,3,10,5,8,4,3,2,3,3,4,5,5,8,4,9,6,6,6,4,5,4,5,5,6,5], -[1,9,5,8,6,5,4,4,4,5,4,6,7,6,8,5,5,4,2,2,3,3,6,6,8], -[1,8,6,6,5,3,5,5,5,8,4,8,4,6,6,6,6,4,4,3,3,2,6,5,9,6], -[0,7,5,4,3,4,4,5,8,5,9,5,8,5,4,4,3,3,3,4,4,7,4,8,5,6], -[1,5,4,4,5,4,7,6,6,8,6,7,6,5,5,2,2,3,3,6,7,7,8,5,5,3], -[0,2,4,6,5,9,5,7,5,4,5,5,4,5,4,3,5,3,7,5,9,8,6,6,4], -[0,2,3,4,4,9,5,9,5,6,4,4,3,4,4,5,6,5,9,5,9,6,5,5,4,3], -[1,4,4,4,5,4,7,4,6,5,4,4,5,4,6,5,7,9,8,11,7,5,4,1,2,4], -[0,3,7,4,6,5,3,3,3,3,4,5,4,7,4,7,6,8,9,7,7,5,4,3,4,3], -[1,9,5,9,5,5,3,2,2,3,3,4,6,4,8,5,7,6,5,5,3,5,4,6,6], -[1,9,5,9,5,6,5,4,4,4,3,5,4,5,7,5,7,5,3,3,1,2,5,5,8,8], -[0,8,7,5,5,5,4,5,7,5,8,4,6,5,6,6,5,5,3,2,1,4,2,7,5,8], -[1,7,6,5,6,4,6,7,6,10,6,9,5,6,4,3,3,2,3,3,5,4,7,3,6,5], -[0,5,6,5,5,7,5,7,8,6,8,6,7,5,4,3,3,2,4,5,7,8,6,7,4], -[0,3,3,4,5,8,6,9,6,7,6,6,5,5,4,4,4,2,6,3,8,6,8,7,4,3], -[1,3,2,3,6,4,10,6,9,5,5,5,5,5,6,6,6,8,6,9,5,6,6,4,4,3], -[0,3,5,4,4,7,3,7,5,6,6,5,4,6,5,7,8,9,11,8,8,6,3,3,3], -[0,3,7,4,8,5,4,3,3,3,4,3,4,6,4,7,5,8,8,8,9,6,5,3,3,3], -[1,7,4,9,5,7,3,3,2,2,2,4,5,5,8,5,9,6,7,7,5,6,5,5,5,6], -[0,6,8,5,7,5,5,5,4,3,5,3,5,6,6,8,6,6,5,2,3,2,4,7,7,8], -[1,8,6,6,5,4,6,5,6,8,4,7,4,6,6,5,6,4,3,2,2,2,6,4,8], -[1,7,8,6,5,4,4,4,6,8,5,9,5,7,4,4,4,3,3,3,4,5,7,5,8,5], -[0,7,6,5,6,6,4,6,6,5,7,5,7,6,4,4,1,2,3,3,6,7,7,8,6,5], -[1,4,3,5,6,6,10,6,8,6,6,6,6,5,6,4,3,4,2,6,4,7,7,6,6,4], -[0,3,3,4,5,9,6,10,6,8,6,5,4,5,5,5,7,5,8,5,8,5,5,5,3], -[0,3,4,4,5,6,5,8,4,7,5,4,5,4,3,6,5,8,9,8,10,7,5,4,1,2], -[1,4,3,7,5,6,5,3,3,4,3,5,5,5,7,4,8,7,9,10,8,8,6,3,3,4], -[0,3,8,5,8,4,4,3,2,2,4,4,5,7,5,10,5,7,6,4,5,4,4,5,6,6], -[1,8,6,8,5,6,5,4,4,4,3,6,5,6,8,6,7,5,3,3,1,2,4,5,8], -[1,8,8,7,5,4,5,5,5,7,5,7,4,6,5,6,7,6,5,4,3,2,4,3,8,6], -[0,9,6,6,5,4,3,5,5,5,8,5,9,5,6,5,3,4,4,4,4,6,4,8,4,7], -[1,6,5,5,5,5,6,5,7,7,6,9,7,7,6,4,3,3,3,5,5,7,8,6,7,4], -[0,4,4,4,5,8,6,9,5,7,5,6,6,6,5,5,3,3,5,3,8,6,8,7,5], -[0,5,4,4,4,6,5,10,6,9,6,5,5,5,4,5,5,5,8,5,9,5,6,6,4,5], -[1,4,4,5,4,4,7,4,7,5,5,5,4,4,5,5,7,8,9,11,8,9,6,4,4,3], -[0,4,7,5,8,5,4,4,3,4,4,4,5,5,3,7,5,8,9,9,9,6,5,4,4], -[0,4,7,5,11,6,8,4,4,3,3,3,4,5,5,8,5,8,5,6,6,4,5,4,5,5], -[1,7,6,8,6,8,6,5,5,5,4,4,4,6,6,6,8,6,6,5,2,3,3,4,7,6], -[0,8,8,6,5,5,4,6,5,6,7,5,8,4,6,6,5,6,5,3,2,3,2,6,4,8], -[1,6,7,5,4,4,5,4,6,7,6,9,6,8,6,5,5,3,4,4,4,4,6,4,7], -[1,4,6,5,4,5,5,4,6,6,6,8,7,8,7,4,5,2,3,3,3,6,7,7,8,6], -[0,5,4,3,5,6,5,8,6,7,5,5,5,6,5,6,4,3,3,2,6,4,8,6,6,5], -[1,4,2,4,4,5,8,5,8,5,6,5,4,4,5,5,6,6,6,9,5,8,6,5,5,3], -[0,3,5,3,5,5,4,6,4,6,5,4,4,4,3,6,6,8,10,9,10,8,6,5,3], -[0,4,6,5,9,5,6,5,4,3,4,4,5,4,3,6,3,8,6,8,9,7,7,5,4,4], -[1,5,5,9,6,9,5,5,4,3,2,3,3,4,6,4,8,5,7,6,5,6,5,6,6,7], -[0,7,8,6,8,5,6,6,4,4,4,3,5,5,6,7,6,7,5,3,3,2,3,4,5,8], -[1,8,8,7,6,5,6,5,7,7,5,9,4,8,6,6,7,6,6,3,2,2,4,2,8], -[1,5,9,6,6,5,5,4,7,7,7,10,6,9,6,7,5,3,4,3,4,4,5,4,7,4], -[0,7,5,6,7,6,6,7,6,7,8,7,8,7,7,6,3,3,1,2,4,5,7,8,6,6], -[1,4,3,4,4,5,8,6,9,6,8,6,7,7,7,6,5,4,4,6,4,7,7,7,6], -[1,5,3,2,2,4,5,5,9,5,8,6,6,6,5,6,6,6,6,8,6,9,5,7,6,4], -[0,5,4,3,5,5,5,6,4,7,5,5,6,4,5,5,4,7,8,9,10,8,8,6,3,4], -[1,3,4,7,5,8,4,4,3,3,3,5,3,4,4,4,7,5,8,9,9,10,6,6,4,4], -[0,4,6,5,9,5,7,4,3,2,2,2,3,4,5,7,5,8,7,6,7,5,6,5,5], -[0,6,7,6,8,6,7,6,5,6,4,4,5,4,6,6,7,9,7,6,5,2,3,2,4,7], -[1,6,8,7,6,5,5,4,7,5,6,7,5,7,4,6,6,6,6,5,3,3,2,2,6,5], -[0,9,7,8,6,5,4,5,4,6,7,5,9,5,6,5,4,4,2,3,3,4,5,7,5,8], -[1,5,6,6,5,6,6,5,6,6,6,8,7,8,7,5,5,2,2,3,3,7,6,8,8], -[1,5,5,4,3,5,6,7,9,6,8,6,7,7,6,6,6,4,3,4,3,6,5,8,6,6], -[0,5,4,3,4,5,6,9,6,10,6,8,6,5,5,5,5,6,6,5,8,5,7,5,4,5], -[1,3,4,4,4,5,5,5,7,5,7,6,4,6,3,4,6,6,8,10,9,11,8,6,5,3], -[0,4,5,5,8,5,6,4,3,4,4,3,5,4,4,6,4,8,7,9,10,8,8,5,3], -[0,4,5,4,9,5,9,5,5,4,3,4,5,4,6,7,5,9,5,7,6,5,6,4,5,5], -[1,5,6,7,5,8,5,6,6,4,5,4,4,5,5,6,8,7,8,5,3,4,2,4,5,5], -[0,9,8,7,6,5,5,5,4,6,6,5,6,3,7,5,7,7,6,6,4,2,3,4,4,7], -[1,5,8,7,5,5,5,3,6,5,6,9,6,8,6,6,6,4,5,4,5,4,5,5,7], -[1,5,7,5,5,6,4,5,6,5,7,7,6,9,7,7,6,3,4,2,3,4,5,7,7,7], -[0,7,5,4,5,5,6,8,6,9,6,7,6,6,6,6,5,4,3,3,4,3,7,6,7,6], -[1,5,4,3,3,5,6,5,9,6,7,5,5,6,4,4,5,5,5,7,6,9,6,7,6], -[1,4,6,5,5,5,5,4,6,4,6,5,5,5,3,4,4,4,6,8,8,10,8,8,6,3], -[0,5,4,5,8,6,8,5,5,4,3,4,5,4,5,5,4,6,4,8,8,8,9,5,5,4], -[1,3,5,7,6,9,6,7,5,4,3,3,3,4,4,5,7,5,8,5,5,6,4,5,5,5], -[0,7,7,6,8,6,7,6,5,6,4,4,4,3,6,6,7,8,6,6,5,1,3,2,4], -[0,7,6,8,7,6,5,4,4,6,5,6,7,5,8,5,7,7,7,7,5,4,3,2,2,6], -[1,4,8,6,6,5,4,3,4,4,6,7,7,9,5,8,6,4,5,3,4,4,4,5,6,4], -[0,8,5,6,6,5,6,6,5,6,6,7,8,7,8,7,5,5,1,3,2,2,5,5,7,6], -[1,5,5,4,3,5,5,5,8,6,8,6,6,6,6,7,6,4,4,4,3,7,5,8,6], -[1,6,5,3,3,4,3,5,7,5,9,5,6,6,4,5,4,5,5,6,6,9,6,8,6,5], -[0,6,4,5,5,4,5,5,5,7,5,7,6,4,6,3,3,5,6,8,9,9,9,7,6,5], -[1,3,5,6,5,9,5,6,4,3,4,4,3,5,4,3,4,3,7,6,9,9,7,8,6,5], -[0,5,5,6,9,6,9,5,4,4,3,2,3,3,4,5,4,7,5,6,6,4,6,4,6], -[0,6,6,7,8,6,7,6,6,6,4,5,4,4,6,5,7,8,8,8,6,4,4,2,3,5], -[1,6,8,7,7,7,5,5,5,5,7,6,6,7,4,8,6,7,8,6,6,4,2,2,4,4], -[0,8,6,9,6,6,5,5,4,7,6,6,8,6,8,5,6,6,3,5,3,3,4,4,4,7], -[1,5,6,6,6,6,5,6,6,5,7,7,7,9,7,7,6,3,4,2,3,5,5,8,7], -[1,6,6,4,3,4,3,6,7,6,9,5,7,6,6,7,7,6,5,4,3,5,4,7,6,7], -[0,6,4,3,3,3,4,6,5,9,5,9,6,6,6,5,5,5,5,6,7,6,8,6,6,5], -[1,4,5,4,3,5,4,4,5,4,6,5,4,5,3,4,3,4,6,8,9,10,8,8,6,3], -[0,5,4,6,7,5,6,4,4,3,3,3,4,2,4,2,2,6,5,7,8,7,9,6,5], -[0,5,4,5,6,5,9,5,6,4,3,3,3,2,5,4,5,7,5,8,6,5,7,4,5,4], -[1,5,6,6,5,7,5,6,6,4,5,3,4,4,3,5,6,7,8,6,6,5,2,4,2,5], -[0,8,7,8,7,6,5,5,4,6,5,6,6,4,6,4,6,6,6,6,4,3,3,2,3], -[0,6,5,9,7,7,6,4,4,5,4,6,7,6,8,5,7,6,4,6,3,4,4,4,5,6], -[1,5,8,5,6,6,5,6,5,5,6,6,7,7,8,8,7,5,5,1,3,2,3,6,6,7], -[0,7,5,5,5,4,6,6,7,9,7,9,7,7,7,8,7,7,4,4,3,2,5,4,7,6], -[1,6,5,4,2,4,5,5,8,6,9,6,7,6,5,6,5,5,6,6,6,7,5,7,5], -[1,5,6,4,4,5,4,6,5,4,6,5,6,6,4,5,2,3,4,5,8,9,8,9,7,5], -[0,5,3,5,5,5,7,4,5,4,4,4,5,4,6,3,4,5,4,7,7,9,9,7,6,5], -[1,3,4,4,5,8,5,8,5,5,4,2,4,4,3,5,5,5,8,5,7,6,4,6,4,5], -[0,6,6,6,7,6,7,5,5,6,3,4,3,3,4,4,6,8,7,8,5,3,4,1,3], -[0,5,5,8,7,7,6,5,4,5,4,6,5,5,5,4,7,6,7,8,6,6,4,2,3,4], -[1,4,8,6,8,6,4,4,3,3,5,4,6,7,5,8,5,6,6,4,5,3,4,4,5,5], -[0,7,5,7,5,5,6,5,6,5,6,6,6,7,9,7,7,6,2,3,1,3,4,4,6,6], -[1,6,6,4,3,5,4,6,7,6,8,6,7,7,6,7,6,5,5,3,3,4,3,7,6], -[1,8,6,4,4,4,2,4,5,5,8,5,7,5,5,5,3,5,4,4,5,7,6,8,6,7], -[0,7,4,6,5,4,5,4,5,5,4,6,5,5,6,2,4,3,4,5,7,8,10,8,7,6], -[1,3,6,4,5,8,6,7,5,5,4,4,4,5,3,4,2,3,5,4,7,7,7,7,5,4], -[0,5,4,7,8,6,10,6,7,5,3,4,3,3,4,4,4,6,5,7,6,4,5,3,4], -[0,4,4,6,6,6,7,6,7,6,4,6,3,4,4,3,6,7,7,9,7,6,5,1,3,2], -[1,5,7,6,7,5,4,4,4,3,7,5,6,6,4,7,4,8,8,6,7,5,4,3,2,4], -[0,6,5,8,6,7,5,4,4,5,4,7,7,7,9,6,8,6,4,6,2,4,3,3,4], -[0,5,4,7,4,5,6,5,6,5,5,6,6,6,8,7,8,7,5,5,1,3,2,3,6,6], -[1,7,6,5,4,4,3,5,5,5,7,4,7,6,7,7,6,7,6,4,3,3,3,5,5,8], -[0,5,5,4,2,2,4,3,4,6,5,8,5,6,6,5,6,5,6,5,7,6,8,6,7,6], -[1,4,5,4,5,4,3,5,4,4,6,5,6,6,4,5,2,4,4,5,8,9,9,9,7], -[1,5,6,3,6,6,6,7,5,5,4,4,3,4,3,4,2,2,3,2,6,6,8,8,7,7], -[0,5,4,5,5,6,8,6,8,5,4,4,3,2,3,3,4,5,5,7,5,6,7,4,7,4], -[1,6,6,5,7,7,5,6,5,5,6,3,5,2,3,5,4,6,7,7,7,5,3,4,1,4], -[0,6,6,8,7,7,6,5,5,6,5,7,4,5,6,3,7,5,7,7,5,5,3,1,2], -[0,3,3,7,6,8,6,5,5,4,4,6,5,6,7,5,7,5,6,6,3,5,2,3,4,4], -[1,4,6,4,6,5,5,6,4,6,6,5,6,7,6,8,7,6,6,2,3,1,2,4,3,6], -[0,5,5,4,3,2,5,3,6,6,6,7,5,8,7,7,8,6,5,5,2,3,4,3,6], -[0,5,6,5,3,3,2,2,4,5,5,7,6,7,6,5,6,4,5,5,5,5,6,5,8,5], -[1,5,6,3,6,4,4,4,4,4,5,4,6,5,4,5,2,3,2,4,5,6,8,9,8,7], -[0,5,3,6,3,6,7,5,7,4,3,3,3,3,4,3,4,2,2,5,5,7,8,7,8,6], -[1,5,5,4,6,6,5,8,5,5,4,2,3,2,3,3,3,5,6,5,7,6,6,7,3], -[1,6,5,5,6,6,6,7,5,6,7,4,6,3,4,3,3,5,6,6,9,6,6,4,1,4], -[0,3,5,7,6,8,6,5,5,4,3,6,3,6,4,4,5,4,7,7,6,6,5,3,4,2], -[1,4,7,5,9,6,6,5,4,3,5,3,6,5,6,7,5,6,5,3,5,2,4,3,3,4], -[0,5,5,6,5,5,6,4,6,4,6,6,5,7,8,8,9,7,5,5,1,2,1,3,5], -[0,5,6,5,4,3,4,3,6,5,6,7,5,7,6,7,8,7,7,6,3,3,2,3,5,4], -[1,7,5,5,4,4,2,4,4,5,7,6,7,6,5,6,3,6,3,5,5,5,5,7,5,6], -[0,5,4,5,3,4,4,4,5,4,4,6,5,5,5,3,5,1,3,4,5,7,9,8,8,6], -[1,5,5,3,6,5,5,7,4,5,3,3,4,4,3,4,2,3,3,3,6,5,7,8,6], -[1,6,5,4,5,5,5,8,5,8,5,4,4,2,4,3,3,4,5,4,7,5,5,6,4,6], -[0,4,4,5,5,5,6,5,6,5,4,6,2,5,2,2,3,4,6,8,7,7,6,3,4,2], -[1,4,6,6,8,6,6,5,3,3,5,3,5,3,3,4,3,6,5,6,7,5,5,3,1,2], -[0,4,4,8,5,7,5,4,4,3,3,5,4,6,6,6,7,5,5,6,3,5,2,3,4], -[0,3,4,6,4,6,5,4,6,3,5,5,4,6,6,7,8,7,6,6,2,4,0,3,4,4], -[1,7,6,5,5,4,3,5,3,6,6,6,7,5,6,6,6,7,6,4,4,2,2,4,3,7], -[0,6,7,6,3,4,3,2,4,4,5,7,5,7,6,4,6,3,5,5,5,5,6,5,7], -[0,5,6,6,4,5,3,4,4,3,4,5,5,6,6,5,6,2,4,2,4,5,6,8,8,7], -[1,7,6,4,6,4,7,8,6,7,5,5,4,4,5,5,3,4,2,2,4,4,6,6,6,7], -[0,5,4,5,3,6,7,6,9,6,6,5,4,4,3,3,4,4,4,6,4,7,6,4,6,3], -[1,5,5,5,6,6,6,7,5,6,6,4,6,2,3,3,3,5,6,7,8,7,5,5,1], -[1,3,3,5,7,5,6,5,4,4,5,4,6,4,5,5,4,6,4,7,7,6,6,4,3,2], -[0,1,3,5,4,7,5,5,5,3,3,4,4,6,6,6,7,5,7,6,4,6,2,4,3,3], -[1,5,5,5,6,4,5,5,3,5,4,5,5,4,6,7,7,8,7,4,5,0,3,2,3,5], -[0,5,5,4,3,2,3,2,5,4,5,5,5,6,5,7,7,7,7,6,4,4,3,3,5], -[0,4,7,5,4,3,1,1,3,2,4,5,4,6,5,6,5,4,6,4,6,5,5,6,7,5], -[1,6,6,5,6,4,4,4,4,4,4,4,6,5,5,5,2,4,1,3,2,4,6,7,7,8], -[0,6,5,5,3,6,5,6,7,4,4,3,3,4,4,3,4,1,2,2,2,6,5,7,8,6], -[1,6,5,4,5,5,6,8,5,7,4,3,4,1,3,2,2,3,3,3,5,4,5,5,3], -[1,6,3,5,6,5,6,7,5,6,5,5,6,3,5,3,3,4,3,6,7,6,7,4,2,4], -[0,1,4,5,6,8,6,5,5,4,4,5,4,6,4,4,4,3,6,5,6,7,4,5,3,1], -[1,2,3,4,7,5,7,6,4,5,4,5,6,4,6,6,5,7,5,5,5,2,4,1,3,3], -[0,4,4,5,4,5,5,4,6,4,5,4,5,6,6,8,9,8,8,6,3,4,1,3,3], -[0,4,6,4,4,3,2,1,4,3,5,5,5,7,5,7,7,7,8,7,6,5,2,3,4,4], -[1,6,5,5,4,3,2,3,2,4,4,5,6,5,7,5,5,7,3,5,4,5,5,6,5,6], -[0,5,5,6,4,5,3,4,4,3,4,4,4,5,5,4,5,1,4,1,3,6,6,8,8], -[0,8,5,6,3,6,4,6,6,5,5,3,3,3,4,4,4,2,3,2,2,3,4,7,7,7], -[1,6,5,3,4,3,5,6,5,7,5,5,5,3,4,2,3,3,4,4,5,4,6,5,4,6], -[0,3,5,4,5,6,5,5,6,5,6,6,3,6,2,3,2,2,4,5,6,8,6,5,5,1], -[1,5,3,5,8,6,7,5,4,4,5,3,6,3,4,3,2,4,4,5,6,6,6,3,3], -[1,4,3,4,6,5,8,5,6,5,3,4,4,4,6,5,5,7,5,6,5,4,5,2,4,3], -[0,4,5,5,4,6,4,4,5,3,5,4,5,5,5,6,8,7,8,7,4,5,0,3,1,3], -[1,6,4,5,5,3,3,4,3,6,4,6,6,5,6,5,7,7,6,7,5,3,3,2,2,5], -[0,4,6,5,3,4,2,2,4,3,5,5,5,6,5,5,5,3,6,3,5,4,4,5,7], -[0,5,6,5,4,5,3,4,3,3,4,4,4,5,4,5,5,2,4,0,3,2,4,7,7,7], -[1,7,5,3,5,2,6,5,6,7,5,5,4,4,4,5,4,5,2,2,2,2,4,5,6,6], -[0,5,5,4,3,4,4,5,7,5,7,4,4,5,2,4,3,3,3,4,4,5,4,5,5,3], -[1,5,4,6,5,5,5,5,5,5,5,4,6,2,4,1,2,3,3,6,6,6,6,5,2], -[1,4,1,4,5,6,7,5,5,4,3,4,5,3,6,3,3,5,3,6,6,6,7,5,4,4], -[0,1,3,3,4,7,5,6,5,3,4,3,4,4,4,6,6,5,7,6,5,6,3,5,2,3], -[1,4,3,4,5,4,5,5,4,6,3,6,5,4,6,6,7,8,7,7,6,2,4,0,3,4], -[0,4,7,5,4,4,2,2,4,2,6,4,4,6,4,6,6,7,7,7,5,5,3,3,4], -[0,4,7,5,6,5,3,2,2,2,4,3,4,5,4,6,5,4,5,3,5,3,5,4,6,5], -[1,6,5,5,6,4,6,3,5,4,4,4,5,5,6,5,5,5,1,3,1,3,4,5,7,6], -[0,6,5,5,2,6,4,7,7,6,6,4,4,4,4,4,5,3,3,1,2,3,3,6,6,6], -[1,6,4,4,5,3,6,6,6,8,5,6,5,2,4,2,3,3,3,3,4,3,5,5,4], -[1,5,3,5,4,4,5,4,5,6,5,5,6,3,6,1,4,2,2,5,5,7,8,6,5,4], -[0,1,5,3,5,6,5,6,4,3,3,4,4,6,3,5,3,3,5,4,6,6,6,6,4,2], -[1,3,2,4,6,5,7,5,5,5,3,4,4,4,6,5,6,6,5,5,5,3,5,2,3], -[1,3,3,4,4,3,5,3,4,5,3,5,2,4,4,4,6,8,7,9,7,5,5,0,3,2], -[0,4,5,5,5,3,2,2,2,1,4,3,5,4,4,5,4,6,8,6,8,5,4,4,2,3], -[1,6,5,6,4,4,4,1,2,2,3,5,5,5,6,4,5,6,3,6,3,4,5,5,5,5], -[0,5,6,5,3,5,3,5,3,4,4,4,5,5,5,5,5,2,4,0,3,2,4,6,7], -[0,7,6,5,4,5,3,7,6,6,7,4,5,4,4,4,4,3,3,1,1,1,2,4,5,6], -[1,7,5,5,5,3,5,5,6,7,5,7,5,4,5,2,4,3,3,4,4,4,6,5,5,5], -[0,4,6,3,6,5,5,5,6,5,6,6,5,6,2,5,1,3,3,3,6,7,6,6,5,2], -[1,4,2,6,6,7,8,6,6,5,4,5,6,3,6,3,3,4,3,5,5,5,6,3,3], -[1,3,1,3,4,5,7,6,7,5,4,5,4,4,5,4,5,6,5,6,5,4,6,2,4,2], -[0,4,4,4,3,4,3,4,4,3,6,2,5,4,4,5,6,7,8,7,7,6,2,4,0,3], -[1,4,4,6,4,3,2,2,1,4,2,6,4,5,6,5,7,7,7,9,6,5,4,2,3,3], -[0,4,7,4,5,4,2,2,2,2,3,3,5,6,4,6,5,4,6,2,5,3,4,5,5], -[0,5,6,5,5,5,3,6,3,4,3,3,3,4,4,5,5,3,5,1,3,0,3,4,5,7], -[1,7,6,5,4,2,6,3,6,5,5,5,4,4,4,4,4,4,3,4,1,3,4,4,6,6], -[0,5,5,4,3,4,3,5,5,5,6,5,5,4,2,4,1,3,3,3,4,5,5,5,5,4], -[1,6,3,6,5,5,6,5,6,6,6,6,6,3,5,1,3,1,2,4,4,6,7,6,4], -[1,4,2,5,3,6,7,6,6,4,4,4,4,3,6,3,4,2,2,4,4,6,6,5,5,4], -[0,3,4,3,5,7,5,7,5,5,5,3,4,3,3,5,5,4,6,5,6,5,3,5,1,3], -[1,3,4,5,4,4,5,4,4,6,3,7,4,5,5,5,6,8,8,9,7,4,5,-1,3], -[1,2,3,5,4,4,3,2,2,4,3,6,4,5,5,4,6,5,6,8,7,7,5,3,4,2], -[0,4,6,5,6,5,4,4,2,2,3,3,4,5,5,6,5,4,6,2,5,3,5,5,4,5], -[1,6,5,5,4,3,5,2,5,3,4,4,4,5,6,6,6,6,3,5,0,3,3,4,7,6], -[0,6,6,4,3,4,2,6,4,5,6,5,5,5,4,6,5,5,4,2,2,1,2,5,5], -[0,7,7,4,5,4,3,5,4,6,7,6,6,5,4,5,2,4,3,3,4,4,4,5,4,4], -[1,6,3,6,3,6,5,4,5,5,5,5,5,5,6,2,4,1,3,3,4,6,7,6,6,5], -[0,3,5,2,5,6,6,7,4,4,4,3,3,5,3,5,2,3,3,3,6,5,6,7,5,4], -[1,3,2,4,4,4,7,5,6,5,4,6,3,4,5,5,5,6,5,6,5,4,6,1,5], -[1,2,3,4,4,3,4,4,4,4,3,6,3,5,3,4,5,5,6,9,8,7,6,2,4,1], -[0,5,5,5,7,5,4,3,2,1,4,2,5,3,3,4,4,5,6,6,8,6,5,5,2,4], -[1,4,5,7,5,5,5,2,3,1,2,4,3,5,5,4,5,5,4,6,3,6,4,5,5,6], -[0,5,7,5,5,6,3,6,3,4,3,4,4,4,5,6,6,5,5,1,4,0,3,4,5], -[0,7,6,5,5,5,3,7,4,7,7,6,6,4,5,5,5,5,4,3,2,0,2,3,3,5], -[1,6,5,5,3,3,4,4,6,6,6,7,6,6,5,2,4,2,3,3,4,4,5,4,5,4], -[0,4,5,3,6,4,4,5,4,5,5,5,6,6,3,6,1,3,2,3,5,5,6,6,5,4], -[1,4,1,5,3,6,6,5,6,5,4,5,5,4,7,4,5,3,3,4,4,6,6,4,5], -[1,3,2,3,2,4,6,4,7,5,4,6,3,5,4,4,5,5,5,7,5,6,5,3,6,2], -[0,4,4,3,5,4,3,4,4,3,5,3,6,3,4,4,4,6,7,7,9,7,4,6,1,4], -[1,3,4,6,4,4,3,2,2,3,2,5,2,5,4,4,5,5,7,9,7,8,5,4,5], -[1,3,5,6,5,6,4,3,3,1,2,3,3,4,4,4,6,5,5,6,4,6,4,5,5,5], -[0,6,6,6,6,6,4,6,3,6,4,4,4,4,4,5,5,6,5,2,4,-1,3,3,4,6], -[1,6,7,6,5,3,5,3,6,5,6,6,4,5,4,4,6,5,4,3,2,3,2,3,5,5], -[0,7,7,5,5,4,4,5,4,5,6,5,6,4,3,5,1,4,2,3,3,4,4,5,5], -[0,5,5,3,6,4,6,5,5,6,6,6,6,7,5,6,2,5,0,2,3,4,6,6,5,5], -[1,4,2,5,2,6,6,6,7,6,6,5,5,5,6,4,5,3,3,3,2,5,4,5,6,3], -[0,4,3,2,4,4,5,7,5,6,6,4,5,3,4,4,4,6,5,5,6,5,5,5,2,5], -[1,2,4,4,3,3,4,3,4,5,3,6,2,5,3,5,6,7,7,9,8,7,6,2,4], -[1,1,5,5,5,5,3,2,2,1,2,4,2,5,3,4,5,4,6,7,7,9,5,5,4,2], -[0,5,4,5,7,5,5,4,1,3,2,2,4,3,4,5,4,5,5,4,7,2,6,3,4,5], -[1,5,5,6,5,4,6,3,6,3,4,3,3,3,4,5,6,5,5,5,1,4,1,4,5,5], -[0,7,6,5,4,4,2,6,3,7,5,4,5,3,4,4,5,5,4,3,3,1,2,4,4], -[0,7,6,5,5,3,4,4,4,7,5,6,7,5,5,5,3,5,2,4,3,3,4,5,4,5], -[1,5,4,6,3,6,5,5,5,5,6,6,6,7,7,3,6,0,3,1,2,5,5,7,7,5], -[0,4,5,3,6,5,7,7,6,6,5,5,5,5,5,5,3,4,2,3,3,4,6,5,5,5], -[1,4,3,4,3,5,6,5,7,5,5,6,4,5,5,5,6,5,6,6,5,6,5,3,5], -[1,2,4,4,4,4,4,4,5,4,4,6,3,7,3,5,4,5,7,8,8,9,7,4,5,1], -[0,5,4,5,7,6,5,4,2,3,3,2,6,3,5,4,4,6,5,7,8,7,7,5,4,5], -[1,2,5,6,5,7,5,4,4,2,3,4,3,4,4,4,6,5,5,7,3,6,3,5,5,5], -[0,6,5,5,5,5,4,6,3,6,2,3,4,3,4,6,6,6,6,3,5,0,4,3,5], -[0,6,6,6,5,4,3,5,3,7,4,6,6,4,5,4,5,6,5,5,4,1,3,1,3,4], -[1,5,6,6,4,5,4,3,5,5,6,6,6,7,6,4,5,3,5,2,4,4,4,5,5,5], -[0,5,6,3,7,4,6,6,5,6,5,5,6,5,5,6,2,4,0,3,3,4,6,6,6], -[0,5,4,2,5,2,6,6,6,6,5,5,5,5,6,6,4,6,3,4,3,4,5,5,6,6], -[1,4,4,3,2,4,4,5,7,5,6,6,3,5,4,5,4,4,5,6,6,7,6,5,6,3], -[0,6,3,5,5,4,4,4,4,5,5,4,6,2,5,2,4,4,6,6,8,8,7,6,2,5], -[1,2,6,6,5,6,5,4,3,1,2,5,2,5,2,3,4,3,5,7,7,8,6,6,6], -[1,3,6,6,5,7,5,6,5,2,3,2,2,3,3,5,5,5,5,5,4,6,3,6,3,4], -[0,5,5,5,6,5,6,6,4,8,4,6,5,4,5,6,6,7,7,5,5,0,4,0,4,5], -[1,5,6,6,5,5,5,3,7,5,8,6,6,7,4,5,6,5,6,5,4,4,1,3,3,4], -[0,6,6,5,6,4,5,4,5,6,6,7,7,5,6,6,3,5,2,4,3,4,4,4,4], -[0,6,5,4,5,3,6,4,6,6,5,5,6,7,7,7,4,6,1,5,1,3,4,6,6,6], -[1,4,3,4,1,6,4,7,6,5,6,5,5,6,6,6,7,5,5,2,4,5,4,6,6,5], -[0,6,3,3,4,3,6,6,5,7,6,5,6,4,6,4,5,6,5,6,7,6,6,6,3,6], -[1,2,5,4,5,5,4,3,4,4,4,5,2,6,2,4,4,5,7,8,8,10,8,5,6], -[1,2,6,4,6,6,5,4,3,2,2,3,2,5,2,4,3,3,5,6,7,9,7,8,6,4], -[0,5,4,5,7,6,7,5,3,5,2,3,3,3,4,4,5,6,5,5,6,3,6,3,5,5], -[1,5,6,7,5,6,6,4,7,3,7,4,4,4,3,5,5,6,6,6,2,5,0,4,4,6], -[0,7,7,7,6,5,4,5,3,7,4,6,5,4,5,4,4,6,4,5,4,2,3,2,3], -[0,6,6,7,7,4,5,3,4,6,5,7,7,6,6,6,5,6,2,5,2,3,4,4,4,4], -[1,4,5,6,4,7,4,7,6,6,6,6,6,7,7,6,7,2,5,1,3,3,4,5,6,5], -[0,5,4,3,5,3,8,7,8,8,6,6,6,6,6,7,5,5,2,3,3,3,5,5,4], -[0,6,4,3,3,2,4,4,5,7,5,6,6,4,6,3,5,4,5,6,6,6,6,6,5,6], -[1,3,5,2,4,4,3,3,4,3,4,5,3,6,2,5,3,4,5,6,8,9,8,7,6,2], -[0,5,2,6,6,6,6,5,3,3,2,3,5,3,6,3,4,4,4,7,7,6,8,6,5,4], -[1,3,5,5,6,7,5,4,5,2,3,2,3,4,3,5,5,5,6,6,4,7,2,7,4], -[1,6,6,6,6,6,5,5,6,3,7,2,5,3,4,5,5,6,6,6,5,6,1,4,2,5], -[0,6,6,7,6,4,4,5,3,6,3,7,5,5,5,4,5,7,6,7,6,5,4,2,4,5], -[1,5,7,5,5,6,3,4,4,4,6,6,6,6,6,6,6,4,6,2,5,4,4,5,5,5], -[0,6,5,4,7,4,7,5,7,7,6,7,6,6,7,7,4,6,1,3,1,3,4,5,7], -[0,7,5,4,5,3,7,5,7,8,7,7,5,5,6,6,6,6,4,5,3,3,4,5,6,6], -[1,5,6,3,3,4,4,5,6,5,6,6,4,6,4,6,4,6,5,6,6,7,5,6,6,3], -[0,7,3,6,4,5,5,4,5,5,5,5,6,3,7,3,5,4,5,6,7,8,9,7,4,6], -[1,2,6,4,6,7,5,5,4,3,4,4,4,6,3,5,3,3,5,6,7,8,7,7,5], -[1,4,6,4,6,7,6,6,5,3,5,2,4,3,3,4,4,4,6,5,5,6,3,6,3,5], -[0,5,6,6,5,5,5,5,3,7,2,7,3,5,5,5,6,7,7,7,6,3,5,0,4,3], -[1,6,7,6,6,5,3,3,5,2,8,4,6,6,4,6,5,6,7,6,6,4,2,4,2], -[1,5,6,6,7,7,4,5,4,4,6,5,6,6,6,7,6,4,6,2,5,2,4,4,4,5], -[0,5,4,5,6,3,7,4,7,5,5,6,5,6,7,7,6,7,2,5,1,4,4,5,6,6], -[1,6,5,4,3,5,3,7,6,7,7,6,5,5,5,6,6,5,6,2,4,4,4,6,6,5], -[0,6,4,4,3,3,5,5,6,7,6,7,6,4,7,4,6,4,5,6,6,5,6,6,5], -[0,7,3,6,4,6,5,5,4,5,5,5,5,4,6,2,6,2,4,4,6,8,8,8,7,7], -[1,3,7,4,8,7,7,7,5,3,3,2,3,5,2,5,2,4,3,4,6,7,7,8,6,6], -[0,6,4,7,6,6,8,6,6,6,3,4,3,4,5,5,5,6,6,6,6,4,6,3,6,4], -[1,6,6,6,6,6,6,5,7,4,7,3,7,4,4,5,6,6,8,7,6,6,1,5,1], -[1,5,6,7,8,6,5,4,5,4,8,4,8,6,6,6,5,5,6,5,7,5,4,4,2,3], -[0,4,5,7,6,5,6,3,5,5,5,7,6,7,8,6,6,6,4,6,3,5,4,4,6,5], -[1,5,6,5,4,6,3,7,4,6,5,5,7,7,7,7,8,5,6,1,5,2,4,5,5,6], -[0,6,4,3,4,2,6,5,7,7,7,7,6,6,7,7,7,7,5,5,3,4,4,5,6], -[0,6,4,5,3,3,4,4,5,6,5,7,6,5,6,3,7,4,5,6,6,6,7,6,6,6], -[1,4,7,3,6,5,5,4,4,4,4,4,4,6,2,5,1,4,3,5,7,7,9,9,8,5], -[0,6,2,7,5,7,7,5,5,4,2,4,4,4,6,3,4,3,4,5,6,7,9,7,7,6], -[1,5,6,5,7,7,6,6,5,3,5,2,4,4,3,5,4,5,6,6,5,6,3,7,4], -[1,7,7,7,7,7,6,7,5,5,7,3,7,3,5,4,3,5,6,6,7,6,3,5,1,5], -[0,5,6,8,7,6,6,4,4,6,3,8,4,7,5,4,5,5,6,7,6,5,5,2,4,3], -[1,5,7,6,7,6,4,5,4,5,6,5,7,6,7,6,6,5,7,3,5,3,4,4,4], -[1,5,5,5,5,5,4,8,5,9,7,7,7,7,7,9,8,7,7,3,6,1,3,3,4,5], -[0,5,5,4,3,2,5,3,8,7,7,8,7,6,7,6,7,6,6,7,3,4,3,4,5,6], -[1,6,5,4,4,4,3,5,5,6,7,6,6,7,4,7,3,6,4,6,6,6,6,7,6,5], -[0,6,3,7,3,5,4,4,4,4,4,5,5,4,7,3,6,3,5,6,7,9,9,7,7], -[0,7,3,7,3,7,6,6,6,4,3,4,3,3,6,3,6,3,4,4,5,7,7,7,9,6], -[1,6,6,4,7,6,6,8,6,5,6,3,5,3,3,4,4,5,6,6,6,6,5,7,3,7], -[0,5,6,7,6,6,6,5,5,7,3,7,2,5,3,3,5,6,7,8,7,6,6,2,6,2], -[1,6,6,6,7,6,4,4,4,3,6,3,7,4,4,5,4,6,7,6,7,6,4,5,3], -[1,5,6,5,7,6,5,7,4,5,5,5,7,6,7,7,6,6,6,4,7,2,5,3,4,5], -[0,5,5,5,5,5,7,4,8,5,7,6,6,7,7,7,7,7,4,6,0,4,1,4,6,6], -[1,7,6,5,4,5,3,7,5,7,7,6,6,6,6,7,6,7,6,4,5,3,3,4,5,6], -[0,6,5,5,3,4,4,4,6,6,6,7,6,6,7,4,7,4,6,6,6,6,6,6,5], -[0,6,3,7,3,6,4,5,5,5,5,5,5,6,7,3,7,2,5,4,5,7,7,7,8,6], -[1,5,7,3,7,5,7,8,7,6,5,4,4,5,4,6,2,4,3,3,5,5,6,8,6,7], -[0,5,4,6,4,7,7,6,7,6,3,5,3,5,4,4,5,5,5,6,5,5,6,4,7], -[0,3,6,6,6,6,6,5,5,5,4,7,2,7,3,5,4,5,7,7,7,7,7,4,6,1], -[1,5,4,7,7,6,5,5,4,4,6,4,8,5,6,5,5,6,5,6,8,5,6,4,3,4], -[0,3,4,7,6,6,6,4,6,4,5,6,6,7,7,7,7,6,5,7,3,6,3,5,5,5], -[1,5,5,5,5,6,4,7,4,7,5,6,6,6,6,8,8,6,7,2,6,1,4,3,5], -[1,7,6,5,5,3,3,5,3,8,5,7,7,6,6,7,7,8,8,7,7,4,5,4,5,7], -[0,6,6,6,4,4,3,3,5,5,6,6,6,6,7,5,7,4,6,5,6,7,7,6,7,7], -[1,5,8,4,8,5,7,6,5,5,5,5,5,6,5,6,2,5,2,4,5,6,7,8,7,7], -[0,6,4,8,5,8,7,7,7,5,4,4,4,4,6,4,6,3,4,4,5,6,7,7,9], -[0,6,6,6,4,7,6,7,8,6,5,5,3,5,3,4,5,4,6,6,5,6,6,4,7,3], -[1,7,5,6,7,7,6,7,7,6,8,4,8,3,7,4,4,5,6,7,8,6,5,6,2,5], -[0,2,6,6,7,7,6,5,5,5,4,7,4,7,5,6,5,4,5,7,6,7,5,4,4,3], -[1,5,5,6,7,6,5,6,3,6,5,5,7,6,7,7,6,6,6,3,7,2,5,3,5], -[1,6,5,5,5,4,4,6,3,8,4,7,6,6,8,8,8,9,9,5,7,2,5,2,4,5], -[0,5,6,5,3,3,3,2,7,4,8,6,6,7,6,6,7,7,8,7,5,5,3,4,5,5], -[1,7,6,5,6,4,4,4,4,6,5,6,6,6,5,6,3,7,3,6,6,6,7,6,6,6], -[0,6,4,7,4,7,5,5,5,4,4,5,4,5,6,3,6,1,5,3,6,7,8,8,8], -[0,7,5,7,3,7,5,7,7,6,5,4,3,4,4,4,6,3,4,3,4,5,6,6,8,6], -[1,7,6,6,7,6,8,8,7,7,7,4,6,3,5,4,5,5,5,5,5,5,5,6,3,7], -[0,4,7,6,7,7,6,6,6,6,5,8,3,7,2,4,4,4,6,6,7,7,7,3,5,2], -[1,7,5,8,9,8,6,6,4,4,6,4,8,4,6,4,4,5,6,6,7,6,5,5,2], -[1,5,3,6,7,6,6,6,4,7,4,6,7,6,8,7,7,8,7,5,7,2,6,2,5,5], -[0,4,5,5,4,5,5,4,8,4,8,6,7,7,7,8,9,8,8,8,4,5,0,5,4,4], -[1,6,6,4,4,4,2,6,3,8,6,8,7,6,6,7,7,8,7,6,7,3,5,3,5], -[1,5,6,5,6,2,4,2,3,5,4,5,6,5,6,6,5,7,4,7,5,6,6,7,7,7], -[0,6,5,7,3,7,4,6,4,4,4,4,4,5,6,4,7,2,6,2,5,5,6,8,8,7], -[1,6,6,3,7,5,8,7,7,7,5,4,4,4,5,6,4,6,2,4,4,4,6,6,6,8], -[0,5,5,5,4,7,7,7,8,6,5,5,3,5,2,4,4,4,5,6,5,7,6,4,7], -[0,3,8,5,7,7,7,6,5,5,5,7,3,6,2,5,2,3,5,5,7,8,7,6,6,2], -[1,6,4,7,7,7,7,6,4,5,4,4,7,4,8,4,5,5,4,6,7,5,7,5,5,5], -[0,3,5,6,5,7,6,5,6,3,5,5,6,6,6,6,7,6,6,7,3,7,2,5,4,4], -[1,6,5,6,6,5,5,7,4,8,5,7,6,6,6,7,7,8,8,5,6,0,4,2,5], -[1,6,6,6,5,4,4,4,3,7,4,7,6,6,6,6,7,7,7,8,7,5,6,3,5,5], -[0,6,7,7,5,6,3,4,5,4,5,5,6,7,6,5,7,4,7,4,7,6,6,7,7,6], -[1,6,6,4,7,4,8,5,6,6,5,6,6,6,6,7,4,6,2,5,3,5,6,7,7,7], -[0,5,4,6,3,8,6,8,8,7,6,5,4,5,4,4,6,3,4,3,4,5,5,7,7], -[0,6,7,5,5,6,5,7,7,7,6,6,4,6,2,5,4,4,5,5,5,6,6,5,7,3], -[1,7,4,7,6,7,6,6,5,6,6,4,8,3,7,3,5,5,5,6,8,7,7,6,3,6], -[0,2,7,5,7,8,6,5,5,4,5,6,4,8,4,6,5,5,6,6,6,7,5,6,5], -[0,4,5,4,6,7,6,7,6,3,6,4,6,6,6,6,6,7,6,6,5,7,3,6,2,5], -[1,5,5,6,5,5,4,5,4,7,4,8,4,6,6,6,7,8,8,8,8,4,7,2,5,5], -[0,5,7,5,5,4,3,2,5,3,7,4,6,6,6,6,7,7,8,7,7,7,4,6,4,5], -[1,6,6,6,6,3,5,3,4,5,5,7,6,5,6,6,4,7,3,6,5,6,6,7,6], -[1,7,6,5,7,3,8,5,7,5,5,5,5,5,5,6,4,6,1,5,1,4,5,6,8,8], -[0,8,7,7,4,8,5,8,7,7,7,5,4,4,4,4,5,3,4,2,3,3,4,5,6,6], -[1,7,5,5,6,5,7,7,8,8,6,6,6,4,6,3,4,5,4,5,6,5,5,6,4,6], -[0,3,7,4,6,7,6,6,6,6,6,7,4,8,3,6,3,4,6,5,6,7,6,5,5], -[0,1,6,3,7,8,7,7,6,4,5,5,4,7,4,7,4,5,5,4,5,6,5,7,4,4], -[1,4,3,6,5,6,7,6,5,5,3,6,5,6,7,6,7,7,6,7,7,4,7,2,6,4], -[0,5,5,5,5,5,3,3,6,3,7,4,7,6,6,7,7,8,9,8,6,6,1,5,2,5], -[1,6,6,6,4,3,3,4,3,7,5,8,6,6,6,6,6,9,7,9,6,5,5,3,5], -[1,5,5,6,6,4,5,3,4,3,4,6,5,5,6,6,5,6,3,7,4,7,6,7,7,7], -[0,6,6,6,4,7,3,8,4,6,4,4,5,4,5,4,5,3,6,1,5,3,5,7,8,8], -[1,7,6,4,6,3,8,5,8,7,6,5,4,4,5,5,4,6,3,4,3,4,5,5,7,8], -[0,5,7,5,5,6,6,7,7,7,7,6,4,6,2,5,3,5,4,5,6,5,6,5,7], -[0,4,8,4,8,7,7,7,7,6,6,6,5,7,2,6,2,4,3,4,6,6,6,6,6,3], -[1,6,2,7,6,8,9,6,5,5,4,4,6,4,8,4,5,4,4,6,5,6,7,5,5,4], -[0,3,5,4,5,7,6,7,7,4,6,4,6,6,6,7,7,6,7,6,5,7,2,6,3,5], -[1,4,5,5,5,4,5,5,4,8,4,8,5,7,7,6,7,8,8,7,7,3,5,1,5], -[1,4,6,6,4,4,3,2,2,5,3,7,5,7,6,5,6,7,6,9,6,7,6,4,6,4], -[0,6,6,6,5,5,2,4,2,3,4,4,6,6,5,5,6,4,7,2,7,4,5,6,6,6], -[1,7,6,5,6,3,8,3,7,5,5,5,5,6,6,7,5,6,2,5,2,4,4,6,7], -[1,7,6,6,6,3,7,4,8,6,7,6,5,5,5,4,5,5,3,5,2,4,3,5,6,7], -[0,5,7,5,5,6,5,7,6,7,7,6,5,6,2,5,2,4,4,4,4,5,5,5,5,4], -[1,6,3,7,5,7,6,6,6,5,5,6,6,4,7,2,5,2,4,5,5,7,7,7,5,6], -[0,2,6,3,7,7,7,6,5,4,5,5,5,7,4,6,4,4,5,5,6,6,6,6,5], -[0,4,5,4,6,6,7,8,7,5,6,3,6,5,5,7,6,7,7,6,5,6,3,6,1,6], -[1,4,5,5,5,5,5,5,4,7,3,7,4,7,5,5,6,7,7,9,8,6,7,1,5,3], -[0,6,6,6,6,5,3,3,3,2,6,4,7,5,5,5,6,6,8,6,8,6,5,6,4,5], -[1,5,6,6,5,4,5,2,4,4,4,6,6,6,7,5,6,7,4,7,3,7,5,5,6], -[1,6,5,5,6,3,6,3,8,4,6,6,5,5,6,6,6,7,3,6,1,4,2,5,6,7], -[0,7,6,5,4,5,3,8,5,8,7,6,5,5,4,5,5,5,6,3,4,2,3,5,5,6], -[1,7,5,7,4,4,6,4,7,6,6,6,6,4,5,2,5,3,5,5,5,6,5,5,4,6], -[0,3,7,3,7,5,6,6,5,5,4,6,4,7,2,7,2,4,4,4,6,6,7,6,5], -[0,3,5,2,7,6,8,7,6,5,5,4,4,5,5,7,3,6,3,4,5,5,5,6,5,5], -[1,4,3,5,4,6,7,6,6,6,3,6,3,5,5,5,6,5,6,7,6,5,6,3,6,3], -[0,6,6,5,5,5,3,4,5,3,6,2,7,4,5,5,6,7,9,7,7,7,3,6,1,6], -[1,5,6,6,5,3,3,2,2,4,3,8,4,6,6,5,6,6,6,8,7,6,6,4,6], -[1,4,6,7,5,5,5,3,4,3,4,5,4,6,6,5,5,6,4,6,3,7,4,6,6,6], -[0,7,6,6,5,6,4,8,4,7,5,5,5,4,5,5,5,4,5,1,4,0,4,4,6,7], -[1,7,6,5,5,4,8,4,9,6,7,6,5,4,4,5,5,5,4,5,2,4,3,4,5], -[1,6,5,7,4,5,5,4,7,6,8,7,6,6,5,3,6,2,5,4,5,5,5,5,5,5], -[0,3,6,2,7,5,7,7,7,7,6,6,7,7,4,7,2,5,2,4,5,5,7,7,5,4], -[1,4,1,6,3,8,7,7,7,5,4,5,4,5,7,4,6,3,4,4,4,5,6,5,7,4], -[0,4,5,3,5,5,5,6,5,4,6,2,5,4,5,6,5,6,6,6,6,6,3,6,2], -[0,5,4,5,5,5,4,4,3,3,6,3,7,3,7,5,6,7,8,8,9,8,6,6,1,5], -[1,3,6,6,5,4,4,2,3,2,2,6,4,6,4,5,5,5,6,8,7,8,6,5,5,4], -[0,6,6,6,7,6,3,5,1,4,3,4,5,4,4,5,5,4,5,2,6,2,7,5,6,6], -[1,6,6,6,5,4,7,3,8,4,5,4,4,4,5,5,5,6,3,5,1,5,3,5,7], -[1,7,7,7,5,4,5,2,8,5,8,6,5,5,4,4,5,5,4,5,3,4,2,4,5,6], -[0,6,7,4,7,4,5,6,5,8,7,7,7,5,4,6,2,5,2,3,4,3,5,4,5,4], -[1,5,3,7,4,8,6,7,7,6,5,5,6,5,7,2,6,1,4,3,4,6,6,6,6,5], -[0,3,6,2,7,6,8,7,6,5,4,4,4,6,4,6,3,5,3,3,4,5,5,5,3], -[0,4,4,3,5,4,6,6,6,6,6,4,6,4,6,5,6,7,6,6,6,5,4,6,2,6], -[1,2,4,4,4,4,4,3,4,5,3,7,3,7,4,5,5,6,7,8,8,7,6,3,6,1], -[0,5,5,6,6,5,3,3,1,2,4,3,7,4,6,4,4,6,6,6,8,5,6,5,3,5], -[1,4,5,6,5,5,5,1,3,2,3,4,4,5,6,6,6,6,4,7,2,7,4,6,6], -[1,6,6,5,4,4,6,2,7,2,6,4,5,5,5,5,5,6,5,6,2,5,1,4,5,6], -[0,7,6,5,5,5,3,6,4,8,7,6,6,4,5,4,4,5,5,3,4,2,4,3,4,6], -[1,6,5,6,3,5,4,4,7,6,6,6,6,5,5,3,5,2,5,4,4,6,5,5,5]] - - -let sunData: [[Int8]] = [[4,3,3,2,3,3,2,2,1,1,1,1,1,3,3,6,5,8,6,8,7,7,6,5], -[4,2,1,1,2,2,3,3,4,4,6,5,7,6,7,5,5,5,6,4,5,5,5,5], -[5,5,4,4,4,6,5,6,6,7,6,6,4,4,3,2,1,0,0,1,3,3,5,6], -[8,7,9,7,7,6,5,4,3,1,1,1,1,2,1,2,2,2,2,4,3,5,4,6], -[5,7,6,6,5,5,4,3,2,2,2,2,3,5,7,7,8,7,8,6,6,4,4,3], -[3,3,3,4,4,6,5,6,7,8,7,9,8,9,9,9,9,9,8,8,6,5,5,3], -[4,2,3,3,5,5,8,7,9,8,9,8,8,6,6,6,4,5,5,6,6,7,6,7], -[6,7,5,6,4,4,3,4,3,3,2,2,3,2,4,3,5,5,7,8,10,9,11,9], -[11,8,7,5,4,2,0,0,-1,0,0,1,2,5,5,7,6,8,7,8,8,8,8,8], -[7,7,6,5,4,3,3,1,3,2,3,3,5,5,6,5,6,5,4,4,3,4,3,5], -[5,7,6,8,8,10,8,8,6,5,3,2,2,1,1,0,0,0,1,0,1,1,3,3], -[5,5,6,6,7,7,6,4,3,1,0,-2,-3,-3,-3,-2,-2,0,0,3,2,4,3,4], -[2,2,2,3,3,2,3,2,2,1,1,0,1,1,2,1,3,3,4,4,4,4,3,3], -[2,1,0,1,-1,1,1,4,4,6,6,6,5,6,4,4,2,2,2,2,2,2,3,2], -[3,2,4,2,4,3,5,4,5,5,6,5,5,4,3,2,0,-1,-1,0,-1,2,2,5], -[5,7,6,7,6,5,3,2,2,0,0,0,0,1,2,2,3,2,3,3,4,4,5,5], -[7,6,7,6,5,4,3,3,1,2,0,2,2,5,5,8,7,9,8,8,6,5,5,4], -[5,3,4,5,6,6,7,7,7,7,8,6,7,7,8,8,8,7,7,7,7,6,5,5], -[4,4,5,6,7,9,10,10,9,10,8,8,7,5,4,2,3,2,5,4,6,6,8,6], -[8,6,8,6,6,5,6,6,5,5,4,4,3,3,1,2,1,4,3,6,6,9,8,9], -[8,8,6,5,4,3,3,2,3,2,4,3,6,6,7,7,7,7,7,6,7,6,6,6], -[6,6,5,5,4,4,3,5,4,6,7,8,9,9,8,8,7,6,5,4,3,2,3,2], -[4,4,6,5,7,7,8,7,7,6,6,5,6,5,5,5,4,4,3,3,2,3,3,5], -[4,6,5,6,6,5,5,3,3,0,0,-1,0,0,1,2,5,4,7,5,7,5,6,5], -[4,3,1,2,0,0,-1,0,0,1,-1,1,0,2,3,5,6,8,7,8,8,7,7,5], -[5,3,3,1,2,1,2,1,3,3,5,4,5,5,5,5,4,5,4,5,5,5,4,6], -[5,5,4,5,5,5,4,4,4,3,2,3,2,1,1,-1,0,-2,0,0,2,3,5,6], -[7,8,8,7,7,6,4,3,1,0,-1,-1,-2,-1,-1,0,-1,1,1,2,3,4,4,5], -[5,6,7,5,6,4,5,3,3,1,1,0,1,2,3,4,5,5,5,5,3,3,2,2], -[2,2,2,4,4,5,6,7,7,8,8,8,8,7,6,6,5,5,5,4,4,2,3,1], -[3,2,4,3,6,7,8,8,9,9,8,8,6,6,4,3,1,2,1,3,3,5,5,7], -[5,7,5,5,4,4,4,3,4,3,3,2,3,3,3,3,4,3,5,5,6,7,8,8], -[8,7,6,5,2,2,1,1,0,2,2,4,5,6,7,8,8,8,7,7,7,7,7,6], -[7,5,7,5,5,4,5,3,4,5,6,6,7,8,8,9,7,7,5,5,4,4,3,4], -[3,5,6,8,9,9,9,9,7,6,5,4,4,2,3,3,3,2,3,2,3,3,4,5], -[5,5,6,7,7,7,6,6,4,3,1,1,-1,1,0,2,2,4,4,6,6,7,6,5], -[5,4,3,1,2,1,3,2,3,1,3,2,3,3,4,4,5,6,6,6,6,7,5,5], -[3,3,1,2,0,1,1,3,4,6,7,8,7,7,7,5,5,3,5,4,4,4,5,4], -[6,4,5,4,5,4,4,4,4,4,4,5,5,4,3,3,1,1,-1,1,1,3,4,6], -[7,8,8,6,6,4,3,1,1,-2,0,-1,0,0,3,2,4,4,5,5,6,6,6,7], -[7,8,6,7,5,5,3,3,1,0,0,1,1,3,5,6,9,8,9,8,8,6,6,4], -[5,3,5,4,4,4,5,5,5,5,5,5,5,5,5,6,6,7,6,7,6,6,5,6], -[4,5,4,6,7,8,9,9,9,7,7,5,4,2,2,0,1,1,2,3,5,6,7,8], -[9,8,7,7,6,6,5,4,2,3,1,1,0,0,-1,0,0,2,3,4,5,7,7,8], -[9,7,7,5,5,2,4,2,3,2,3,3,4,4,5,5,4,5,5,5,4,5,4,6], -[4,5,5,5,5,5,5,6,6,6,6,6,7,7,6,5,5,2,3,1,2,0,1,1], -[3,3,5,6,7,8,8,9,7,6,5,5,3,4,2,3,0,1,0,0,0,1,1,2], -[3,3,4,4,5,5,6,4,4,2,2,0,1,0,1,2,3,3,4,4,5,4,4,4], -[3,3,1,2,1,0,1,1,1,2,3,3,4,4,5,5,7,7,8,6,7,6,6,4], -[4,1,3,1,1,1,2,4,4,6,7,8,8,9,7,7,5,5,4,5,4,5,4,5], -[5,6,6,6,5,5,6,5,6,5,6,4,5,4,4,2,3,1,2,2,3,4,5,7], -[7,8,8,8,7,7,5,5,2,2,0,2,1,2,3,3,4,5,5,5,5,5,6,5], -[8,6,7,6,7,5,6,4,5,3,4,3,5,6,6,8,9,10,9,9,7,7,5,5], -[3,3,2,4,4,5,6,8,8,8,9,9,9,8,8,7,8,7,8,6,7,6,6,5], -[4,4,4,5,5,7,6,8,8,8,7,8,6,6,4,4,3,4,3,5,6,8,8,8], -[9,8,8,6,6,3,3,2,3,1,1,0,1,2,3,3,4,5,6,7,7,8,9,10], -[8,8,5,5,3,1,-1,-1,-2,-1,0,2,3,4,6,6,8,7,8,6,7,6,7,6], -[7,6,7,6,6,5,4,5,4,4,3,5,4,6,6,6,6,5,4,4,3,4,3,4], -[5,5,6,7,8,8,9,6,7,4,3,1,1,-1,0,-1,1,0,1,1,2,3,3,5], -[4,5,5,6,6,6,4,5,2,2,0,-1,-2,-2,-2,-1,0,2,3,4,5,5,6,4], -[4,2,3,1,2,1,2,2,2,3,2,3,2,3,2,4,3,4,4,6,5,6,4,5], -[3,3,1,1,0,2,2,3,5,5,7,7,7,6,6,3,4,1,1,1,2,2,4,4], -[4,5,5,5,5,6,5,5,5,5,4,5,4,4,3,2,0,0,-1,-1,0,2,4,5], -[7,6,8,7,8,5,5,3,2,0,1,0,1,2,2,3,5,5,4,5,4,4,3,5], -[4,5,4,6,4,5,4,4,3,3,3,4,5,6,8,8,9,8,10,8,9,6,6,4], -[4,3,3,3,5,6,7,9,8,10,8,9,9,9,8,9,8,9,7,8,7,7,6,6], -[5,4,6,6,7,7,9,8,9,8,9,7,6,5,4,4,4,3,4,5,6,7,8,9], -[8,9,8,8,6,6,5,5,3,3,3,3,3,3,4,4,4,5,6,6,8,7,9,8], -[9,7,8,5,5,4,3,3,2,3,3,5,5,7,7,8,7,8,7,7,6,6,6,6], -[5,6,5,5,5,6,6,6,7,6,8,6,8,8,8,7,7,5,6,4,4,3,3,4], -[4,6,5,7,7,7,7,8,6,6,4,4,3,3,3,3,2,3,2,3,3,3,5,4], -[6,4,5,3,5,3,3,2,2,0,0,-1,0,-1,0,2,3,5,6,8,7,8,7,7], -[5,5,3,3,1,1,0,1,0,0,1,2,3,3,4,4,6,5,8,7,8,7,8,6], -[6,4,3,2,2,3,1,3,2,4,4,5,5,5,5,4,2,3,2,3,3,5,5,5], -[7,7,8,7,8,7,7,5,6,4,4,2,2,1,1,0,0,0,-1,1,2,3,4,8], -[7,9,9,10,9,8,6,4,2,1,0,-1,-2,-1,0,1,3,2,4,4,5,4,6,4], -[6,5,6,5,7,6,6,5,5,4,3,4,3,5,4,6,6,7,6,7,6,6,4,4], -[3,3,3,3,4,6,8,9,10,10,10,9,9,7,8,5,5,5,4,4,5,5,5,5], -[4,5,4,6,5,7,8,9,9,10,8,8,7,5,4,3,3,1,2,3,4,5,8,7], -[9,8,8,6,6,5,4,3,3,3,3,3,3,5,4,5,5,6,5,7,6,8,7,9], -[8,8,7,5,5,3,3,2,3,2,4,5,7,8,10,9,10,8,9,6,7,5,5,5], -[5,6,6,6,6,7,6,7,7,8,6,9,8,9,9,9,8,7,6,6,4,3,4,3], -[5,5,7,7,10,10,10,9,9,7,7,5,4,4,3,4,3,5,4,4,4,5,4,5], -[4,6,5,6,6,6,6,5,4,4,2,2,2,1,2,3,4,5,8,7,8,7,7,6], -[5,3,3,2,2,2,2,3,3,5,5,6,5,7,6,8,7,8,7,9,8,8,7,6], -[5,3,3,2,1,1,3,4,6,7,8,8,9,8,7,6,6,4,3,4,4,4,5,6], -[6,7,5,7,6,6,5,5,4,5,4,4,4,4,4,4,4,3,3,2,3,4,6,6], -[8,8,9,8,7,6,4,3,1,1,-1,0,0,2,2,4,5,7,6,8,7,8,6,6], -[5,5,4,5,4,4,4,2,3,1,2,2,4,4,6,6,9,9,10,8,9,8,7,6], -[5,5,4,4,4,6,6,8,7,9,8,8,7,6,6,7,6,6,7,6,7,7,8,7], -[8,6,8,7,8,7,8,7,8,6,5,4,3,2,1,2,1,1,2,4,5,7,8,10], -[9,10,9,8,7,6,5,4,3,2,1,1,2,1,2,1,3,2,5,5,7,7,9,8], -[9,9,8,7,5,5,4,4,3,4,2,4,4,5,5,6,5,6,5,5,4,5,5,4], -[5,5,6,5,6,6,8,6,8,7,8,6,7,6,6,5,4,4,2,2,1,2,1,3], -[3,5,4,7,7,9,8,9,7,7,5,4,4,2,2,1,2,1,1,1,2,2,4,3], -[5,3,4,4,4,4,3,4,2,3,1,1,0,2,2,3,3,6,5,6,7,7,5,5], -[4,3,1,1,1,0,1,1,3,2,4,4,6,6,8,7,8,6,7,7,7,7,6,6], -[5,4,3,4,2,3,3,4,5,6,7,9,8,8,8,7,6,6,5,4,5,5,6,6], -[7,7,9,8,9,7,8,6,6,5,4,4,4,4,3,4,3,4,3,4,4,5,5,8], -[7,9,9,10,9,9,8,6,5,2,2,1,2,2,4,5,7,7,8,7,8,7,7,6], -[6,6,6,6,5,7,6,7,6,7,5,7,6,7,8,9,10,10,10,10,9,8,7,5], -[4,3,4,3,5,5,8,8,11,11,11,11,11,10,8,8,7,7,6,7,7,8,6,8], -[6,8,6,7,6,7,7,7,7,7,7,7,6,5,5,3,3,2,4,3,6,7,9,8], -[9,8,8,5,4,3,2,1,1,1,0,2,1,4,3,5,4,6,6,8,7,8,8,9], -[9,8,7,5,5,3,3,1,2,1,3,3,6,6,8,8,8,8,7,6,6,6,6,6], -[5,6,6,7,6,6,5,6,5,6,4,5,5,6,6,5,5,5,4,3,3,2,3,3], -[5,5,7,7,10,9,10,8,7,6,4,3,1,0,0,1,1,2,1,3,3,5,5,6], -[5,6,6,6,6,6,5,5,4,2,2,-1,-1,-1,0,0,2,2,5,5,6,7,7,7], -[6,5,4,3,3,3,2,4,3,5,4,5,4,5,5,5,4,5,4,6,6,6,6,5], -[6,4,5,4,5,4,6,6,7,8,8,8,9,7,6,5,3,3,1,1,0,3,3,5], -[6,8,8,9,9,8,8,7,7,5,5,4,4,3,4,2,3,1,1,0,2,2,5,4], -[6,7,8,8,7,8,6,6,3,4,2,2,3,4,4,6,7,7,7,7,6,6,6,5], -[5,4,5,4,6,4,5,5,6,6,7,7,8,9,10,11,11,11,10,10,9,9,6,6], -[4,5,3,4,5,6,7,8,9,10,11,11,11,11,10,9,10,8,9,7,9,8,8,8], -[8,7,8,7,8,9,8,9,8,8,7,7,6,7,5,5,4,5,5,8,8,10,10,11], -[11,11,9,8,8,6,5,3,4,3,4,2,4,4,5,5,7,8,9,9,9,10,9,10], -[9,9,8,8,6,7,4,5,3,5,4,7,7,8,9,10,10,10,9,8,9,7,7,6], -[7,6,7,6,7,7,8,8,8,8,8,8,8,8,7,7,6,7,5,5,4,4,3,5], -[4,5,5,6,7,7,8,8,8,5,6,3,3,2,2,2,4,3,4,4,5,6,6,6], -[6,5,5,4,3,4,2,3,2,3,1,1,0,2,1,3,4,6,6,8,8,7,8,6], -[5,3,3,0,0,-1,0,-1,0,0,3,3,5,5,6,6,6,6,6,6,6,7,6,7], -[5,5,4,4,3,4,3,4,4,5,6,6,7,6,6,5,5,3,3,2,3,3,6,5], -[7,8,9,9,9,9,7,6,4,4,2,2,1,2,1,2,1,2,2,2,3,4,5,6], -[8,8,10,9,9,7,7,5,5,2,1,-1,0,1,2,3,5,6,7,8,7,8,7,7], -[5,6,5,7,6,7,6,7,7,7,6,6,6,6,6,6,8,7,9,8,9,7,7,5], -[6,4,5,4,6,6,8,10,11,11,11,11,9,8,6,6,4,5,3,5,5,6,6,8], -[7,7,7,7,8,8,9,8,9,8,8,6,6,4,4,2,3,1,2,2,5,6,7,9], -[9,9,8,8,5,6,4,4,3,4,2,4,4,5,5,6,5,6,6,6,7,7,7,7], -[8,7,7,5,6,4,4,3,3,4,5,6,8,9,9,10,9,9,7,7,5,5,4,5], -[4,6,5,7,7,8,8,8,9,8,8,8,8,8,9,8,9,7,6,5,5,4,4,4], -[4,5,6,7,8,9,8,9,8,7,4,4,2,3,2,3,3,5,5,6,7,7,8,7], -[7,5,6,4,5,4,5,3,4,2,3,2,2,2,2,4,5,7,8,10,9,11,9,9], -[7,6,3,4,2,2,2,3,3,4,5,6,7,7,7,7,7,7,8,7,8,7,8,7], -[7,5,6,5,5,4,5,6,6,7,7,8,7,8,7,7,4,4,3,4,4,5,6,8], -[8,9,9,9,9,8,8,6,6,4,4,3,3,2,2,2,3,2,3,2,3,5,5,7], -[7,8,7,8,6,7,5,5,2,2,0,1,1,2,3,4,6,6,8,8,8,7,7,6], -[6,5,5,4,5,5,6,5,5,5,6,7,7,8,8,9,8,9,8,9,8,9,6,7], -[5,5,4,5,5,6,7,8,9,8,9,9,9,8,8,6,6,5,6,5,6,6,7,7], -[8,8,8,8,7,8,8,8,7,7,6,6,4,5,3,3,2,3,3,5,6,7,8,9], -[10,10,11,8,8,6,5,4,3,2,2,1,2,3,3,4,5,6,6,7,6,8,7,8], -[8,9,7,8,6,6,6,6,5,4,5,5,6,6,8,7,8,7,7,6,6,4,5,4], -[5,4,5,6,7,9,9,10,9,10,8,9,7,8,6,6,4,5,3,3,2,2,2,3], -[3,4,5,6,8,8,9,9,9,7,6,4,4,2,2,1,2,1,3,3,4,5,4,5], -[4,4,3,4,3,4,3,4,3,4,3,3,3,3,3,4,5,5,7,7,8,7,7,5], -[5,4,3,1,2,1,2,2,3,4,6,7,8,9,8,9,8,8,6,7,6,7,6,6], -[6,6,4,4,4,4,6,5,7,7,8,8,10,9,10,8,7,6,5,4,4,4,5,7], -[7,9,9,10,9,10,8,8,6,6,4,4,4,4,5,5,6,6,6,5,7,6,7,7], -[9,7,9,8,8,7,7,6,5,4,3,2,3,4,5,7,8,10,10,12,11,10,8,8], -[6,6,5,6,6,6,6,6,8,7,8,7,8,8,9,9,11,10,12,11,12,11,11,9], -[7,6,5,4,5,6,7,9,10,11,10,10,8,9,7,7,5,6,6,6,7,8,8,9], -[9,8,9,7,7,6,7,5,6,5,5,4,4,3,3,3,3,3,4,4,6,9,9,11], -[10,11,9,9,7,5,2,3,1,1,1,2,2,3,4,4,5,5,7,6,7,7,8,8], -[8,7,7,6,5,4,3,2,1,2,2,4,4,6,6,7,7,7,5,6,4,5,4,5], -[4,4,5,5,7,6,9,8,8,7,7,6,6,5,5,5,5,4,4,3,2,2,3,4], -[4,6,6,8,7,9,8,8,6,6,3,3,0,0,0,0,1,2,3,3,5,5,6,6], -[6,5,6,4,5,4,4,3,3,2,1,1,1,1,1,3,3,6,5,7,8,8,7,8], -[6,6,4,3,3,2,3,3,4,4,5,6,7,7,7,5,6,5,6,4,6,6,7,6], -[6,6,5,6,6,6,6,8,7,8,8,9,7,8,6,5,3,2,2,1,1,2,4,4], -[7,7,9,9,10,9,9,7,7,5,5,4,3,3,2,3,2,3,3,4,3,4,3,5], -[4,7,6,7,7,7,7,6,6,4,4,4,4,4,5,5,8,7,9,8,9,7,7,5], -[4,3,4,3,4,4,5,6,7,8,8,10,9,11,10,11,9,10,9,9,8,8,7,6], -[6,4,4,4,6,5,8,8,11,10,12,11,11,10,10,8,8,7,7,7,7,7,8,9], -[8,9,8,9,8,8,7,7,6,7,6,6,6,5,5,4,5,5,6,6,8,8,10,10], -[11,10,10,9,8,6,5,4,2,3,2,3,3,5,6,8,7,9,9,10,9,10,9,9], -[9,9,8,7,7,6,6,5,5,4,5,6,7,7,9,9,10,9,9,7,8,6,6,6], -[5,5,5,6,6,9,8,9,8,9,7,8,6,6,6,6,5,5,5,4,5,4,5,4], -[6,5,8,6,8,8,8,7,7,5,4,2,1,0,0,1,0,2,3,4,5,7,6,7], -[5,6,3,3,2,2,1,1,1,0,1,0,1,1,1,2,3,3,5,6,7,7,8,7], -[7,5,4,3,1,1,1,1,1,3,4,5,5,6,6,7,5,5,3,5,5,5,6,6], -[6,6,7,5,6,4,6,5,5,4,6,5,6,6,5,5,4,2,2,2,1,2,2,5], -[6,8,9,10,10,10,9,7,5,4,3,2,1,1,1,1,3,2,5,4,5,4,6,5], -[7,7,8,8,8,8,7,6,5,4,3,3,2,2,3,6,6,9,7,10,9,8,7,6], -[6,5,5,5,5,6,7,7,9,7,9,8,9,8,9,8,9,8,9,8,9,8,7,7], -[6,6,5,5,5,7,8,10,11,12,11,11,10,9,7,6,5,4,4,4,5,5,7,6], -[8,7,9,7,8,7,8,7,8,7,6,6,5,5,4,4,2,3,3,4,5,7,7,8], -[7,9,7,6,6,5,4,3,3,2,3,4,5,5,7,6,8,7,8,6,6,6,6,6], -[6,6,5,5,4,5,4,4,4,5,6,7,8,9,10,10,10,9,7,7,5,4,4,2], -[3,2,4,4,6,6,8,8,8,8,9,7,7,8,7,7,7,6,6,5,4,4,3,4], -[4,5,4,6,6,7,7,7,6,6,4,4,3,2,3,2,4,5,6,6,8,7,9,7], -[7,5,5,3,2,3,2,2,2,2,1,2,1,4,4,5,5,7,7,9,9,10,10,9], -[8,6,5,3,2,1,2,2,3,4,5,6,7,8,8,8,8,7,7,7,7,8,8,9], -[7,8,7,7,6,7,6,6,6,6,6,6,5,6,5,4,4,3,3,2,4,3,5,5], -[8,8,9,8,9,8,8,6,4,3,2,1,0,1,0,1,2,3,3,5,4,6,6,7], -[6,7,6,6,6,6,7,4,5,3,3,1,2,2,4,4,5,6,8,8,8,8,8,7], -[5,5,3,4,3,3,4,5,5,6,6,7,6,7,7,6,7,6,6,6,7,7,7,5], -[6,4,6,4,6,5,7,6,8,8,8,8,7,7,6,5,4,4,3,4,3,6,5,8], -[8,10,9,10,8,7,6,6,5,3,3,2,2,1,2,1,2,2,3,3,5,6,8,8], -[10,10,9,8,7,6,5,4,1,2,0,1,0,2,4,5,5,7,6,7,7,6,6,7], -[7,7,7,6,8,6,6,5,7,5,5,4,6,6,7,7,7,6,6,6,4,4,3,4], -[3,5,4,6,7,9,9,11,10,9,8,7,6,4,4,3,3,2,2,1,3,2,3,2], -[3,3,5,5,6,7,7,9,7,7,4,4,2,2,0,1,0,2,2,4,4,6,5,5], -[5,4,4,2,2,2,2,1,4,2,4,3,4,3,5,4,5,5,6,6,7,7,7,7], -[5,4,2,2,0,1,0,2,3,5,6,8,8,9,9,8,8,7,6,5,5,4,5,4], -[5,4,6,5,7,6,6,7,7,7,8,8,9,9,8,8,6,6,4,4,3,3,3,6], -[5,7,8,10,8,9,8,6,6,4,4,2,3,2,5,4,6,6,7,7,8,7,7,7], -[7,7,6,7,7,6,6,6,4,4,3,4,3,5,5,8,9,11,11,12,11,11,11,8], -[7,5,5,3,5,4,5,5,7,7,8,8,8,9,9,9,9,10,9,10,9,9,8,8], -[7,6,5,6,5,7,7,8,9,9,10,8,8,7,7,4,5,3,4,4,6,6,8,8], -[10,10,10,10,9,8,7,7,5,5,3,3,2,2,2,2,1,2,2,4,5,6,8,9], -[8,8,8,6,6,4,3,1,2,0,1,0,2,2,4,4,5,5,5,5,5,5,4,5], -[4,6,5,5,4,5,3,4,4,5,4,6,6,7,7,7,7,6,5,4,3,2,3,1], -[3,2,3,4,5,7,7,8,8,7,6,6,4,4,3,3,2,3,1,3,2,3,2,4], -[3,4,4,4,5,5,6,4,6,3,3,1,1,-1,0,0,1,2,4,4,6,7,7,7], -[6,6,4,4,2,2,1,1,0,2,0,1,1,2,3,4,4,5,5,6,7,8,8,7], -[8,5,6,3,4,2,3,2,4,3,5,6,6,6,6,7,5,6,4,5,4,5,4,6], -[5,7,6,8,7,8,8,8,7,6,6,5,6,5,5,3,4,2,2,1,2,1,3,4], -[6,6,8,9,10,9,9,9,7,6,3,3,2,1,1,3,2,3,4,5,4,5,5,5], -[5,5,5,5,5,4,6,5,6,5,5,4,5,4,5,6,7,8,8,8,8,8,7,6], -[3,4,2,3,2,3,4,6,6,8,9,10,10,10,10,9,10,8,8,7,8,7,7,6], -[6,4,5,3,4,4,6,7,8,9,9,10,9,9,7,8,6,5,4,5,4,6,7,7], -[8,9,8,7,7,6,6,4,4,3,4,2,4,4,5,5,6,5,6,6,7,9,9,10], -[9,10,7,8,6,5,3,2,0,1,0,2,3,4,6,7,8,9,10,9,8,8,8,6], -[7,5,7,5,5,4,5,4,4,4,5,5,6,7,7,9,8,9,7,8,7,6,5,5], -[4,4,5,6,7,7,8,8,8,6,6,4,4,3,3,2,3,2,3,2,4,3,5,5], -[4,4,4,4,4,5,4,5,3,3,0,0,-2,-2,-3,-2,-2,0,1,3,4,5,7,6], -[6,4,4,2,2,1,1,0,0,0,1,1,2,1,1,2,2,3,3,5,5,6,5,6], -[4,4,2,3,1,1,1,1,2,2,4,4,5,6,5,4,4,2,2,1,1,1,2,2], -[4,4,5,5,5,6,6,7,5,6,4,5,4,5,4,4,2,2,0,1,0,0,2,3], -[4,6,8,7,9,7,8,6,5,3,2,0,0,-1,0,1,3,3,5,5,5,6,4,6], -[5,5,4,6,4,5,5,5,3,4,2,3,3,3,4,6,7,8,9,8,10,8,9,6], -[7,4,4,3,4,4,6,6,7,8,8,8,8,8,7,7,7,7,6,8,7,8,7,7], -[6,7,6,5,6,7,9,8,10,9,10,8,8,6,5,3,3,2,3,2,4,5,6,8], -[8,10,8,9,8,8,7,7,5,6,3,4,2,2,2,2,1,1,2,3,4,4,6,6], -[8,6,8,6,7,4,5,3,3,2,3,3,4,5,5,5,6,6,5,5,4,5,3,4], -[3,4,3,4,3,4,4,5,5,5,7,7,8,8,9,8,8,6,6,3,4,2,3,1], -[2,2,2,3,4,6,7,8,8,9,7,8,6,7,5,5,4,4,3,4,3,3,3,3], -[4,3,4,3,4,4,5,4,4,3,4,2,2,1,1,2,3,4,5,7,7,8,7,8], -[5,6,3,3,1,1,0,0,0,0,1,2,4,4,6,6,8,7,9,8,9,9,10,7], -[8,6,5,3,3,2,2,2,2,4,4,5,6,8,8,8,7,7,6,6,5,5,6,6], -[6,6,7,6,7,7,8,6,7,5,5,3,4,3,5,3,4,3,3,2,3,3,4,6], -[6,8,8,9,9,10,8,8,6,5,2,2,0,0,-1,0,2,3,4,5,6,6,6,5], -[6,5,5,4,5,4,4,4,3,3,3,2,2,3,2,4,4,6,6,8,7,8,6,5], -[4,3,2,2,2,2,4,4,7,6,8,8,9,8,8,6,7,4,5,4,5,5,5,5], -[4,5,4,4,4,5,5,7,6,9,8,8,6,6,4,4,2,2,1,1,2,2,4,5], -[7,6,8,6,6,5,5,3,4,2,2,2,2,1,2,2,2,3,3,4,3,5,5,7], -[6,8,6,7,5,5,3,2,2,0,0,1,3,3,5,5,7,6,7,6,6,5,5,4], -[4,4,4,4,4,5,4,5,5,6,5,6,5,7,7,8,6,7,5,5,4,4,3,2], -[3,2,3,4,6,6,9,8,9,7,8,6,5,3,3,2,2,2,2,3,3,4,3,4], -[4,4,3,5,4,5,4,5,5,5,2,2,1,0,-1,-1,1,1,3,4,6,6,7,5], -[6,4,3,1,1,0,0,0,1,1,2,3,3,4,4,5,3,5,4,6,5,6,5,6], -[5,5,3,3,2,1,2,2,3,3,6,7,8,8,9,7,7,5,4,3,2,3,3,4], -[4,5,5,6,6,7,6,7,6,7,5,6,6,6,5,5,5,4,3,2,2,1,3,4], -[5,5,7,7,8,7,8,5,5,3,3,2,1,2,2,3,5,7,6,8,7,9,7,8], -[6,6,4,4,4,4,3,3,4,2,3,3,4,5,6,7,9,8,10,10,11,10,9,7], -[7,5,4,2,2,3,3,4,5,6,7,8,7,9,8,9,8,8,8,9,8,9,9,8], -[9,7,7,6,7,6,7,6,7,6,7,5,5,4,4,2,3,2,2,3,4,5,6,8], -[8,10,8,9,6,7,5,3,2,1,0,-1,-1,-1,-1,-1,0,1,2,2,4,4,7,6], -[7,6,6,6,5,4,3,3,1,1,0,1,1,2,2,3,3,4,3,4,4,4,3,3], -[3,2,3,2,3,4,4,4,5,4,5,4,5,4,5,4,4,3,3,1,1,0,0,0], -[0,1,1,4,3,6,6,7,6,8,6,5,3,2,1,0,1,0,1,0,1,0,2,2], -[4,3,4,3,3,3,3,3,3,2,2,1,0,-1,-1,0,-1,1,2,4,3,6,5,6], -[4,4,3,2,1,0,0,-1,1,0,1,2,3,3,4,4,5,4,5,4,6,6,6,6], -[5,5,4,4,3,3,2,4,3,5,5,7,6,7,7,8,6,5,4,3,2,2,3,3], -[5,5,7,7,8,8,9,8,8,7,6,5,5,4,4,3,3,3,2,2,1,2,1,4], -[3,5,6,8,8,9,9,7,7,6,4,3,2,1,2,2,3,3,5,6,7,6,6,5], -[5,3,3,3,3,4,4,6,5,6,5,6,5,6,6,7,6,8,7,8,8,8,7,6], -[5,3,2,2,2,1,3,4,7,7,10,9,11,10,9,8,7,6,6,5,5,5,5,6], -[5,6,4,6,4,6,5,7,7,8,7,8,7,7,7,5,5,3,4,3,4,4,6,6], -[8,8,9,7,7,5,5,3,3,2,1,2,2,3,3,4,3,5,5,7,5,7,7,8], -[6,7,6,5,5,4,3,1,1,-1,1,0,3,4,7,7,9,9,10,8,8,7,6,6], -[5,5,3,4,4,5,4,5,4,6,4,5,5,5,6,7,7,7,7,6,6,4,4,2], -[3,2,4,3,5,5,6,6,6,5,5,3,2,1,0,1,0,1,2,3,3,4,4,5], -[4,5,4,5,4,3,4,3,3,1,1,-1,-1,-3,-2,-3,-2,0,3,3,6,5,6,7], -[6,5,3,2,1,1,-1,0,-1,0,-1,1,1,2,2,2,2,3,2,4,3,4,5,4], -[6,3,4,2,3,2,3,2,3,3,5,4,6,5,5,5,5,3,2,1,0,1,1,3], -[3,5,5,6,6,7,7,7,6,5,4,4,3,3,3,2,3,1,1,1,1,0,2,2], -[4,4,6,5,6,6,6,6,4,4,2,1,0,1,1,2,2,5,4,6,6,7,6,6], -[5,4,3,3,3,3,4,3,5,3,5,4,5,4,6,7,8,7,9,8,9,9,8,7], -[5,5,3,4,2,3,3,6,6,8,8,9,9,9,8,8,7,6,7,5,6,5,6,6], -[7,6,7,6,7,7,7,8,8,8,7,7,7,6,4,4,2,2,1,3,3,4,4,6], -[7,8,8,8,7,6,6,4,4,3,3,1,2,1,3,2,2,2,4,3,5,5,5,5], -[5,6,5,5,4,4,3,4,2,3,2,3,3,5,5,6,7,7,6,5,5,4,3,2], -[3,1,2,1,3,2,5,5,6,6,8,7,8,8,7,7,6,6,5,4,3,3,1,2], -[0,2,1,2,2,4,5,6,7,7,6,5,5,4,4,2,3,2,3,2,4,3,4,4], -[4,3,3,2,2,2,2,3,1,2,1,1,1,1,1,2,2,4,4,6,7,9,9,8], -[7,6,5,2,1,-1,0,-2,-1,-1,1,1,2,4,5,6,7,6,7,6,7,7,7,8], -[6,7,5,5,3,4,2,2,2,3,3,5,5,6,7,7,7,6,6,4,5,4,5,4], -[7,6,9,9,10,9,10,9,7,6,4,3,2,1,1,2,1,3,2,4,3,5,4,5], -[5,7,7,7,8,8,8,6,6,2,2,-2,-1,-2,-2,-1,1,1,4,5,7,7,6,7], -[5,5,3,4,3,4,3,4,4,5,3,4,3,3,3,3,4,5,6,6,7,7,7,5], -[6,4,3,2,3,2,3,5,6,6,8,8,7,8,6,5,4,3,2,3,2,4,3,5], -[4,5,4,5,5,6,5,6,7,6,7,5,6,4,4,1,1,0,0,0,2,2,4,5], -[7,7,7,7,6,6,4,4,1,2,0,1,0,2,1,3,2,3,3,3,4,4,5,5], -[6,5,6,4,5,3,3,2,2,1,2,1,3,4,6,7,7,7,7,6,5,5,3,3], -[2,3,2,4,4,6,6,6,6,7,7,7,7,7,7,6,7,5,6,4,5,3,4,1], -[2,1,4,4,5,6,7,9,8,8,6,6,4,4,2,2,1,2,2,3,3,4,4,5], -[5,4,4,4,4,3,4,3,5,3,4,1,2,0,1,1,2,1,4,4,6,6,7,7], -[5,5,3,3,1,2,0,1,1,3,3,5,5,6,6,6,6,5,5,4,5,4,5,4], -[5,3,4,2,3,3,3,4,4,6,7,8,9,9,9,9,7,6,4,3,2,2,1,2], -[2,4,4,6,6,7,8,8,8,7,8,6,6,5,6,5,5,5,5,3,4,3,4,4], -[4,5,4,5,5,6,4,6,4,4,3,3,2,3,3,5,6,7,7,9,9,9,9,7], -[6,3,3,2,2,1,2,2,3,3,4,4,6,7,7,9,9,11,11,12,11,11,9,10], -[7,7,4,4,3,3,3,4,4,5,7,7,8,8,8,7,8,7,7,7,7,7,8,7], -[8,7,7,7,6,6,6,6,4,4,3,3,2,3,2,2,1,2,1,2,3,4,6,7], -[8,9,9,8,8,7,6,4,3,1,0,-1,-1,-3,-1,0,1,1,2,3,4,5,5,6], -[6,6,5,6,4,5,3,2,1,2,0,1,1,1,3,3,4,3,4,3,4,2,3,1], -[2,1,2,1,3,3,4,5,5,6,6,6,5,5,3,4,3,3,2,3,1,1,0,1], -[0,1,1,2,3,4,6,6,7,5,6,3,3,1,0,-1,-1,-2,0,0,2,2,3,4], -[4,3,3,3,1,1,0,2,0,2,0,1,0,0,0,1,1,2,2,3,4,5,6,6], -[6,5,4,1,1,-1,0,-1,-1,0,1,2,4,5,6,6,6,6,5,5,4,5,4,6], -[5,6,4,5,4,4,4,4,4,4,5,5,7,6,8,6,8,6,6,3,3,3,3,3], -[4,5,6,8,8,10,9,10,8,8,5,5,3,3,3,4,3,4,3,4,4,4,4,5], -[6,5,6,6,8,7,8,7,8,5,5,3,2,1,2,2,3,5,6,8,8,9,8,8], -[5,5,4,4,2,4,3,5,5,6,7,7,7,6,7,7,7,7,8,7,9,7,8,7], -[6,4,4,3,3,3,4,6,7,9,9,11,10,10,9,9,6,6,5,5,4,5,5,6], -[6,5,6,5,6,6,6,6,7,7,7,7,7,6,6,4,4,3,2,2,3,4,5,6], -[6,8,6,7,5,5,3,3,2,2,1,2,2,3,4,4,6,6,7,6,7,6,6,6], -[7,5,5,4,4,3,3,1,1,0,1,2,4,5,7,8,8,10,8,8,6,6,5,4], -[2,2,1,2,2,2,4,4,6,5,6,4,6,5,7,5,7,5,6,5,5,5,5,5], -[4,3,4,5,5,6,6,8,6,6,4,3,1,1,0,0,-1,0,1,3,4,5,6,6], -[7,5,6,3,4,3,3,2,1,0,0,-1,-2,-2,-2,-1,-2,1,1,3,4,7,7,8], -[6,7,4,5,3,2,2,1,1,1,2,2,3,4,4,4,4,3,4,2,4,3,5,5], -[5,4,5,5,5,6,5,6,6,7,5,6,5,7,5,5,4,4,1,1,0,0,0,1], -[2,3,5,6,9,8,10,9,10,7,7,5,4,3,2,2,1,1,2,1,2,3,2,4], -[3,5,5,6,5,7,6,7,5,5,4,4,3,2,2,3,4,5,6,6,8,7,8,6], -[6,4,4,2,3,2,3,4,4,5,5,6,6,8,7,9,8,9,8,9,8,8,8,8], -[6,6,4,3,4,3,5,5,8,7,10,9,10,10,10,8,8,7,6,5,6,5,6,7], -[7,8,7,8,7,9,8,8,6,7,6,6,5,5,4,4,4,3,3,3,4,4,6,6], -[8,8,10,8,9,7,6,5,4,2,2,1,2,1,2,4,4,6,5,6,5,7,5,7], -[5,5,4,6,5,5,5,4,4,4,4,3,5,6,7,7,8,7,8,6,6,5,5,3], -[2,2,1,2,2,4,5,8,7,9,8,9,8,8,6,7,6,6,4,5,4,4,3,2], -[2,1,3,2,4,4,7,6,8,7,8,6,6,4,3,2,2,2,3,3,4,6,5,7], -[5,5,3,4,2,1,1,1,1,1,1,2,3,3,4,3,4,4,6,5,7,7,8,7], -[7,6,5,3,2,0,-1,0,-1,0,1,3,5,8,8,10,9,10,7,8,7,7,7,7], -[6,7,6,5,6,4,6,4,6,4,6,5,7,7,8,8,8,7,6,5,5,4,3,4], -[4,6,6,8,7,9,8,8,7,6,4,3,2,1,1,1,3,3,4,4,5,5,6,5], -[6,6,6,6,7,6,6,6,5,3,2,1,1,0,0,1,2,5,5,8,8,10,9,9], -[6,6,4,4,3,2,4,3,4,4,5,4,5,4,6,5,5,5,6,5,7,7,7,7], -[6,5,4,4,3,4,4,6,6,9,8,9,8,8,6,6,4,3,2,2,2,2,4,4], -[6,6,7,7,8,7,8,7,7,6,7,5,5,3,2,2,0,1,0,1,1,2,3,5], -[5,7,6,7,6,6,5,4,2,1,1,1,1,2,3,2,4,3,4,4,5,4,5,4], -[4,3,4,4,4,4,3,4,3,4,3,4,5,7,7,8,7,8,7,7,5,4,3,3], -[2,2,2,2,3,3,6,6,8,7,8,7,8,6,7,6,6,6,5,5,4,4,3,4], -[2,4,3,4,4,6,6,7,7,7,6,6,4,3,2,1,2,1,3,3,5,5,7,6], -[7,5,6,4,4,4,3,3,2,2,2,2,1,2,1,2,2,4,4,6,6,8,8,8], -[7,6,5,4,3,2,2,1,3,2,4,3,5,6,8,7,7,6,6,6,5,5,5,5], -[5,6,5,6,5,7,6,7,7,8,7,8,7,8,8,8,7,6,5,4,3,2,3,2], -[4,4,6,6,8,8,9,9,9,8,7,6,5,4,3,4,3,5,4,5,5,6,5,6], -[5,6,5,5,5,5,5,5,5,4,5,3,4,4,5,5,6,6,9,9,10,11,11,9], -[7,6,4,3,2,2,1,3,2,5,5,6,7,8,8,9,9,10,9,10,9,9,9,8], -[7,6,6,3,4,2,4,3,6,6,8,7,9,8,8,8,6,6,5,5,5,6,6,7], -[7,9,8,10,8,9,8,8,6,5,4,4,4,3,2,1,3,1,2,2,4,4,6,7], -[8,7,9,7,8,7,6,5,2,2,-1,0,-2,0,0,1,2,3,4,5,4,5,5,5], -[4,4,5,4,5,4,5,4,5,3,4,3,4,4,5,5,6,5,6,5,5,4,3,3], -[1,2,1,3,3,4,5,7,8,9,7,8,6,6,4,4,3,2,3,1,2,1,2,1], -[2,1,3,2,4,4,6,6,6,7,6,6,4,3,1,0,-2,0,-1,1,2,4,4,6], -[5,5,4,4,2,2,2,1,2,1,2,1,3,2,4,2,3,2,4,3,5,6,6,6], -[6,6,5,5,2,2,1,2,1,3,3,5,6,8,9,9,9,7,7,5,5,4,4,3], -[5,3,5,5,7,6,7,7,9,8,9,8,9,9,9,9,8,8,6,6,4,3,2,4], -[3,5,5,8,9,11,11,11,10,9,8,7,5,5,5,4,5,5,6,6,7,7,7,6], -[6,5,5,6,6,6,7,8,6,7,5,5,3,5,4,5,6,8,8,10,10,11,11,9], -[9,6,5,4,3,2,5,4,6,6,8,8,9,9,10,10,10,10,10,9,9,9,9,9], -[7,7,5,5,4,5,5,7,7,9,11,11,10,10,9,8,7,6,6,4,6,4,6,6], -[8,6,8,8,8,7,7,7,7,6,5,6,5,5,4,5,3,4,3,5,4,6,7,7], -[8,7,7,7,6,4,5,2,3,0,1,0,2,2,4,5,6,6,7,7,7,7,7,7], -[5,5,3,4,2,3,2,3,2,3,3,4,4,6,7,8,8,9,9,8,8,7,6,4], -[5,3,4,2,4,4,5,6,7,7,7,6,7,6,5,5,5,6,4,5,4,5,4,5], -[4,5,4,5,5,5,5,5,5,4,3,2,2,0,0,-1,0,-1,2,2,5,6,7,7], -[8,7,7,6,4,4,2,2,1,1,0,0,-1,1,1,2,1,2,3,4,5,6,7,7], -[8,7,7,6,5,3,3,2,2,2,3,3,5,5,6,7,6,6,5,4,3,3,3,4], -[4,6,4,7,6,8,8,9,9,9,8,8,7,7,7,5,6,4,4,3,2,1,2,2], -[3,4,5,6,8,10,10,11,10,9,7,6,4,4,2,2,1,3,2,4,4,5,5,5], -[6,5,4,4,5,4,6,5,6,5,6,5,4,4,5,4,6,6,7,7,8,9,8,8], -[6,6,3,4,2,3,2,4,4,6,7,9,8,10,10,10,9,9,8,8,8,7,7,6], -[7,5,6,4,5,5,6,6,7,8,9,10,10,11,9,10,7,7,5,5,4,5,5,6], -[6,7,8,9,10,9,9,8,7,6,6,5,5,4,5,4,5,3,4,4,4,5,5,7], -[7,7,7,8,7,8,6,7,4,4,2,3,2,3,3,5,6,7,7,8,7,6,7,5], -[6,3,5,3,4,4,6,5,6,6,6,6,6,6,7,8,8,9,8,8,6,6,4,4], -[2,2,1,2,3,5,6,8,10,10,11,10,9,7,7,6,5,4,5,5,6,4,6,4], -[4,3,4,3,4,4,4,7,6,7,6,6,4,4,2,2,1,2,2,4,4,6,8,8], -[7,6,6,4,3,1,2,0,1,0,2,2,4,3,4,5,5,6,6,6,7,8,9,9], -[8,9,6,6,3,3,2,1,1,2,2,4,6,7,9,8,9,8,8,6,7,4,5,5], -[6,5,6,5,6,6,6,6,6,7,6,6,5,6,5,6,6,7,5,5,4,5,3,4], -[5,5,7,8,10,10,11,10,10,7,6,4,3,1,2,1,3,2,5,5,6,7,7,8], -[7,7,6,7,5,6,5,6,5,5,3,3,1,2,2,3,3,5,6,7,8,9,9,8], -[9,6,7,4,4,3,4,4,5,6,7,7,8,8,7,8,7,7,6,6,6,7,6,8], -[6,7,5,6,6,7,7,7,9,9,10,9,9,8,7,5,5,3,3,1,2,2,4,4], -[6,6,7,8,8,9,8,8,7,8,6,6,4,4,3,3,1,2,1,1,2,3,4,4], -[6,5,7,6,6,5,6,4,5,3,4,3,4,3,4,5,5,7,6,6,5,5,4,4], -[2,3,2,3,2,3,3,4,5,6,6,6,7,8,9,9,10,8,9,7,7,5,4,2], -[1,1,1,1,2,4,5,7,8,10,9,9,9,9,7,7,5,7,4,5,4,5,4,4], -[4,4,4,3,5,5,6,6,7,5,6,4,5,4,3,3,3,2,4,4,5,6,7,9], -[8,7,5,6,4,4,2,3,1,2,2,3,3,4,4,5,6,6,7,7,7,7,8,7], -[8,7,7,5,5,5,5,3,3,4,5,6,7,8,9,10,9,10,8,8,5,6,4,5], -[4,4,5,6,7,8,9,9,10,10,10,9,9,8,8,7,8,6,7,5,5,4,4,4], -[4,4,4,6,6,8,9,11,9,10,8,8,5,5,4,4,4,5,5,6,8,9,9,8], -[8,6,5,4,4,3,4,4,4,3,5,4,5,5,5,6,6,8,8,9,9,10,9,9], -[7,6,3,3,1,1,1,2,3,4,5,6,9,9,9,8,9,8,9,8,9,8,9,8], -[8,7,8,6,5,6,5,6,6,8,7,8,8,8,7,7,6,6,4,5,4,4,5,6], -[7,8,10,9,10,8,8,6,6,3,2,1,1,0,1,1,1,2,2,3,3,4,5,7], -[7,8,8,8,7,8,6,4,3,2,0,0,-1,0,1,2,4,4,6,6,6,5,6,5], -[6,2,5,4,4,5,5,5,5,5,4,4,4,4,4,5,4,6,4,5,4,5,4,3], -[2,2,1,2,4,4,7,8,9,9,9,7,7,5,4,3,2,1,2,1,2,3,3,4], -[4,5,4,5,4,5,5,7,6,7,5,5,3,2,1,0,-1,-1,-1,0,2,4,6,6], -[7,5,6,4,4,2,2,2,2,2,2,3,4,5,4,5,4,5,4,5,4,5,4,6], -[4,6,4,4,4,4,3,4,4,4,6,6,8,9,10,10,11,8,8,5,5,3,3,2], -[3,3,4,5,6,7,8,10,9,11,9,10,9,10,8,9,8,8,6,6,5,4,4,3], -[4,4,6,7,9,9,10,9,10,8,9,6,6,4,5,4,5,6,7,8,8,9,8,9], -[7,8,5,6,5,5,5,6,6,5,6,6,5,6,7,7,8,9,10,10,11,11,11,9], -[9,7,7,4,4,4,4,5,6,7,8,9,9,10,10,11,10,10,8,9,8,8,8,7], -[8,7,7,6,7,6,8,8,10,9,11,10,11,9,9,8,7,5,5,5,5,4,4,6], -[7,8,7,9,8,9,8,8,6,7,5,6,4,3,3,3,4,3,3,3,4,4,6,5], -[6,5,6,5,6,5,4,4,3,3,3,3,3,4,5,6,6,8,7,8,6,7,5,5], -[4,3,3,2,2,3,3,3,4,4,6,6,7,6,8,7,8,7,8,6,7,5,5,3], -[3,2,1,2,1,3,3,6,6,8,7,7,6,5,4,5,4,3,3,3,4,4,5,4], -[6,5,6,5,5,4,5,4,5,3,4,3,3,1,1,0,0,1,1,3,4,7,6,8], -[8,9,6,6,5,4,3,1,1,0,-1,0,1,1,3,3,4,3,5,5,6,6,7,6], -[7,7,6,6,5,6,5,5,4,5,3,5,4,7,6,7,6,7,6,5,4,4,4,3], -[4,4,6,6,9,9,10,10,12,10,10,8,7,5,6,5,5,4,4,3,4,3,2,3], -[3,4,5,7,6,9,9,10,10,10,8,6,4,4,3,2,1,2,4,4,5,6,7,6], -[7,5,5,4,4,4,4,6,5,6,6,6,6,6,6,6,5,7,6,8,7,9,7,7], -[6,5,4,3,2,2,3,3,6,6,9,9,10,10,11,10,10,8,8,6,6,6,5,6], -[5,6,4,6,4,6,5,7,7,9,9,10,10,10,9,9,8,6,4,4,4,3,4,4], -[6,6,8,8,9,8,8,7,6,4,4,4,4,4,4,5,4,5,5,6,5,6,5,6], -[5,6,5,5,6,5,5,4,4,3,3,2,3,3,5,5,8,8,10,8,8,7,7,5], -[4,3,3,3,2,4,3,6,5,7,6,7,7,8,7,9,9,10,9,9,8,7,6,4], -[5,2,2,2,3,3,6,6,9,8,10,8,8,6,6,4,4,4,4,5,4,5,4,6], -[4,5,4,5,3,4,4,5,5,5,4,4,3,3,2,1,1,1,3,3,5,6,8,8], -[8,8,6,6,4,2,1,1,0,0,0,2,2,4,4,6,5,5,5,5,5,5,5,5], -[6,4,5,4,4,2,3,1,3,2,4,4,5,6,8,8,8,8,7,5,4,4,3,3], -[2,4,3,6,5,7,8,9,9,9,7,8,7,6,6,5,5,4,5,4,5,3,4,3], -[4,3,6,6,7,7,7,7,7,6,4,4,2,2,1,2,1,3,3,6,6,7,7,8], -[7,7,5,5,4,4,5,3,4,3,4,3,4,3,4,4,6,5,7,7,8,8,9,9], -[8,8,6,5,4,4,3,4,5,7,6,7,7,8,7,7,6,7,5,5,5,5,6,5], -[7,5,7,6,8,6,9,7,9,8,9,8,8,6,5,4,3,3,1,2,1,3,2,4], -[5,7,7,8,8,9,8,8,7,6,5,3,3,2,2,0,1,0,2,1,3,3,4,4], -[4,4,4,5,4,5,4,6,4,4,3,3,2,3,4,5,5,5,5,5,5,4,4,3], -[3,1,1,0,2,2,4,4,7,6,8,7,8,8,8,7,7,6,6,6,5,4,3,2], -[1,2,0,2,1,4,4,7,8,9,9,9,9,8,6,5,5,3,3,2,4,3,5,3], -[5,5,6,4,5,4,4,4,3,5,4,4,4,4,3,3,2,3,2,5,4,6,7,8], -[7,8,7,5,5,3,3,2,2,1,2,2,4,4,6,7,8,8,8,7,8,7,7,7], -[6,7,6,6,5,6,4,6,5,6,5,8,7,9,9,10,10,10,9,8,7,5,5,3], -[4,3,5,5,7,8,10,11,11,11,11,10,8,7,7,7,6,7,6,7,6,7,6,6], -[5,6,5,6,6,8,9,8,9,7,7,5,6,3,4,2,3,3,5,6,8,9,9,8], -[8,7,5,4,3,3,3,4,3,4,4,5,4,6,6,7,7,7,8,8,8,9,9,8], -[8,6,6,4,4,2,4,3,4,5,7,7,9,9,9,8,8,7,6,6,5,5,5,6], -[5,6,5,6,5,6,5,6,6,7,7,6,6,6,7,5,5,2,3,1,2,1,2,3], -[5,6,7,7,8,8,7,7,5,5,2,2,1,1,1,2,2,3,2,4,3,4,4,4], -[5,4,5,4,5,4,5,3,4,2,2,0,1,0,3,3,5,6,7,6,6,6,5,4], -[2,2,0,2,1,2,3,5,5,6,6,7,6,6,6,6,7,6,6,5,5,4,4,2], -[3,1,2,1,3,4,6,7,8,9,8,8,6,6,4,3,1,1,0,1,2,3,3,4], -[4,5,4,4,4,4,4,4,5,4,5,3,3,2,2,-1,0,-1,1,1,3,4,6,6], -[7,7,5,6,3,3,2,3,1,2,2,3,3,5,5,6,6,6,5,5,4,4,4,4], -[5,4,5,3,5,4,5,4,6,5,7,7,8,9,8,9,9,9,7,6,4,4,2,2], -[1,3,2,5,5,8,8,9,10,10,11,10,9,7,8,6,6,5,5,4,5,4,5,4], -[4,4,5,5,6,7,6,8,7,8,6,6,4,4,4,5,4,5,5,7,8,8,9,9], -[8,6,5,4,3,2,4,3,4,3,4,4,5,5,6,7,8,9,9,9,10,10,9,10], -[8,8,6,5,3,4,3,4,4,6,7,9,9,10,10,10,10,9,9,7,7,6,7,6], -[7,6,6,6,7,7,7,8,7,8,7,7,6,7,5,6,4,4,3,4,3,4,4,5], -[5,6,7,7,7,7,7,6,6,4,4,2,2,1,1,2,3,2,3,4,5,5,5,6], -[5,6,4,5,4,4,3,3,2,2,1,1,1,2,2,4,5,6,6,6,6,5,5,3], -[3,1,1,0,0,0,2,2,3,4,5,5,5,5,4,5,4,5,4,5,3,4,3,3], -[1,1,0,2,1,3,4,5,6,6,7,6,5,4,4,1,1,0,0,0,2,2,4,4], -[5,5,5,5,4,4,2,3,1,2,0,1,0,1,0,0,-1,0,0,1,2,3,5,5], -[7,6,7,5,5,3,3,1,1,0,1,0,2,2,4,5,5,6,5,5,4,5,3,5], -[3,5,4,6,5,6,5,6,6,6,6,6,6,6,7,7,8,6,6,5,5,2,3,1], -[1,2,3,4,6,9,10,12,12,11,9,9,7,6,4,5,2,3,3,4,3,4,3,3], -[4,3,4,5,5,6,8,7,10,8,8,6,5,3,3,2,2,2,3,4,5,7,7,8], -[6,7,3,4,2,3,2,3,4,5,5,7,6,6,6,6,7,6,6,6,7,6,7,5], -[6,3,4,3,2,1,3,4,5,6,8,10,10,11,10,10,7,7,5,5,4,4,3,4], -[4,5,5,5,6,6,7,7,8,8,8,7,9,7,8,6,6,3,3,2,1,2,2,3], -[3,5,5,7,7,8,6,6,5,5,2,3,2,2,2,4,4,5,4,4,5,4,5,4], -[5,4,5,4,4,3,4,3,3,3,3,2,3,4,5,7,8,9,8,10,8,8,6,5], -[3,3,1,1,2,2,3,4,5,6,7,7,8,8,8,8,7,7,8,7,7,5,6,4], -[4,2,2,2,2,4,5,7,7,9,7,8,6,6,4,4,2,3,2,3,4,5,6,6], -[7,6,6,5,5,3,4,2,4,2,2,1,2,1,1,1,0,1,2,2,4,5,6,7], -[6,7,5,5,3,3,1,1,-1,0,0,1,2,3,5,5,6,6,6,5,5,3,4,3], -[4,4,5,4,5,4,4,5,5,6,5,6,6,7,7,8,6,7,5,6,4,3,2,2], -[1,2,3,3,4,6,7,8,9,8,9,6,6,4,5,3,3,2,3,3,4,3,3,5], -[4,5,4,5,4,6,5,7,5,5,4,4,3,2,1,2,2,3,4,5,7,7,8,7], -[8,5,6,3,4,2,2,2,2,2,3,3,4,5,5,6,6,6,6,8,7,8,7,7], -[6,7,5,4,3,3,4,4,5,5,7,7,8,8,9,8,7,6,5,4,4,3,4,4], -[5,5,6,7,7,9,8,10,8,9,7,8,6,6,4,4,3,3,1,1,0,1,2,3], -[4,4,6,6,8,6,8,6,7,5,4,3,2,1,1,1,1,2,2,2,3,4,2,3], -[2,3,2,3,2,3,3,3,4,3,4,4,4,4,4,5,6,5,7,5,5,4,4,2], -[1,-1,-1,-2,-1,0,2,4,5,8,7,9,8,9,8,8,6,6,5,4,3,4,2,2], -[1,0,1,0,1,1,3,4,7,7,9,8,8,6,6,4,3,1,2,1,1,2,3,5], -[5,5,5,5,3,4,2,3,1,2,1,3,2,2,3,3,3,3,4,4,5,5,6,6], -[7,6,7,5,5,3,2,1,1,1,1,2,3,5,5,7,7,10,8,8,6,6,5,5], -[5,5,4,5,5,5,7,6,7,6,7,7,8,8,10,9,10,9,10,8,8,6,5,4], -[3,3,4,6,6,8,9,11,10,11,9,8,6,6,4,4,4,4,5,5,6,6,6,5], -[6,5,5,4,5,5,6,6,7,5,6,4,4,2,2,2,1,3,4,6,6,9,8,10], -[8,8,6,5,4,3,3,3,3,3,3,3,4,4,5,5,6,4,7,5,7,6,7,6], -[6,5,4,4,2,2,2,3,2,5,4,6,6,7,7,7,5,5,3,3,2,2,3,2], -[4,3,5,5,6,5,7,6,7,5,6,5,5,4,4,2,2,1,0,-1,-1,0,1,3], -[2,5,5,6,6,6,5,5,3,3,1,0,-1,-1,-1,0,1,2,2,3,3,3,4,3], -[3,2,2,2,2,2,2,2,1,2,1,1,1,2,2,4,5,6,5,7,6,6,4,4], -[3,1,1,0,1,1,3,4,6,5,7,6,7,6,6,5,5,4,4,4,4,4,3,3], -[3,3,2,3,3,5,5,7,6,9,7,7,6,4,3,1,1,-1,0,0,1,2,3,4], -[6,5,7,5,6,5,5,4,4,4,3,3,3,3,1,2,1,1,0,1,1,4,4,5], -[5,6,5,5,5,5,4,4,4,3,3,3,5,5,6,6,8,6,6,4,5,2,3,2], -[2,1,2,3,3,4,5,7,8,9,9,10,9,10,10,9,9,8,6,6,4,3,2,0], -[1,0,2,1,4,5,9,9,11,11,11,10,10,8,7,6,5,4,4,5,4,5,3,5], -[3,4,2,4,3,4,5,6,5,5,6,5,5,5,5,4,5,5,7,7,8,8,9,7], -[7,5,4,3,2,1,1,1,2,4,3,6,5,8,8,10,9,10,9,10,9,9,8,7], -[7,6,5,4,4,3,4,3,6,5,7,7,10,10,10,10,10,8,8,6,6,5,4,5], -[4,5,4,7,6,8,7,9,8,8,6,6,5,5,4,5,4,4,4,3,4,3,5,4], -[6,5,7,6,8,7,7,6,4,4,2,1,0,0,0,0,1,3,3,5,4,5,4,4], -[4,3,2,1,1,1,2,1,2,1,2,1,2,1,2,3,5,4,5,4,5,4,4,3], -[1,1,0,0,-1,0,1,3,4,7,6,8,6,6,4,4,4,3,2,3,3,3,3,1], -[3,0,2,1,2,1,3,3,4,4,6,5,4,4,2,1,-1,-1,-2,-1,-1,1,1,3], -[4,5,4,5,3,4,2,1,1,1,1,0,0,0,1,1,2,1,2,1,3,3,4,4], -[6,5,5,4,4,3,2,3,1,1,0,1,1,4,4,6,6,7,7,6,5,4,4,2], -[3,2,4,3,5,5,6,6,8,7,8,6,8,7,7,7,7,7,6,6,5,4,3,3], -[2,3,2,4,5,8,9,11,10,11,10,8,7,5,4,3,2,2,4,4,5,4,6,5], -[6,4,5,4,5,5,6,6,6,6,5,5,3,4,2,3,1,2,3,5,5,7,7,8], -[8,6,5,4,3,3,3,2,4,4,5,5,6,6,7,7,7,5,7,5,5,5,5,5], -[5,5,4,4,3,4,3,5,5,9,8,10,9,10,10,8,8,6,5,3,3,1,2,2], -[3,3,5,4,6,6,7,7,8,8,8,8,8,7,6,6,4,3,2,1,0,1,1,2], -[2,4,4,5,5,5,5,5,5,4,3,2,2,2,3,3,5,5,6,5,6,5,5,3], -[3,2,1,1,0,2,0,3,2,3,2,5,3,6,6,7,8,9,8,9,8,7,6,4], -[3,1,1,-1,0,0,2,3,5,6,7,8,8,8,8,8,7,8,7,7,7,6,5,6], -[4,4,2,3,3,4,4,5,5,6,6,5,6,4,4,2,2,1,2,1,4,4,5,6], -[7,6,6,5,5,4,3,3,1,1,0,1,0,1,1,1,1,2,2,4,4,5,6,6], -[6,7,7,6,6,4,4,3,4,2,3,1,3,3,5,5,6,6,6,5,5,4,3,3], -[1,2,2,3,3,5,5,7,7,8,7,8,7,6,5,4,5,4,5,3,3,2,3,0], -[2,0,3,2,5,6,8,9,9,10,9,9,7,6,4,3,1,1,1,2,2,4,4,5], -[5,5,5,4,4,3,4,4,5,3,5,3,3,2,3,2,2,2,4,4,5,7,7,7], -[7,6,5,4,2,2,1,2,1,4,3,5,5,7,7,7,8,7,7,6,6,6,6,6], -[6,5,6,4,5,4,5,5,6,6,8,8,9,9,8,8,7,7,5,5,2,3,2,3], -[3,5,5,6,7,9,9,9,8,7,8,5,6,4,5,3,2,1,2,1,2,1,3,2], -[3,4,5,6,6,7,7,7,6,5,3,3,1,2,0,2,2,3,3,5,4,4,5,4], -[3,2,3,1,2,2,4,3,5,4,5,4,5,5,5,5,6,6,6,5,5,5,3,3], -[1,1,-1,0,-1,1,2,4,6,8,9,10,10,9,8,6,5,3,4,2,3,2,3,2], -[2,2,3,2,3,3,4,5,6,7,7,8,7,7,5,5,2,2,-1,1,1,3,3,5], -[5,5,6,4,4,3,3,2,3,2,3,2,3,3,5,4,6,5,5,5,5,4,4,5], -[5,5,4,5,4,4,3,3,3,4,3,5,5,8,8,10,11,11,11,9,9,7,6,3], -[4,2,4,2,4,4,6,7,8,9,9,10,10,10,10,10,10,11,9,10,8,7,5,5], -[3,3,2,4,5,7,8,9,10,9,10,8,8,6,6,5,5,5,6,6,7,8,8,9], -[8,7,6,6,5,5,4,6,5,5,3,5,3,3,3,3,3,5,5,6,7,8,10,8], -[9,7,6,3,3,1,1,1,2,2,3,3,5,5,6,6,6,7,6,5,5,6,5,6], -[4,5,4,4,3,4,4,5,5,6,7,7,8,7,7,6,5,4,3,2,1,1,2,1], -[2,2,4,4,6,7,6,7,6,6,5,5,3,4,1,2,0,0,-1,0,-1,0,1,1], -[3,2,3,3,5,4,5,3,4,2,3,0,0,-1,0,0,2,3,4,3,3,4,3,3], -[2,2,0,1,0,2,1,2,2,3,3,4,3,4,4,5,6,5,6,6,6,4,5,3], -[3,0,1,0,1,1,3,3,5,6,7,8,8,8,7,6,5,5,4,5,3,4,3,4], -[3,4,4,4,4,5,6,6,7,6,7,6,6,5,4,2,1,0,0,0,2,2,4,6], -[6,7,6,7,5,7,5,5,3,3,1,2,1,2,2,3,3,3,3,3,3,3,5,4], -[5,4,6,4,6,5,5,5,5,4,5,5,5,6,6,7,7,8,7,8,5,5,3,3], -[1,2,1,3,3,5,6,9,10,10,11,10,11,9,9,7,8,6,6,5,5,4,4,2], -[3,1,2,3,4,6,7,9,10,11,9,10,8,8,5,5,4,4,3,3,4,5,5,6], -[7,6,5,4,4,3,5,4,5,4,5,4,6,5,5,5,5,6,7,7,7,8,8,9], -[7,7,4,5,2,2,1,2,1,3,4,5,7,8,9,10,10,9,10,8,8,7,8,6], -[6,5,5,4,5,4,4,5,6,7,7,9,9,10,10,10,9,9,7,7,5,5,4,4], -[4,5,6,7,7,8,10,8,9,6,7,4,5,3,3,4,4,3,4,3,3,4,4,4], -[4,5,4,6,5,6,5,6,4,3,2,2,0,0,0,1,3,3,4,5,6,6,6,5], -[5,2,3,2,2,1,3,3,4,4,4,4,4,4,4,4,4,5,5,6,5,6,4,4], -[2,1,0,0,-1,1,2,3,6,6,8,8,8,6,6,4,3,1,1,1,2,1,3,2], -[2,3,3,4,3,4,4,5,4,7,5,7,5,5,3,2,0,-1,-2,-2,-1,0,2,4], -[6,5,7,5,6,4,5,3,3,1,2,1,2,2,3,3,3,4,4,3,2,3,2,4], -[3,5,4,5,4,5,5,5,4,4,4,5,6,7,8,7,9,8,9,7,7,5,4,3], -[2,2,2,3,5,6,7,9,10,11,11,11,10,10,10,10,8,8,7,6,6,5,4,3], -[4,3,4,4,6,7,9,10,12,11,12,9,9,7,6,4,4,4,4,4,5,6,6,7], -[7,7,5,6,5,6,5,6,6,7,6,7,5,5,4,4,5,5,6,6,7,7,9,7], -[8,6,6,5,5,4,4,4,5,5,6,7,8,9,9,10,9,9,7,8,6,5,5,5], -[4,4,3,4,5,5,6,6,9,8,11,9,11,10,11,9,9,6,5,3,3,2,1,2], -[2,3,4,5,6,7,8,9,8,10,8,8,6,7,5,5,4,4,3,3,2,2,4,3], -[4,3,4,2,4,4,5,4,5,4,4,3,3,4,3,5,6,7,7,8,6,7,6,6], -[3,3,1,-1,0,1,1,2,3,3,5,6,6,7,9,8,10,9,10,9,10,8,7,6], -[5,3,2,1,1,2,2,4,5,7,7,9,8,9,9,8,6,7,5,6,5,6,6,6], -[6,4,5,4,6,4,5,4,6,5,6,5,5,4,4,3,3,2,3,3,3,5,6,8], -[8,10,9,10,7,7,5,5,3,3,1,1,0,1,1,3,4,4,6,5,5,5,6,5], -[6,5,6,5,5,5,5,5,4,5,4,4,4,5,5,6,6,8,7,7,6,6,4,3], -[2,2,2,2,4,5,8,8,10,10,12,10,10,8,8,5,6,5,5,4,5,4,3,4], -[2,4,3,4,4,6,6,9,9,10,9,9,7,6,4,3,2,1,2,2,3,4,5,5], -[7,5,6,4,4,3,3,3,4,5,5,5,4,5,4,4,4,5,4,6,6,7,6,7], -[6,7,4,4,4,3,3,2,4,3,5,5,7,8,10,9,9,8,8,6,7,5,5,5], -[5,5,4,5,4,6,6,7,7,8,8,9,8,10,9,9,7,7,5,5,3,2,2,2], -[3,3,5,6,8,8,10,9,10,9,8,6,5,4,4,3,2,3,3,3,3,3,2,3], -[3,4,4,5,5,6,6,6,6,5,4,4,3,2,2,2,3,4,6,6,6,5,5,4], -[4,2,2,1,1,2,3,5,5,7,6,7,6,8,6,7,7,7,6,7,6,6,4,4], -[3,1,1,0,1,1,3,5,8,8,11,10,12,10,9,7,6,4,3,2,2,3,2,4], -[3,4,3,5,3,5,5,6,6,8,6,8,6,7,6,4,3,2,1,0,1,2,4,4], -[6,5,6,6,6,6,5,4,3,4,3,4,4,5,6,7,7,8,7,8,6,7,5,6], -[5,4,3,4,4,4,5,4,6,4,6,6,8,8,10,10,12,11,12,10,9,8,6,5], -[4,3,2,3,3,5,7,9,9,11,11,12,11,11,10,10,10,10,9,9,9,8,8,7], -[7,5,6,5,7,7,9,9,10,9,9,8,7,5,4,4,3,4,5,5,6,8,9,10], -[9,9,7,7,5,5,4,4,4,3,3,2,3,2,3,3,4,4,6,6,7,8,8,9], -[9,8,7,6,5,5,4,5,4,6,4,6,5,8,7,7,6,7,5,5,5,4,5,5], -[5,4,5,4,6,5,7,6,9,8,9,8,9,7,7,5,4,3,2,1,0,1,0,1], -[1,3,3,6,6,8,9,9,8,9,7,6,5,4,3,2,2,1,1,0,1,0,2,1], -[3,2,3,3,4,4,5,5,5,5,4,4,2,3,2,4,3,4,4,6,5,5,4,4], -[2,1,1,0,0,0,2,2,4,4,6,6,8,7,9,8,8,8,7,6,7,6,5,5], -[3,2,0,2,1,3,2,6,6,9,9,11,10,11,9,8,7,5,4,4,3,3,4,4], -[6,4,6,6,7,6,7,7,7,7,7,6,7,6,5,5,3,4,2,3,3,4,4,6], -[6,7,7,8,7,8,7,6,6,4,4,4,4,3,5,5,7,7,7,6,7,6,6,5], -[4,4,4,5,5,6,7,8,7,9,8,9,9,10,9,10,10,10,9,9,8,6,5,3], -[3,1,2,1,4,5,8,10,12,13,15,14,14,12,10,9,8,7,7,6,5,5,4,5], -[3,4,3,4,4,7,7,9,11,11,12,11,10,9,8,6,6,4,4,4,6,6,7,7], -[8,6,6,5,4,4,3,4,4,6,5,7,7,8,8,8,8,8,8,9,8,9,8,7], -[8,6,6,3,3,2,3,2,4,4,6,7,10,11,13,12,12,11,10,10,9,7,6,6], -[5,6,4,6,5,6,5,7,7,8,8,9,9,10,10,10,9,9,8,6,6,4,4,4], -[5,4,6,5,8,8,8,8,7,7,5,5,4,3,3,4,3,5,4,6,5,6,6,7], -[6,6,5,5,6,5,6,5,5,3,4,1,1,0,1,1,3,4,6,7,7,7,7,7], -[5,4,3,2,1,3,2,3,3,5,4,5,4,5,5,5,4,5,5,6,6,5,6,5], -[5,3,3,2,3,3,5,5,7,8,9,9,9,8,6,4,2,2,0,1,1,2,2,4], -[4,5,5,7,6,7,7,7,7,6,6,5,5,4,4,1,1,-1,-1,-1,0,1,3,4], -[5,6,6,7,6,6,6,6,4,4,2,4,2,4,4,5,5,6,5,6,5,4,3,3], -[3,3,4,3,5,4,7,6,7,7,8,8,9,9,10,9,10,10,10,8,7,7,4,4], -[2,2,1,4,4,6,8,10,11,12,13,13,13,11,11,9,9,7,8,6,7,5,6,5], -[5,4,6,6,7,7,9,10,10,11,10,10,9,8,6,6,5,5,4,6,6,7,8,9], -[7,7,7,7,6,5,5,4,5,4,5,5,6,5,7,7,8,7,7,7,7,7,7,6], -[7,7,6,7,5,5,4,5,4,6,6,8,8,9,10,10,11,9,9,6,6,3,3,2], -[3,2,4,4,7,6,8,8,10,10,10,10,10,11,10,9,7,7,4,4,1,2,-1,0], -[1,2,3,5,6,7,8,9,9,8,7,6,6,5,6,5,5,3,4,1,3,2,2,2], -[2,2,2,2,2,4,3,4,4,5,4,5,4,5,5,6,7,8,7,8,7,6,5,3], -[3,1,1,-1,0,-1,0,0,3,3,6,8,9,9,10,10,9,10,9,8,6,6,4,4], -[2,3,1,1,1,2,2,3,4,6,7,8,10,10,11,9,9,6,6,3,5,4,4,4], -[6,6,7,8,7,7,6,6,5,5,3,4,3,4,4,5,4,5,3,4,3,4,4,5], -[6,6,8,7,8,6,6,4,3,1,1,-1,1,1,3,4,6,6,7,6,6,6,4,5], -[3,5,4,6,5,7,6,7,6,6,6,6,6,7,8,8,9,8,9,7,7,5,5,3], -[3,2,3,2,5,5,8,9,10,11,10,10,9,9,7,7,4,4,3,4,2,4,3,4], -[4,4,5,5,6,6,8,8,9,8,8,7,7,5,5,3,3,1,2,1,3,4,5,5], -[7,7,6,6,5,5,4,5,4,4,3,5,5,5,6,6,6,6,6,5,5,4,5,5], -[5,4,6,4,4,3,4,3,3,5,5,7,9,10,10,11,10,10,7,7,3,4,1,3], -[1,4,3,5,5,6,7,8,8,8,9,9,10,10,10,9,9,7,6,3,3,1,1,0], -[1,3,3,5,7,8,9,9,8,8,6,6,4,5,4,5,4,4,4,4,4,3,4,3], -[4,2,3,2,4,4,4,4,5,3,4,3,4,3,4,5,6,8,7,8,7,7,5,5], -[3,3,1,2,1,2,2,3,3,5,7,7,8,8,9,8,9,7,8,6,7,5,6,3], -[4,2,2,1,3,2,4,6,6,8,8,10,9,10,9,9,6,6,3,2,1,2,2,4], -[4,5,5,6,7,6,7,6,6,5,6,5,6,5,7,6,6,3,3,3,2,3,3,4], -[4,6,5,7,5,6,5,5,3,4,2,3,4,5,6,8,9,9,9,8,7,5,5,3], -[4,2,3,2,4,3,4,4,5,6,7,8,9,10,11,12,11,13,11,11,8,8,6,5], -[3,3,2,3,3,5,6,7,9,9,10,10,11,10,11,10,10,8,8,6,7,5,6,6], -[5,5,6,6,5,6,5,6,6,6,5,6,4,5,4,4,4,4,4,4,5,6,7,8], -[9,9,9,7,7,5,4,3,3,1,2,1,3,3,4,5,6,6,6,7,5,6,6,7], -[6,7,6,7,5,5,4,4,3,3,3,4,5,6,7,6,8,6,7,4,4,3,2,1], -[3,2,4,5,6,7,8,8,9,8,7,8,7,6,6,6,3,3,1,1,-1,0,0,0], -[2,2,4,5,7,7,9,8,8,6,5,3,3,1,2,1,1,1,1,1,0,1,1,2], -[2,3,2,3,2,3,2,4,4,4,3,3,3,3,3,3,4,4,5,4,5,4,5,2], -[3,1,2,0,1,0,2,2,3,4,6,7,8,9,9,9,7,7,5,6,4,4,3,3], -[3,3,2,2,2,4,4,5,7,7,8,8,10,10,10,7,8,5,4,2,1,0,2,3], -[4,6,6,8,8,8,7,8,6,6,5,5,4,5,5,5,5,4,4,2,3,2,3,4], -[6,5,8,7,8,7,7,5,5,3,4,3,3,5,5,7,8,9,9,9,7,7,4,5], -[3,3,3,5,5,6,7,7,8,8,8,8,10,10,11,10,11,10,11,8,9,7,6,4], -[3,3,2,3,4,6,7,10,11,13,12,14,11,12,9,9,7,7,5,5,5,6,6,6], -[6,5,6,5,7,5,7,7,8,8,8,7,8,7,7,6,4,5,4,4,4,6,7,8], -[7,8,7,7,5,5,3,3,3,3,4,5,6,7,9,8,10,8,10,8,8,7,7,6], -[7,5,6,5,4,4,4,3,3,4,5,7,8,11,12,13,10,11,8,8,5,5,3,3], -[2,3,4,5,6,5,7,7,8,7,8,8,8,9,9,9,9,7,7,4,3,3,2,3], -[3,5,5,7,7,8,7,8,6,6,4,4,3,2,2,3,3,3,4,3,5,4,5,3], -[5,3,4,3,4,3,3,3,2,2,1,1,1,1,2,4,3,5,5,7,6,7,5,6], -[4,3,2,1,1,1,2,2,4,4,5,6,7,6,7,6,7,5,5,4,5,4,4,4], -[4,3,3,3,3,4,4,5,6,7,7,8,7,8,7,5,4,2,0,-1,-1,-1,0,1], -[4,5,6,6,8,7,7,7,6,5,4,4,4,4,3,3,3,2,2,1,0,1,1,3], -[3,5,5,7,6,6,5,6,4,3,4,3,4,4,6,5,8,7,8,6,7,5,5,2], -[2,1,2,2,3,3,5,6,7,8,8,9,10,11,11,11,10,10,8,8,7,6,4,4], -[3,2,3,2,4,5,7,8,10,10,12,12,12,10,10,9,9,7,6,5,5,5,4,6], -[5,6,6,7,7,7,6,7,7,8,6,7,7,6,6,5,5,4,5,4,6,6,7,7], -[8,8,8,7,7,6,4,4,3,3,2,4,4,6,7,8,7,9,7,8,7,7,6,7], -[6,6,5,6,6,6,5,4,5,5,6,6,8,9,11,10,10,9,9,7,6,4,4,3], -[2,3,4,5,5,7,8,9,8,10,8,9,8,8,8,7,7,5,4,3,3,1,2,1], -[3,2,4,4,6,6,7,7,7,7,5,5,4,4,2,4,3,4,4,5,4,5,4,4], -[2,3,2,2,1,2,2,1,2,2,3,2,4,4,6,5,6,6,8,6,8,6,7,5], -[4,2,1,0,-1,-1,-1,1,1,3,4,7,8,10,9,9,8,9,7,7,6,6,6,5], -[5,4,4,3,4,2,4,4,5,4,6,6,7,7,8,7,6,5,3,2,2,2,2,4], -[4,7,6,8,7,7,5,5,3,2,1,1,0,1,2,2,4,2,4,3,3,3,4,4], -[5,6,7,7,8,7,6,5,4,3,1,1,1,3,2,6,6,8,7,8,7,7,6,5], -[3,4,3,3,4,4,6,6,7,7,7,6,7,6,7,7,8,7,8,6,6,5,5,4], -[3,3,2,4,4,6,6,10,10,11,10,10,9,8,7,6,4,2,3,2,3,3,4,4], -[5,5,6,6,7,6,7,7,7,6,6,6,5,4,3,3,1,2,1,2,2,4,3,5], -[5,6,6,6,5,4,4,3,3,2,3,3,5,5,7,5,7,6,6,4,5,4,4,3], -[4,4,3,4,4,4,3,4,4,6,6,7,8,10,10,10,9,8,7,4,3,2,1,0], -[1,0,3,3,6,5,8,8,9,8,9,8,8,8,8,7,7,5,4,3,1,1,-1,1], -[1,3,3,5,6,6,7,7,6,6,5,4,3,2,3,2,3,3,4,4,5,3,5,3], -[4,3,3,3,2,2,3,3,3,4,2,4,3,5,4,6,6,8,6,8,7,7,6,6], -[5,3,3,1,2,1,2,2,5,5,6,7,8,8,10,8,8,7,6,5,5,5,4,5], -[4,5,4,5,5,6,6,7,7,8,8,9,9,8,8,7,7,4,4,1,1,0,3,3], -[5,5,8,7,9,8,8,7,6,5,4,5,4,5,4,5,4,5,3,5,3,4,3,4], -[4,5,5,5,6,6,6,6,6,4,5,4,5,5,7,8,9,9,10,9,9,7,7,5], -[4,4,2,3,2,3,3,5,6,8,7,9,10,11,10,10,11,10,10,9,8,7,6,5], -[5,2,3,2,3,3,6,6,7,8,9,9,9,9,9,8,6,7,5,5,4,6,5,7], -[6,9,8,8,7,7,6,5,5,3,4,3,3,3,3,2,4,3,5,4,6,6,7,7], -[9,8,8,7,6,5,3,2,0,1,-1,0,0,2,4,5,6,7,5,6,5,5,5,5], -[6,5,6,5,6,5,5,4,5,4,5,5,6,6,7,8,7,7,5,5,3,3,1,2], -[1,3,2,5,5,8,8,9,9,9,7,6,6,5,4,3,3,1,3,0,1,0,1,-1], -[2,1,4,3,6,7,7,8,6,7,5,4,2,2,0,1,0,2,1,3,2,3,2,3], -[2,2,2,1,2,1,2,2,4,3,4,3,4,4,5,5,5,5,5,5,4,4,4,4], -[2,3,0,1,-1,-1,-1,1,2,4,6,8,9,10,9,8,9,6,6,4,3,2,2,1], -[3,2,3,3,4,4,4,5,5,7,7,7,9,9,8,8,5,6,3,2,0,0,0,3], -[3,5,6,7,8,8,7,6,5,4,4,2,3,3,5,4,5,5,5,4,5,4,4,4], -[5,4,5,6,5,6,5,5,4,4,3,4,3,5,5,8,9,10,10,10,9,8,7,5], -[5,3,3,3,4,3,6,6,8,8,9,8,10,9,9,10,10,10,9,9,8,8,6,6], -[5,4,3,5,4,6,7,9,9,10,11,11,11,9,9,6,7,4,5,3,5,4,6,6], -[7,7,7,7,7,7,6,7,6,6,6,6,5,6,4,5,3,5,4,4,5,6,6,8], -[8,7,8,6,6,4,3,2,2,1,3,3,4,5,7,7,8,8,7,7,5,6,4,5], -[4,5,4,5,3,4,3,3,3,4,5,6,8,8,9,9,9,8,8,5,5,2,3,1], -[3,2,4,4,6,6,7,8,7,7,6,6,5,6,5,5,4,5,2,3,2,2,1,2], -[2,3,3,4,5,5,4,4,4,2,2,-1,0,-1,0,-1,1,1,2,2,4,4,5,5], -[5,5,3,3,2,2,1,1,0,1,0,1,0,1,2,3,4,4,5,5,6,5,6,5], -[6,3,4,1,2,1,1,1,2,2,3,5,5,6,6,6,4,4,3,3,2,3,2,3], -[3,5,4,5,6,6,6,6,6,5,6,5,5,5,5,3,3,0,0,-2,-1,-1,1,1], -[3,5,7,7,8,9,9,8,6,5,3,3,1,1,0,1,1,1,1,2,2,2,2,2], -[3,3,4,4,5,5,7,5,6,5,5,4,5,5,4,6,7,7,7,7,6,5,3,4], -[2,2,1,2,2,3,4,6,7,8,10,11,11,10,11,9,9,7,7,5,6,4,4,3], -[3,2,3,2,4,4,6,7,9,10,10,11,10,11,8,9,6,5,3,4,2,3,3,5], -[5,7,7,6,6,5,5,4,5,4,5,4,6,5,5,5,6,4,4,5,5,5,5,7], -[7,8,6,7,5,5,3,3,2,2,1,3,4,5,7,9,9,9,8,7,7,5,5,3], -[5,4,5,4,5,4,5,5,5,5,6,7,8,9,9,10,9,10,7,7,5,4,2,2], -[1,2,3,4,5,7,9,9,9,9,8,7,7,6,7,5,5,4,4,2,3,2,2,2], -[2,3,3,4,4,6,6,6,5,6,3,4,2,2,1,2,2,3,3,4,5,5,5,4], -[4,3,2,1,1,0,1,0,1,1,3,3,4,4,5,5,5,6,6,7,7,7,6,6], -[4,4,1,2,0,1,0,0,2,3,4,6,8,8,10,8,8,5,5,3,3,2,3,2], -[4,3,4,4,4,4,4,5,3,5,4,5,4,6,6,6,4,4,1,1,-1,0,1,2], -[4,5,7,7,8,7,7,5,5,2,2,0,1,0,1,2,3,4,4,5,4,4,4,4], -[3,5,4,5,4,5,4,4,3,2,1,1,2,2,4,5,6,7,8,7,8,6,6,4], -[4,3,3,2,4,3,4,5,6,6,6,7,8,8,7,8,7,8,7,7,5,7,5,6], -[4,5,4,4,5,6,7,8,9,8,9,8,7,6,5,4,3,1,2,1,2,3,4,6], -[6,7,6,7,7,7,5,6,5,5,3,3,2,2,1,1,1,1,1,2,3,3,5,5], -[7,6,8,5,7,5,4,3,2,2,2,3,3,5,5,6,5,6,5,5,3,4,2,3], -[2,3,3,4,4,4,4,5,5,5,6,6,8,8,9,8,8,6,6,3,3,0,1,-1], -[0,0,1,3,4,5,6,9,8,8,7,8,6,7,5,5,4,4,2,2,1,1,1,0], -[1,1,3,3,4,3,5,4,4,4,4,3,3,2,2,2,3,3,4,4,4,5,4,5], -[3,4,2,2,0,1,-1,1,0,1,1,3,4,4,6,6,8,6,8,7,7,6,6,5], -[5,3,4,2,1,1,1,2,2,4,4,7,7,9,8,10,8,8,6,5,4,4,4,4], -[4,5,5,5,6,6,6,6,7,6,6,6,7,6,6,5,5,4,3,2,2,1,2,3], -[4,6,6,8,8,9,7,8,6,5,3,2,2,2,2,3,4,5,6,6,6,6,6,4], -[6,4,5,4,5,4,5,5,5,4,3,3,4,5,4,7,6,9,8,10,8,8,6,6], -[3,3,2,1,1,1,3,4,6,6,8,8,9,9,9,9,8,7,7,5,6,5,6,5], -[5,5,4,5,4,5,5,7,7,8,7,8,7,6,5,5,3,3,2,2,2,3,4,5], -[6,7,8,6,6,5,4,2,2,1,1,0,1,0,1,2,1,2,1,3,3,5,4,6], -[6,7,7,7,5,5,4,2,1,0,0,0,1,3,5,5,7,5,6,5,6,4,5,3], -[4,3,4,4,4,5,5,5,4,6,4,5,4,6,6,7,5,6,4,4,2,2,1,1], -[1,2,3,3,6,6,9,8,9,8,8,6,5,3,3,2,2,1,0,0,1,1,1,2], -[2,3,3,5,4,6,5,6,5,5,3,3,1,0,0,-1,0,0,2,1,4,3,5,3], -[4,3,3,1,2,1,1,1,2,2,3,4,3,4,4,4,3,5,3,4,3,5,3,5], -[4,3,3,2,1,1,2,2,3,4,7,6,9,8,9,8,7,4,4,1,1,0,1,1], -[2,4,4,5,5,6,6,7,6,7,6,6,6,6,6,6,5,3,2,1,-1,0,0,0], -[3,3,6,6,8,7,7,6,5,4,3,3,2,3,2,4,4,6,5,6,4,5,4,5], -[3,4,3,4,4,5,5,5,5,4,4,4,5,6,7,8,10,10,11,9,10,8,8,6], -[4,3,1,2,2,3,3,6,7,9,8,10,10,11,11,11,9,10,8,8,8,7,7,5], -[5,5,5,4,6,6,7,7,9,9,10,9,9,8,8,7,6,5,4,5,4,6,5,7], -[7,9,7,8,7,6,6,5,4,4,3,4,3,3,4,4,5,4,5,4,6,5,6,6], -[7,6,7,5,5,3,3,3,2,2,1,3,3,6,6,8,7,9,7,7,6,6,5,4], -[4,4,3,3,3,3,4,3,5,4,6,5,7,7,7,7,8,6,6,4,3,2,1,1], -[0,1,1,2,2,5,4,6,5,6,5,4,3,2,2,2,2,1,2,0,1,0,1,1], -[2,2,3,3,4,2,3,3,2,1,1,0,-1,0,-1,0,-1,2,1,3,3,5,4,5], -[3,4,2,1,0,0,-1,-1,0,-2,0,-1,1,2,4,3,4,3,4,3,5,5,5,5], -[4,4,3,2,2,1,0,2,1,3,3,5,5,7,7,6,6,5,3,2,2,2,2,2], -[4,4,6,5,7,8,8,7,7,5,5,5,4,3,3,4,2,3,1,1,0,1,0,2], -[3,5,5,8,8,8,8,7,7,4,4,1,1,0,1,0,2,2,5,3,5,4,5,3], -[3,3,3,3,4,4,5,6,5,5,5,5,4,5,5,6,6,7,7,8,6,7,5,5], -[4,3,3,1,2,2,4,4,6,7,10,10,10,9,10,9,8,6,5,4,3,4,4,4], -[4,5,4,5,4,5,5,7,7,8,8,8,8,7,6,5,5,2,3,1,2,1,4,5], -[7,7,8,6,7,6,5,4,3,2,2,3,2,3,3,5,3,5,3,5,4,5,5,6], -[6,6,6,6,5,4,4,2,2,1,1,1,3,4,6,7,9,8,9,7,7,5,4,4], -[3,3,3,4,3,6,5,6,6,7,6,6,7,8,8,8,9,8,7,6,5,3,3,1], -[3,1,3,4,5,6,8,8,9,7,7,6,5,4,3,3,3,3,3,3,2,3,2,4], -[3,4,3,4,3,4,4,4,4,3,3,2,2,0,1,0,3,2,5,4,7,6,8,6], -[6,5,3,2,1,0,0,1,-1,1,1,3,3,5,5,5,5,6,5,6,5,6,5,5], -[6,4,4,2,1,0,1,1,2,2,4,5,6,7,8,7,6,5,3,3,1,1,1,3], -[2,5,5,7,7,7,6,7,6,5,5,5,4,4,4,2,3,2,2,0,1,0,2,2], -[3,4,6,6,7,7,6,5,3,3,1,0,0,0,0,2,1,4,3,5,5,6,5,4], -[4,4,4,3,4,4,4,3,4,3,4,3,4,4,6,6,7,7,8,7,8,7,6,6], -[4,4,3,3,3,4,3,5,6,7,8,8,8,8,8,7,7,5,6,5,5,5,5,4], -[6,4,6,5,7,7,8,8,7,7,8,8,6,7,5,5,2,2,1,2,1,3,3,6], -[6,8,8,9,8,8,7,6,6,4,4,2,2,2,2,2,3,2,4,2,4,3,4,5], -[6,5,5,6,5,5,4,4,3,3,3,4,4,6,6,6,6,7,6,5,4,3,2,2], -[2,1,2,2,4,4,5,6,7,7,8,8,8,9,8,8,7,6,4,4,1,2,0,0], -[-1,1,0,3,4,5,7,7,8,8,8,7,6,5,5,3,3,2,3,1,2,1,2,2], -[3,2,2,2,2,2,2,3,2,3,2,3,2,2,2,3,3,4,4,5,5,6,7,6], -[6,4,3,2,1,0,0,-1,0,1,2,3,5,5,7,8,8,8,8,7,7,6,6,6], -[5,6,4,4,2,3,2,3,2,4,5,6,7,8,9,9,10,8,8,4,5,3,4,4], -[5,5,7,7,9,9,9,9,8,7,5,5,5,5,4,6,5,6,5,5,4,5,4,5], -[5,6,7,8,8,8,8,7,6,4,4,2,2,1,2,2,5,5,7,7,8,7,7,6], -[5,5,4,3,2,3,3,5,4,5,4,6,5,5,6,7,8,8,9,9,9,8,8,7], -[7,5,5,3,3,2,4,4,6,7,8,9,9,9,8,8,6,7,4,5,4,5,4,5], -[5,6,5,6,4,5,4,5,5,5,6,5,5,5,5,2,3,1,2,1,2,2,4,5], -[7,8,8,7,7,5,4,3,1,2,-1,1,0,1,2,3,3,4,3,4,4,5,5,5], -[6,6,7,5,6,3,4,2,1,-1,0,1,1,3,5,6,7,8,7,6,5,4,3,3], -[2,4,2,4,3,5,5,6,6,5,5,5,6,6,6,6,7,5,6,4,4,2,3,0], -[2,2,3,4,6,6,8,8,8,7,6,5,3,3,1,1,0,1,0,1,1,3,3,3], -[4,4,4,4,4,3,4,4,5,3,4,2,1,0,0,0,1,1,3,2,4,5,5,5], -[5,5,3,3,1,1,1,1,1,2,2,4,5,5,5,5,5,4,4,3,4,3,4,3], -[5,4,4,2,4,3,3,4,5,5,6,7,8,8,8,9,6,6,2,3,-1,1,-1,1], -[1,3,4,6,7,7,8,8,9,7,7,5,6,5,5,5,5,3,3,1,1,1,1,2], -[3,4,4,5,6,7,6,6,5,5,3,4,3,3,3,4,5,7,7,7,7,7,7,6], -[5,3,3,2,4,2,4,4,5,4,6,6,7,7,8,9,10,11,11,11,10,9,8,8], -[6,6,4,4,2,4,4,5,6,7,9,10,11,10,11,10,11,8,9,7,8,6,8,7], -[8,7,7,7,8,7,7,8,7,7,6,7,5,7,5,5,4,5,3,4,4,5,6,8], -[8,9,9,9,9,7,7,5,4,2,2,1,1,1,2,3,5,5,5,7,6,7,7,8], -[7,9,7,7,6,6,4,4,3,3,1,3,3,4,5,6,7,6,7,5,6,5,4,3], -[4,2,4,2,3,4,5,5,5,5,5,5,5,6,5,5,4,4,2,3,1,2,1,1], -[1,2,2,3,5,5,7,6,8,6,7,5,4,2,1,0,0,-1,0,-1,1,1,2,3], -[3,4,3,3,2,2,1,2,0,1,0,0,0,0,-1,0,0,1,2,2,4,4,6,5], -[6,4,4,2,2,0,0,-1,-1,0,1,2,3,4,6,7,5,7,5,6,4,5,4,5], -[4,5,4,5,4,4,4,4,4,4,5,5,7,7,8,7,7,6,5,2,2,1,1,2], -[4,5,7,8,8,10,9,10,8,8,6,6,3,4,3,3,3,4,2,3,2,3,3,3], -[5,4,7,7,9,8,9,8,8,6,6,3,3,2,2,3,4,5,5,7,7,7,6,6], -[5,5,3,4,3,5,4,5,6,7,7,7,8,8,8,7,9,7,9,8,8,7,7,5], -[6,4,4,3,3,3,5,6,8,10,11,11,11,12,10,10,7,7,4,5,3,4,3,5], -[5,6,5,6,7,6,7,6,8,7,8,7,8,7,7,6,5,3,3,2,2,3,4,5], -[5,7,6,7,6,6,4,4,3,3,2,4,3,4,6,6,6,6,7,5,6,5,6,4], -[6,4,5,5,5,3,4,3,3,3,2,4,6,8,8,10,10,11,10,10,7,7,5,4], -[3,3,2,3,3,4,6,6,7,6,8,7,8,8,9,8,10,8,9,7,7,4,5,3], -[3,3,3,4,5,6,6,8,7,8,6,7,4,4,3,4,4,4,5,6,6,6,8,7], -[8,6,6,4,5,3,4,2,3,2,2,1,1,1,1,2,2,4,5,7,7,9,8,9], -[7,8,5,4,3,1,1,0,0,1,1,2,4,4,6,5,7,5,6,5,7,6,7,7], -[7,6,7,6,6,6,5,5,4,5,5,6,5,7,6,7,5,5,3,3,1,2,2,3], -[4,5,7,7,9,8,8,7,7,6,5,3,2,2,2,1,1,1,1,1,1,2,2,4], -[4,5,5,7,6,7,6,6,5,4,3,2,2,1,2,2,4,4,5,5,8,6,7,5], -[6,4,5,3,3,3,3,3,3,4,4,5,5,6,6,8,7,8,7,9,7,8,6,7], -[6,5,5,4,3,3,5,5,7,7,9,8,11,9,9,8,8,6,6,4,5,5,5,6], -[7,8,7,9,8,9,7,8,7,8,6,6,4,5,4,4,4,3,2,2,3,3,5,5], -[8,8,10,9,10,7,7,5,4,3,2,1,1,2,2,3,3,5,4,6,5,6,5,6], -[5,6,6,7,6,6,6,5,4,4,4,3,5,5,6,7,7,6,8,5,6,4,4,3], -[2,3,3,4,4,5,6,8,8,10,8,8,8,8,7,7,5,6,4,4,2,2,2,0], -[2,1,3,3,5,5,7,7,9,8,8,7,6,4,3,2,2,2,1,2,2,3,3,4], -[3,4,3,4,2,3,2,3,2,2,3,3,3,4,4,4,4,4,5,5,6,6,7,6], -[7,5,5,2,2,1,0,1,1,2,2,5,6,8,9,11,9,10,8,8,6,6,5,5], -[5,5,5,5,5,5,6,5,6,5,8,7,9,9,11,11,10,9,8,7,5,4,3,4], -[4,6,6,9,9,11,9,9,8,7,6,5,4,5,5,5,5,6,6,5,7,5,6,5], -[6,6,7,6,8,8,8,7,6,5,4,3,3,3,3,5,5,8,9,10,10,11,10,10], -[8,7,5,6,4,4,4,4,5,5,6,5,6,7,7,7,8,7,9,8,9,9,9,8], -[8,7,6,5,4,4,4,5,5,8,7,9,8,8,7,6,5,4,3,3,3,4,5,5], -[7,7,9,8,9,8,8,8,7,6,6,5,5,4,3,3,1,1,0,1,1,3,4,6], -[6,9,8,9,8,8,5,4,3,1,0,0,1,1,2,2,4,3,4,4,5,3,5,4], -[5,4,5,6,5,5,4,4,3,4,2,4,4,6,6,8,8,9,6,7,5,5,3,3], -[2,2,3,3,4,4,7,6,8,8,9,7,8,7,7,6,6,6,5,4,4,3,2,3], -[1,4,3,5,5,7,7,8,8,7,6,5,4,3,2,2,2,1,3,2,4,4,6,4], -[6,5,6,5,5,4,4,3,3,3,3,3,2,3,2,2,2,4,3,6,5,7,7,8], -[6,7,5,5,4,3,3,1,3,2,4,4,6,6,8,7,8,7,6,5,5,5,4,5], -[4,6,5,6,5,6,6,7,6,8,7,8,8,8,8,8,7,7,5,3,2,1,1,1], -[3,3,7,7,9,9,11,10,9,9,8,7,5,5,4,5,4,5,4,5,4,5,4,5], -[4,5,5,5,5,6,6,6,6,5,5,4,5,4,6,5,7,7,9,9,10,8,10,8], -[7,6,4,3,3,3,3,4,4,7,6,8,9,10,10,12,12,12,11,11,10,10,9,8], -[8,6,6,4,5,4,5,5,7,8,10,10,12,12,12,11,10,10,9,8,7,7,7,7], -[7,9,8,10,9,9,8,7,7,6,6,6,6,6,7,5,6,5,6,5,6,7,8,8], -[10,9,11,9,9,8,7,6,3,2,0,1,1,2,2,4,6,7,7,8,8,8,8,7], -[7,6,6,5,5,4,5,3,3,2,3,2,4,4,6,6,7,8,8,7,7,6,5,5], -[3,5,4,4,4,6,5,8,8,8,7,7,6,5,4,4,5,4,4,2,3,2,3,1], -[3,2,4,3,5,5,6,6,6,5,4,3,2,1,0,0,-2,0,-1,1,1,4,4,5], -[5,5,4,4,3,3,2,1,1,1,1,0,2,1,2,1,3,2,3,3,5,5,7,7], -[7,7,5,5,4,3,1,1,0,2,1,4,4,6,6,7,8,7,6,4,3,3,4,4], -[5,5,7,5,7,7,7,6,7,6,6,7,7,7,8,8,7,7,5,5,3,3,1,3], -[3,6,7,10,10,11,11,11,10,8,7,5,5,4,4,3,4,3,5,5,6,5,6,5], -[6,6,7,7,8,9,8,8,7,7,5,5,3,3,3,4,5,6,7,9,9,10,9,9], -[8,6,6,5,5,4,6,5,7,7,9,8,9,8,9,9,8,9,8,8,7,8,7,8], -[7,7,5,6,5,6,6,8,9,10,11,11,10,11,10,8,7,5,5,3,4,3,5,4], -[7,6,8,8,9,8,8,8,8,8,6,7,5,6,4,5,3,4,3,3,3,5,5,6], -[7,7,8,8,7,6,6,5,5,3,3,2,3,4,5,5,7,7,7,7,7,7,6,6], -[6,5,4,5,4,5,4,5,3,5,4,6,6,7,9,10,11,11,10,9,8,6,5,3], -[4,3,4,3,4,4,6,7,8,9,9,9,9,9,8,9,8,8,7,8,6,7,5,5], -[4,6,5,6,5,7,6,7,7,6,6,4,5,4,4,2,3,3,5,4,7,7,8,8], -[8,8,7,6,4,4,3,3,2,2,1,2,1,3,3,4,5,6,7,7,8,9,10,9], -[10,9,8,7,6,4,3,2,3,2,3,4,5,6,7,8,7,8,6,6,4,5,5,6], -[5,7,5,7,7,7,7,8,7,6,6,6,6,6,6,5,6,4,4,2,2,1,2,1], -[4,4,6,7,9,9,11,10,9,8,6,5,3,4,2,2,2,2,2,4,3,5,5,5], -[5,5,5,5,6,6,6,5,6,4,5,3,4,3,4,4,5,5,6,7,7,8,8,8], -[7,6,4,4,2,4,3,4,4,6,6,8,8,9,10,9,9,9,8,8,8,6,7,6], -[8,6,7,5,6,6,6,7,7,8,9,9,9,10,9,9,7,7,5,5,3,5,4,6], -[6,8,8,10,9,10,9,8,8,6,6,4,5,4,5,4,4,3,3,3,5,4,6,7], -[7,9,9,10,8,9,7,7,5,5,2,2,1,2,3,5,6,7,7,7,6,7,6,6], -[6,5,6,5,7,5,6,6,6,6,6,5,6,6,7,8,8,9,8,8,6,6,4,4], -[3,3,2,4,3,6,7,8,10,10,10,9,9,8,8,6,6,4,5,4,4,2,4,3], -[4,3,4,4,5,5,6,7,6,8,6,6,4,5,3,2,2,2,2,3,4,5,6,7], -[7,6,6,4,3,1,2,1,2,1,2,2,4,4,5,5,5,6,6,6,6,7,7,8], -[7,8,6,6,3,3,2,1,1,2,3,5,7,9,10,11,11,10,10,7,8,6,6,4], -[6,5,7,6,7,7,7,7,7,7,7,7,7,8,8,10,8,10,7,8,6,5,4,4], -[4,6,7,8,10,10,10,9,9,6,7,4,4,3,4,4,5,6,7,7,9,9,9,10], -[9,9,8,8,7,7,6,6,5,5,3,3,2,2,2,4,5,8,8,10,11,11,12,10], -[10,7,7,5,5,3,3,3,4,4,5,6,6,7,7,8,7,8,7,8,7,9,7,9], -[8,9,7,7,7,7,7,8,8,8,8,8,8,7,7,5,5,3,4,2,3,2,4,5], -[6,7,9,9,9,9,8,8,6,6,4,4,2,2,1,2,1,1,0,1,1,2,3,5], -[7,6,8,7,8,6,5,4,3,2,2,1,2,1,3,3,4,5,4,5,4,5,3,4], -[3,5,3,5,3,4,4,5,4,4,4,4,5,6,7,7,8,7,8,6,6,3,4,1], -[2,1,1,1,3,4,5,7,7,8,7,9,7,7,6,7,4,5,4,4,3,3,3,3], -[4,3,5,4,6,6,7,6,7,5,5,4,4,2,2,2,2,1,2,2,4,5,6,8], -[7,8,6,7,5,5,3,3,2,2,2,3,2,3,3,3,5,4,6,5,6,6,7,7], -[8,7,8,6,7,5,5,3,4,4,4,5,6,8,8,9,8,9,6,7,5,5,4,5], -[4,6,6,7,8,9,10,10,11,10,10,8,8,8,8,7,7,5,5,4,3,3,2,2], -[3,5,5,8,8,10,10,12,10,10,8,8,6,4,3,4,4,4,4,5,6,6,7,7], -[7,5,7,5,6,5,6,6,6,6,6,6,6,7,7,7,7,9,9,10,9,10,9,10], -[7,8,5,4,2,4,3,3,4,5,7,8,10,11,12,11,12,11,11,9,9,8,9,7], -[8,7,7,6,6,6,5,7,7,8,9,10,10,11,11,11,9,9,7,7,6,6,7,7], -[9,9,11,10,11,9,9,7,7,5,5,3,3,3,3,5,5,5,5,6,6,7,7,8], -[8,10,8,9,8,8,6,5,3,2,0,0,0,1,3,4,6,7,9,8,9,7,8,7], -[7,6,7,6,7,6,6,6,5,5,4,5,4,5,5,7,6,8,7,7,6,7,5,5], -[4,4,3,4,5,5,7,7,8,8,8,6,5,3,3,2,3,2,2,1,2,2,2,4], -[3,4,4,5,4,6,5,7,6,7,5,5,2,2,0,0,-1,-2,-1,1,3,3,6,5], -[7,6,7,4,4,2,3,1,2,1,2,1,3,2,3,3,3,4,3,4,3,5,5,6], -[5,6,5,6,4,3,3,3,3,3,4,5,7,8,9,9,10,8,8,5,4,3,3,3], -[3,4,4,5,7,8,8,9,8,9,8,9,7,9,8,8,7,8,6,5,4,3,3,3], -[4,4,7,7,10,9,11,10,9,7,7,5,5,4,3,4,4,5,5,7,7,7,7,8], -[7,7,6,7,5,6,6,5,6,5,5,5,5,4,6,6,7,7,9,9,10,10,10,9], -[9,7,6,5,4,4,4,5,5,6,6,8,9,9,9,10,9,9,8,9,7,8,8,8], -[7,7,7,7,7,7,8,8,9,8,10,9,9,9,8,7,7,5,5,3,3,3,4,6], -[6,8,8,10,8,10,8,8,7,7,6,5,4,4,4,3,4,3,4,3,4,4,6,5], -[7,6,7,7,7,6,6,4,3,3,2,3,3,4,5,6,6,8,7,8,6,7,5,6], -[4,4,3,4,4,4,4,4,5,5,6,6,8,8,9,9,10,10,10,8,8,6,5,4], -[3,3,2,3,2,4,4,7,7,8,8,8,7,7,6,6,6,6,5,5,6,5,5,5], -[6,5,6,5,5,5,5,3,4,3,3,2,3,2,2,2,2,3,3,5,6,8,8,10], -[10,11,8,8,6,5,3,1,0,-1,-1,-1,0,0,3,3,5,4,6,6,8,8,9,9], -[9,8,8,7,5,4,3,3,1,1,0,2,2,4,5,6,6,7,6,6,4,4,4,4], -[5,6,7,7,8,9,10,9,10,8,7,6,5,3,3,4,3,3,3,3,2,3,2,4], -[3,6,5,8,8,9,9,9,9,7,6,4,2,0,0,-1,-1,0,2,2,4,4,6,5], -[7,6,6,4,5,4,4,5,5,5,4,4,3,4,3,5,3,5,5,6,6,8,7,7], -[7,6,5,4,4,3,4,3,5,5,7,7,9,9,10,9,9,7,7,6,6,5,5,6], -[6,6,6,7,5,6,5,7,7,9,8,10,8,9,8,8,6,5,4,2,3,2,3,3], -[6,7,9,9,10,8,9,7,7,5,5,4,3,3,3,3,3,4,3,5,4,4,4,6], -[5,7,7,8,7,7,6,5,4,2,3,2,3,2,4,4,7,6,8,7,8,6,6,5], -[5,4,3,4,3,4,4,5,5,7,6,7,6,8,7,8,8,8,7,7,6,6,5,3], -[3,2,3,2,4,4,7,7,9,8,9,9,8,6,5,5,4,4,3,3,3,4,3,4], -[3,5,4,5,4,5,5,5,5,5,5,5,4,3,3,1,2,0,2,2,4,5,7,6], -[8,6,7,4,5,3,2,2,1,2,1,3,3,5,6,7,6,7,5,6,5,6,6,6], -[7,6,6,5,4,3,4,3,3,3,5,5,7,8,10,10,11,10,8,7,5,4,3,3], -[3,5,4,7,6,8,8,9,8,9,9,8,8,8,8,8,8,8,8,6,6,4,5,4], -[6,5,7,7,8,8,9,9,7,7,5,5,3,3,2,4,4,6,6,8,8,11,10,9], -[8,8,7,6,4,4,4,3,4,2,3,2,3,3,5,5,7,7,9,9,11,11,11,11], -[10,9,8,6,5,5,4,4,4,5,5,7,6,7,8,8,7,7,7,6,7,6,8,7], -[8,8,8,7,8,7,8,7,7,7,6,5,5,5,4,4,2,3,1,1,1,3,2,5], -[6,7,8,9,8,10,8,7,6,4,3,2,1,0,1,-1,0,-1,1,1,3,3,5,5], -[5,6,6,6,6,6,5,5,2,3,1,1,0,2,2,3,3,4,4,4,4,4,3,3], -[3,2,3,2,3,2,4,3,5,5,6,5,7,5,6,6,6,6,6,5,4,4,2,3], -[1,2,1,3,2,4,4,7,7,8,8,8,7,6,5,4,3,2,2,2,3,2,4,3], -[5,5,5,5,5,5,5,4,3,3,3,3,2,3,1,1,0,2,1,4,4,5,6,8], -[7,8,6,6,5,4,3,1,2,0,1,1,3,3,5,5,6,6,7,6,7,6,6,7], -[6,7,6,6,6,6,4,4,4,4,4,6,6,7,8,9,10,9,8,7,6,4,4,3], -[4,4,6,5,8,8,10,10,11,10,9,8,7,7,6,6,6,6,5,6,4,4,4,4], -[3,5,5,6,6,8,9,9,9,8,7,5,5,3,4,2,4,3,5,6,8,7,9,8], -[8,7,6,5,4,4,3,4,4,5,4,5,5,6,6,7,7,8,7,8,9,9,9,8], -[8,7,6,3,4,2,3,3,5,5,7,8,9,10,10,10,10,9,8,8,6,7,6,7], -[6,8,6,7,6,7,6,6,6,6,7,7,8,7,7,7,7,4,6,3,4,3,5,4], -[7,7,8,8,9,8,7,7,4,3,1,1,0,2,1,3,2,4,3,5,5,7,6,7], -[8,8,8,8,7,6,6,3,3,1,1,-1,0,0,2,3,5,6,7,7,7,7,6,6], -[5,5,3,4,3,4,3,4,3,4,3,4,3,4,3,4,5,5,5,5,5,4,4,2], -[3,2,3,3,4,4,6,7,8,7,7,6,5,4,1,1,-1,1,-1,1,1,2,3,5], -[5,6,5,6,5,5,5,3,4,3,2,1,1,-1,-1,-2,-1,-3,-1,-1,2,3,5,6], -[7,7,7,6,5,3,2,2,0,1,-1,1,0,2,3,4,4,4,3,3,3,3,4,4], -[5,5,6,5,6,4,5,3,5,4,5,5,6,6,7,7,7,7,6,4,3,3,1,2], -[1,3,3,6,6,8,8,9,9,8,8,7,7,5,6,5,5,4,4,2,4,3,4,3], -[4,4,6,6,7,7,8,8,8,7,5,5,2,3,2,3,3,4,4,6,6,7,8,8], -[8,7,7,5,6,4,4,3,4,3,4,4,4,4,6,6,7,8,8,8,9,9,8,9], -[7,8,6,6,4,5,3,4,5,5,6,8,8,9,10,9,10,7,7,6,7,6,6,5], -[7,6,7,7,8,7,8,9,9,8,7,8,7,7,6,6,4,5,3,3,2,3,3,5], -[5,7,7,8,9,8,9,7,6,5,5,2,3,2,3,3,3,3,4,4,4,4,5,5], -[5,6,4,5,4,5,3,4,3,3,2,2,2,4,5,6,8,8,9,7,8,6,6,3], -[4,2,2,0,2,2,3,3,4,5,5,6,7,8,7,9,8,8,7,7,5,6,4,4], -[1,2,1,2,1,2,3,4,6,6,7,6,7,5,6,4,5,3,3,3,5,4,5,5], -[6,6,6,6,4,4,2,3,1,2,-1,1,0,1,0,1,1,2,2,4,4,6,7,7], -[8,8,8,5,5,2,1,-1,-2,-3,-3,-2,-1,0,2,4,4,5,6,6,5,6,5,6], -[6,7,5,7,6,6,5,4,4,3,3,4,4,5,5,5,7,5,7,4,5,3,4,2], -[4,3,5,5,7,8,9,10,9,9,6,6,3,3,1,2,1,2,1,3,3,3,3,3], -[4,4,5,5,7,6,7,7,8,6,6,3,3,0,1,0,1,1,1,3,5,6,7,8], -[7,7,5,5,3,4,3,3,2,4,3,4,4,4,4,4,5,5,5,5,7,6,7,6], -[7,5,5,3,3,3,3,2,3,4,5,8,7,8,8,8,6,7,4,4,3,4,3,5], -[4,5,5,6,7,6,7,6,7,6,7,6,7,5,6,5,5,2,2,0,1,1,2,4], -[5,7,7,9,8,9,7,6,4,4,1,1,0,1,1,2,3,3,3,4,3,4,5,5], -[6,5,6,5,6,4,4,3,3,1,1,1,1,2,3,4,5,7,7,8,7,6,5,5], -[3,4,2,3,3,3,3,4,5,5,6,5,6,5,7,6,7,6,6,5,6,5,5,3], -[3,2,2,3,3,4,5,7,6,8,7,7,5,5,3,2,2,2,1,1,2,3,4,5], -[6,6,6,5,5,4,4,3,3,2,3,2,2,0,1,0,1,1,1,2,3,5,5,8], -[7,8,6,7,4,4,2,1,0,0,0,1,2,3,5,5,7,6,7,5,6,4,5,4], -[5,4,5,4,5,5,4,4,4,5,5,6,6,8,7,9,9,9,7,7,5,5,3,3], -[2,3,4,5,6,6,8,8,8,8,8,6,6,5,5,5,5,4,5,5,5,5,4,5], -[5,6,5,6,5,6,5,6,4,5,3,2,1,1,1,1,2,3,6,6,8,9,10,9], -[10,8,8,5,5,3,3,1,2,2,2,1,2,3,3,5,6,7,7,8,8,10,8,9], -[8,8,7,6,4,4,3,2,3,3,4,4,5,5,7,6,7,4,5,4,4,3,4,4], -[6,6,7,7,7,9,8,9,7,8,5,5,4,3,3,2,2,1,0,0,0,1,2,2], -[5,5,8,8,9,8,9,6,6,3,2,1,0,-2,-2,-1,-1,0,0,1,1,2,3,3], -[3,4,4,5,4,5,4,4,4,2,2,1,2,1,2,3,4,3,5,4,4,3,3,1], -[2,1,1,0,1,2,3,4,5,7,6,7,6,7,6,6,5,5,4,3,2,3,1,1], -[1,1,1,1,2,3,4,4,6,7,8,7,7,5,4,3,2,1,0,0,0,1,2,4], -[4,6,5,6,4,4,2,2,2,1,1,1,1,1,1,1,2,2,2,2,4,3,6,5], -[7,7,8,6,6,4,3,1,0,0,0,1,1,3,4,7,6,8,7,8,5,6,5,6], -[5,5,5,5,5,5,6,5,6,5,5,5,7,7,8,8,9,8,8,6,6,4,4,4], -[3,3,4,6,7,9,10,11,11,11,8,8,6,6,4,4,4,5,4,5,5,6,6,5], -[6,5,6,6,7,6,8,7,8,6,6,5,4,3,2,2,2,3,4,6,6,9,9,10], -[8,8,5,6,4,4,2,3,3,3,4,4,5,6,7,6,8,7,9,8,9,8,9,8], -[8,6,6,4,4,3,2,4,3,6,6,7,7,9,9,9,8,8,6,6,4,5,4,5], -[5,5,6,6,6,5,6,5,6,5,6,5,5,5,5,5,5,4,3,3,2,3,4,5], -[5,8,6,9,7,8,6,4,3,1,0,-1,-1,-1,0,0,3,3,4,4,6,5,6,5], -[6,4,5,4,4,2,2,1,0,0,-2,-2,-1,0,0,3,4,7,6,8,7,7,6,5], -[4,3,2,2,2,1,3,3,4,3,4,3,4,4,4,4,4,4,5,4,4,4,4,4], -[3,4,2,3,2,4,4,5,4,6,5,4,2,2,1,-1,-1,-1,-2,-1,1,2,3,3], -[6,5,6,5,5,4,4,3,2,1,1,0,-1,-1,-2,-1,-2,-1,-1,1,1,3,4,6], -[6,7,7,6,5,5,3,2,2,0,1,0,2,2,4,3,5,4,5,3,3,2,3,3], -[3,3,3,4,4,5,4,5,6,7,6,6,6,7,6,6,6,6,5,4,2,2,1,0], -[1,1,3,3,5,6,8,8,9,8,9,8,7,5,5,3,3,3,2,2,2,3,2,5], -[4,5,4,5,5,5,5,5,5,4,4,3,4,2,3,3,4,3,5,4,7,7,8,7], -[7,7,6,4,3,3,1,2,1,2,1,4,4,6,6,8,8,8,8,9,8,8,8,8], -[8,6,7,5,5,4,4,3,4,4,6,6,7,7,9,8,9,8,7,5,5,5,5,5], -[5,7,6,8,7,9,8,8,7,7,6,5,5,4,4,3,3,2,3,2,3,2,4,4], -[6,6,8,7,9,7,8,6,5,4,2,1,0,0,-1,1,1,3,3,5,4,6,5,6], -[5,5,5,4,3,3,4,3,4,2,3,1,2,2,3,4,6,6,7,6,7,5,5,4], -[3,2,1,1,0,2,1,3,4,6,6,7,6,7,5,6,5,5,5,5,5,4,5,4], -[4,2,3,2,3,2,3,3,4,5,5,4,4,4,3,1,0,0,0,1,0,2,4,5], -[5,7,6,6,4,3,1,0,-1,-2,-2,-2,-2,-1,0,-1,1,1,2,2,4,4,6,6], -[8,7,7,7,6,4,2,1,-1,-1,-2,-1,-1,1,2,5,5,7,6,6,5,5,5,5], -[5,4,5,5,6,5,6,5,5,4,4,3,3,3,5,5,5,6,5,5,4,4,3,3], -[2,3,3,6,6,9,9,10,9,9,7,6,4,3,1,1,1,1,2,2,4,4,5,5], -[7,5,7,6,7,6,6,6,5,6,3,3,1,1,0,0,-1,1,2,5,4,7,7,8], -[8,8,6,6,5,4,3,2,4,3,4,4,5,4,5,5,6,5,6,5,6,5,5,6], -[6,6,5,6,4,5,3,5,5,7,7,8,8,9,8,8,6,5,4,2,2,1,2,2], -[3,4,6,6,7,7,8,7,7,7,6,6,6,6,5,4,3,3,1,1,-1,1,1,2], -[2,5,5,7,6,6,6,5,5,3,3,0,2,1,2,2,4,3,5,4,5,4,4,4], -[4,3,3,3,2,3,2,3,2,3,2,3,3,4,4,6,8,9,8,8,8,6,6,4], -[3,1,2,0,1,0,3,3,5,5,7,6,7,7,7,7,6,7,6,7,5,6,4,4], -[3,4,2,4,3,5,5,5,6,6,6,5,6,4,4,3,3,2,3,2,3,4,6,5], -[8,7,7,6,6,4,4,3,1,2,1,1,0,1,1,3,2,3,2,4,4,5,6,7], -[8,8,7,6,6,4,4,2,3,0,2,1,3,4,5,6,8,8,9,7,6,6,6,6], -[4,5,4,5,4,6,5,7,6,7,6,7,7,7,7,7,8,7,7,6,6,4,5,3], -[3,2,4,4,5,6,8,8,8,8,7,7,6,5,4,4,2,4,3,4,4,7,6,8], -[7,7,7,6,6,5,5,4,5,3,3,2,1,1,1,2,2,3,5,5,8,9,10,9], -[9,9,7,6,3,3,0,1,-1,1,0,2,1,3,4,6,5,6,7,6,7,7,8,7], -[9,7,8,6,6,4,5,4,4,4,5,4,6,6,6,6,5,5,4,4,3,4,3,4], -[5,7,6,9,8,9,9,8,6,5,4,2,2,0,1,0,1,0,1,0,2,2,3,3], -[5,5,6,7,7,7,6,7,4,3,1,0,-2,-1,-2,-1,-1,1,1,3,4,4,5,5], -[5,4,4,3,4,3,4,3,4,2,3,2,2,2,2,3,4,5,5,5,4,5,3,4], -[2,2,0,2,1,2,2,4,5,6,6,7,7,6,5,3,4,3,3,2,3,2,3,2], -[3,2,3,2,3,3,4,5,5,6,5,6,5,4,3,2,0,0,-2,0,-1,1,2,4], -[5,6,7,5,6,4,4,2,2,0,1,-1,1,1,2,2,3,3,3,3,3,3,4,5], -[5,7,5,6,4,4,3,3,1,2,1,2,2,4,6,8,8,9,9,8,7,5,5,3], -[4,3,5,4,6,6,7,7,7,7,7,7,7,8,8,9,8,9,8,8,7,6,4,5], -[3,4,4,5,6,8,9,9,10,9,9,7,7,5,5,3,5,4,5,4,6,7,8,8], -[8,7,6,6,5,6,5,6,5,6,4,4,3,3,2,3,4,5,5,7,8,9,10,10], -[10,8,8,6,5,2,3,2,3,3,3,4,5,6,7,7,8,9,8,8,7,8,6,8], -[7,8,6,6,4,5,4,4,5,5,6,7,8,7,8,7,8,6,6,4,5,3,4,4], -[6,6,7,7,8,8,7,7,6,5,4,4,3,3,2,3,1,2,0,2,1,2,3,4], -[5,5,6,6,7,5,5,3,3,0,0,-2,-2,-2,-2,-1,1,2,4,3,5,5,4,5], -[5,5,4,5,3,4,2,2,1,1,1,2,1,2,2,4,5,5,7,6,7,5,6,4], -[5,2,3,2,2,2,2,3,4,4,5,5,5,5,4,4,3,3,2,3,3,4,3,4], -[4,4,4,5,5,6,6,5,5,5,5,3,3,1,2,-1,-1,-1,-1,-1,1,2,3,5], -[7,8,7,8,6,7,4,4,2,2,0,0,-1,0,-1,1,1,1,2,2,2,3,4,4], -[7,6,8,6,7,5,6,4,3,2,2,2,2,3,4,5,6,7,6,6,5,5,2,3], -[2,4,3,4,5,6,7,8,8,9,9,8,9,7,7,6,6,5,6,5,5,3,3,2], -[3,3,3,4,5,6,8,9,9,10,8,8,6,6,4,4,3,2,2,3,3,5,5,6], -[7,6,6,5,5,4,5,3,4,3,4,3,5,4,4,4,4,5,6,7,7,8,8,9], -[8,9,7,6,4,3,2,2,2,2,3,4,6,7,9,8,10,9,10,8,8,7,8,7], -[8,6,7,5,5,5,5,5,5,6,6,8,7,9,10,10,9,9,7,7,5,5,4,5], -[5,5,6,8,9,8,9,8,9,6,7,5,5,4,4,4,5,4,5,4,4,4,5,6], -[6,6,6,7,7,7,6,6,5,4,2,1,1,1,1,2,3,5,7,6,8,6,8,6], -[6,4,4,3,4,3,3,2,3,4,4,4,4,4,5,6,7,8,7,9,8,8,7,7], -[5,4,2,2,1,1,2,3,5,5,7,7,8,6,7,5,5,4,5,4,5,4,5,5], -[4,5,3,4,3,3,3,4,2,4,3,4,2,3,2,2,1,1,-1,0,1,3,5,6], -[8,8,9,7,7,5,4,1,1,-1,-1,-2,-1,0,0,2,2,3,3,4,4,5,5,7], -[6,7,6,7,5,5,4,2,1,0,0,0,1,2,4,5,7,7,8,7,7,5,5,4], -[4,4,4,4,6,6,7,8,7,8,6,7,6,6,6,7,5,6,5,6,5,5,5,4], -[4,5,6,6,7,8,9,10,10,8,8,6,5,3,2,1,1,1,2,2,4,5,6,8], -[8,9,8,8,7,7,5,6,5,5,4,3,2,2,2,1,2,3,4,4,6,7,9,9], -[10,8,9,7,6,5,4,4,3,4,4,4,5,6,6,7,6,7,5,6,5,6,5,6], -[5,6,6,7,6,6,6,6,7,6,8,7,8,7,8,6,6,5,4,3,2,1,2,3], -[3,5,6,7,7,9,8,9,8,7,6,6,4,4,3,3,3,1,1,1,1,1,3,3], -[4,4,6,5,7,5,6,5,4,3,2,1,1,1,1,2,3,5,4,7,6,6,5,5], -[3,4,2,3,1,2,2,2,3,2,3,3,5,5,6,6,8,7,9,7,8,6,7,5], -[5,4,3,2,1,2,3,5,5,6,6,8,8,9,7,7,7,6,5,5,5,5,5,5], -[6,6,7,5,6,5,6,6,6,5,5,4,5,4,4,3,2,2,2,2,3,5,5,7], -[8,9,9,9,8,7,5,4,3,2,2,1,1,1,2,3,5,5,7,6,7,6,8,7], -[8,8,9,8,7,7,6,6,4,4,3,4,4,5,6,8,8,10,9,10,8,8,6,6], -[4,4,4,4,5,5,7,8,9,9,11,9,9,8,8,7,7,7,7,7,7,7,6,7], -[6,6,5,6,6,7,7,9,8,9,8,7,6,5,4,3,2,3,3,3,5,5,8,8], -[9,7,8,6,6,3,3,3,2,2,2,1,1,2,2,3,3,5,4,6,7,8,8,9], -[9,9,7,6,5,4,3,2,2,1,2,3,5,5,7,7,9,7,8,6,7,6,7,7], -[7,7,7,7,6,6,5,6,5,6,5,6,5,6,6,7,7,6,4,4,2,3,2,3], -[5,4,8,8,9,9,10,8,8,6,5,3,3,1,1,1,1,2,2,3,2,3,3,4], -[5,7,6,7,7,8,7,7,5,3,2,1,1,0,0,0,2,2,5,5,6,5,7,5], -[5,4,4,3,3,4,4,4,4,5,4,5,3,5,5,5,5,6,5,7,6,6,5,5], -[4,3,2,1,2,2,4,4,7,7,9,9,9,7,7,6,4,3,3,2,2,3,3,4], -[4,6,5,6,5,6,5,6,5,6,5,5,5,5,3,3,2,0,1,-1,2,1,4,4], -[7,7,8,7,7,5,5,3,2,2,0,1,1,2,3,5,5,6,5,7,5,6,5,6], -[5,6,6,6,6,5,5,4,4,3,4,4,5,5,8,9,11,10,11,9,10,8,7,5], -[4,4,4,4,4,6,6,8,8,10,9,10,9,9,9,10,9,9,8,9,8,8,7,6], -[7,5,7,6,8,7,9,9,9,9,9,7,7,6,5,5,3,5,5,7,7,10,9,11], -[10,11,9,9,7,6,5,5,4,4,3,2,3,3,4,3,6,6,8,8,10,10,11,11], -[11,10,9,8,6,5,4,4,2,4,3,5,5,6,7,9,8,9,9,8,8,8,8,8], -[8,7,8,7,8,7,7,6,7,6,8,6,7,6,7,6,6,6,4,4,3,4,3,5], -[4,7,6,8,7,8,7,7,7,5,3,3,2,1,2,1,1,0,2,1,3,2,4,4], -[6,5,6,5,6,6,5,5,3,3,0,0,-1,0,0,1,2,4,4,5,5,6,5,6], -[5,4,3,2,2,1,1,0,2,1,3,2,3,4,5,4,5,6,6,6,6,6,6,5], -[4,4,3,3,1,3,2,4,4,6,5,7,6,6,6,6,5,4,3,3,3,3,4,4], -[6,6,8,6,8,7,6,6,5,5,4,3,2,2,1,2,0,1,0,2,1,3,4,7], -[7,9,8,9,8,8,6,5,4,2,0,-1,0,0,1,2,4,3,5,4,5,5,5,6], -[7,7,7,7,7,8,7,7,6,6,5,5,4,5,5,7,7,8,8,7,7,6,5,4], -[4,3,4,4,6,6,9,9,11,11,12,11,10,8,7,7,5,6,5,6,4,5,4,5], -[4,5,4,6,6,8,8,10,10,10,10,9,8,6,6,4,3,2,3,3,5,5,8,7], -[8,8,7,7,6,6,4,4,4,5,4,5,4,5,5,7,5,7,6,8,7,8,9,9], -[9,8,8,6,5,3,4,2,4,3,6,5,8,8,10,11,10,11,10,9,8,7,7,7], -[6,7,6,8,7,8,6,7,7,7,8,8,9,9,10,10,10,9,8,6,6,5,5,4], -[6,6,8,8,10,9,10,9,8,7,5,5,4,4,3,4,4,5,4,6,5,6,6,7], -[7,7,7,7,7,8,7,6,6,3,4,1,1,1,3,2,5,6,9,8,9,9,9,9], -[8,7,6,5,3,4,3,4,3,4,3,4,4,5,5,6,6,7,7,8,8,7,8,7], -[7,5,5,2,3,3,4,4,5,6,7,7,8,7,5,5,4,3,2,4,3,5,5,7], -[7,8,7,8,8,7,6,5,6,4,4,3,3,2,2,1,1,-1,1,-1,2,2,5,6], -[7,8,9,9,7,7,4,4,2,2,-1,0,-1,0,1,3,4,5,5,6,5,5,5,5], -[6,5,6,5,7,6,6,5,5,4,5,4,5,6,7,7,8,9,9,8,7,7,5,5], -[4,4,3,5,5,6,7,9,9,10,10,9,9,8,8,7,7,6,6,6,6,5,6,5], -[6,5,7,6,7,8,8,9,8,9,7,7,5,5,3,3,3,4,4,5,5,8,8,10], -[10,10,9,8,7,6,6,4,5,3,4,3,4,3,4,5,6,6,7,7,8,8,9,10], -[10,10,8,9,6,6,4,5,4,5,5,6,6,7,8,8,9,8,8,7,7,6,7,5], -[7,6,7,6,8,7,8,8,9,9,9,8,8,8,7,7,6,6,3,4,2,2,2,3], -[3,5,5,7,7,9,9,9,9,7,7,5,4,3,3,2,2,1,3,2,3,3,4,4], -[5,4,4,5,4,5,4,5,4,5,3,4,2,2,2,4,5,6,7,7,7,7,6,5], -[6,3,4,2,2,0,2,2,3,4,5,6,8,7,8,9,8,9,8,9,7,8,6,7], -[5,5,3,4,2,3,3,4,5,6,8,8,9,9,9,8,7,5,6,5,5,4,6,6], -[7,7,8,8,7,7,6,6,4,5,4,4,3,4,4,5,4,4,4,5,5,6,8,9], -[10,10,11,9,9,7,6,4,3,1,2,0,1,1,3,5,6,8,9,9,9,9,8,8], -[7,9,7,8,7,7,6,6,6,5,5,5,5,6,7,8,9,10,11,11,11,9,9,7], -[7,5,6,5,7,7,9,10,9,10,9,9,8,7,5,5,4,6,4,5,5,7,7,7], -[7,7,6,6,6,7,7,6,7,6,6,4,4,2,2,0,1,0,1,1,4,5,8,9], -[10,10,9,9,7,6,4,4,2,3,2,2,2,2,2,3,3,4,5,5,6,6,8,8], -[9,8,8,6,7,5,4,2,2,2,3,4,5,6,6,7,7,7,5,6,4,5,3,5]] +let sunData: [[Int8]] = [[4, 3, 3, 2, 3, 3, 2, 2, 1, 1, 1, 1, 1, 3, 3, 6, 5, 8, 6, 8, 7, 7, 6, 5], +[4, 2, 1, 1, 2, 2, 3, 3, 4, 4, 6, 5, 7, 6, 7, 5, 5, 5, 6, 4, 5, 5, 5, 5], +[5, 5, 4, 4, 4, 6, 5, 6, 6, 7, 6, 6, 4, 4, 3, 2, 1, 0, 0, 1, 3, 3, 5, 6], +[8, 7, 9, 7, 7, 6, 5, 4, 3, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 4, 3, 5, 4, 6], +[5, 7, 6, 6, 5, 5, 4, 3, 2, 2, 2, 2, 3, 5, 7, 7, 8, 7, 8, 6, 6, 4, 4, 3], +[3, 3, 3, 4, 4, 6, 5, 6, 7, 8, 7, 9, 8, 9, 9, 9, 9, 9, 8, 8, 6, 5, 5, 3], +[4, 2, 3, 3, 5, 5, 8, 7, 9, 8, 9, 8, 8, 6, 6, 6, 4, 5, 5, 6, 6, 7, 6, 7], +[6, 7, 5, 6, 4, 4, 3, 4, 3, 3, 2, 2, 3, 2, 4, 3, 5, 5, 7, 8, 10, 9, 11, 9], +[11, 8, 7, 5, 4, 2, 0, 0, -1, 0, 0, 1, 2, 5, 5, 7, 6, 8, 7, 8, 8, 8, 8, 8], +[7, 7, 6, 5, 4, 3, 3, 1, 3, 2, 3, 3, 5, 5, 6, 5, 6, 5, 4, 4, 3, 4, 3, 5], +[5, 7, 6, 8, 8, 10, 8, 8, 6, 5, 3, 2, 2, 1, 1, 0, 0, 0, 1, 0, 1, 1, 3, 3], +[5, 5, 6, 6, 7, 7, 6, 4, 3, 1, 0, -2, -3, -3, -3, -2, -2, 0, 0, 3, 2, 4, 3, 4], +[2, 2, 2, 3, 3, 2, 3, 2, 2, 1, 1, 0, 1, 1, 2, 1, 3, 3, 4, 4, 4, 4, 3, 3], +[2, 1, 0, 1, -1, 1, 1, 4, 4, 6, 6, 6, 5, 6, 4, 4, 2, 2, 2, 2, 2, 2, 3, 2], +[3, 2, 4, 2, 4, 3, 5, 4, 5, 5, 6, 5, 5, 4, 3, 2, 0, -1, -1, 0, -1, 2, 2, 5], +[5, 7, 6, 7, 6, 5, 3, 2, 2, 0, 0, 0, 0, 1, 2, 2, 3, 2, 3, 3, 4, 4, 5, 5], +[7, 6, 7, 6, 5, 4, 3, 3, 1, 2, 0, 2, 2, 5, 5, 8, 7, 9, 8, 8, 6, 5, 5, 4], +[5, 3, 4, 5, 6, 6, 7, 7, 7, 7, 8, 6, 7, 7, 8, 8, 8, 7, 7, 7, 7, 6, 5, 5], +[4, 4, 5, 6, 7, 9, 10, 10, 9, 10, 8, 8, 7, 5, 4, 2, 3, 2, 5, 4, 6, 6, 8, 6], +[8, 6, 8, 6, 6, 5, 6, 6, 5, 5, 4, 4, 3, 3, 1, 2, 1, 4, 3, 6, 6, 9, 8, 9], +[8, 8, 6, 5, 4, 3, 3, 2, 3, 2, 4, 3, 6, 6, 7, 7, 7, 7, 7, 6, 7, 6, 6, 6], +[6, 6, 5, 5, 4, 4, 3, 5, 4, 6, 7, 8, 9, 9, 8, 8, 7, 6, 5, 4, 3, 2, 3, 2], +[4, 4, 6, 5, 7, 7, 8, 7, 7, 6, 6, 5, 6, 5, 5, 5, 4, 4, 3, 3, 2, 3, 3, 5], +[4, 6, 5, 6, 6, 5, 5, 3, 3, 0, 0, -1, 0, 0, 1, 2, 5, 4, 7, 5, 7, 5, 6, 5], +[4, 3, 1, 2, 0, 0, -1, 0, 0, 1, -1, 1, 0, 2, 3, 5, 6, 8, 7, 8, 8, 7, 7, 5], +[5, 3, 3, 1, 2, 1, 2, 1, 3, 3, 5, 4, 5, 5, 5, 5, 4, 5, 4, 5, 5, 5, 4, 6], +[5, 5, 4, 5, 5, 5, 4, 4, 4, 3, 2, 3, 2, 1, 1, -1, 0, -2, 0, 0, 2, 3, 5, 6], +[7, 8, 8, 7, 7, 6, 4, 3, 1, 0, -1, -1, -2, -1, -1, 0, -1, 1, 1, 2, 3, 4, 4, 5], +[5, 6, 7, 5, 6, 4, 5, 3, 3, 1, 1, 0, 1, 2, 3, 4, 5, 5, 5, 5, 3, 3, 2, 2], +[2, 2, 2, 4, 4, 5, 6, 7, 7, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 4, 4, 2, 3, 1], +[3, 2, 4, 3, 6, 7, 8, 8, 9, 9, 8, 8, 6, 6, 4, 3, 1, 2, 1, 3, 3, 5, 5, 7], +[5, 7, 5, 5, 4, 4, 4, 3, 4, 3, 3, 2, 3, 3, 3, 3, 4, 3, 5, 5, 6, 7, 8, 8], +[8, 7, 6, 5, 2, 2, 1, 1, 0, 2, 2, 4, 5, 6, 7, 8, 8, 8, 7, 7, 7, 7, 7, 6], +[7, 5, 7, 5, 5, 4, 5, 3, 4, 5, 6, 6, 7, 8, 8, 9, 7, 7, 5, 5, 4, 4, 3, 4], +[3, 5, 6, 8, 9, 9, 9, 9, 7, 6, 5, 4, 4, 2, 3, 3, 3, 2, 3, 2, 3, 3, 4, 5], +[5, 5, 6, 7, 7, 7, 6, 6, 4, 3, 1, 1, -1, 1, 0, 2, 2, 4, 4, 6, 6, 7, 6, 5], +[5, 4, 3, 1, 2, 1, 3, 2, 3, 1, 3, 2, 3, 3, 4, 4, 5, 6, 6, 6, 6, 7, 5, 5], +[3, 3, 1, 2, 0, 1, 1, 3, 4, 6, 7, 8, 7, 7, 7, 5, 5, 3, 5, 4, 4, 4, 5, 4], +[6, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 5, 5, 4, 3, 3, 1, 1, -1, 1, 1, 3, 4, 6], +[7, 8, 8, 6, 6, 4, 3, 1, 1, -2, 0, -1, 0, 0, 3, 2, 4, 4, 5, 5, 6, 6, 6, 7], +[7, 8, 6, 7, 5, 5, 3, 3, 1, 0, 0, 1, 1, 3, 5, 6, 9, 8, 9, 8, 8, 6, 6, 4], +[5, 3, 5, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 7, 6, 7, 6, 6, 5, 6], +[4, 5, 4, 6, 7, 8, 9, 9, 9, 7, 7, 5, 4, 2, 2, 0, 1, 1, 2, 3, 5, 6, 7, 8], +[9, 8, 7, 7, 6, 6, 5, 4, 2, 3, 1, 1, 0, 0, -1, 0, 0, 2, 3, 4, 5, 7, 7, 8], +[9, 7, 7, 5, 5, 2, 4, 2, 3, 2, 3, 3, 4, 4, 5, 5, 4, 5, 5, 5, 4, 5, 4, 6], +[4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 6, 5, 5, 2, 3, 1, 2, 0, 1, 1], +[3, 3, 5, 6, 7, 8, 8, 9, 7, 6, 5, 5, 3, 4, 2, 3, 0, 1, 0, 0, 0, 1, 1, 2], +[3, 3, 4, 4, 5, 5, 6, 4, 4, 2, 2, 0, 1, 0, 1, 2, 3, 3, 4, 4, 5, 4, 4, 4], +[3, 3, 1, 2, 1, 0, 1, 1, 1, 2, 3, 3, 4, 4, 5, 5, 7, 7, 8, 6, 7, 6, 6, 4], +[4, 1, 3, 1, 1, 1, 2, 4, 4, 6, 7, 8, 8, 9, 7, 7, 5, 5, 4, 5, 4, 5, 4, 5], +[5, 6, 6, 6, 5, 5, 6, 5, 6, 5, 6, 4, 5, 4, 4, 2, 3, 1, 2, 2, 3, 4, 5, 7], +[7, 8, 8, 8, 7, 7, 5, 5, 2, 2, 0, 2, 1, 2, 3, 3, 4, 5, 5, 5, 5, 5, 6, 5], +[8, 6, 7, 6, 7, 5, 6, 4, 5, 3, 4, 3, 5, 6, 6, 8, 9, 10, 9, 9, 7, 7, 5, 5], +[3, 3, 2, 4, 4, 5, 6, 8, 8, 8, 9, 9, 9, 8, 8, 7, 8, 7, 8, 6, 7, 6, 6, 5], +[4, 4, 4, 5, 5, 7, 6, 8, 8, 8, 7, 8, 6, 6, 4, 4, 3, 4, 3, 5, 6, 8, 8, 8], +[9, 8, 8, 6, 6, 3, 3, 2, 3, 1, 1, 0, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 10], +[8, 8, 5, 5, 3, 1, -1, -1, -2, -1, 0, 2, 3, 4, 6, 6, 8, 7, 8, 6, 7, 6, 7, 6], +[7, 6, 7, 6, 6, 5, 4, 5, 4, 4, 3, 5, 4, 6, 6, 6, 6, 5, 4, 4, 3, 4, 3, 4], +[5, 5, 6, 7, 8, 8, 9, 6, 7, 4, 3, 1, 1, -1, 0, -1, 1, 0, 1, 1, 2, 3, 3, 5], +[4, 5, 5, 6, 6, 6, 4, 5, 2, 2, 0, -1, -2, -2, -2, -1, 0, 2, 3, 4, 5, 5, 6, 4], +[4, 2, 3, 1, 2, 1, 2, 2, 2, 3, 2, 3, 2, 3, 2, 4, 3, 4, 4, 6, 5, 6, 4, 5], +[3, 3, 1, 1, 0, 2, 2, 3, 5, 5, 7, 7, 7, 6, 6, 3, 4, 1, 1, 1, 2, 2, 4, 4], +[4, 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 4, 4, 3, 2, 0, 0, -1, -1, 0, 2, 4, 5], +[7, 6, 8, 7, 8, 5, 5, 3, 2, 0, 1, 0, 1, 2, 2, 3, 5, 5, 4, 5, 4, 4, 3, 5], +[4, 5, 4, 6, 4, 5, 4, 4, 3, 3, 3, 4, 5, 6, 8, 8, 9, 8, 10, 8, 9, 6, 6, 4], +[4, 3, 3, 3, 5, 6, 7, 9, 8, 10, 8, 9, 9, 9, 8, 9, 8, 9, 7, 8, 7, 7, 6, 6], +[5, 4, 6, 6, 7, 7, 9, 8, 9, 8, 9, 7, 6, 5, 4, 4, 4, 3, 4, 5, 6, 7, 8, 9], +[8, 9, 8, 8, 6, 6, 5, 5, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5, 6, 6, 8, 7, 9, 8], +[9, 7, 8, 5, 5, 4, 3, 3, 2, 3, 3, 5, 5, 7, 7, 8, 7, 8, 7, 7, 6, 6, 6, 6], +[5, 6, 5, 5, 5, 6, 6, 6, 7, 6, 8, 6, 8, 8, 8, 7, 7, 5, 6, 4, 4, 3, 3, 4], +[4, 6, 5, 7, 7, 7, 7, 8, 6, 6, 4, 4, 3, 3, 3, 3, 2, 3, 2, 3, 3, 3, 5, 4], +[6, 4, 5, 3, 5, 3, 3, 2, 2, 0, 0, -1, 0, -1, 0, 2, 3, 5, 6, 8, 7, 8, 7, 7], +[5, 5, 3, 3, 1, 1, 0, 1, 0, 0, 1, 2, 3, 3, 4, 4, 6, 5, 8, 7, 8, 7, 8, 6], +[6, 4, 3, 2, 2, 3, 1, 3, 2, 4, 4, 5, 5, 5, 5, 4, 2, 3, 2, 3, 3, 5, 5, 5], +[7, 7, 8, 7, 8, 7, 7, 5, 6, 4, 4, 2, 2, 1, 1, 0, 0, 0, -1, 1, 2, 3, 4, 8], +[7, 9, 9, 10, 9, 8, 6, 4, 2, 1, 0, -1, -2, -1, 0, 1, 3, 2, 4, 4, 5, 4, 6, 4], +[6, 5, 6, 5, 7, 6, 6, 5, 5, 4, 3, 4, 3, 5, 4, 6, 6, 7, 6, 7, 6, 6, 4, 4], +[3, 3, 3, 3, 4, 6, 8, 9, 10, 10, 10, 9, 9, 7, 8, 5, 5, 5, 4, 4, 5, 5, 5, 5], +[4, 5, 4, 6, 5, 7, 8, 9, 9, 10, 8, 8, 7, 5, 4, 3, 3, 1, 2, 3, 4, 5, 8, 7], +[9, 8, 8, 6, 6, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 5, 5, 6, 5, 7, 6, 8, 7, 9], +[8, 8, 7, 5, 5, 3, 3, 2, 3, 2, 4, 5, 7, 8, 10, 9, 10, 8, 9, 6, 7, 5, 5, 5], +[5, 6, 6, 6, 6, 7, 6, 7, 7, 8, 6, 9, 8, 9, 9, 9, 8, 7, 6, 6, 4, 3, 4, 3], +[5, 5, 7, 7, 10, 10, 10, 9, 9, 7, 7, 5, 4, 4, 3, 4, 3, 5, 4, 4, 4, 5, 4, 5], +[4, 6, 5, 6, 6, 6, 6, 5, 4, 4, 2, 2, 2, 1, 2, 3, 4, 5, 8, 7, 8, 7, 7, 6], +[5, 3, 3, 2, 2, 2, 2, 3, 3, 5, 5, 6, 5, 7, 6, 8, 7, 8, 7, 9, 8, 8, 7, 6], +[5, 3, 3, 2, 1, 1, 3, 4, 6, 7, 8, 8, 9, 8, 7, 6, 6, 4, 3, 4, 4, 4, 5, 6], +[6, 7, 5, 7, 6, 6, 5, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 3, 4, 6, 6], +[8, 8, 9, 8, 7, 6, 4, 3, 1, 1, -1, 0, 0, 2, 2, 4, 5, 7, 6, 8, 7, 8, 6, 6], +[5, 5, 4, 5, 4, 4, 4, 2, 3, 1, 2, 2, 4, 4, 6, 6, 9, 9, 10, 8, 9, 8, 7, 6], +[5, 5, 4, 4, 4, 6, 6, 8, 7, 9, 8, 8, 7, 6, 6, 7, 6, 6, 7, 6, 7, 7, 8, 7], +[8, 6, 8, 7, 8, 7, 8, 7, 8, 6, 5, 4, 3, 2, 1, 2, 1, 1, 2, 4, 5, 7, 8, 10], +[9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 1, 2, 1, 3, 2, 5, 5, 7, 7, 9, 8], +[9, 9, 8, 7, 5, 5, 4, 4, 3, 4, 2, 4, 4, 5, 5, 6, 5, 6, 5, 5, 4, 5, 5, 4], +[5, 5, 6, 5, 6, 6, 8, 6, 8, 7, 8, 6, 7, 6, 6, 5, 4, 4, 2, 2, 1, 2, 1, 3], +[3, 5, 4, 7, 7, 9, 8, 9, 7, 7, 5, 4, 4, 2, 2, 1, 2, 1, 1, 1, 2, 2, 4, 3], +[5, 3, 4, 4, 4, 4, 3, 4, 2, 3, 1, 1, 0, 2, 2, 3, 3, 6, 5, 6, 7, 7, 5, 5], +[4, 3, 1, 1, 1, 0, 1, 1, 3, 2, 4, 4, 6, 6, 8, 7, 8, 6, 7, 7, 7, 7, 6, 6], +[5, 4, 3, 4, 2, 3, 3, 4, 5, 6, 7, 9, 8, 8, 8, 7, 6, 6, 5, 4, 5, 5, 6, 6], +[7, 7, 9, 8, 9, 7, 8, 6, 6, 5, 4, 4, 4, 4, 3, 4, 3, 4, 3, 4, 4, 5, 5, 8], +[7, 9, 9, 10, 9, 9, 8, 6, 5, 2, 2, 1, 2, 2, 4, 5, 7, 7, 8, 7, 8, 7, 7, 6], +[6, 6, 6, 6, 5, 7, 6, 7, 6, 7, 5, 7, 6, 7, 8, 9, 10, 10, 10, 10, 9, 8, 7, 5], +[4, 3, 4, 3, 5, 5, 8, 8, 11, 11, 11, 11, 11, 10, 8, 8, 7, 7, 6, 7, 7, 8, 6, 8], +[6, 8, 6, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 5, 5, 3, 3, 2, 4, 3, 6, 7, 9, 8], +[9, 8, 8, 5, 4, 3, 2, 1, 1, 1, 0, 2, 1, 4, 3, 5, 4, 6, 6, 8, 7, 8, 8, 9], +[9, 8, 7, 5, 5, 3, 3, 1, 2, 1, 3, 3, 6, 6, 8, 8, 8, 8, 7, 6, 6, 6, 6, 6], +[5, 6, 6, 7, 6, 6, 5, 6, 5, 6, 4, 5, 5, 6, 6, 5, 5, 5, 4, 3, 3, 2, 3, 3], +[5, 5, 7, 7, 10, 9, 10, 8, 7, 6, 4, 3, 1, 0, 0, 1, 1, 2, 1, 3, 3, 5, 5, 6], +[5, 6, 6, 6, 6, 6, 5, 5, 4, 2, 2, -1, -1, -1, 0, 0, 2, 2, 5, 5, 6, 7, 7, 7], +[6, 5, 4, 3, 3, 3, 2, 4, 3, 5, 4, 5, 4, 5, 5, 5, 4, 5, 4, 6, 6, 6, 6, 5], +[6, 4, 5, 4, 5, 4, 6, 6, 7, 8, 8, 8, 9, 7, 6, 5, 3, 3, 1, 1, 0, 3, 3, 5], +[6, 8, 8, 9, 9, 8, 8, 7, 7, 5, 5, 4, 4, 3, 4, 2, 3, 1, 1, 0, 2, 2, 5, 4], +[6, 7, 8, 8, 7, 8, 6, 6, 3, 4, 2, 2, 3, 4, 4, 6, 7, 7, 7, 7, 6, 6, 6, 5], +[5, 4, 5, 4, 6, 4, 5, 5, 6, 6, 7, 7, 8, 9, 10, 11, 11, 11, 10, 10, 9, 9, 6, 6], +[4, 5, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11, 10, 9, 10, 8, 9, 7, 9, 8, 8, 8], +[8, 7, 8, 7, 8, 9, 8, 9, 8, 8, 7, 7, 6, 7, 5, 5, 4, 5, 5, 8, 8, 10, 10, 11], +[11, 11, 9, 8, 8, 6, 5, 3, 4, 3, 4, 2, 4, 4, 5, 5, 7, 8, 9, 9, 9, 10, 9, 10], +[9, 9, 8, 8, 6, 7, 4, 5, 3, 5, 4, 7, 7, 8, 9, 10, 10, 10, 9, 8, 9, 7, 7, 6], +[7, 6, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 7, 5, 5, 4, 4, 3, 5], +[4, 5, 5, 6, 7, 7, 8, 8, 8, 5, 6, 3, 3, 2, 2, 2, 4, 3, 4, 4, 5, 6, 6, 6], +[6, 5, 5, 4, 3, 4, 2, 3, 2, 3, 1, 1, 0, 2, 1, 3, 4, 6, 6, 8, 8, 7, 8, 6], +[5, 3, 3, 0, 0, -1, 0, -1, 0, 0, 3, 3, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 6, 7], +[5, 5, 4, 4, 3, 4, 3, 4, 4, 5, 6, 6, 7, 6, 6, 5, 5, 3, 3, 2, 3, 3, 6, 5], +[7, 8, 9, 9, 9, 9, 7, 6, 4, 4, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 3, 4, 5, 6], +[8, 8, 10, 9, 9, 7, 7, 5, 5, 2, 1, -1, 0, 1, 2, 3, 5, 6, 7, 8, 7, 8, 7, 7], +[5, 6, 5, 7, 6, 7, 6, 7, 7, 7, 6, 6, 6, 6, 6, 6, 8, 7, 9, 8, 9, 7, 7, 5], +[6, 4, 5, 4, 6, 6, 8, 10, 11, 11, 11, 11, 9, 8, 6, 6, 4, 5, 3, 5, 5, 6, 6, 8], +[7, 7, 7, 7, 8, 8, 9, 8, 9, 8, 8, 6, 6, 4, 4, 2, 3, 1, 2, 2, 5, 6, 7, 9], +[9, 9, 8, 8, 5, 6, 4, 4, 3, 4, 2, 4, 4, 5, 5, 6, 5, 6, 6, 6, 7, 7, 7, 7], +[8, 7, 7, 5, 6, 4, 4, 3, 3, 4, 5, 6, 8, 9, 9, 10, 9, 9, 7, 7, 5, 5, 4, 5], +[4, 6, 5, 7, 7, 8, 8, 8, 9, 8, 8, 8, 8, 8, 9, 8, 9, 7, 6, 5, 5, 4, 4, 4], +[4, 5, 6, 7, 8, 9, 8, 9, 8, 7, 4, 4, 2, 3, 2, 3, 3, 5, 5, 6, 7, 7, 8, 7], +[7, 5, 6, 4, 5, 4, 5, 3, 4, 2, 3, 2, 2, 2, 2, 4, 5, 7, 8, 10, 9, 11, 9, 9], +[7, 6, 3, 4, 2, 2, 2, 3, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 8, 7, 8, 7, 8, 7], +[7, 5, 6, 5, 5, 4, 5, 6, 6, 7, 7, 8, 7, 8, 7, 7, 4, 4, 3, 4, 4, 5, 6, 8], +[8, 9, 9, 9, 9, 8, 8, 6, 6, 4, 4, 3, 3, 2, 2, 2, 3, 2, 3, 2, 3, 5, 5, 7], +[7, 8, 7, 8, 6, 7, 5, 5, 2, 2, 0, 1, 1, 2, 3, 4, 6, 6, 8, 8, 8, 7, 7, 6], +[6, 5, 5, 4, 5, 5, 6, 5, 5, 5, 6, 7, 7, 8, 8, 9, 8, 9, 8, 9, 8, 9, 6, 7], +[5, 5, 4, 5, 5, 6, 7, 8, 9, 8, 9, 9, 9, 8, 8, 6, 6, 5, 6, 5, 6, 6, 7, 7], +[8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 6, 6, 4, 5, 3, 3, 2, 3, 3, 5, 6, 7, 8, 9], +[10, 10, 11, 8, 8, 6, 5, 4, 3, 2, 2, 1, 2, 3, 3, 4, 5, 6, 6, 7, 6, 8, 7, 8], +[8, 9, 7, 8, 6, 6, 6, 6, 5, 4, 5, 5, 6, 6, 8, 7, 8, 7, 7, 6, 6, 4, 5, 4], +[5, 4, 5, 6, 7, 9, 9, 10, 9, 10, 8, 9, 7, 8, 6, 6, 4, 5, 3, 3, 2, 2, 2, 3], +[3, 4, 5, 6, 8, 8, 9, 9, 9, 7, 6, 4, 4, 2, 2, 1, 2, 1, 3, 3, 4, 5, 4, 5], +[4, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 5, 5, 7, 7, 8, 7, 7, 5], +[5, 4, 3, 1, 2, 1, 2, 2, 3, 4, 6, 7, 8, 9, 8, 9, 8, 8, 6, 7, 6, 7, 6, 6], +[6, 6, 4, 4, 4, 4, 6, 5, 7, 7, 8, 8, 10, 9, 10, 8, 7, 6, 5, 4, 4, 4, 5, 7], +[7, 9, 9, 10, 9, 10, 8, 8, 6, 6, 4, 4, 4, 4, 5, 5, 6, 6, 6, 5, 7, 6, 7, 7], +[9, 7, 9, 8, 8, 7, 7, 6, 5, 4, 3, 2, 3, 4, 5, 7, 8, 10, 10, 12, 11, 10, 8, 8], +[6, 6, 5, 6, 6, 6, 6, 6, 8, 7, 8, 7, 8, 8, 9, 9, 11, 10, 12, 11, 12, 11, 11, 9], +[7, 6, 5, 4, 5, 6, 7, 9, 10, 11, 10, 10, 8, 9, 7, 7, 5, 6, 6, 6, 7, 8, 8, 9], +[9, 8, 9, 7, 7, 6, 7, 5, 6, 5, 5, 4, 4, 3, 3, 3, 3, 3, 4, 4, 6, 9, 9, 11], +[10, 11, 9, 9, 7, 5, 2, 3, 1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 7, 6, 7, 7, 8, 8], +[8, 7, 7, 6, 5, 4, 3, 2, 1, 2, 2, 4, 4, 6, 6, 7, 7, 7, 5, 6, 4, 5, 4, 5], +[4, 4, 5, 5, 7, 6, 9, 8, 8, 7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 3, 2, 2, 3, 4], +[4, 6, 6, 8, 7, 9, 8, 8, 6, 6, 3, 3, 0, 0, 0, 0, 1, 2, 3, 3, 5, 5, 6, 6], +[6, 5, 6, 4, 5, 4, 4, 3, 3, 2, 1, 1, 1, 1, 1, 3, 3, 6, 5, 7, 8, 8, 7, 8], +[6, 6, 4, 3, 3, 2, 3, 3, 4, 4, 5, 6, 7, 7, 7, 5, 6, 5, 6, 4, 6, 6, 7, 6], +[6, 6, 5, 6, 6, 6, 6, 8, 7, 8, 8, 9, 7, 8, 6, 5, 3, 2, 2, 1, 1, 2, 4, 4], +[7, 7, 9, 9, 10, 9, 9, 7, 7, 5, 5, 4, 3, 3, 2, 3, 2, 3, 3, 4, 3, 4, 3, 5], +[4, 7, 6, 7, 7, 7, 7, 6, 6, 4, 4, 4, 4, 4, 5, 5, 8, 7, 9, 8, 9, 7, 7, 5], +[4, 3, 4, 3, 4, 4, 5, 6, 7, 8, 8, 10, 9, 11, 10, 11, 9, 10, 9, 9, 8, 8, 7, 6], +[6, 4, 4, 4, 6, 5, 8, 8, 11, 10, 12, 11, 11, 10, 10, 8, 8, 7, 7, 7, 7, 7, 8, 9], +[8, 9, 8, 9, 8, 8, 7, 7, 6, 7, 6, 6, 6, 5, 5, 4, 5, 5, 6, 6, 8, 8, 10, 10], +[11, 10, 10, 9, 8, 6, 5, 4, 2, 3, 2, 3, 3, 5, 6, 8, 7, 9, 9, 10, 9, 10, 9, 9], +[9, 9, 8, 7, 7, 6, 6, 5, 5, 4, 5, 6, 7, 7, 9, 9, 10, 9, 9, 7, 8, 6, 6, 6], +[5, 5, 5, 6, 6, 9, 8, 9, 8, 9, 7, 8, 6, 6, 6, 6, 5, 5, 5, 4, 5, 4, 5, 4], +[6, 5, 8, 6, 8, 8, 8, 7, 7, 5, 4, 2, 1, 0, 0, 1, 0, 2, 3, 4, 5, 7, 6, 7], +[5, 6, 3, 3, 2, 2, 1, 1, 1, 0, 1, 0, 1, 1, 1, 2, 3, 3, 5, 6, 7, 7, 8, 7], +[7, 5, 4, 3, 1, 1, 1, 1, 1, 3, 4, 5, 5, 6, 6, 7, 5, 5, 3, 5, 5, 5, 6, 6], +[6, 6, 7, 5, 6, 4, 6, 5, 5, 4, 6, 5, 6, 6, 5, 5, 4, 2, 2, 2, 1, 2, 2, 5], +[6, 8, 9, 10, 10, 10, 9, 7, 5, 4, 3, 2, 1, 1, 1, 1, 3, 2, 5, 4, 5, 4, 6, 5], +[7, 7, 8, 8, 8, 8, 7, 6, 5, 4, 3, 3, 2, 2, 3, 6, 6, 9, 7, 10, 9, 8, 7, 6], +[6, 5, 5, 5, 5, 6, 7, 7, 9, 7, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 7, 7], +[6, 6, 5, 5, 5, 7, 8, 10, 11, 12, 11, 11, 10, 9, 7, 6, 5, 4, 4, 4, 5, 5, 7, 6], +[8, 7, 9, 7, 8, 7, 8, 7, 8, 7, 6, 6, 5, 5, 4, 4, 2, 3, 3, 4, 5, 7, 7, 8], +[7, 9, 7, 6, 6, 5, 4, 3, 3, 2, 3, 4, 5, 5, 7, 6, 8, 7, 8, 6, 6, 6, 6, 6], +[6, 6, 5, 5, 4, 5, 4, 4, 4, 5, 6, 7, 8, 9, 10, 10, 10, 9, 7, 7, 5, 4, 4, 2], +[3, 2, 4, 4, 6, 6, 8, 8, 8, 8, 9, 7, 7, 8, 7, 7, 7, 6, 6, 5, 4, 4, 3, 4], +[4, 5, 4, 6, 6, 7, 7, 7, 6, 6, 4, 4, 3, 2, 3, 2, 4, 5, 6, 6, 8, 7, 9, 7], +[7, 5, 5, 3, 2, 3, 2, 2, 2, 2, 1, 2, 1, 4, 4, 5, 5, 7, 7, 9, 9, 10, 10, 9], +[8, 6, 5, 3, 2, 1, 2, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 7, 7, 7, 7, 8, 8, 9], +[7, 8, 7, 7, 6, 7, 6, 6, 6, 6, 6, 6, 5, 6, 5, 4, 4, 3, 3, 2, 4, 3, 5, 5], +[8, 8, 9, 8, 9, 8, 8, 6, 4, 3, 2, 1, 0, 1, 0, 1, 2, 3, 3, 5, 4, 6, 6, 7], +[6, 7, 6, 6, 6, 6, 7, 4, 5, 3, 3, 1, 2, 2, 4, 4, 5, 6, 8, 8, 8, 8, 8, 7], +[5, 5, 3, 4, 3, 3, 4, 5, 5, 6, 6, 7, 6, 7, 7, 6, 7, 6, 6, 6, 7, 7, 7, 5], +[6, 4, 6, 4, 6, 5, 7, 6, 8, 8, 8, 8, 7, 7, 6, 5, 4, 4, 3, 4, 3, 6, 5, 8], +[8, 10, 9, 10, 8, 7, 6, 6, 5, 3, 3, 2, 2, 1, 2, 1, 2, 2, 3, 3, 5, 6, 8, 8], +[10, 10, 9, 8, 7, 6, 5, 4, 1, 2, 0, 1, 0, 2, 4, 5, 5, 7, 6, 7, 7, 6, 6, 7], +[7, 7, 7, 6, 8, 6, 6, 5, 7, 5, 5, 4, 6, 6, 7, 7, 7, 6, 6, 6, 4, 4, 3, 4], +[3, 5, 4, 6, 7, 9, 9, 11, 10, 9, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1, 3, 2, 3, 2], +[3, 3, 5, 5, 6, 7, 7, 9, 7, 7, 4, 4, 2, 2, 0, 1, 0, 2, 2, 4, 4, 6, 5, 5], +[5, 4, 4, 2, 2, 2, 2, 1, 4, 2, 4, 3, 4, 3, 5, 4, 5, 5, 6, 6, 7, 7, 7, 7], +[5, 4, 2, 2, 0, 1, 0, 2, 3, 5, 6, 8, 8, 9, 9, 8, 8, 7, 6, 5, 5, 4, 5, 4], +[5, 4, 6, 5, 7, 6, 6, 7, 7, 7, 8, 8, 9, 9, 8, 8, 6, 6, 4, 4, 3, 3, 3, 6], +[5, 7, 8, 10, 8, 9, 8, 6, 6, 4, 4, 2, 3, 2, 5, 4, 6, 6, 7, 7, 8, 7, 7, 7], +[7, 7, 6, 7, 7, 6, 6, 6, 4, 4, 3, 4, 3, 5, 5, 8, 9, 11, 11, 12, 11, 11, 11, 8], +[7, 5, 5, 3, 5, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 10, 9, 10, 9, 9, 8, 8], +[7, 6, 5, 6, 5, 7, 7, 8, 9, 9, 10, 8, 8, 7, 7, 4, 5, 3, 4, 4, 6, 6, 8, 8], +[10, 10, 10, 10, 9, 8, 7, 7, 5, 5, 3, 3, 2, 2, 2, 2, 1, 2, 2, 4, 5, 6, 8, 9], +[8, 8, 8, 6, 6, 4, 3, 1, 2, 0, 1, 0, 2, 2, 4, 4, 5, 5, 5, 5, 5, 5, 4, 5], +[4, 6, 5, 5, 4, 5, 3, 4, 4, 5, 4, 6, 6, 7, 7, 7, 7, 6, 5, 4, 3, 2, 3, 1], +[3, 2, 3, 4, 5, 7, 7, 8, 8, 7, 6, 6, 4, 4, 3, 3, 2, 3, 1, 3, 2, 3, 2, 4], +[3, 4, 4, 4, 5, 5, 6, 4, 6, 3, 3, 1, 1, -1, 0, 0, 1, 2, 4, 4, 6, 7, 7, 7], +[6, 6, 4, 4, 2, 2, 1, 1, 0, 2, 0, 1, 1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 8, 7], +[8, 5, 6, 3, 4, 2, 3, 2, 4, 3, 5, 6, 6, 6, 6, 7, 5, 6, 4, 5, 4, 5, 4, 6], +[5, 7, 6, 8, 7, 8, 8, 8, 7, 6, 6, 5, 6, 5, 5, 3, 4, 2, 2, 1, 2, 1, 3, 4], +[6, 6, 8, 9, 10, 9, 9, 9, 7, 6, 3, 3, 2, 1, 1, 3, 2, 3, 4, 5, 4, 5, 5, 5], +[5, 5, 5, 5, 5, 4, 6, 5, 6, 5, 5, 4, 5, 4, 5, 6, 7, 8, 8, 8, 8, 8, 7, 6], +[3, 4, 2, 3, 2, 3, 4, 6, 6, 8, 9, 10, 10, 10, 10, 9, 10, 8, 8, 7, 8, 7, 7, 6], +[6, 4, 5, 3, 4, 4, 6, 7, 8, 9, 9, 10, 9, 9, 7, 8, 6, 5, 4, 5, 4, 6, 7, 7], +[8, 9, 8, 7, 7, 6, 6, 4, 4, 3, 4, 2, 4, 4, 5, 5, 6, 5, 6, 6, 7, 9, 9, 10], +[9, 10, 7, 8, 6, 5, 3, 2, 0, 1, 0, 2, 3, 4, 6, 7, 8, 9, 10, 9, 8, 8, 8, 6], +[7, 5, 7, 5, 5, 4, 5, 4, 4, 4, 5, 5, 6, 7, 7, 9, 8, 9, 7, 8, 7, 6, 5, 5], +[4, 4, 5, 6, 7, 7, 8, 8, 8, 6, 6, 4, 4, 3, 3, 2, 3, 2, 3, 2, 4, 3, 5, 5], +[4, 4, 4, 4, 4, 5, 4, 5, 3, 3, 0, 0, -2, -2, -3, -2, -2, 0, 1, 3, 4, 5, 7, 6], +[6, 4, 4, 2, 2, 1, 1, 0, 0, 0, 1, 1, 2, 1, 1, 2, 2, 3, 3, 5, 5, 6, 5, 6], +[4, 4, 2, 3, 1, 1, 1, 1, 2, 2, 4, 4, 5, 6, 5, 4, 4, 2, 2, 1, 1, 1, 2, 2], +[4, 4, 5, 5, 5, 6, 6, 7, 5, 6, 4, 5, 4, 5, 4, 4, 2, 2, 0, 1, 0, 0, 2, 3], +[4, 6, 8, 7, 9, 7, 8, 6, 5, 3, 2, 0, 0, -1, 0, 1, 3, 3, 5, 5, 5, 6, 4, 6], +[5, 5, 4, 6, 4, 5, 5, 5, 3, 4, 2, 3, 3, 3, 4, 6, 7, 8, 9, 8, 10, 8, 9, 6], +[7, 4, 4, 3, 4, 4, 6, 6, 7, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 8, 7, 8, 7, 7], +[6, 7, 6, 5, 6, 7, 9, 8, 10, 9, 10, 8, 8, 6, 5, 3, 3, 2, 3, 2, 4, 5, 6, 8], +[8, 10, 8, 9, 8, 8, 7, 7, 5, 6, 3, 4, 2, 2, 2, 2, 1, 1, 2, 3, 4, 4, 6, 6], +[8, 6, 8, 6, 7, 4, 5, 3, 3, 2, 3, 3, 4, 5, 5, 5, 6, 6, 5, 5, 4, 5, 3, 4], +[3, 4, 3, 4, 3, 4, 4, 5, 5, 5, 7, 7, 8, 8, 9, 8, 8, 6, 6, 3, 4, 2, 3, 1], +[2, 2, 2, 3, 4, 6, 7, 8, 8, 9, 7, 8, 6, 7, 5, 5, 4, 4, 3, 4, 3, 3, 3, 3], +[4, 3, 4, 3, 4, 4, 5, 4, 4, 3, 4, 2, 2, 1, 1, 2, 3, 4, 5, 7, 7, 8, 7, 8], +[5, 6, 3, 3, 1, 1, 0, 0, 0, 0, 1, 2, 4, 4, 6, 6, 8, 7, 9, 8, 9, 9, 10, 7], +[8, 6, 5, 3, 3, 2, 2, 2, 2, 4, 4, 5, 6, 8, 8, 8, 7, 7, 6, 6, 5, 5, 6, 6], +[6, 6, 7, 6, 7, 7, 8, 6, 7, 5, 5, 3, 4, 3, 5, 3, 4, 3, 3, 2, 3, 3, 4, 6], +[6, 8, 8, 9, 9, 10, 8, 8, 6, 5, 2, 2, 0, 0, -1, 0, 2, 3, 4, 5, 6, 6, 6, 5], +[6, 5, 5, 4, 5, 4, 4, 4, 3, 3, 3, 2, 2, 3, 2, 4, 4, 6, 6, 8, 7, 8, 6, 5], +[4, 3, 2, 2, 2, 2, 4, 4, 7, 6, 8, 8, 9, 8, 8, 6, 7, 4, 5, 4, 5, 5, 5, 5], +[4, 5, 4, 4, 4, 5, 5, 7, 6, 9, 8, 8, 6, 6, 4, 4, 2, 2, 1, 1, 2, 2, 4, 5], +[7, 6, 8, 6, 6, 5, 5, 3, 4, 2, 2, 2, 2, 1, 2, 2, 2, 3, 3, 4, 3, 5, 5, 7], +[6, 8, 6, 7, 5, 5, 3, 2, 2, 0, 0, 1, 3, 3, 5, 5, 7, 6, 7, 6, 6, 5, 5, 4], +[4, 4, 4, 4, 4, 5, 4, 5, 5, 6, 5, 6, 5, 7, 7, 8, 6, 7, 5, 5, 4, 4, 3, 2], +[3, 2, 3, 4, 6, 6, 9, 8, 9, 7, 8, 6, 5, 3, 3, 2, 2, 2, 2, 3, 3, 4, 3, 4], +[4, 4, 3, 5, 4, 5, 4, 5, 5, 5, 2, 2, 1, 0, -1, -1, 1, 1, 3, 4, 6, 6, 7, 5], +[6, 4, 3, 1, 1, 0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 3, 5, 4, 6, 5, 6, 5, 6], +[5, 5, 3, 3, 2, 1, 2, 2, 3, 3, 6, 7, 8, 8, 9, 7, 7, 5, 4, 3, 2, 3, 3, 4], +[4, 5, 5, 6, 6, 7, 6, 7, 6, 7, 5, 6, 6, 6, 5, 5, 5, 4, 3, 2, 2, 1, 3, 4], +[5, 5, 7, 7, 8, 7, 8, 5, 5, 3, 3, 2, 1, 2, 2, 3, 5, 7, 6, 8, 7, 9, 7, 8], +[6, 6, 4, 4, 4, 4, 3, 3, 4, 2, 3, 3, 4, 5, 6, 7, 9, 8, 10, 10, 11, 10, 9, 7], +[7, 5, 4, 2, 2, 3, 3, 4, 5, 6, 7, 8, 7, 9, 8, 9, 8, 8, 8, 9, 8, 9, 9, 8], +[9, 7, 7, 6, 7, 6, 7, 6, 7, 6, 7, 5, 5, 4, 4, 2, 3, 2, 2, 3, 4, 5, 6, 8], +[8, 10, 8, 9, 6, 7, 5, 3, 2, 1, 0, -1, -1, -1, -1, -1, 0, 1, 2, 2, 4, 4, 7, 6], +[7, 6, 6, 6, 5, 4, 3, 3, 1, 1, 0, 1, 1, 2, 2, 3, 3, 4, 3, 4, 4, 4, 3, 3], +[3, 2, 3, 2, 3, 4, 4, 4, 5, 4, 5, 4, 5, 4, 5, 4, 4, 3, 3, 1, 1, 0, 0, 0], +[0, 1, 1, 4, 3, 6, 6, 7, 6, 8, 6, 5, 3, 2, 1, 0, 1, 0, 1, 0, 1, 0, 2, 2], +[4, 3, 4, 3, 3, 3, 3, 3, 3, 2, 2, 1, 0, -1, -1, 0, -1, 1, 2, 4, 3, 6, 5, 6], +[4, 4, 3, 2, 1, 0, 0, -1, 1, 0, 1, 2, 3, 3, 4, 4, 5, 4, 5, 4, 6, 6, 6, 6], +[5, 5, 4, 4, 3, 3, 2, 4, 3, 5, 5, 7, 6, 7, 7, 8, 6, 5, 4, 3, 2, 2, 3, 3], +[5, 5, 7, 7, 8, 8, 9, 8, 8, 7, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 1, 2, 1, 4], +[3, 5, 6, 8, 8, 9, 9, 7, 7, 6, 4, 3, 2, 1, 2, 2, 3, 3, 5, 6, 7, 6, 6, 5], +[5, 3, 3, 3, 3, 4, 4, 6, 5, 6, 5, 6, 5, 6, 6, 7, 6, 8, 7, 8, 8, 8, 7, 6], +[5, 3, 2, 2, 2, 1, 3, 4, 7, 7, 10, 9, 11, 10, 9, 8, 7, 6, 6, 5, 5, 5, 5, 6], +[5, 6, 4, 6, 4, 6, 5, 7, 7, 8, 7, 8, 7, 7, 7, 5, 5, 3, 4, 3, 4, 4, 6, 6], +[8, 8, 9, 7, 7, 5, 5, 3, 3, 2, 1, 2, 2, 3, 3, 4, 3, 5, 5, 7, 5, 7, 7, 8], +[6, 7, 6, 5, 5, 4, 3, 1, 1, -1, 1, 0, 3, 4, 7, 7, 9, 9, 10, 8, 8, 7, 6, 6], +[5, 5, 3, 4, 4, 5, 4, 5, 4, 6, 4, 5, 5, 5, 6, 7, 7, 7, 7, 6, 6, 4, 4, 2], +[3, 2, 4, 3, 5, 5, 6, 6, 6, 5, 5, 3, 2, 1, 0, 1, 0, 1, 2, 3, 3, 4, 4, 5], +[4, 5, 4, 5, 4, 3, 4, 3, 3, 1, 1, -1, -1, -3, -2, -3, -2, 0, 3, 3, 6, 5, 6, 7], +[6, 5, 3, 2, 1, 1, -1, 0, -1, 0, -1, 1, 1, 2, 2, 2, 2, 3, 2, 4, 3, 4, 5, 4], +[6, 3, 4, 2, 3, 2, 3, 2, 3, 3, 5, 4, 6, 5, 5, 5, 5, 3, 2, 1, 0, 1, 1, 3], +[3, 5, 5, 6, 6, 7, 7, 7, 6, 5, 4, 4, 3, 3, 3, 2, 3, 1, 1, 1, 1, 0, 2, 2], +[4, 4, 6, 5, 6, 6, 6, 6, 4, 4, 2, 1, 0, 1, 1, 2, 2, 5, 4, 6, 6, 7, 6, 6], +[5, 4, 3, 3, 3, 3, 4, 3, 5, 3, 5, 4, 5, 4, 6, 7, 8, 7, 9, 8, 9, 9, 8, 7], +[5, 5, 3, 4, 2, 3, 3, 6, 6, 8, 8, 9, 9, 9, 8, 8, 7, 6, 7, 5, 6, 5, 6, 6], +[7, 6, 7, 6, 7, 7, 7, 8, 8, 8, 7, 7, 7, 6, 4, 4, 2, 2, 1, 3, 3, 4, 4, 6], +[7, 8, 8, 8, 7, 6, 6, 4, 4, 3, 3, 1, 2, 1, 3, 2, 2, 2, 4, 3, 5, 5, 5, 5], +[5, 6, 5, 5, 4, 4, 3, 4, 2, 3, 2, 3, 3, 5, 5, 6, 7, 7, 6, 5, 5, 4, 3, 2], +[3, 1, 2, 1, 3, 2, 5, 5, 6, 6, 8, 7, 8, 8, 7, 7, 6, 6, 5, 4, 3, 3, 1, 2], +[0, 2, 1, 2, 2, 4, 5, 6, 7, 7, 6, 5, 5, 4, 4, 2, 3, 2, 3, 2, 4, 3, 4, 4], +[4, 3, 3, 2, 2, 2, 2, 3, 1, 2, 1, 1, 1, 1, 1, 2, 2, 4, 4, 6, 7, 9, 9, 8], +[7, 6, 5, 2, 1, -1, 0, -2, -1, -1, 1, 1, 2, 4, 5, 6, 7, 6, 7, 6, 7, 7, 7, 8], +[6, 7, 5, 5, 3, 4, 2, 2, 2, 3, 3, 5, 5, 6, 7, 7, 7, 6, 6, 4, 5, 4, 5, 4], +[7, 6, 9, 9, 10, 9, 10, 9, 7, 6, 4, 3, 2, 1, 1, 2, 1, 3, 2, 4, 3, 5, 4, 5], +[5, 7, 7, 7, 8, 8, 8, 6, 6, 2, 2, -2, -1, -2, -2, -1, 1, 1, 4, 5, 7, 7, 6, 7], +[5, 5, 3, 4, 3, 4, 3, 4, 4, 5, 3, 4, 3, 3, 3, 3, 4, 5, 6, 6, 7, 7, 7, 5], +[6, 4, 3, 2, 3, 2, 3, 5, 6, 6, 8, 8, 7, 8, 6, 5, 4, 3, 2, 3, 2, 4, 3, 5], +[4, 5, 4, 5, 5, 6, 5, 6, 7, 6, 7, 5, 6, 4, 4, 1, 1, 0, 0, 0, 2, 2, 4, 5], +[7, 7, 7, 7, 6, 6, 4, 4, 1, 2, 0, 1, 0, 2, 1, 3, 2, 3, 3, 3, 4, 4, 5, 5], +[6, 5, 6, 4, 5, 3, 3, 2, 2, 1, 2, 1, 3, 4, 6, 7, 7, 7, 7, 6, 5, 5, 3, 3], +[2, 3, 2, 4, 4, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 7, 5, 6, 4, 5, 3, 4, 1], +[2, 1, 4, 4, 5, 6, 7, 9, 8, 8, 6, 6, 4, 4, 2, 2, 1, 2, 2, 3, 3, 4, 4, 5], +[5, 4, 4, 4, 4, 3, 4, 3, 5, 3, 4, 1, 2, 0, 1, 1, 2, 1, 4, 4, 6, 6, 7, 7], +[5, 5, 3, 3, 1, 2, 0, 1, 1, 3, 3, 5, 5, 6, 6, 6, 6, 5, 5, 4, 5, 4, 5, 4], +[5, 3, 4, 2, 3, 3, 3, 4, 4, 6, 7, 8, 9, 9, 9, 9, 7, 6, 4, 3, 2, 2, 1, 2], +[2, 4, 4, 6, 6, 7, 8, 8, 8, 7, 8, 6, 6, 5, 6, 5, 5, 5, 5, 3, 4, 3, 4, 4], +[4, 5, 4, 5, 5, 6, 4, 6, 4, 4, 3, 3, 2, 3, 3, 5, 6, 7, 7, 9, 9, 9, 9, 7], +[6, 3, 3, 2, 2, 1, 2, 2, 3, 3, 4, 4, 6, 7, 7, 9, 9, 11, 11, 12, 11, 11, 9, 10], +[7, 7, 4, 4, 3, 3, 3, 4, 4, 5, 7, 7, 8, 8, 8, 7, 8, 7, 7, 7, 7, 7, 8, 7], +[8, 7, 7, 7, 6, 6, 6, 6, 4, 4, 3, 3, 2, 3, 2, 2, 1, 2, 1, 2, 3, 4, 6, 7], +[8, 9, 9, 8, 8, 7, 6, 4, 3, 1, 0, -1, -1, -3, -1, 0, 1, 1, 2, 3, 4, 5, 5, 6], +[6, 6, 5, 6, 4, 5, 3, 2, 1, 2, 0, 1, 1, 1, 3, 3, 4, 3, 4, 3, 4, 2, 3, 1], +[2, 1, 2, 1, 3, 3, 4, 5, 5, 6, 6, 6, 5, 5, 3, 4, 3, 3, 2, 3, 1, 1, 0, 1], +[0, 1, 1, 2, 3, 4, 6, 6, 7, 5, 6, 3, 3, 1, 0, -1, -1, -2, 0, 0, 2, 2, 3, 4], +[4, 3, 3, 3, 1, 1, 0, 2, 0, 2, 0, 1, 0, 0, 0, 1, 1, 2, 2, 3, 4, 5, 6, 6], +[6, 5, 4, 1, 1, -1, 0, -1, -1, 0, 1, 2, 4, 5, 6, 6, 6, 6, 5, 5, 4, 5, 4, 6], +[5, 6, 4, 5, 4, 4, 4, 4, 4, 4, 5, 5, 7, 6, 8, 6, 8, 6, 6, 3, 3, 3, 3, 3], +[4, 5, 6, 8, 8, 10, 9, 10, 8, 8, 5, 5, 3, 3, 3, 4, 3, 4, 3, 4, 4, 4, 4, 5], +[6, 5, 6, 6, 8, 7, 8, 7, 8, 5, 5, 3, 2, 1, 2, 2, 3, 5, 6, 8, 8, 9, 8, 8], +[5, 5, 4, 4, 2, 4, 3, 5, 5, 6, 7, 7, 7, 6, 7, 7, 7, 7, 8, 7, 9, 7, 8, 7], +[6, 4, 4, 3, 3, 3, 4, 6, 7, 9, 9, 11, 10, 10, 9, 9, 6, 6, 5, 5, 4, 5, 5, 6], +[6, 5, 6, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 4, 4, 3, 2, 2, 3, 4, 5, 6], +[6, 8, 6, 7, 5, 5, 3, 3, 2, 2, 1, 2, 2, 3, 4, 4, 6, 6, 7, 6, 7, 6, 6, 6], +[7, 5, 5, 4, 4, 3, 3, 1, 1, 0, 1, 2, 4, 5, 7, 8, 8, 10, 8, 8, 6, 6, 5, 4], +[2, 2, 1, 2, 2, 2, 4, 4, 6, 5, 6, 4, 6, 5, 7, 5, 7, 5, 6, 5, 5, 5, 5, 5], +[4, 3, 4, 5, 5, 6, 6, 8, 6, 6, 4, 3, 1, 1, 0, 0, -1, 0, 1, 3, 4, 5, 6, 6], +[7, 5, 6, 3, 4, 3, 3, 2, 1, 0, 0, -1, -2, -2, -2, -1, -2, 1, 1, 3, 4, 7, 7, 8], +[6, 7, 4, 5, 3, 2, 2, 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 3, 4, 2, 4, 3, 5, 5], +[5, 4, 5, 5, 5, 6, 5, 6, 6, 7, 5, 6, 5, 7, 5, 5, 4, 4, 1, 1, 0, 0, 0, 1], +[2, 3, 5, 6, 9, 8, 10, 9, 10, 7, 7, 5, 4, 3, 2, 2, 1, 1, 2, 1, 2, 3, 2, 4], +[3, 5, 5, 6, 5, 7, 6, 7, 5, 5, 4, 4, 3, 2, 2, 3, 4, 5, 6, 6, 8, 7, 8, 6], +[6, 4, 4, 2, 3, 2, 3, 4, 4, 5, 5, 6, 6, 8, 7, 9, 8, 9, 8, 9, 8, 8, 8, 8], +[6, 6, 4, 3, 4, 3, 5, 5, 8, 7, 10, 9, 10, 10, 10, 8, 8, 7, 6, 5, 6, 5, 6, 7], +[7, 8, 7, 8, 7, 9, 8, 8, 6, 7, 6, 6, 5, 5, 4, 4, 4, 3, 3, 3, 4, 4, 6, 6], +[8, 8, 10, 8, 9, 7, 6, 5, 4, 2, 2, 1, 2, 1, 2, 4, 4, 6, 5, 6, 5, 7, 5, 7], +[5, 5, 4, 6, 5, 5, 5, 4, 4, 4, 4, 3, 5, 6, 7, 7, 8, 7, 8, 6, 6, 5, 5, 3], +[2, 2, 1, 2, 2, 4, 5, 8, 7, 9, 8, 9, 8, 8, 6, 7, 6, 6, 4, 5, 4, 4, 3, 2], +[2, 1, 3, 2, 4, 4, 7, 6, 8, 7, 8, 6, 6, 4, 3, 2, 2, 2, 3, 3, 4, 6, 5, 7], +[5, 5, 3, 4, 2, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 3, 4, 4, 6, 5, 7, 7, 8, 7], +[7, 6, 5, 3, 2, 0, -1, 0, -1, 0, 1, 3, 5, 8, 8, 10, 9, 10, 7, 8, 7, 7, 7, 7], +[6, 7, 6, 5, 6, 4, 6, 4, 6, 4, 6, 5, 7, 7, 8, 8, 8, 7, 6, 5, 5, 4, 3, 4], +[4, 6, 6, 8, 7, 9, 8, 8, 7, 6, 4, 3, 2, 1, 1, 1, 3, 3, 4, 4, 5, 5, 6, 5], +[6, 6, 6, 6, 7, 6, 6, 6, 5, 3, 2, 1, 1, 0, 0, 1, 2, 5, 5, 8, 8, 10, 9, 9], +[6, 6, 4, 4, 3, 2, 4, 3, 4, 4, 5, 4, 5, 4, 6, 5, 5, 5, 6, 5, 7, 7, 7, 7], +[6, 5, 4, 4, 3, 4, 4, 6, 6, 9, 8, 9, 8, 8, 6, 6, 4, 3, 2, 2, 2, 2, 4, 4], +[6, 6, 7, 7, 8, 7, 8, 7, 7, 6, 7, 5, 5, 3, 2, 2, 0, 1, 0, 1, 1, 2, 3, 5], +[5, 7, 6, 7, 6, 6, 5, 4, 2, 1, 1, 1, 1, 2, 3, 2, 4, 3, 4, 4, 5, 4, 5, 4], +[4, 3, 4, 4, 4, 4, 3, 4, 3, 4, 3, 4, 5, 7, 7, 8, 7, 8, 7, 7, 5, 4, 3, 3], +[2, 2, 2, 2, 3, 3, 6, 6, 8, 7, 8, 7, 8, 6, 7, 6, 6, 6, 5, 5, 4, 4, 3, 4], +[2, 4, 3, 4, 4, 6, 6, 7, 7, 7, 6, 6, 4, 3, 2, 1, 2, 1, 3, 3, 5, 5, 7, 6], +[7, 5, 6, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 2, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8], +[7, 6, 5, 4, 3, 2, 2, 1, 3, 2, 4, 3, 5, 6, 8, 7, 7, 6, 6, 6, 5, 5, 5, 5], +[5, 6, 5, 6, 5, 7, 6, 7, 7, 8, 7, 8, 7, 8, 8, 8, 7, 6, 5, 4, 3, 2, 3, 2], +[4, 4, 6, 6, 8, 8, 9, 9, 9, 8, 7, 6, 5, 4, 3, 4, 3, 5, 4, 5, 5, 6, 5, 6], +[5, 6, 5, 5, 5, 5, 5, 5, 5, 4, 5, 3, 4, 4, 5, 5, 6, 6, 9, 9, 10, 11, 11, 9], +[7, 6, 4, 3, 2, 2, 1, 3, 2, 5, 5, 6, 7, 8, 8, 9, 9, 10, 9, 10, 9, 9, 9, 8], +[7, 6, 6, 3, 4, 2, 4, 3, 6, 6, 8, 7, 9, 8, 8, 8, 6, 6, 5, 5, 5, 6, 6, 7], +[7, 9, 8, 10, 8, 9, 8, 8, 6, 5, 4, 4, 4, 3, 2, 1, 3, 1, 2, 2, 4, 4, 6, 7], +[8, 7, 9, 7, 8, 7, 6, 5, 2, 2, -1, 0, -2, 0, 0, 1, 2, 3, 4, 5, 4, 5, 5, 5], +[4, 4, 5, 4, 5, 4, 5, 4, 5, 3, 4, 3, 4, 4, 5, 5, 6, 5, 6, 5, 5, 4, 3, 3], +[1, 2, 1, 3, 3, 4, 5, 7, 8, 9, 7, 8, 6, 6, 4, 4, 3, 2, 3, 1, 2, 1, 2, 1], +[2, 1, 3, 2, 4, 4, 6, 6, 6, 7, 6, 6, 4, 3, 1, 0, -2, 0, -1, 1, 2, 4, 4, 6], +[5, 5, 4, 4, 2, 2, 2, 1, 2, 1, 2, 1, 3, 2, 4, 2, 3, 2, 4, 3, 5, 6, 6, 6], +[6, 6, 5, 5, 2, 2, 1, 2, 1, 3, 3, 5, 6, 8, 9, 9, 9, 7, 7, 5, 5, 4, 4, 3], +[5, 3, 5, 5, 7, 6, 7, 7, 9, 8, 9, 8, 9, 9, 9, 9, 8, 8, 6, 6, 4, 3, 2, 4], +[3, 5, 5, 8, 9, 11, 11, 11, 10, 9, 8, 7, 5, 5, 5, 4, 5, 5, 6, 6, 7, 7, 7, 6], +[6, 5, 5, 6, 6, 6, 7, 8, 6, 7, 5, 5, 3, 5, 4, 5, 6, 8, 8, 10, 10, 11, 11, 9], +[9, 6, 5, 4, 3, 2, 5, 4, 6, 6, 8, 8, 9, 9, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9], +[7, 7, 5, 5, 4, 5, 5, 7, 7, 9, 11, 11, 10, 10, 9, 8, 7, 6, 6, 4, 6, 4, 6, 6], +[8, 6, 8, 8, 8, 7, 7, 7, 7, 6, 5, 6, 5, 5, 4, 5, 3, 4, 3, 5, 4, 6, 7, 7], +[8, 7, 7, 7, 6, 4, 5, 2, 3, 0, 1, 0, 2, 2, 4, 5, 6, 6, 7, 7, 7, 7, 7, 7], +[5, 5, 3, 4, 2, 3, 2, 3, 2, 3, 3, 4, 4, 6, 7, 8, 8, 9, 9, 8, 8, 7, 6, 4], +[5, 3, 4, 2, 4, 4, 5, 6, 7, 7, 7, 6, 7, 6, 5, 5, 5, 6, 4, 5, 4, 5, 4, 5], +[4, 5, 4, 5, 5, 5, 5, 5, 5, 4, 3, 2, 2, 0, 0, -1, 0, -1, 2, 2, 5, 6, 7, 7], +[8, 7, 7, 6, 4, 4, 2, 2, 1, 1, 0, 0, -1, 1, 1, 2, 1, 2, 3, 4, 5, 6, 7, 7], +[8, 7, 7, 6, 5, 3, 3, 2, 2, 2, 3, 3, 5, 5, 6, 7, 6, 6, 5, 4, 3, 3, 3, 4], +[4, 6, 4, 7, 6, 8, 8, 9, 9, 9, 8, 8, 7, 7, 7, 5, 6, 4, 4, 3, 2, 1, 2, 2], +[3, 4, 5, 6, 8, 10, 10, 11, 10, 9, 7, 6, 4, 4, 2, 2, 1, 3, 2, 4, 4, 5, 5, 5], +[6, 5, 4, 4, 5, 4, 6, 5, 6, 5, 6, 5, 4, 4, 5, 4, 6, 6, 7, 7, 8, 9, 8, 8], +[6, 6, 3, 4, 2, 3, 2, 4, 4, 6, 7, 9, 8, 10, 10, 10, 9, 9, 8, 8, 8, 7, 7, 6], +[7, 5, 6, 4, 5, 5, 6, 6, 7, 8, 9, 10, 10, 11, 9, 10, 7, 7, 5, 5, 4, 5, 5, 6], +[6, 7, 8, 9, 10, 9, 9, 8, 7, 6, 6, 5, 5, 4, 5, 4, 5, 3, 4, 4, 4, 5, 5, 7], +[7, 7, 7, 8, 7, 8, 6, 7, 4, 4, 2, 3, 2, 3, 3, 5, 6, 7, 7, 8, 7, 6, 7, 5], +[6, 3, 5, 3, 4, 4, 6, 5, 6, 6, 6, 6, 6, 6, 7, 8, 8, 9, 8, 8, 6, 6, 4, 4], +[2, 2, 1, 2, 3, 5, 6, 8, 10, 10, 11, 10, 9, 7, 7, 6, 5, 4, 5, 5, 6, 4, 6, 4], +[4, 3, 4, 3, 4, 4, 4, 7, 6, 7, 6, 6, 4, 4, 2, 2, 1, 2, 2, 4, 4, 6, 8, 8], +[7, 6, 6, 4, 3, 1, 2, 0, 1, 0, 2, 2, 4, 3, 4, 5, 5, 6, 6, 6, 7, 8, 9, 9], +[8, 9, 6, 6, 3, 3, 2, 1, 1, 2, 2, 4, 6, 7, 9, 8, 9, 8, 8, 6, 7, 4, 5, 5], +[6, 5, 6, 5, 6, 6, 6, 6, 6, 7, 6, 6, 5, 6, 5, 6, 6, 7, 5, 5, 4, 5, 3, 4], +[5, 5, 7, 8, 10, 10, 11, 10, 10, 7, 6, 4, 3, 1, 2, 1, 3, 2, 5, 5, 6, 7, 7, 8], +[7, 7, 6, 7, 5, 6, 5, 6, 5, 5, 3, 3, 1, 2, 2, 3, 3, 5, 6, 7, 8, 9, 9, 8], +[9, 6, 7, 4, 4, 3, 4, 4, 5, 6, 7, 7, 8, 8, 7, 8, 7, 7, 6, 6, 6, 7, 6, 8], +[6, 7, 5, 6, 6, 7, 7, 7, 9, 9, 10, 9, 9, 8, 7, 5, 5, 3, 3, 1, 2, 2, 4, 4], +[6, 6, 7, 8, 8, 9, 8, 8, 7, 8, 6, 6, 4, 4, 3, 3, 1, 2, 1, 1, 2, 3, 4, 4], +[6, 5, 7, 6, 6, 5, 6, 4, 5, 3, 4, 3, 4, 3, 4, 5, 5, 7, 6, 6, 5, 5, 4, 4], +[2, 3, 2, 3, 2, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, 9, 10, 8, 9, 7, 7, 5, 4, 2], +[1, 1, 1, 1, 2, 4, 5, 7, 8, 10, 9, 9, 9, 9, 7, 7, 5, 7, 4, 5, 4, 5, 4, 4], +[4, 4, 4, 3, 5, 5, 6, 6, 7, 5, 6, 4, 5, 4, 3, 3, 3, 2, 4, 4, 5, 6, 7, 9], +[8, 7, 5, 6, 4, 4, 2, 3, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 7, 8, 7], +[8, 7, 7, 5, 5, 5, 5, 3, 3, 4, 5, 6, 7, 8, 9, 10, 9, 10, 8, 8, 5, 6, 4, 5], +[4, 4, 5, 6, 7, 8, 9, 9, 10, 10, 10, 9, 9, 8, 8, 7, 8, 6, 7, 5, 5, 4, 4, 4], +[4, 4, 4, 6, 6, 8, 9, 11, 9, 10, 8, 8, 5, 5, 4, 4, 4, 5, 5, 6, 8, 9, 9, 8], +[8, 6, 5, 4, 4, 3, 4, 4, 4, 3, 5, 4, 5, 5, 5, 6, 6, 8, 8, 9, 9, 10, 9, 9], +[7, 6, 3, 3, 1, 1, 1, 2, 3, 4, 5, 6, 9, 9, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8], +[8, 7, 8, 6, 5, 6, 5, 6, 6, 8, 7, 8, 8, 8, 7, 7, 6, 6, 4, 5, 4, 4, 5, 6], +[7, 8, 10, 9, 10, 8, 8, 6, 6, 3, 2, 1, 1, 0, 1, 1, 1, 2, 2, 3, 3, 4, 5, 7], +[7, 8, 8, 8, 7, 8, 6, 4, 3, 2, 0, 0, -1, 0, 1, 2, 4, 4, 6, 6, 6, 5, 6, 5], +[6, 2, 5, 4, 4, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 5, 4, 6, 4, 5, 4, 5, 4, 3], +[2, 2, 1, 2, 4, 4, 7, 8, 9, 9, 9, 7, 7, 5, 4, 3, 2, 1, 2, 1, 2, 3, 3, 4], +[4, 5, 4, 5, 4, 5, 5, 7, 6, 7, 5, 5, 3, 2, 1, 0, -1, -1, -1, 0, 2, 4, 6, 6], +[7, 5, 6, 4, 4, 2, 2, 2, 2, 2, 2, 3, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 6], +[4, 6, 4, 4, 4, 4, 3, 4, 4, 4, 6, 6, 8, 9, 10, 10, 11, 8, 8, 5, 5, 3, 3, 2], +[3, 3, 4, 5, 6, 7, 8, 10, 9, 11, 9, 10, 9, 10, 8, 9, 8, 8, 6, 6, 5, 4, 4, 3], +[4, 4, 6, 7, 9, 9, 10, 9, 10, 8, 9, 6, 6, 4, 5, 4, 5, 6, 7, 8, 8, 9, 8, 9], +[7, 8, 5, 6, 5, 5, 5, 6, 6, 5, 6, 6, 5, 6, 7, 7, 8, 9, 10, 10, 11, 11, 11, 9], +[9, 7, 7, 4, 4, 4, 4, 5, 6, 7, 8, 9, 9, 10, 10, 11, 10, 10, 8, 9, 8, 8, 8, 7], +[8, 7, 7, 6, 7, 6, 8, 8, 10, 9, 11, 10, 11, 9, 9, 8, 7, 5, 5, 5, 5, 4, 4, 6], +[7, 8, 7, 9, 8, 9, 8, 8, 6, 7, 5, 6, 4, 3, 3, 3, 4, 3, 3, 3, 4, 4, 6, 5], +[6, 5, 6, 5, 6, 5, 4, 4, 3, 3, 3, 3, 3, 4, 5, 6, 6, 8, 7, 8, 6, 7, 5, 5], +[4, 3, 3, 2, 2, 3, 3, 3, 4, 4, 6, 6, 7, 6, 8, 7, 8, 7, 8, 6, 7, 5, 5, 3], +[3, 2, 1, 2, 1, 3, 3, 6, 6, 8, 7, 7, 6, 5, 4, 5, 4, 3, 3, 3, 4, 4, 5, 4], +[6, 5, 6, 5, 5, 4, 5, 4, 5, 3, 4, 3, 3, 1, 1, 0, 0, 1, 1, 3, 4, 7, 6, 8], +[8, 9, 6, 6, 5, 4, 3, 1, 1, 0, -1, 0, 1, 1, 3, 3, 4, 3, 5, 5, 6, 6, 7, 6], +[7, 7, 6, 6, 5, 6, 5, 5, 4, 5, 3, 5, 4, 7, 6, 7, 6, 7, 6, 5, 4, 4, 4, 3], +[4, 4, 6, 6, 9, 9, 10, 10, 12, 10, 10, 8, 7, 5, 6, 5, 5, 4, 4, 3, 4, 3, 2, 3], +[3, 4, 5, 7, 6, 9, 9, 10, 10, 10, 8, 6, 4, 4, 3, 2, 1, 2, 4, 4, 5, 6, 7, 6], +[7, 5, 5, 4, 4, 4, 4, 6, 5, 6, 6, 6, 6, 6, 6, 6, 5, 7, 6, 8, 7, 9, 7, 7], +[6, 5, 4, 3, 2, 2, 3, 3, 6, 6, 9, 9, 10, 10, 11, 10, 10, 8, 8, 6, 6, 6, 5, 6], +[5, 6, 4, 6, 4, 6, 5, 7, 7, 9, 9, 10, 10, 10, 9, 9, 8, 6, 4, 4, 4, 3, 4, 4], +[6, 6, 8, 8, 9, 8, 8, 7, 6, 4, 4, 4, 4, 4, 4, 5, 4, 5, 5, 6, 5, 6, 5, 6], +[5, 6, 5, 5, 6, 5, 5, 4, 4, 3, 3, 2, 3, 3, 5, 5, 8, 8, 10, 8, 8, 7, 7, 5], +[4, 3, 3, 3, 2, 4, 3, 6, 5, 7, 6, 7, 7, 8, 7, 9, 9, 10, 9, 9, 8, 7, 6, 4], +[5, 2, 2, 2, 3, 3, 6, 6, 9, 8, 10, 8, 8, 6, 6, 4, 4, 4, 4, 5, 4, 5, 4, 6], +[4, 5, 4, 5, 3, 4, 4, 5, 5, 5, 4, 4, 3, 3, 2, 1, 1, 1, 3, 3, 5, 6, 8, 8], +[8, 8, 6, 6, 4, 2, 1, 1, 0, 0, 0, 2, 2, 4, 4, 6, 5, 5, 5, 5, 5, 5, 5, 5], +[6, 4, 5, 4, 4, 2, 3, 1, 3, 2, 4, 4, 5, 6, 8, 8, 8, 8, 7, 5, 4, 4, 3, 3], +[2, 4, 3, 6, 5, 7, 8, 9, 9, 9, 7, 8, 7, 6, 6, 5, 5, 4, 5, 4, 5, 3, 4, 3], +[4, 3, 6, 6, 7, 7, 7, 7, 7, 6, 4, 4, 2, 2, 1, 2, 1, 3, 3, 6, 6, 7, 7, 8], +[7, 7, 5, 5, 4, 4, 5, 3, 4, 3, 4, 3, 4, 3, 4, 4, 6, 5, 7, 7, 8, 8, 9, 9], +[8, 8, 6, 5, 4, 4, 3, 4, 5, 7, 6, 7, 7, 8, 7, 7, 6, 7, 5, 5, 5, 5, 6, 5], +[7, 5, 7, 6, 8, 6, 9, 7, 9, 8, 9, 8, 8, 6, 5, 4, 3, 3, 1, 2, 1, 3, 2, 4], +[5, 7, 7, 8, 8, 9, 8, 8, 7, 6, 5, 3, 3, 2, 2, 0, 1, 0, 2, 1, 3, 3, 4, 4], +[4, 4, 4, 5, 4, 5, 4, 6, 4, 4, 3, 3, 2, 3, 4, 5, 5, 5, 5, 5, 5, 4, 4, 3], +[3, 1, 1, 0, 2, 2, 4, 4, 7, 6, 8, 7, 8, 8, 8, 7, 7, 6, 6, 6, 5, 4, 3, 2], +[1, 2, 0, 2, 1, 4, 4, 7, 8, 9, 9, 9, 9, 8, 6, 5, 5, 3, 3, 2, 4, 3, 5, 3], +[5, 5, 6, 4, 5, 4, 4, 4, 3, 5, 4, 4, 4, 4, 3, 3, 2, 3, 2, 5, 4, 6, 7, 8], +[7, 8, 7, 5, 5, 3, 3, 2, 2, 1, 2, 2, 4, 4, 6, 7, 8, 8, 8, 7, 8, 7, 7, 7], +[6, 7, 6, 6, 5, 6, 4, 6, 5, 6, 5, 8, 7, 9, 9, 10, 10, 10, 9, 8, 7, 5, 5, 3], +[4, 3, 5, 5, 7, 8, 10, 11, 11, 11, 11, 10, 8, 7, 7, 7, 6, 7, 6, 7, 6, 7, 6, 6], +[5, 6, 5, 6, 6, 8, 9, 8, 9, 7, 7, 5, 6, 3, 4, 2, 3, 3, 5, 6, 8, 9, 9, 8], +[8, 7, 5, 4, 3, 3, 3, 4, 3, 4, 4, 5, 4, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 8], +[8, 6, 6, 4, 4, 2, 4, 3, 4, 5, 7, 7, 9, 9, 9, 8, 8, 7, 6, 6, 5, 5, 5, 6], +[5, 6, 5, 6, 5, 6, 5, 6, 6, 7, 7, 6, 6, 6, 7, 5, 5, 2, 3, 1, 2, 1, 2, 3], +[5, 6, 7, 7, 8, 8, 7, 7, 5, 5, 2, 2, 1, 1, 1, 2, 2, 3, 2, 4, 3, 4, 4, 4], +[5, 4, 5, 4, 5, 4, 5, 3, 4, 2, 2, 0, 1, 0, 3, 3, 5, 6, 7, 6, 6, 6, 5, 4], +[2, 2, 0, 2, 1, 2, 3, 5, 5, 6, 6, 7, 6, 6, 6, 6, 7, 6, 6, 5, 5, 4, 4, 2], +[3, 1, 2, 1, 3, 4, 6, 7, 8, 9, 8, 8, 6, 6, 4, 3, 1, 1, 0, 1, 2, 3, 3, 4], +[4, 5, 4, 4, 4, 4, 4, 4, 5, 4, 5, 3, 3, 2, 2, -1, 0, -1, 1, 1, 3, 4, 6, 6], +[7, 7, 5, 6, 3, 3, 2, 3, 1, 2, 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 4, 4, 4, 4], +[5, 4, 5, 3, 5, 4, 5, 4, 6, 5, 7, 7, 8, 9, 8, 9, 9, 9, 7, 6, 4, 4, 2, 2], +[1, 3, 2, 5, 5, 8, 8, 9, 10, 10, 11, 10, 9, 7, 8, 6, 6, 5, 5, 4, 5, 4, 5, 4], +[4, 4, 5, 5, 6, 7, 6, 8, 7, 8, 6, 6, 4, 4, 4, 5, 4, 5, 5, 7, 8, 8, 9, 9], +[8, 6, 5, 4, 3, 2, 4, 3, 4, 3, 4, 4, 5, 5, 6, 7, 8, 9, 9, 9, 10, 10, 9, 10], +[8, 8, 6, 5, 3, 4, 3, 4, 4, 6, 7, 9, 9, 10, 10, 10, 10, 9, 9, 7, 7, 6, 7, 6], +[7, 6, 6, 6, 7, 7, 7, 8, 7, 8, 7, 7, 6, 7, 5, 6, 4, 4, 3, 4, 3, 4, 4, 5], +[5, 6, 7, 7, 7, 7, 7, 6, 6, 4, 4, 2, 2, 1, 1, 2, 3, 2, 3, 4, 5, 5, 5, 6], +[5, 6, 4, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 2, 2, 4, 5, 6, 6, 6, 6, 5, 5, 3], +[3, 1, 1, 0, 0, 0, 2, 2, 3, 4, 5, 5, 5, 5, 4, 5, 4, 5, 4, 5, 3, 4, 3, 3], +[1, 1, 0, 2, 1, 3, 4, 5, 6, 6, 7, 6, 5, 4, 4, 1, 1, 0, 0, 0, 2, 2, 4, 4], +[5, 5, 5, 5, 4, 4, 2, 3, 1, 2, 0, 1, 0, 1, 0, 0, -1, 0, 0, 1, 2, 3, 5, 5], +[7, 6, 7, 5, 5, 3, 3, 1, 1, 0, 1, 0, 2, 2, 4, 5, 5, 6, 5, 5, 4, 5, 3, 5], +[3, 5, 4, 6, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 8, 6, 6, 5, 5, 2, 3, 1], +[1, 2, 3, 4, 6, 9, 10, 12, 12, 11, 9, 9, 7, 6, 4, 5, 2, 3, 3, 4, 3, 4, 3, 3], +[4, 3, 4, 5, 5, 6, 8, 7, 10, 8, 8, 6, 5, 3, 3, 2, 2, 2, 3, 4, 5, 7, 7, 8], +[6, 7, 3, 4, 2, 3, 2, 3, 4, 5, 5, 7, 6, 6, 6, 6, 7, 6, 6, 6, 7, 6, 7, 5], +[6, 3, 4, 3, 2, 1, 3, 4, 5, 6, 8, 10, 10, 11, 10, 10, 7, 7, 5, 5, 4, 4, 3, 4], +[4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, 7, 9, 7, 8, 6, 6, 3, 3, 2, 1, 2, 2, 3], +[3, 5, 5, 7, 7, 8, 6, 6, 5, 5, 2, 3, 2, 2, 2, 4, 4, 5, 4, 4, 5, 4, 5, 4], +[5, 4, 5, 4, 4, 3, 4, 3, 3, 3, 3, 2, 3, 4, 5, 7, 8, 9, 8, 10, 8, 8, 6, 5], +[3, 3, 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 8, 8, 7, 7, 8, 7, 7, 5, 6, 4], +[4, 2, 2, 2, 2, 4, 5, 7, 7, 9, 7, 8, 6, 6, 4, 4, 2, 3, 2, 3, 4, 5, 6, 6], +[7, 6, 6, 5, 5, 3, 4, 2, 4, 2, 2, 1, 2, 1, 1, 1, 0, 1, 2, 2, 4, 5, 6, 7], +[6, 7, 5, 5, 3, 3, 1, 1, -1, 0, 0, 1, 2, 3, 5, 5, 6, 6, 6, 5, 5, 3, 4, 3], +[4, 4, 5, 4, 5, 4, 4, 5, 5, 6, 5, 6, 6, 7, 7, 8, 6, 7, 5, 6, 4, 3, 2, 2], +[1, 2, 3, 3, 4, 6, 7, 8, 9, 8, 9, 6, 6, 4, 5, 3, 3, 2, 3, 3, 4, 3, 3, 5], +[4, 5, 4, 5, 4, 6, 5, 7, 5, 5, 4, 4, 3, 2, 1, 2, 2, 3, 4, 5, 7, 7, 8, 7], +[8, 5, 6, 3, 4, 2, 2, 2, 2, 2, 3, 3, 4, 5, 5, 6, 6, 6, 6, 8, 7, 8, 7, 7], +[6, 7, 5, 4, 3, 3, 4, 4, 5, 5, 7, 7, 8, 8, 9, 8, 7, 6, 5, 4, 4, 3, 4, 4], +[5, 5, 6, 7, 7, 9, 8, 10, 8, 9, 7, 8, 6, 6, 4, 4, 3, 3, 1, 1, 0, 1, 2, 3], +[4, 4, 6, 6, 8, 6, 8, 6, 7, 5, 4, 3, 2, 1, 1, 1, 1, 2, 2, 2, 3, 4, 2, 3], +[2, 3, 2, 3, 2, 3, 3, 3, 4, 3, 4, 4, 4, 4, 4, 5, 6, 5, 7, 5, 5, 4, 4, 2], +[1, -1, -1, -2, -1, 0, 2, 4, 5, 8, 7, 9, 8, 9, 8, 8, 6, 6, 5, 4, 3, 4, 2, 2], +[1, 0, 1, 0, 1, 1, 3, 4, 7, 7, 9, 8, 8, 6, 6, 4, 3, 1, 2, 1, 1, 2, 3, 5], +[5, 5, 5, 5, 3, 4, 2, 3, 1, 2, 1, 3, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6], +[7, 6, 7, 5, 5, 3, 2, 1, 1, 1, 1, 2, 3, 5, 5, 7, 7, 10, 8, 8, 6, 6, 5, 5], +[5, 5, 4, 5, 5, 5, 7, 6, 7, 6, 7, 7, 8, 8, 10, 9, 10, 9, 10, 8, 8, 6, 5, 4], +[3, 3, 4, 6, 6, 8, 9, 11, 10, 11, 9, 8, 6, 6, 4, 4, 4, 4, 5, 5, 6, 6, 6, 5], +[6, 5, 5, 4, 5, 5, 6, 6, 7, 5, 6, 4, 4, 2, 2, 2, 1, 3, 4, 6, 6, 9, 8, 10], +[8, 8, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 4, 7, 5, 7, 6, 7, 6], +[6, 5, 4, 4, 2, 2, 2, 3, 2, 5, 4, 6, 6, 7, 7, 7, 5, 5, 3, 3, 2, 2, 3, 2], +[4, 3, 5, 5, 6, 5, 7, 6, 7, 5, 6, 5, 5, 4, 4, 2, 2, 1, 0, -1, -1, 0, 1, 3], +[2, 5, 5, 6, 6, 6, 5, 5, 3, 3, 1, 0, -1, -1, -1, 0, 1, 2, 2, 3, 3, 3, 4, 3], +[3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 4, 5, 6, 5, 7, 6, 6, 4, 4], +[3, 1, 1, 0, 1, 1, 3, 4, 6, 5, 7, 6, 7, 6, 6, 5, 5, 4, 4, 4, 4, 4, 3, 3], +[3, 3, 2, 3, 3, 5, 5, 7, 6, 9, 7, 7, 6, 4, 3, 1, 1, -1, 0, 0, 1, 2, 3, 4], +[6, 5, 7, 5, 6, 5, 5, 4, 4, 4, 3, 3, 3, 3, 1, 2, 1, 1, 0, 1, 1, 4, 4, 5], +[5, 6, 5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 5, 5, 6, 6, 8, 6, 6, 4, 5, 2, 3, 2], +[2, 1, 2, 3, 3, 4, 5, 7, 8, 9, 9, 10, 9, 10, 10, 9, 9, 8, 6, 6, 4, 3, 2, 0], +[1, 0, 2, 1, 4, 5, 9, 9, 11, 11, 11, 10, 10, 8, 7, 6, 5, 4, 4, 5, 4, 5, 3, 5], +[3, 4, 2, 4, 3, 4, 5, 6, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 7, 7, 8, 8, 9, 7], +[7, 5, 4, 3, 2, 1, 1, 1, 2, 4, 3, 6, 5, 8, 8, 10, 9, 10, 9, 10, 9, 9, 8, 7], +[7, 6, 5, 4, 4, 3, 4, 3, 6, 5, 7, 7, 10, 10, 10, 10, 10, 8, 8, 6, 6, 5, 4, 5], +[4, 5, 4, 7, 6, 8, 7, 9, 8, 8, 6, 6, 5, 5, 4, 5, 4, 4, 4, 3, 4, 3, 5, 4], +[6, 5, 7, 6, 8, 7, 7, 6, 4, 4, 2, 1, 0, 0, 0, 0, 1, 3, 3, 5, 4, 5, 4, 4], +[4, 3, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 5, 4, 5, 4, 5, 4, 4, 3], +[1, 1, 0, 0, -1, 0, 1, 3, 4, 7, 6, 8, 6, 6, 4, 4, 4, 3, 2, 3, 3, 3, 3, 1], +[3, 0, 2, 1, 2, 1, 3, 3, 4, 4, 6, 5, 4, 4, 2, 1, -1, -1, -2, -1, -1, 1, 1, 3], +[4, 5, 4, 5, 3, 4, 2, 1, 1, 1, 1, 0, 0, 0, 1, 1, 2, 1, 2, 1, 3, 3, 4, 4], +[6, 5, 5, 4, 4, 3, 2, 3, 1, 1, 0, 1, 1, 4, 4, 6, 6, 7, 7, 6, 5, 4, 4, 2], +[3, 2, 4, 3, 5, 5, 6, 6, 8, 7, 8, 6, 8, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 3], +[2, 3, 2, 4, 5, 8, 9, 11, 10, 11, 10, 8, 7, 5, 4, 3, 2, 2, 4, 4, 5, 4, 6, 5], +[6, 4, 5, 4, 5, 5, 6, 6, 6, 6, 5, 5, 3, 4, 2, 3, 1, 2, 3, 5, 5, 7, 7, 8], +[8, 6, 5, 4, 3, 3, 3, 2, 4, 4, 5, 5, 6, 6, 7, 7, 7, 5, 7, 5, 5, 5, 5, 5], +[5, 5, 4, 4, 3, 4, 3, 5, 5, 9, 8, 10, 9, 10, 10, 8, 8, 6, 5, 3, 3, 1, 2, 2], +[3, 3, 5, 4, 6, 6, 7, 7, 8, 8, 8, 8, 8, 7, 6, 6, 4, 3, 2, 1, 0, 1, 1, 2], +[2, 4, 4, 5, 5, 5, 5, 5, 5, 4, 3, 2, 2, 2, 3, 3, 5, 5, 6, 5, 6, 5, 5, 3], +[3, 2, 1, 1, 0, 2, 0, 3, 2, 3, 2, 5, 3, 6, 6, 7, 8, 9, 8, 9, 8, 7, 6, 4], +[3, 1, 1, -1, 0, 0, 2, 3, 5, 6, 7, 8, 8, 8, 8, 8, 7, 8, 7, 7, 7, 6, 5, 6], +[4, 4, 2, 3, 3, 4, 4, 5, 5, 6, 6, 5, 6, 4, 4, 2, 2, 1, 2, 1, 4, 4, 5, 6], +[7, 6, 6, 5, 5, 4, 3, 3, 1, 1, 0, 1, 0, 1, 1, 1, 1, 2, 2, 4, 4, 5, 6, 6], +[6, 7, 7, 6, 6, 4, 4, 3, 4, 2, 3, 1, 3, 3, 5, 5, 6, 6, 6, 5, 5, 4, 3, 3], +[1, 2, 2, 3, 3, 5, 5, 7, 7, 8, 7, 8, 7, 6, 5, 4, 5, 4, 5, 3, 3, 2, 3, 0], +[2, 0, 3, 2, 5, 6, 8, 9, 9, 10, 9, 9, 7, 6, 4, 3, 1, 1, 1, 2, 2, 4, 4, 5], +[5, 5, 5, 4, 4, 3, 4, 4, 5, 3, 5, 3, 3, 2, 3, 2, 2, 2, 4, 4, 5, 7, 7, 7], +[7, 6, 5, 4, 2, 2, 1, 2, 1, 4, 3, 5, 5, 7, 7, 7, 8, 7, 7, 6, 6, 6, 6, 6], +[6, 5, 6, 4, 5, 4, 5, 5, 6, 6, 8, 8, 9, 9, 8, 8, 7, 7, 5, 5, 2, 3, 2, 3], +[3, 5, 5, 6, 7, 9, 9, 9, 8, 7, 8, 5, 6, 4, 5, 3, 2, 1, 2, 1, 2, 1, 3, 2], +[3, 4, 5, 6, 6, 7, 7, 7, 6, 5, 3, 3, 1, 2, 0, 2, 2, 3, 3, 5, 4, 4, 5, 4], +[3, 2, 3, 1, 2, 2, 4, 3, 5, 4, 5, 4, 5, 5, 5, 5, 6, 6, 6, 5, 5, 5, 3, 3], +[1, 1, -1, 0, -1, 1, 2, 4, 6, 8, 9, 10, 10, 9, 8, 6, 5, 3, 4, 2, 3, 2, 3, 2], +[2, 2, 3, 2, 3, 3, 4, 5, 6, 7, 7, 8, 7, 7, 5, 5, 2, 2, -1, 1, 1, 3, 3, 5], +[5, 5, 6, 4, 4, 3, 3, 2, 3, 2, 3, 2, 3, 3, 5, 4, 6, 5, 5, 5, 5, 4, 4, 5], +[5, 5, 4, 5, 4, 4, 3, 3, 3, 4, 3, 5, 5, 8, 8, 10, 11, 11, 11, 9, 9, 7, 6, 3], +[4, 2, 4, 2, 4, 4, 6, 7, 8, 9, 9, 10, 10, 10, 10, 10, 10, 11, 9, 10, 8, 7, 5, 5], +[3, 3, 2, 4, 5, 7, 8, 9, 10, 9, 10, 8, 8, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 9], +[8, 7, 6, 6, 5, 5, 4, 6, 5, 5, 3, 5, 3, 3, 3, 3, 3, 5, 5, 6, 7, 8, 10, 8], +[9, 7, 6, 3, 3, 1, 1, 1, 2, 2, 3, 3, 5, 5, 6, 6, 6, 7, 6, 5, 5, 6, 5, 6], +[4, 5, 4, 4, 3, 4, 4, 5, 5, 6, 7, 7, 8, 7, 7, 6, 5, 4, 3, 2, 1, 1, 2, 1], +[2, 2, 4, 4, 6, 7, 6, 7, 6, 6, 5, 5, 3, 4, 1, 2, 0, 0, -1, 0, -1, 0, 1, 1], +[3, 2, 3, 3, 5, 4, 5, 3, 4, 2, 3, 0, 0, -1, 0, 0, 2, 3, 4, 3, 3, 4, 3, 3], +[2, 2, 0, 1, 0, 2, 1, 2, 2, 3, 3, 4, 3, 4, 4, 5, 6, 5, 6, 6, 6, 4, 5, 3], +[3, 0, 1, 0, 1, 1, 3, 3, 5, 6, 7, 8, 8, 8, 7, 6, 5, 5, 4, 5, 3, 4, 3, 4], +[3, 4, 4, 4, 4, 5, 6, 6, 7, 6, 7, 6, 6, 5, 4, 2, 1, 0, 0, 0, 2, 2, 4, 6], +[6, 7, 6, 7, 5, 7, 5, 5, 3, 3, 1, 2, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 5, 4], +[5, 4, 6, 4, 6, 5, 5, 5, 5, 4, 5, 5, 5, 6, 6, 7, 7, 8, 7, 8, 5, 5, 3, 3], +[1, 2, 1, 3, 3, 5, 6, 9, 10, 10, 11, 10, 11, 9, 9, 7, 8, 6, 6, 5, 5, 4, 4, 2], +[3, 1, 2, 3, 4, 6, 7, 9, 10, 11, 9, 10, 8, 8, 5, 5, 4, 4, 3, 3, 4, 5, 5, 6], +[7, 6, 5, 4, 4, 3, 5, 4, 5, 4, 5, 4, 6, 5, 5, 5, 5, 6, 7, 7, 7, 8, 8, 9], +[7, 7, 4, 5, 2, 2, 1, 2, 1, 3, 4, 5, 7, 8, 9, 10, 10, 9, 10, 8, 8, 7, 8, 6], +[6, 5, 5, 4, 5, 4, 4, 5, 6, 7, 7, 9, 9, 10, 10, 10, 9, 9, 7, 7, 5, 5, 4, 4], +[4, 5, 6, 7, 7, 8, 10, 8, 9, 6, 7, 4, 5, 3, 3, 4, 4, 3, 4, 3, 3, 4, 4, 4], +[4, 5, 4, 6, 5, 6, 5, 6, 4, 3, 2, 2, 0, 0, 0, 1, 3, 3, 4, 5, 6, 6, 6, 5], +[5, 2, 3, 2, 2, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 6, 5, 6, 4, 4], +[2, 1, 0, 0, -1, 1, 2, 3, 6, 6, 8, 8, 8, 6, 6, 4, 3, 1, 1, 1, 2, 1, 3, 2], +[2, 3, 3, 4, 3, 4, 4, 5, 4, 7, 5, 7, 5, 5, 3, 2, 0, -1, -2, -2, -1, 0, 2, 4], +[6, 5, 7, 5, 6, 4, 5, 3, 3, 1, 2, 1, 2, 2, 3, 3, 3, 4, 4, 3, 2, 3, 2, 4], +[3, 5, 4, 5, 4, 5, 5, 5, 4, 4, 4, 5, 6, 7, 8, 7, 9, 8, 9, 7, 7, 5, 4, 3], +[2, 2, 2, 3, 5, 6, 7, 9, 10, 11, 11, 11, 10, 10, 10, 10, 8, 8, 7, 6, 6, 5, 4, 3], +[4, 3, 4, 4, 6, 7, 9, 10, 12, 11, 12, 9, 9, 7, 6, 4, 4, 4, 4, 4, 5, 6, 6, 7], +[7, 7, 5, 6, 5, 6, 5, 6, 6, 7, 6, 7, 5, 5, 4, 4, 5, 5, 6, 6, 7, 7, 9, 7], +[8, 6, 6, 5, 5, 4, 4, 4, 5, 5, 6, 7, 8, 9, 9, 10, 9, 9, 7, 8, 6, 5, 5, 5], +[4, 4, 3, 4, 5, 5, 6, 6, 9, 8, 11, 9, 11, 10, 11, 9, 9, 6, 5, 3, 3, 2, 1, 2], +[2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 8, 8, 6, 7, 5, 5, 4, 4, 3, 3, 2, 2, 4, 3], +[4, 3, 4, 2, 4, 4, 5, 4, 5, 4, 4, 3, 3, 4, 3, 5, 6, 7, 7, 8, 6, 7, 6, 6], +[3, 3, 1, -1, 0, 1, 1, 2, 3, 3, 5, 6, 6, 7, 9, 8, 10, 9, 10, 9, 10, 8, 7, 6], +[5, 3, 2, 1, 1, 2, 2, 4, 5, 7, 7, 9, 8, 9, 9, 8, 6, 7, 5, 6, 5, 6, 6, 6], +[6, 4, 5, 4, 6, 4, 5, 4, 6, 5, 6, 5, 5, 4, 4, 3, 3, 2, 3, 3, 3, 5, 6, 8], +[8, 10, 9, 10, 7, 7, 5, 5, 3, 3, 1, 1, 0, 1, 1, 3, 4, 4, 6, 5, 5, 5, 6, 5], +[6, 5, 6, 5, 5, 5, 5, 5, 4, 5, 4, 4, 4, 5, 5, 6, 6, 8, 7, 7, 6, 6, 4, 3], +[2, 2, 2, 2, 4, 5, 8, 8, 10, 10, 12, 10, 10, 8, 8, 5, 6, 5, 5, 4, 5, 4, 3, 4], +[2, 4, 3, 4, 4, 6, 6, 9, 9, 10, 9, 9, 7, 6, 4, 3, 2, 1, 2, 2, 3, 4, 5, 5], +[7, 5, 6, 4, 4, 3, 3, 3, 4, 5, 5, 5, 4, 5, 4, 4, 4, 5, 4, 6, 6, 7, 6, 7], +[6, 7, 4, 4, 4, 3, 3, 2, 4, 3, 5, 5, 7, 8, 10, 9, 9, 8, 8, 6, 7, 5, 5, 5], +[5, 5, 4, 5, 4, 6, 6, 7, 7, 8, 8, 9, 8, 10, 9, 9, 7, 7, 5, 5, 3, 2, 2, 2], +[3, 3, 5, 6, 8, 8, 10, 9, 10, 9, 8, 6, 5, 4, 4, 3, 2, 3, 3, 3, 3, 3, 2, 3], +[3, 4, 4, 5, 5, 6, 6, 6, 6, 5, 4, 4, 3, 2, 2, 2, 3, 4, 6, 6, 6, 5, 5, 4], +[4, 2, 2, 1, 1, 2, 3, 5, 5, 7, 6, 7, 6, 8, 6, 7, 7, 7, 6, 7, 6, 6, 4, 4], +[3, 1, 1, 0, 1, 1, 3, 5, 8, 8, 11, 10, 12, 10, 9, 7, 6, 4, 3, 2, 2, 3, 2, 4], +[3, 4, 3, 5, 3, 5, 5, 6, 6, 8, 6, 8, 6, 7, 6, 4, 3, 2, 1, 0, 1, 2, 4, 4], +[6, 5, 6, 6, 6, 6, 5, 4, 3, 4, 3, 4, 4, 5, 6, 7, 7, 8, 7, 8, 6, 7, 5, 6], +[5, 4, 3, 4, 4, 4, 5, 4, 6, 4, 6, 6, 8, 8, 10, 10, 12, 11, 12, 10, 9, 8, 6, 5], +[4, 3, 2, 3, 3, 5, 7, 9, 9, 11, 11, 12, 11, 11, 10, 10, 10, 10, 9, 9, 9, 8, 8, 7], +[7, 5, 6, 5, 7, 7, 9, 9, 10, 9, 9, 8, 7, 5, 4, 4, 3, 4, 5, 5, 6, 8, 9, 10], +[9, 9, 7, 7, 5, 5, 4, 4, 4, 3, 3, 2, 3, 2, 3, 3, 4, 4, 6, 6, 7, 8, 8, 9], +[9, 8, 7, 6, 5, 5, 4, 5, 4, 6, 4, 6, 5, 8, 7, 7, 6, 7, 5, 5, 5, 4, 5, 5], +[5, 4, 5, 4, 6, 5, 7, 6, 9, 8, 9, 8, 9, 7, 7, 5, 4, 3, 2, 1, 0, 1, 0, 1], +[1, 3, 3, 6, 6, 8, 9, 9, 8, 9, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0, 1, 0, 2, 1], +[3, 2, 3, 3, 4, 4, 5, 5, 5, 5, 4, 4, 2, 3, 2, 4, 3, 4, 4, 6, 5, 5, 4, 4], +[2, 1, 1, 0, 0, 0, 2, 2, 4, 4, 6, 6, 8, 7, 9, 8, 8, 8, 7, 6, 7, 6, 5, 5], +[3, 2, 0, 2, 1, 3, 2, 6, 6, 9, 9, 11, 10, 11, 9, 8, 7, 5, 4, 4, 3, 3, 4, 4], +[6, 4, 6, 6, 7, 6, 7, 7, 7, 7, 7, 6, 7, 6, 5, 5, 3, 4, 2, 3, 3, 4, 4, 6], +[6, 7, 7, 8, 7, 8, 7, 6, 6, 4, 4, 4, 4, 3, 5, 5, 7, 7, 7, 6, 7, 6, 6, 5], +[4, 4, 4, 5, 5, 6, 7, 8, 7, 9, 8, 9, 9, 10, 9, 10, 10, 10, 9, 9, 8, 6, 5, 3], +[3, 1, 2, 1, 4, 5, 8, 10, 12, 13, 15, 14, 14, 12, 10, 9, 8, 7, 7, 6, 5, 5, 4, 5], +[3, 4, 3, 4, 4, 7, 7, 9, 11, 11, 12, 11, 10, 9, 8, 6, 6, 4, 4, 4, 6, 6, 7, 7], +[8, 6, 6, 5, 4, 4, 3, 4, 4, 6, 5, 7, 7, 8, 8, 8, 8, 8, 8, 9, 8, 9, 8, 7], +[8, 6, 6, 3, 3, 2, 3, 2, 4, 4, 6, 7, 10, 11, 13, 12, 12, 11, 10, 10, 9, 7, 6, 6], +[5, 6, 4, 6, 5, 6, 5, 7, 7, 8, 8, 9, 9, 10, 10, 10, 9, 9, 8, 6, 6, 4, 4, 4], +[5, 4, 6, 5, 8, 8, 8, 8, 7, 7, 5, 5, 4, 3, 3, 4, 3, 5, 4, 6, 5, 6, 6, 7], +[6, 6, 5, 5, 6, 5, 6, 5, 5, 3, 4, 1, 1, 0, 1, 1, 3, 4, 6, 7, 7, 7, 7, 7], +[5, 4, 3, 2, 1, 3, 2, 3, 3, 5, 4, 5, 4, 5, 5, 5, 4, 5, 5, 6, 6, 5, 6, 5], +[5, 3, 3, 2, 3, 3, 5, 5, 7, 8, 9, 9, 9, 8, 6, 4, 2, 2, 0, 1, 1, 2, 2, 4], +[4, 5, 5, 7, 6, 7, 7, 7, 7, 6, 6, 5, 5, 4, 4, 1, 1, -1, -1, -1, 0, 1, 3, 4], +[5, 6, 6, 7, 6, 6, 6, 6, 4, 4, 2, 4, 2, 4, 4, 5, 5, 6, 5, 6, 5, 4, 3, 3], +[3, 3, 4, 3, 5, 4, 7, 6, 7, 7, 8, 8, 9, 9, 10, 9, 10, 10, 10, 8, 7, 7, 4, 4], +[2, 2, 1, 4, 4, 6, 8, 10, 11, 12, 13, 13, 13, 11, 11, 9, 9, 7, 8, 6, 7, 5, 6, 5], +[5, 4, 6, 6, 7, 7, 9, 10, 10, 11, 10, 10, 9, 8, 6, 6, 5, 5, 4, 6, 6, 7, 8, 9], +[7, 7, 7, 7, 6, 5, 5, 4, 5, 4, 5, 5, 6, 5, 7, 7, 8, 7, 7, 7, 7, 7, 7, 6], +[7, 7, 6, 7, 5, 5, 4, 5, 4, 6, 6, 8, 8, 9, 10, 10, 11, 9, 9, 6, 6, 3, 3, 2], +[3, 2, 4, 4, 7, 6, 8, 8, 10, 10, 10, 10, 10, 11, 10, 9, 7, 7, 4, 4, 1, 2, -1, 0], +[1, 2, 3, 5, 6, 7, 8, 9, 9, 8, 7, 6, 6, 5, 6, 5, 5, 3, 4, 1, 3, 2, 2, 2], +[2, 2, 2, 2, 2, 4, 3, 4, 4, 5, 4, 5, 4, 5, 5, 6, 7, 8, 7, 8, 7, 6, 5, 3], +[3, 1, 1, -1, 0, -1, 0, 0, 3, 3, 6, 8, 9, 9, 10, 10, 9, 10, 9, 8, 6, 6, 4, 4], +[2, 3, 1, 1, 1, 2, 2, 3, 4, 6, 7, 8, 10, 10, 11, 9, 9, 6, 6, 3, 5, 4, 4, 4], +[6, 6, 7, 8, 7, 7, 6, 6, 5, 5, 3, 4, 3, 4, 4, 5, 4, 5, 3, 4, 3, 4, 4, 5], +[6, 6, 8, 7, 8, 6, 6, 4, 3, 1, 1, -1, 1, 1, 3, 4, 6, 6, 7, 6, 6, 6, 4, 5], +[3, 5, 4, 6, 5, 7, 6, 7, 6, 6, 6, 6, 6, 7, 8, 8, 9, 8, 9, 7, 7, 5, 5, 3], +[3, 2, 3, 2, 5, 5, 8, 9, 10, 11, 10, 10, 9, 9, 7, 7, 4, 4, 3, 4, 2, 4, 3, 4], +[4, 4, 5, 5, 6, 6, 8, 8, 9, 8, 8, 7, 7, 5, 5, 3, 3, 1, 2, 1, 3, 4, 5, 5], +[7, 7, 6, 6, 5, 5, 4, 5, 4, 4, 3, 5, 5, 5, 6, 6, 6, 6, 6, 5, 5, 4, 5, 5], +[5, 4, 6, 4, 4, 3, 4, 3, 3, 5, 5, 7, 9, 10, 10, 11, 10, 10, 7, 7, 3, 4, 1, 3], +[1, 4, 3, 5, 5, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10, 9, 9, 7, 6, 3, 3, 1, 1, 0], +[1, 3, 3, 5, 7, 8, 9, 9, 8, 8, 6, 6, 4, 5, 4, 5, 4, 4, 4, 4, 4, 3, 4, 3], +[4, 2, 3, 2, 4, 4, 4, 4, 5, 3, 4, 3, 4, 3, 4, 5, 6, 8, 7, 8, 7, 7, 5, 5], +[3, 3, 1, 2, 1, 2, 2, 3, 3, 5, 7, 7, 8, 8, 9, 8, 9, 7, 8, 6, 7, 5, 6, 3], +[4, 2, 2, 1, 3, 2, 4, 6, 6, 8, 8, 10, 9, 10, 9, 9, 6, 6, 3, 2, 1, 2, 2, 4], +[4, 5, 5, 6, 7, 6, 7, 6, 6, 5, 6, 5, 6, 5, 7, 6, 6, 3, 3, 3, 2, 3, 3, 4], +[4, 6, 5, 7, 5, 6, 5, 5, 3, 4, 2, 3, 4, 5, 6, 8, 9, 9, 9, 8, 7, 5, 5, 3], +[4, 2, 3, 2, 4, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 11, 13, 11, 11, 8, 8, 6, 5], +[3, 3, 2, 3, 3, 5, 6, 7, 9, 9, 10, 10, 11, 10, 11, 10, 10, 8, 8, 6, 7, 5, 6, 6], +[5, 5, 6, 6, 5, 6, 5, 6, 6, 6, 5, 6, 4, 5, 4, 4, 4, 4, 4, 4, 5, 6, 7, 8], +[9, 9, 9, 7, 7, 5, 4, 3, 3, 1, 2, 1, 3, 3, 4, 5, 6, 6, 6, 7, 5, 6, 6, 7], +[6, 7, 6, 7, 5, 5, 4, 4, 3, 3, 3, 4, 5, 6, 7, 6, 8, 6, 7, 4, 4, 3, 2, 1], +[3, 2, 4, 5, 6, 7, 8, 8, 9, 8, 7, 8, 7, 6, 6, 6, 3, 3, 1, 1, -1, 0, 0, 0], +[2, 2, 4, 5, 7, 7, 9, 8, 8, 6, 5, 3, 3, 1, 2, 1, 1, 1, 1, 1, 0, 1, 1, 2], +[2, 3, 2, 3, 2, 3, 2, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 5, 4, 5, 4, 5, 2], +[3, 1, 2, 0, 1, 0, 2, 2, 3, 4, 6, 7, 8, 9, 9, 9, 7, 7, 5, 6, 4, 4, 3, 3], +[3, 3, 2, 2, 2, 4, 4, 5, 7, 7, 8, 8, 10, 10, 10, 7, 8, 5, 4, 2, 1, 0, 2, 3], +[4, 6, 6, 8, 8, 8, 7, 8, 6, 6, 5, 5, 4, 5, 5, 5, 5, 4, 4, 2, 3, 2, 3, 4], +[6, 5, 8, 7, 8, 7, 7, 5, 5, 3, 4, 3, 3, 5, 5, 7, 8, 9, 9, 9, 7, 7, 4, 5], +[3, 3, 3, 5, 5, 6, 7, 7, 8, 8, 8, 8, 10, 10, 11, 10, 11, 10, 11, 8, 9, 7, 6, 4], +[3, 3, 2, 3, 4, 6, 7, 10, 11, 13, 12, 14, 11, 12, 9, 9, 7, 7, 5, 5, 5, 6, 6, 6], +[6, 5, 6, 5, 7, 5, 7, 7, 8, 8, 8, 7, 8, 7, 7, 6, 4, 5, 4, 4, 4, 6, 7, 8], +[7, 8, 7, 7, 5, 5, 3, 3, 3, 3, 4, 5, 6, 7, 9, 8, 10, 8, 10, 8, 8, 7, 7, 6], +[7, 5, 6, 5, 4, 4, 4, 3, 3, 4, 5, 7, 8, 11, 12, 13, 10, 11, 8, 8, 5, 5, 3, 3], +[2, 3, 4, 5, 6, 5, 7, 7, 8, 7, 8, 8, 8, 9, 9, 9, 9, 7, 7, 4, 3, 3, 2, 3], +[3, 5, 5, 7, 7, 8, 7, 8, 6, 6, 4, 4, 3, 2, 2, 3, 3, 3, 4, 3, 5, 4, 5, 3], +[5, 3, 4, 3, 4, 3, 3, 3, 2, 2, 1, 1, 1, 1, 2, 4, 3, 5, 5, 7, 6, 7, 5, 6], +[4, 3, 2, 1, 1, 1, 2, 2, 4, 4, 5, 6, 7, 6, 7, 6, 7, 5, 5, 4, 5, 4, 4, 4], +[4, 3, 3, 3, 3, 4, 4, 5, 6, 7, 7, 8, 7, 8, 7, 5, 4, 2, 0, -1, -1, -1, 0, 1], +[4, 5, 6, 6, 8, 7, 7, 7, 6, 5, 4, 4, 4, 4, 3, 3, 3, 2, 2, 1, 0, 1, 1, 3], +[3, 5, 5, 7, 6, 6, 5, 6, 4, 3, 4, 3, 4, 4, 6, 5, 8, 7, 8, 6, 7, 5, 5, 2], +[2, 1, 2, 2, 3, 3, 5, 6, 7, 8, 8, 9, 10, 11, 11, 11, 10, 10, 8, 8, 7, 6, 4, 4], +[3, 2, 3, 2, 4, 5, 7, 8, 10, 10, 12, 12, 12, 10, 10, 9, 9, 7, 6, 5, 5, 5, 4, 6], +[5, 6, 6, 7, 7, 7, 6, 7, 7, 8, 6, 7, 7, 6, 6, 5, 5, 4, 5, 4, 6, 6, 7, 7], +[8, 8, 8, 7, 7, 6, 4, 4, 3, 3, 2, 4, 4, 6, 7, 8, 7, 9, 7, 8, 7, 7, 6, 7], +[6, 6, 5, 6, 6, 6, 5, 4, 5, 5, 6, 6, 8, 9, 11, 10, 10, 9, 9, 7, 6, 4, 4, 3], +[2, 3, 4, 5, 5, 7, 8, 9, 8, 10, 8, 9, 8, 8, 8, 7, 7, 5, 4, 3, 3, 1, 2, 1], +[3, 2, 4, 4, 6, 6, 7, 7, 7, 7, 5, 5, 4, 4, 2, 4, 3, 4, 4, 5, 4, 5, 4, 4], +[2, 3, 2, 2, 1, 2, 2, 1, 2, 2, 3, 2, 4, 4, 6, 5, 6, 6, 8, 6, 8, 6, 7, 5], +[4, 2, 1, 0, -1, -1, -1, 1, 1, 3, 4, 7, 8, 10, 9, 9, 8, 9, 7, 7, 6, 6, 6, 5], +[5, 4, 4, 3, 4, 2, 4, 4, 5, 4, 6, 6, 7, 7, 8, 7, 6, 5, 3, 2, 2, 2, 2, 4], +[4, 7, 6, 8, 7, 7, 5, 5, 3, 2, 1, 1, 0, 1, 2, 2, 4, 2, 4, 3, 3, 3, 4, 4], +[5, 6, 7, 7, 8, 7, 6, 5, 4, 3, 1, 1, 1, 3, 2, 6, 6, 8, 7, 8, 7, 7, 6, 5], +[3, 4, 3, 3, 4, 4, 6, 6, 7, 7, 7, 6, 7, 6, 7, 7, 8, 7, 8, 6, 6, 5, 5, 4], +[3, 3, 2, 4, 4, 6, 6, 10, 10, 11, 10, 10, 9, 8, 7, 6, 4, 2, 3, 2, 3, 3, 4, 4], +[5, 5, 6, 6, 7, 6, 7, 7, 7, 6, 6, 6, 5, 4, 3, 3, 1, 2, 1, 2, 2, 4, 3, 5], +[5, 6, 6, 6, 5, 4, 4, 3, 3, 2, 3, 3, 5, 5, 7, 5, 7, 6, 6, 4, 5, 4, 4, 3], +[4, 4, 3, 4, 4, 4, 3, 4, 4, 6, 6, 7, 8, 10, 10, 10, 9, 8, 7, 4, 3, 2, 1, 0], +[1, 0, 3, 3, 6, 5, 8, 8, 9, 8, 9, 8, 8, 8, 8, 7, 7, 5, 4, 3, 1, 1, -1, 1], +[1, 3, 3, 5, 6, 6, 7, 7, 6, 6, 5, 4, 3, 2, 3, 2, 3, 3, 4, 4, 5, 3, 5, 3], +[4, 3, 3, 3, 2, 2, 3, 3, 3, 4, 2, 4, 3, 5, 4, 6, 6, 8, 6, 8, 7, 7, 6, 6], +[5, 3, 3, 1, 2, 1, 2, 2, 5, 5, 6, 7, 8, 8, 10, 8, 8, 7, 6, 5, 5, 5, 4, 5], +[4, 5, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 8, 8, 7, 7, 4, 4, 1, 1, 0, 3, 3], +[5, 5, 8, 7, 9, 8, 8, 7, 6, 5, 4, 5, 4, 5, 4, 5, 4, 5, 3, 5, 3, 4, 3, 4], +[4, 5, 5, 5, 6, 6, 6, 6, 6, 4, 5, 4, 5, 5, 7, 8, 9, 9, 10, 9, 9, 7, 7, 5], +[4, 4, 2, 3, 2, 3, 3, 5, 6, 8, 7, 9, 10, 11, 10, 10, 11, 10, 10, 9, 8, 7, 6, 5], +[5, 2, 3, 2, 3, 3, 6, 6, 7, 8, 9, 9, 9, 9, 9, 8, 6, 7, 5, 5, 4, 6, 5, 7], +[6, 9, 8, 8, 7, 7, 6, 5, 5, 3, 4, 3, 3, 3, 3, 2, 4, 3, 5, 4, 6, 6, 7, 7], +[9, 8, 8, 7, 6, 5, 3, 2, 0, 1, -1, 0, 0, 2, 4, 5, 6, 7, 5, 6, 5, 5, 5, 5], +[6, 5, 6, 5, 6, 5, 5, 4, 5, 4, 5, 5, 6, 6, 7, 8, 7, 7, 5, 5, 3, 3, 1, 2], +[1, 3, 2, 5, 5, 8, 8, 9, 9, 9, 7, 6, 6, 5, 4, 3, 3, 1, 3, 0, 1, 0, 1, -1], +[2, 1, 4, 3, 6, 7, 7, 8, 6, 7, 5, 4, 2, 2, 0, 1, 0, 2, 1, 3, 2, 3, 2, 3], +[2, 2, 2, 1, 2, 1, 2, 2, 4, 3, 4, 3, 4, 4, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4], +[2, 3, 0, 1, -1, -1, -1, 1, 2, 4, 6, 8, 9, 10, 9, 8, 9, 6, 6, 4, 3, 2, 2, 1], +[3, 2, 3, 3, 4, 4, 4, 5, 5, 7, 7, 7, 9, 9, 8, 8, 5, 6, 3, 2, 0, 0, 0, 3], +[3, 5, 6, 7, 8, 8, 7, 6, 5, 4, 4, 2, 3, 3, 5, 4, 5, 5, 5, 4, 5, 4, 4, 4], +[5, 4, 5, 6, 5, 6, 5, 5, 4, 4, 3, 4, 3, 5, 5, 8, 9, 10, 10, 10, 9, 8, 7, 5], +[5, 3, 3, 3, 4, 3, 6, 6, 8, 8, 9, 8, 10, 9, 9, 10, 10, 10, 9, 9, 8, 8, 6, 6], +[5, 4, 3, 5, 4, 6, 7, 9, 9, 10, 11, 11, 11, 9, 9, 6, 7, 4, 5, 3, 5, 4, 6, 6], +[7, 7, 7, 7, 7, 7, 6, 7, 6, 6, 6, 6, 5, 6, 4, 5, 3, 5, 4, 4, 5, 6, 6, 8], +[8, 7, 8, 6, 6, 4, 3, 2, 2, 1, 3, 3, 4, 5, 7, 7, 8, 8, 7, 7, 5, 6, 4, 5], +[4, 5, 4, 5, 3, 4, 3, 3, 3, 4, 5, 6, 8, 8, 9, 9, 9, 8, 8, 5, 5, 2, 3, 1], +[3, 2, 4, 4, 6, 6, 7, 8, 7, 7, 6, 6, 5, 6, 5, 5, 4, 5, 2, 3, 2, 2, 1, 2], +[2, 3, 3, 4, 5, 5, 4, 4, 4, 2, 2, -1, 0, -1, 0, -1, 1, 1, 2, 2, 4, 4, 5, 5], +[5, 5, 3, 3, 2, 2, 1, 1, 0, 1, 0, 1, 0, 1, 2, 3, 4, 4, 5, 5, 6, 5, 6, 5], +[6, 3, 4, 1, 2, 1, 1, 1, 2, 2, 3, 5, 5, 6, 6, 6, 4, 4, 3, 3, 2, 3, 2, 3], +[3, 5, 4, 5, 6, 6, 6, 6, 6, 5, 6, 5, 5, 5, 5, 3, 3, 0, 0, -2, -1, -1, 1, 1], +[3, 5, 7, 7, 8, 9, 9, 8, 6, 5, 3, 3, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2], +[3, 3, 4, 4, 5, 5, 7, 5, 6, 5, 5, 4, 5, 5, 4, 6, 7, 7, 7, 7, 6, 5, 3, 4], +[2, 2, 1, 2, 2, 3, 4, 6, 7, 8, 10, 11, 11, 10, 11, 9, 9, 7, 7, 5, 6, 4, 4, 3], +[3, 2, 3, 2, 4, 4, 6, 7, 9, 10, 10, 11, 10, 11, 8, 9, 6, 5, 3, 4, 2, 3, 3, 5], +[5, 7, 7, 6, 6, 5, 5, 4, 5, 4, 5, 4, 6, 5, 5, 5, 6, 4, 4, 5, 5, 5, 5, 7], +[7, 8, 6, 7, 5, 5, 3, 3, 2, 2, 1, 3, 4, 5, 7, 9, 9, 9, 8, 7, 7, 5, 5, 3], +[5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 6, 7, 8, 9, 9, 10, 9, 10, 7, 7, 5, 4, 2, 2], +[1, 2, 3, 4, 5, 7, 9, 9, 9, 9, 8, 7, 7, 6, 7, 5, 5, 4, 4, 2, 3, 2, 2, 2], +[2, 3, 3, 4, 4, 6, 6, 6, 5, 6, 3, 4, 2, 2, 1, 2, 2, 3, 3, 4, 5, 5, 5, 4], +[4, 3, 2, 1, 1, 0, 1, 0, 1, 1, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 6, 6], +[4, 4, 1, 2, 0, 1, 0, 0, 2, 3, 4, 6, 8, 8, 10, 8, 8, 5, 5, 3, 3, 2, 3, 2], +[4, 3, 4, 4, 4, 4, 4, 5, 3, 5, 4, 5, 4, 6, 6, 6, 4, 4, 1, 1, -1, 0, 1, 2], +[4, 5, 7, 7, 8, 7, 7, 5, 5, 2, 2, 0, 1, 0, 1, 2, 3, 4, 4, 5, 4, 4, 4, 4], +[3, 5, 4, 5, 4, 5, 4, 4, 3, 2, 1, 1, 2, 2, 4, 5, 6, 7, 8, 7, 8, 6, 6, 4], +[4, 3, 3, 2, 4, 3, 4, 5, 6, 6, 6, 7, 8, 8, 7, 8, 7, 8, 7, 7, 5, 7, 5, 6], +[4, 5, 4, 4, 5, 6, 7, 8, 9, 8, 9, 8, 7, 6, 5, 4, 3, 1, 2, 1, 2, 3, 4, 6], +[6, 7, 6, 7, 7, 7, 5, 6, 5, 5, 3, 3, 2, 2, 1, 1, 1, 1, 1, 2, 3, 3, 5, 5], +[7, 6, 8, 5, 7, 5, 4, 3, 2, 2, 2, 3, 3, 5, 5, 6, 5, 6, 5, 5, 3, 4, 2, 3], +[2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 8, 8, 9, 8, 8, 6, 6, 3, 3, 0, 1, -1], +[0, 0, 1, 3, 4, 5, 6, 9, 8, 8, 7, 8, 6, 7, 5, 5, 4, 4, 2, 2, 1, 1, 1, 0], +[1, 1, 3, 3, 4, 3, 5, 4, 4, 4, 4, 3, 3, 2, 2, 2, 3, 3, 4, 4, 4, 5, 4, 5], +[3, 4, 2, 2, 0, 1, -1, 1, 0, 1, 1, 3, 4, 4, 6, 6, 8, 6, 8, 7, 7, 6, 6, 5], +[5, 3, 4, 2, 1, 1, 1, 2, 2, 4, 4, 7, 7, 9, 8, 10, 8, 8, 6, 5, 4, 4, 4, 4], +[4, 5, 5, 5, 6, 6, 6, 6, 7, 6, 6, 6, 7, 6, 6, 5, 5, 4, 3, 2, 2, 1, 2, 3], +[4, 6, 6, 8, 8, 9, 7, 8, 6, 5, 3, 2, 2, 2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 4], +[6, 4, 5, 4, 5, 4, 5, 5, 5, 4, 3, 3, 4, 5, 4, 7, 6, 9, 8, 10, 8, 8, 6, 6], +[3, 3, 2, 1, 1, 1, 3, 4, 6, 6, 8, 8, 9, 9, 9, 9, 8, 7, 7, 5, 6, 5, 6, 5], +[5, 5, 4, 5, 4, 5, 5, 7, 7, 8, 7, 8, 7, 6, 5, 5, 3, 3, 2, 2, 2, 3, 4, 5], +[6, 7, 8, 6, 6, 5, 4, 2, 2, 1, 1, 0, 1, 0, 1, 2, 1, 2, 1, 3, 3, 5, 4, 6], +[6, 7, 7, 7, 5, 5, 4, 2, 1, 0, 0, 0, 1, 3, 5, 5, 7, 5, 6, 5, 6, 4, 5, 3], +[4, 3, 4, 4, 4, 5, 5, 5, 4, 6, 4, 5, 4, 6, 6, 7, 5, 6, 4, 4, 2, 2, 1, 1], +[1, 2, 3, 3, 6, 6, 9, 8, 9, 8, 8, 6, 5, 3, 3, 2, 2, 1, 0, 0, 1, 1, 1, 2], +[2, 3, 3, 5, 4, 6, 5, 6, 5, 5, 3, 3, 1, 0, 0, -1, 0, 0, 2, 1, 4, 3, 5, 3], +[4, 3, 3, 1, 2, 1, 1, 1, 2, 2, 3, 4, 3, 4, 4, 4, 3, 5, 3, 4, 3, 5, 3, 5], +[4, 3, 3, 2, 1, 1, 2, 2, 3, 4, 7, 6, 9, 8, 9, 8, 7, 4, 4, 1, 1, 0, 1, 1], +[2, 4, 4, 5, 5, 6, 6, 7, 6, 7, 6, 6, 6, 6, 6, 6, 5, 3, 2, 1, -1, 0, 0, 0], +[3, 3, 6, 6, 8, 7, 7, 6, 5, 4, 3, 3, 2, 3, 2, 4, 4, 6, 5, 6, 4, 5, 4, 5], +[3, 4, 3, 4, 4, 5, 5, 5, 5, 4, 4, 4, 5, 6, 7, 8, 10, 10, 11, 9, 10, 8, 8, 6], +[4, 3, 1, 2, 2, 3, 3, 6, 7, 9, 8, 10, 10, 11, 11, 11, 9, 10, 8, 8, 8, 7, 7, 5], +[5, 5, 5, 4, 6, 6, 7, 7, 9, 9, 10, 9, 9, 8, 8, 7, 6, 5, 4, 5, 4, 6, 5, 7], +[7, 9, 7, 8, 7, 6, 6, 5, 4, 4, 3, 4, 3, 3, 4, 4, 5, 4, 5, 4, 6, 5, 6, 6], +[7, 6, 7, 5, 5, 3, 3, 3, 2, 2, 1, 3, 3, 6, 6, 8, 7, 9, 7, 7, 6, 6, 5, 4], +[4, 4, 3, 3, 3, 3, 4, 3, 5, 4, 6, 5, 7, 7, 7, 7, 8, 6, 6, 4, 3, 2, 1, 1], +[0, 1, 1, 2, 2, 5, 4, 6, 5, 6, 5, 4, 3, 2, 2, 2, 2, 1, 2, 0, 1, 0, 1, 1], +[2, 2, 3, 3, 4, 2, 3, 3, 2, 1, 1, 0, -1, 0, -1, 0, -1, 2, 1, 3, 3, 5, 4, 5], +[3, 4, 2, 1, 0, 0, -1, -1, 0, -2, 0, -1, 1, 2, 4, 3, 4, 3, 4, 3, 5, 5, 5, 5], +[4, 4, 3, 2, 2, 1, 0, 2, 1, 3, 3, 5, 5, 7, 7, 6, 6, 5, 3, 2, 2, 2, 2, 2], +[4, 4, 6, 5, 7, 8, 8, 7, 7, 5, 5, 5, 4, 3, 3, 4, 2, 3, 1, 1, 0, 1, 0, 2], +[3, 5, 5, 8, 8, 8, 8, 7, 7, 4, 4, 1, 1, 0, 1, 0, 2, 2, 5, 3, 5, 4, 5, 3], +[3, 3, 3, 3, 4, 4, 5, 6, 5, 5, 5, 5, 4, 5, 5, 6, 6, 7, 7, 8, 6, 7, 5, 5], +[4, 3, 3, 1, 2, 2, 4, 4, 6, 7, 10, 10, 10, 9, 10, 9, 8, 6, 5, 4, 3, 4, 4, 4], +[4, 5, 4, 5, 4, 5, 5, 7, 7, 8, 8, 8, 8, 7, 6, 5, 5, 2, 3, 1, 2, 1, 4, 5], +[7, 7, 8, 6, 7, 6, 5, 4, 3, 2, 2, 3, 2, 3, 3, 5, 3, 5, 3, 5, 4, 5, 5, 6], +[6, 6, 6, 6, 5, 4, 4, 2, 2, 1, 1, 1, 3, 4, 6, 7, 9, 8, 9, 7, 7, 5, 4, 4], +[3, 3, 3, 4, 3, 6, 5, 6, 6, 7, 6, 6, 7, 8, 8, 8, 9, 8, 7, 6, 5, 3, 3, 1], +[3, 1, 3, 4, 5, 6, 8, 8, 9, 7, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 2, 3, 2, 4], +[3, 4, 3, 4, 3, 4, 4, 4, 4, 3, 3, 2, 2, 0, 1, 0, 3, 2, 5, 4, 7, 6, 8, 6], +[6, 5, 3, 2, 1, 0, 0, 1, -1, 1, 1, 3, 3, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 5], +[6, 4, 4, 2, 1, 0, 1, 1, 2, 2, 4, 5, 6, 7, 8, 7, 6, 5, 3, 3, 1, 1, 1, 3], +[2, 5, 5, 7, 7, 7, 6, 7, 6, 5, 5, 5, 4, 4, 4, 2, 3, 2, 2, 0, 1, 0, 2, 2], +[3, 4, 6, 6, 7, 7, 6, 5, 3, 3, 1, 0, 0, 0, 0, 2, 1, 4, 3, 5, 5, 6, 5, 4], +[4, 4, 4, 3, 4, 4, 4, 3, 4, 3, 4, 3, 4, 4, 6, 6, 7, 7, 8, 7, 8, 7, 6, 6], +[4, 4, 3, 3, 3, 4, 3, 5, 6, 7, 8, 8, 8, 8, 8, 7, 7, 5, 6, 5, 5, 5, 5, 4], +[6, 4, 6, 5, 7, 7, 8, 8, 7, 7, 8, 8, 6, 7, 5, 5, 2, 2, 1, 2, 1, 3, 3, 6], +[6, 8, 8, 9, 8, 8, 7, 6, 6, 4, 4, 2, 2, 2, 2, 2, 3, 2, 4, 2, 4, 3, 4, 5], +[6, 5, 5, 6, 5, 5, 4, 4, 3, 3, 3, 4, 4, 6, 6, 6, 6, 7, 6, 5, 4, 3, 2, 2], +[2, 1, 2, 2, 4, 4, 5, 6, 7, 7, 8, 8, 8, 9, 8, 8, 7, 6, 4, 4, 1, 2, 0, 0], +[-1, 1, 0, 3, 4, 5, 7, 7, 8, 8, 8, 7, 6, 5, 5, 3, 3, 2, 3, 1, 2, 1, 2, 2], +[3, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 6], +[6, 4, 3, 2, 1, 0, 0, -1, 0, 1, 2, 3, 5, 5, 7, 8, 8, 8, 8, 7, 7, 6, 6, 6], +[5, 6, 4, 4, 2, 3, 2, 3, 2, 4, 5, 6, 7, 8, 9, 9, 10, 8, 8, 4, 5, 3, 4, 4], +[5, 5, 7, 7, 9, 9, 9, 9, 8, 7, 5, 5, 5, 5, 4, 6, 5, 6, 5, 5, 4, 5, 4, 5], +[5, 6, 7, 8, 8, 8, 8, 7, 6, 4, 4, 2, 2, 1, 2, 2, 5, 5, 7, 7, 8, 7, 7, 6], +[5, 5, 4, 3, 2, 3, 3, 5, 4, 5, 4, 6, 5, 5, 6, 7, 8, 8, 9, 9, 9, 8, 8, 7], +[7, 5, 5, 3, 3, 2, 4, 4, 6, 7, 8, 9, 9, 9, 8, 8, 6, 7, 4, 5, 4, 5, 4, 5], +[5, 6, 5, 6, 4, 5, 4, 5, 5, 5, 6, 5, 5, 5, 5, 2, 3, 1, 2, 1, 2, 2, 4, 5], +[7, 8, 8, 7, 7, 5, 4, 3, 1, 2, -1, 1, 0, 1, 2, 3, 3, 4, 3, 4, 4, 5, 5, 5], +[6, 6, 7, 5, 6, 3, 4, 2, 1, -1, 0, 1, 1, 3, 5, 6, 7, 8, 7, 6, 5, 4, 3, 3], +[2, 4, 2, 4, 3, 5, 5, 6, 6, 5, 5, 5, 6, 6, 6, 6, 7, 5, 6, 4, 4, 2, 3, 0], +[2, 2, 3, 4, 6, 6, 8, 8, 8, 7, 6, 5, 3, 3, 1, 1, 0, 1, 0, 1, 1, 3, 3, 3], +[4, 4, 4, 4, 4, 3, 4, 4, 5, 3, 4, 2, 1, 0, 0, 0, 1, 1, 3, 2, 4, 5, 5, 5], +[5, 5, 3, 3, 1, 1, 1, 1, 1, 2, 2, 4, 5, 5, 5, 5, 5, 4, 4, 3, 4, 3, 4, 3], +[5, 4, 4, 2, 4, 3, 3, 4, 5, 5, 6, 7, 8, 8, 8, 9, 6, 6, 2, 3, -1, 1, -1, 1], +[1, 3, 4, 6, 7, 7, 8, 8, 9, 7, 7, 5, 6, 5, 5, 5, 5, 3, 3, 1, 1, 1, 1, 2], +[3, 4, 4, 5, 6, 7, 6, 6, 5, 5, 3, 4, 3, 3, 3, 4, 5, 7, 7, 7, 7, 7, 7, 6], +[5, 3, 3, 2, 4, 2, 4, 4, 5, 4, 6, 6, 7, 7, 8, 9, 10, 11, 11, 11, 10, 9, 8, 8], +[6, 6, 4, 4, 2, 4, 4, 5, 6, 7, 9, 10, 11, 10, 11, 10, 11, 8, 9, 7, 8, 6, 8, 7], +[8, 7, 7, 7, 8, 7, 7, 8, 7, 7, 6, 7, 5, 7, 5, 5, 4, 5, 3, 4, 4, 5, 6, 8], +[8, 9, 9, 9, 9, 7, 7, 5, 4, 2, 2, 1, 1, 1, 2, 3, 5, 5, 5, 7, 6, 7, 7, 8], +[7, 9, 7, 7, 6, 6, 4, 4, 3, 3, 1, 3, 3, 4, 5, 6, 7, 6, 7, 5, 6, 5, 4, 3], +[4, 2, 4, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 4, 4, 2, 3, 1, 2, 1, 1], +[1, 2, 2, 3, 5, 5, 7, 6, 8, 6, 7, 5, 4, 2, 1, 0, 0, -1, 0, -1, 1, 1, 2, 3], +[3, 4, 3, 3, 2, 2, 1, 2, 0, 1, 0, 0, 0, 0, -1, 0, 0, 1, 2, 2, 4, 4, 6, 5], +[6, 4, 4, 2, 2, 0, 0, -1, -1, 0, 1, 2, 3, 4, 6, 7, 5, 7, 5, 6, 4, 5, 4, 5], +[4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 7, 7, 6, 5, 2, 2, 1, 1, 2], +[4, 5, 7, 8, 8, 10, 9, 10, 8, 8, 6, 6, 3, 4, 3, 3, 3, 4, 2, 3, 2, 3, 3, 3], +[5, 4, 7, 7, 9, 8, 9, 8, 8, 6, 6, 3, 3, 2, 2, 3, 4, 5, 5, 7, 7, 7, 6, 6], +[5, 5, 3, 4, 3, 5, 4, 5, 6, 7, 7, 7, 8, 8, 8, 7, 9, 7, 9, 8, 8, 7, 7, 5], +[6, 4, 4, 3, 3, 3, 5, 6, 8, 10, 11, 11, 11, 12, 10, 10, 7, 7, 4, 5, 3, 4, 3, 5], +[5, 6, 5, 6, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, 7, 6, 5, 3, 3, 2, 2, 3, 4, 5], +[5, 7, 6, 7, 6, 6, 4, 4, 3, 3, 2, 4, 3, 4, 6, 6, 6, 6, 7, 5, 6, 5, 6, 4], +[6, 4, 5, 5, 5, 3, 4, 3, 3, 3, 2, 4, 6, 8, 8, 10, 10, 11, 10, 10, 7, 7, 5, 4], +[3, 3, 2, 3, 3, 4, 6, 6, 7, 6, 8, 7, 8, 8, 9, 8, 10, 8, 9, 7, 7, 4, 5, 3], +[3, 3, 3, 4, 5, 6, 6, 8, 7, 8, 6, 7, 4, 4, 3, 4, 4, 4, 5, 6, 6, 6, 8, 7], +[8, 6, 6, 4, 5, 3, 4, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 4, 5, 7, 7, 9, 8, 9], +[7, 8, 5, 4, 3, 1, 1, 0, 0, 1, 1, 2, 4, 4, 6, 5, 7, 5, 6, 5, 7, 6, 7, 7], +[7, 6, 7, 6, 6, 6, 5, 5, 4, 5, 5, 6, 5, 7, 6, 7, 5, 5, 3, 3, 1, 2, 2, 3], +[4, 5, 7, 7, 9, 8, 8, 7, 7, 6, 5, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 4], +[4, 5, 5, 7, 6, 7, 6, 6, 5, 4, 3, 2, 2, 1, 2, 2, 4, 4, 5, 5, 8, 6, 7, 5], +[6, 4, 5, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 8, 7, 8, 7, 9, 7, 8, 6, 7], +[6, 5, 5, 4, 3, 3, 5, 5, 7, 7, 9, 8, 11, 9, 9, 8, 8, 6, 6, 4, 5, 5, 5, 6], +[7, 8, 7, 9, 8, 9, 7, 8, 7, 8, 6, 6, 4, 5, 4, 4, 4, 3, 2, 2, 3, 3, 5, 5], +[8, 8, 10, 9, 10, 7, 7, 5, 4, 3, 2, 1, 1, 2, 2, 3, 3, 5, 4, 6, 5, 6, 5, 6], +[5, 6, 6, 7, 6, 6, 6, 5, 4, 4, 4, 3, 5, 5, 6, 7, 7, 6, 8, 5, 6, 4, 4, 3], +[2, 3, 3, 4, 4, 5, 6, 8, 8, 10, 8, 8, 8, 8, 7, 7, 5, 6, 4, 4, 2, 2, 2, 0], +[2, 1, 3, 3, 5, 5, 7, 7, 9, 8, 8, 7, 6, 4, 3, 2, 2, 2, 1, 2, 2, 3, 3, 4], +[3, 4, 3, 4, 2, 3, 2, 3, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6, 6, 7, 6], +[7, 5, 5, 2, 2, 1, 0, 1, 1, 2, 2, 5, 6, 8, 9, 11, 9, 10, 8, 8, 6, 6, 5, 5], +[5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 8, 7, 9, 9, 11, 11, 10, 9, 8, 7, 5, 4, 3, 4], +[4, 6, 6, 9, 9, 11, 9, 9, 8, 7, 6, 5, 4, 5, 5, 5, 5, 6, 6, 5, 7, 5, 6, 5], +[6, 6, 7, 6, 8, 8, 8, 7, 6, 5, 4, 3, 3, 3, 3, 5, 5, 8, 9, 10, 10, 11, 10, 10], +[8, 7, 5, 6, 4, 4, 4, 4, 5, 5, 6, 5, 6, 7, 7, 7, 8, 7, 9, 8, 9, 9, 9, 8], +[8, 7, 6, 5, 4, 4, 4, 5, 5, 8, 7, 9, 8, 8, 7, 6, 5, 4, 3, 3, 3, 4, 5, 5], +[7, 7, 9, 8, 9, 8, 8, 8, 7, 6, 6, 5, 5, 4, 3, 3, 1, 1, 0, 1, 1, 3, 4, 6], +[6, 9, 8, 9, 8, 8, 5, 4, 3, 1, 0, 0, 1, 1, 2, 2, 4, 3, 4, 4, 5, 3, 5, 4], +[5, 4, 5, 6, 5, 5, 4, 4, 3, 4, 2, 4, 4, 6, 6, 8, 8, 9, 6, 7, 5, 5, 3, 3], +[2, 2, 3, 3, 4, 4, 7, 6, 8, 8, 9, 7, 8, 7, 7, 6, 6, 6, 5, 4, 4, 3, 2, 3], +[1, 4, 3, 5, 5, 7, 7, 8, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 3, 2, 4, 4, 6, 4], +[6, 5, 6, 5, 5, 4, 4, 3, 3, 3, 3, 3, 2, 3, 2, 2, 2, 4, 3, 6, 5, 7, 7, 8], +[6, 7, 5, 5, 4, 3, 3, 1, 3, 2, 4, 4, 6, 6, 8, 7, 8, 7, 6, 5, 5, 5, 4, 5], +[4, 6, 5, 6, 5, 6, 6, 7, 6, 8, 7, 8, 8, 8, 8, 8, 7, 7, 5, 3, 2, 1, 1, 1], +[3, 3, 7, 7, 9, 9, 11, 10, 9, 9, 8, 7, 5, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5], +[4, 5, 5, 5, 5, 6, 6, 6, 6, 5, 5, 4, 5, 4, 6, 5, 7, 7, 9, 9, 10, 8, 10, 8], +[7, 6, 4, 3, 3, 3, 3, 4, 4, 7, 6, 8, 9, 10, 10, 12, 12, 12, 11, 11, 10, 10, 9, 8], +[8, 6, 6, 4, 5, 4, 5, 5, 7, 8, 10, 10, 12, 12, 12, 11, 10, 10, 9, 8, 7, 7, 7, 7], +[7, 9, 8, 10, 9, 9, 8, 7, 7, 6, 6, 6, 6, 6, 7, 5, 6, 5, 6, 5, 6, 7, 8, 8], +[10, 9, 11, 9, 9, 8, 7, 6, 3, 2, 0, 1, 1, 2, 2, 4, 6, 7, 7, 8, 8, 8, 8, 7], +[7, 6, 6, 5, 5, 4, 5, 3, 3, 2, 3, 2, 4, 4, 6, 6, 7, 8, 8, 7, 7, 6, 5, 5], +[3, 5, 4, 4, 4, 6, 5, 8, 8, 8, 7, 7, 6, 5, 4, 4, 5, 4, 4, 2, 3, 2, 3, 1], +[3, 2, 4, 3, 5, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, -2, 0, -1, 1, 1, 4, 4, 5], +[5, 5, 4, 4, 3, 3, 2, 1, 1, 1, 1, 0, 2, 1, 2, 1, 3, 2, 3, 3, 5, 5, 7, 7], +[7, 7, 5, 5, 4, 3, 1, 1, 0, 2, 1, 4, 4, 6, 6, 7, 8, 7, 6, 4, 3, 3, 4, 4], +[5, 5, 7, 5, 7, 7, 7, 6, 7, 6, 6, 7, 7, 7, 8, 8, 7, 7, 5, 5, 3, 3, 1, 3], +[3, 6, 7, 10, 10, 11, 11, 11, 10, 8, 7, 5, 5, 4, 4, 3, 4, 3, 5, 5, 6, 5, 6, 5], +[6, 6, 7, 7, 8, 9, 8, 8, 7, 7, 5, 5, 3, 3, 3, 4, 5, 6, 7, 9, 9, 10, 9, 9], +[8, 6, 6, 5, 5, 4, 6, 5, 7, 7, 9, 8, 9, 8, 9, 9, 8, 9, 8, 8, 7, 8, 7, 8], +[7, 7, 5, 6, 5, 6, 6, 8, 9, 10, 11, 11, 10, 11, 10, 8, 7, 5, 5, 3, 4, 3, 5, 4], +[7, 6, 8, 8, 9, 8, 8, 8, 8, 8, 6, 7, 5, 6, 4, 5, 3, 4, 3, 3, 3, 5, 5, 6], +[7, 7, 8, 8, 7, 6, 6, 5, 5, 3, 3, 2, 3, 4, 5, 5, 7, 7, 7, 7, 7, 7, 6, 6], +[6, 5, 4, 5, 4, 5, 4, 5, 3, 5, 4, 6, 6, 7, 9, 10, 11, 11, 10, 9, 8, 6, 5, 3], +[4, 3, 4, 3, 4, 4, 6, 7, 8, 9, 9, 9, 9, 9, 8, 9, 8, 8, 7, 8, 6, 7, 5, 5], +[4, 6, 5, 6, 5, 7, 6, 7, 7, 6, 6, 4, 5, 4, 4, 2, 3, 3, 5, 4, 7, 7, 8, 8], +[8, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1, 2, 1, 3, 3, 4, 5, 6, 7, 7, 8, 9, 10, 9], +[10, 9, 8, 7, 6, 4, 3, 2, 3, 2, 3, 4, 5, 6, 7, 8, 7, 8, 6, 6, 4, 5, 5, 6], +[5, 7, 5, 7, 7, 7, 7, 8, 7, 6, 6, 6, 6, 6, 6, 5, 6, 4, 4, 2, 2, 1, 2, 1], +[4, 4, 6, 7, 9, 9, 11, 10, 9, 8, 6, 5, 3, 4, 2, 2, 2, 2, 2, 4, 3, 5, 5, 5], +[5, 5, 5, 5, 6, 6, 6, 5, 6, 4, 5, 3, 4, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 8], +[7, 6, 4, 4, 2, 4, 3, 4, 4, 6, 6, 8, 8, 9, 10, 9, 9, 9, 8, 8, 8, 6, 7, 6], +[8, 6, 7, 5, 6, 6, 6, 7, 7, 8, 9, 9, 9, 10, 9, 9, 7, 7, 5, 5, 3, 5, 4, 6], +[6, 8, 8, 10, 9, 10, 9, 8, 8, 6, 6, 4, 5, 4, 5, 4, 4, 3, 3, 3, 5, 4, 6, 7], +[7, 9, 9, 10, 8, 9, 7, 7, 5, 5, 2, 2, 1, 2, 3, 5, 6, 7, 7, 7, 6, 7, 6, 6], +[6, 5, 6, 5, 7, 5, 6, 6, 6, 6, 6, 5, 6, 6, 7, 8, 8, 9, 8, 8, 6, 6, 4, 4], +[3, 3, 2, 4, 3, 6, 7, 8, 10, 10, 10, 9, 9, 8, 8, 6, 6, 4, 5, 4, 4, 2, 4, 3], +[4, 3, 4, 4, 5, 5, 6, 7, 6, 8, 6, 6, 4, 5, 3, 2, 2, 2, 2, 3, 4, 5, 6, 7], +[7, 6, 6, 4, 3, 1, 2, 1, 2, 1, 2, 2, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8], +[7, 8, 6, 6, 3, 3, 2, 1, 1, 2, 3, 5, 7, 9, 10, 11, 11, 10, 10, 7, 8, 6, 6, 4], +[6, 5, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 10, 8, 10, 7, 8, 6, 5, 4, 4], +[4, 6, 7, 8, 10, 10, 10, 9, 9, 6, 7, 4, 4, 3, 4, 4, 5, 6, 7, 7, 9, 9, 9, 10], +[9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 3, 3, 2, 2, 2, 4, 5, 8, 8, 10, 11, 11, 12, 10], +[10, 7, 7, 5, 5, 3, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 7, 8, 7, 8, 7, 9, 7, 9], +[8, 9, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 7, 7, 5, 5, 3, 4, 2, 3, 2, 4, 5], +[6, 7, 9, 9, 9, 9, 8, 8, 6, 6, 4, 4, 2, 2, 1, 2, 1, 1, 0, 1, 1, 2, 3, 5], +[7, 6, 8, 7, 8, 6, 5, 4, 3, 2, 2, 1, 2, 1, 3, 3, 4, 5, 4, 5, 4, 5, 3, 4], +[3, 5, 3, 5, 3, 4, 4, 5, 4, 4, 4, 4, 5, 6, 7, 7, 8, 7, 8, 6, 6, 3, 4, 1], +[2, 1, 1, 1, 3, 4, 5, 7, 7, 8, 7, 9, 7, 7, 6, 7, 4, 5, 4, 4, 3, 3, 3, 3], +[4, 3, 5, 4, 6, 6, 7, 6, 7, 5, 5, 4, 4, 2, 2, 2, 2, 1, 2, 2, 4, 5, 6, 8], +[7, 8, 6, 7, 5, 5, 3, 3, 2, 2, 2, 3, 2, 3, 3, 3, 5, 4, 6, 5, 6, 6, 7, 7], +[8, 7, 8, 6, 7, 5, 5, 3, 4, 4, 4, 5, 6, 8, 8, 9, 8, 9, 6, 7, 5, 5, 4, 5], +[4, 6, 6, 7, 8, 9, 10, 10, 11, 10, 10, 8, 8, 8, 8, 7, 7, 5, 5, 4, 3, 3, 2, 2], +[3, 5, 5, 8, 8, 10, 10, 12, 10, 10, 8, 8, 6, 4, 3, 4, 4, 4, 4, 5, 6, 6, 7, 7], +[7, 5, 7, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 9, 9, 10, 9, 10, 9, 10], +[7, 8, 5, 4, 2, 4, 3, 3, 4, 5, 7, 8, 10, 11, 12, 11, 12, 11, 11, 9, 9, 8, 9, 7], +[8, 7, 7, 6, 6, 6, 5, 7, 7, 8, 9, 10, 10, 11, 11, 11, 9, 9, 7, 7, 6, 6, 7, 7], +[9, 9, 11, 10, 11, 9, 9, 7, 7, 5, 5, 3, 3, 3, 3, 5, 5, 5, 5, 6, 6, 7, 7, 8], +[8, 10, 8, 9, 8, 8, 6, 5, 3, 2, 0, 0, 0, 1, 3, 4, 6, 7, 9, 8, 9, 7, 8, 7], +[7, 6, 7, 6, 7, 6, 6, 6, 5, 5, 4, 5, 4, 5, 5, 7, 6, 8, 7, 7, 6, 7, 5, 5], +[4, 4, 3, 4, 5, 5, 7, 7, 8, 8, 8, 6, 5, 3, 3, 2, 3, 2, 2, 1, 2, 2, 2, 4], +[3, 4, 4, 5, 4, 6, 5, 7, 6, 7, 5, 5, 2, 2, 0, 0, -1, -2, -1, 1, 3, 3, 6, 5], +[7, 6, 7, 4, 4, 2, 3, 1, 2, 1, 2, 1, 3, 2, 3, 3, 3, 4, 3, 4, 3, 5, 5, 6], +[5, 6, 5, 6, 4, 3, 3, 3, 3, 3, 4, 5, 7, 8, 9, 9, 10, 8, 8, 5, 4, 3, 3, 3], +[3, 4, 4, 5, 7, 8, 8, 9, 8, 9, 8, 9, 7, 9, 8, 8, 7, 8, 6, 5, 4, 3, 3, 3], +[4, 4, 7, 7, 10, 9, 11, 10, 9, 7, 7, 5, 5, 4, 3, 4, 4, 5, 5, 7, 7, 7, 7, 8], +[7, 7, 6, 7, 5, 6, 6, 5, 6, 5, 5, 5, 5, 4, 6, 6, 7, 7, 9, 9, 10, 10, 10, 9], +[9, 7, 6, 5, 4, 4, 4, 5, 5, 6, 6, 8, 9, 9, 9, 10, 9, 9, 8, 9, 7, 8, 8, 8], +[7, 7, 7, 7, 7, 7, 8, 8, 9, 8, 10, 9, 9, 9, 8, 7, 7, 5, 5, 3, 3, 3, 4, 6], +[6, 8, 8, 10, 8, 10, 8, 8, 7, 7, 6, 5, 4, 4, 4, 3, 4, 3, 4, 3, 4, 4, 6, 5], +[7, 6, 7, 7, 7, 6, 6, 4, 3, 3, 2, 3, 3, 4, 5, 6, 6, 8, 7, 8, 6, 7, 5, 6], +[4, 4, 3, 4, 4, 4, 4, 4, 5, 5, 6, 6, 8, 8, 9, 9, 10, 10, 10, 8, 8, 6, 5, 4], +[3, 3, 2, 3, 2, 4, 4, 7, 7, 8, 8, 8, 7, 7, 6, 6, 6, 6, 5, 5, 6, 5, 5, 5], +[6, 5, 6, 5, 5, 5, 5, 3, 4, 3, 3, 2, 3, 2, 2, 2, 2, 3, 3, 5, 6, 8, 8, 10], +[10, 11, 8, 8, 6, 5, 3, 1, 0, -1, -1, -1, 0, 0, 3, 3, 5, 4, 6, 6, 8, 8, 9, 9], +[9, 8, 8, 7, 5, 4, 3, 3, 1, 1, 0, 2, 2, 4, 5, 6, 6, 7, 6, 6, 4, 4, 4, 4], +[5, 6, 7, 7, 8, 9, 10, 9, 10, 8, 7, 6, 5, 3, 3, 4, 3, 3, 3, 3, 2, 3, 2, 4], +[3, 6, 5, 8, 8, 9, 9, 9, 9, 7, 6, 4, 2, 0, 0, -1, -1, 0, 2, 2, 4, 4, 6, 5], +[7, 6, 6, 4, 5, 4, 4, 5, 5, 5, 4, 4, 3, 4, 3, 5, 3, 5, 5, 6, 6, 8, 7, 7], +[7, 6, 5, 4, 4, 3, 4, 3, 5, 5, 7, 7, 9, 9, 10, 9, 9, 7, 7, 6, 6, 5, 5, 6], +[6, 6, 6, 7, 5, 6, 5, 7, 7, 9, 8, 10, 8, 9, 8, 8, 6, 5, 4, 2, 3, 2, 3, 3], +[6, 7, 9, 9, 10, 8, 9, 7, 7, 5, 5, 4, 3, 3, 3, 3, 3, 4, 3, 5, 4, 4, 4, 6], +[5, 7, 7, 8, 7, 7, 6, 5, 4, 2, 3, 2, 3, 2, 4, 4, 7, 6, 8, 7, 8, 6, 6, 5], +[5, 4, 3, 4, 3, 4, 4, 5, 5, 7, 6, 7, 6, 8, 7, 8, 8, 8, 7, 7, 6, 6, 5, 3], +[3, 2, 3, 2, 4, 4, 7, 7, 9, 8, 9, 9, 8, 6, 5, 5, 4, 4, 3, 3, 3, 4, 3, 4], +[3, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 5, 4, 3, 3, 1, 2, 0, 2, 2, 4, 5, 7, 6], +[8, 6, 7, 4, 5, 3, 2, 2, 1, 2, 1, 3, 3, 5, 6, 7, 6, 7, 5, 6, 5, 6, 6, 6], +[7, 6, 6, 5, 4, 3, 4, 3, 3, 3, 5, 5, 7, 8, 10, 10, 11, 10, 8, 7, 5, 4, 3, 3], +[3, 5, 4, 7, 6, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 4, 5, 4], +[6, 5, 7, 7, 8, 8, 9, 9, 7, 7, 5, 5, 3, 3, 2, 4, 4, 6, 6, 8, 8, 11, 10, 9], +[8, 8, 7, 6, 4, 4, 4, 3, 4, 2, 3, 2, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 11, 11], +[10, 9, 8, 6, 5, 5, 4, 4, 4, 5, 5, 7, 6, 7, 8, 8, 7, 7, 7, 6, 7, 6, 8, 7], +[8, 8, 8, 7, 8, 7, 8, 7, 7, 7, 6, 5, 5, 5, 4, 4, 2, 3, 1, 1, 1, 3, 2, 5], +[6, 7, 8, 9, 8, 10, 8, 7, 6, 4, 3, 2, 1, 0, 1, -1, 0, -1, 1, 1, 3, 3, 5, 5], +[5, 6, 6, 6, 6, 6, 5, 5, 2, 3, 1, 1, 0, 2, 2, 3, 3, 4, 4, 4, 4, 4, 3, 3], +[3, 2, 3, 2, 3, 2, 4, 3, 5, 5, 6, 5, 7, 5, 6, 6, 6, 6, 6, 5, 4, 4, 2, 3], +[1, 2, 1, 3, 2, 4, 4, 7, 7, 8, 8, 8, 7, 6, 5, 4, 3, 2, 2, 2, 3, 2, 4, 3], +[5, 5, 5, 5, 5, 5, 5, 4, 3, 3, 3, 3, 2, 3, 1, 1, 0, 2, 1, 4, 4, 5, 6, 8], +[7, 8, 6, 6, 5, 4, 3, 1, 2, 0, 1, 1, 3, 3, 5, 5, 6, 6, 7, 6, 7, 6, 6, 7], +[6, 7, 6, 6, 6, 6, 4, 4, 4, 4, 4, 6, 6, 7, 8, 9, 10, 9, 8, 7, 6, 4, 4, 3], +[4, 4, 6, 5, 8, 8, 10, 10, 11, 10, 9, 8, 7, 7, 6, 6, 6, 6, 5, 6, 4, 4, 4, 4], +[3, 5, 5, 6, 6, 8, 9, 9, 9, 8, 7, 5, 5, 3, 4, 2, 4, 3, 5, 6, 8, 7, 9, 8], +[8, 7, 6, 5, 4, 4, 3, 4, 4, 5, 4, 5, 5, 6, 6, 7, 7, 8, 7, 8, 9, 9, 9, 8], +[8, 7, 6, 3, 4, 2, 3, 3, 5, 5, 7, 8, 9, 10, 10, 10, 10, 9, 8, 8, 6, 7, 6, 7], +[6, 8, 6, 7, 6, 7, 6, 6, 6, 6, 7, 7, 8, 7, 7, 7, 7, 4, 6, 3, 4, 3, 5, 4], +[7, 7, 8, 8, 9, 8, 7, 7, 4, 3, 1, 1, 0, 2, 1, 3, 2, 4, 3, 5, 5, 7, 6, 7], +[8, 8, 8, 8, 7, 6, 6, 3, 3, 1, 1, -1, 0, 0, 2, 3, 5, 6, 7, 7, 7, 7, 6, 6], +[5, 5, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 5, 5, 5, 5, 4, 4, 2], +[3, 2, 3, 3, 4, 4, 6, 7, 8, 7, 7, 6, 5, 4, 1, 1, -1, 1, -1, 1, 1, 2, 3, 5], +[5, 6, 5, 6, 5, 5, 5, 3, 4, 3, 2, 1, 1, -1, -1, -2, -1, -3, -1, -1, 2, 3, 5, 6], +[7, 7, 7, 6, 5, 3, 2, 2, 0, 1, -1, 1, 0, 2, 3, 4, 4, 4, 3, 3, 3, 3, 4, 4], +[5, 5, 6, 5, 6, 4, 5, 3, 5, 4, 5, 5, 6, 6, 7, 7, 7, 7, 6, 4, 3, 3, 1, 2], +[1, 3, 3, 6, 6, 8, 8, 9, 9, 8, 8, 7, 7, 5, 6, 5, 5, 4, 4, 2, 4, 3, 4, 3], +[4, 4, 6, 6, 7, 7, 8, 8, 8, 7, 5, 5, 2, 3, 2, 3, 3, 4, 4, 6, 6, 7, 8, 8], +[8, 7, 7, 5, 6, 4, 4, 3, 4, 3, 4, 4, 4, 4, 6, 6, 7, 8, 8, 8, 9, 9, 8, 9], +[7, 8, 6, 6, 4, 5, 3, 4, 5, 5, 6, 8, 8, 9, 10, 9, 10, 7, 7, 6, 7, 6, 6, 5], +[7, 6, 7, 7, 8, 7, 8, 9, 9, 8, 7, 8, 7, 7, 6, 6, 4, 5, 3, 3, 2, 3, 3, 5], +[5, 7, 7, 8, 9, 8, 9, 7, 6, 5, 5, 2, 3, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5], +[5, 6, 4, 5, 4, 5, 3, 4, 3, 3, 2, 2, 2, 4, 5, 6, 8, 8, 9, 7, 8, 6, 6, 3], +[4, 2, 2, 0, 2, 2, 3, 3, 4, 5, 5, 6, 7, 8, 7, 9, 8, 8, 7, 7, 5, 6, 4, 4], +[1, 2, 1, 2, 1, 2, 3, 4, 6, 6, 7, 6, 7, 5, 6, 4, 5, 3, 3, 3, 5, 4, 5, 5], +[6, 6, 6, 6, 4, 4, 2, 3, 1, 2, -1, 1, 0, 1, 0, 1, 1, 2, 2, 4, 4, 6, 7, 7], +[8, 8, 8, 5, 5, 2, 1, -1, -2, -3, -3, -2, -1, 0, 2, 4, 4, 5, 6, 6, 5, 6, 5, 6], +[6, 7, 5, 7, 6, 6, 5, 4, 4, 3, 3, 4, 4, 5, 5, 5, 7, 5, 7, 4, 5, 3, 4, 2], +[4, 3, 5, 5, 7, 8, 9, 10, 9, 9, 6, 6, 3, 3, 1, 2, 1, 2, 1, 3, 3, 3, 3, 3], +[4, 4, 5, 5, 7, 6, 7, 7, 8, 6, 6, 3, 3, 0, 1, 0, 1, 1, 1, 3, 5, 6, 7, 8], +[7, 7, 5, 5, 3, 4, 3, 3, 2, 4, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 7, 6, 7, 6], +[7, 5, 5, 3, 3, 3, 3, 2, 3, 4, 5, 8, 7, 8, 8, 8, 6, 7, 4, 4, 3, 4, 3, 5], +[4, 5, 5, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 5, 6, 5, 5, 2, 2, 0, 1, 1, 2, 4], +[5, 7, 7, 9, 8, 9, 7, 6, 4, 4, 1, 1, 0, 1, 1, 2, 3, 3, 3, 4, 3, 4, 5, 5], +[6, 5, 6, 5, 6, 4, 4, 3, 3, 1, 1, 1, 1, 2, 3, 4, 5, 7, 7, 8, 7, 6, 5, 5], +[3, 4, 2, 3, 3, 3, 3, 4, 5, 5, 6, 5, 6, 5, 7, 6, 7, 6, 6, 5, 6, 5, 5, 3], +[3, 2, 2, 3, 3, 4, 5, 7, 6, 8, 7, 7, 5, 5, 3, 2, 2, 2, 1, 1, 2, 3, 4, 5], +[6, 6, 6, 5, 5, 4, 4, 3, 3, 2, 3, 2, 2, 0, 1, 0, 1, 1, 1, 2, 3, 5, 5, 8], +[7, 8, 6, 7, 4, 4, 2, 1, 0, 0, 0, 1, 2, 3, 5, 5, 7, 6, 7, 5, 6, 4, 5, 4], +[5, 4, 5, 4, 5, 5, 4, 4, 4, 5, 5, 6, 6, 8, 7, 9, 9, 9, 7, 7, 5, 5, 3, 3], +[2, 3, 4, 5, 6, 6, 8, 8, 8, 8, 8, 6, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5, 4, 5], +[5, 6, 5, 6, 5, 6, 5, 6, 4, 5, 3, 2, 1, 1, 1, 1, 2, 3, 6, 6, 8, 9, 10, 9], +[10, 8, 8, 5, 5, 3, 3, 1, 2, 2, 2, 1, 2, 3, 3, 5, 6, 7, 7, 8, 8, 10, 8, 9], +[8, 8, 7, 6, 4, 4, 3, 2, 3, 3, 4, 4, 5, 5, 7, 6, 7, 4, 5, 4, 4, 3, 4, 4], +[6, 6, 7, 7, 7, 9, 8, 9, 7, 8, 5, 5, 4, 3, 3, 2, 2, 1, 0, 0, 0, 1, 2, 2], +[5, 5, 8, 8, 9, 8, 9, 6, 6, 3, 2, 1, 0, -2, -2, -1, -1, 0, 0, 1, 1, 2, 3, 3], +[3, 4, 4, 5, 4, 5, 4, 4, 4, 2, 2, 1, 2, 1, 2, 3, 4, 3, 5, 4, 4, 3, 3, 1], +[2, 1, 1, 0, 1, 2, 3, 4, 5, 7, 6, 7, 6, 7, 6, 6, 5, 5, 4, 3, 2, 3, 1, 1], +[1, 1, 1, 1, 2, 3, 4, 4, 6, 7, 8, 7, 7, 5, 4, 3, 2, 1, 0, 0, 0, 1, 2, 4], +[4, 6, 5, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 3, 6, 5], +[7, 7, 8, 6, 6, 4, 3, 1, 0, 0, 0, 1, 1, 3, 4, 7, 6, 8, 7, 8, 5, 6, 5, 6], +[5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 5, 5, 7, 7, 8, 8, 9, 8, 8, 6, 6, 4, 4, 4], +[3, 3, 4, 6, 7, 9, 10, 11, 11, 11, 8, 8, 6, 6, 4, 4, 4, 5, 4, 5, 5, 6, 6, 5], +[6, 5, 6, 6, 7, 6, 8, 7, 8, 6, 6, 5, 4, 3, 2, 2, 2, 3, 4, 6, 6, 9, 9, 10], +[8, 8, 5, 6, 4, 4, 2, 3, 3, 3, 4, 4, 5, 6, 7, 6, 8, 7, 9, 8, 9, 8, 9, 8], +[8, 6, 6, 4, 4, 3, 2, 4, 3, 6, 6, 7, 7, 9, 9, 9, 8, 8, 6, 6, 4, 5, 4, 5], +[5, 5, 6, 6, 6, 5, 6, 5, 6, 5, 6, 5, 5, 5, 5, 5, 5, 4, 3, 3, 2, 3, 4, 5], +[5, 8, 6, 9, 7, 8, 6, 4, 3, 1, 0, -1, -1, -1, 0, 0, 3, 3, 4, 4, 6, 5, 6, 5], +[6, 4, 5, 4, 4, 2, 2, 1, 0, 0, -2, -2, -1, 0, 0, 3, 4, 7, 6, 8, 7, 7, 6, 5], +[4, 3, 2, 2, 2, 1, 3, 3, 4, 3, 4, 3, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4], +[3, 4, 2, 3, 2, 4, 4, 5, 4, 6, 5, 4, 2, 2, 1, -1, -1, -1, -2, -1, 1, 2, 3, 3], +[6, 5, 6, 5, 5, 4, 4, 3, 2, 1, 1, 0, -1, -1, -2, -1, -2, -1, -1, 1, 1, 3, 4, 6], +[6, 7, 7, 6, 5, 5, 3, 2, 2, 0, 1, 0, 2, 2, 4, 3, 5, 4, 5, 3, 3, 2, 3, 3], +[3, 3, 3, 4, 4, 5, 4, 5, 6, 7, 6, 6, 6, 7, 6, 6, 6, 6, 5, 4, 2, 2, 1, 0], +[1, 1, 3, 3, 5, 6, 8, 8, 9, 8, 9, 8, 7, 5, 5, 3, 3, 3, 2, 2, 2, 3, 2, 5], +[4, 5, 4, 5, 5, 5, 5, 5, 5, 4, 4, 3, 4, 2, 3, 3, 4, 3, 5, 4, 7, 7, 8, 7], +[7, 7, 6, 4, 3, 3, 1, 2, 1, 2, 1, 4, 4, 6, 6, 8, 8, 8, 8, 9, 8, 8, 8, 8], +[8, 6, 7, 5, 5, 4, 4, 3, 4, 4, 6, 6, 7, 7, 9, 8, 9, 8, 7, 5, 5, 5, 5, 5], +[5, 7, 6, 8, 7, 9, 8, 8, 7, 7, 6, 5, 5, 4, 4, 3, 3, 2, 3, 2, 3, 2, 4, 4], +[6, 6, 8, 7, 9, 7, 8, 6, 5, 4, 2, 1, 0, 0, -1, 1, 1, 3, 3, 5, 4, 6, 5, 6], +[5, 5, 5, 4, 3, 3, 4, 3, 4, 2, 3, 1, 2, 2, 3, 4, 6, 6, 7, 6, 7, 5, 5, 4], +[3, 2, 1, 1, 0, 2, 1, 3, 4, 6, 6, 7, 6, 7, 5, 6, 5, 5, 5, 5, 5, 4, 5, 4], +[4, 2, 3, 2, 3, 2, 3, 3, 4, 5, 5, 4, 4, 4, 3, 1, 0, 0, 0, 1, 0, 2, 4, 5], +[5, 7, 6, 6, 4, 3, 1, 0, -1, -2, -2, -2, -2, -1, 0, -1, 1, 1, 2, 2, 4, 4, 6, 6], +[8, 7, 7, 7, 6, 4, 2, 1, -1, -1, -2, -1, -1, 1, 2, 5, 5, 7, 6, 6, 5, 5, 5, 5], +[5, 4, 5, 5, 6, 5, 6, 5, 5, 4, 4, 3, 3, 3, 5, 5, 5, 6, 5, 5, 4, 4, 3, 3], +[2, 3, 3, 6, 6, 9, 9, 10, 9, 9, 7, 6, 4, 3, 1, 1, 1, 1, 2, 2, 4, 4, 5, 5], +[7, 5, 7, 6, 7, 6, 6, 6, 5, 6, 3, 3, 1, 1, 0, 0, -1, 1, 2, 5, 4, 7, 7, 8], +[8, 8, 6, 6, 5, 4, 3, 2, 4, 3, 4, 4, 5, 4, 5, 5, 6, 5, 6, 5, 6, 5, 5, 6], +[6, 6, 5, 6, 4, 5, 3, 5, 5, 7, 7, 8, 8, 9, 8, 8, 6, 5, 4, 2, 2, 1, 2, 2], +[3, 4, 6, 6, 7, 7, 8, 7, 7, 7, 6, 6, 6, 6, 5, 4, 3, 3, 1, 1, -1, 1, 1, 2], +[2, 5, 5, 7, 6, 6, 6, 5, 5, 3, 3, 0, 2, 1, 2, 2, 4, 3, 5, 4, 5, 4, 4, 4], +[4, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 4, 4, 6, 8, 9, 8, 8, 8, 6, 6, 4], +[3, 1, 2, 0, 1, 0, 3, 3, 5, 5, 7, 6, 7, 7, 7, 7, 6, 7, 6, 7, 5, 6, 4, 4], +[3, 4, 2, 4, 3, 5, 5, 5, 6, 6, 6, 5, 6, 4, 4, 3, 3, 2, 3, 2, 3, 4, 6, 5], +[8, 7, 7, 6, 6, 4, 4, 3, 1, 2, 1, 1, 0, 1, 1, 3, 2, 3, 2, 4, 4, 5, 6, 7], +[8, 8, 7, 6, 6, 4, 4, 2, 3, 0, 2, 1, 3, 4, 5, 6, 8, 8, 9, 7, 6, 6, 6, 6], +[4, 5, 4, 5, 4, 6, 5, 7, 6, 7, 6, 7, 7, 7, 7, 7, 8, 7, 7, 6, 6, 4, 5, 3], +[3, 2, 4, 4, 5, 6, 8, 8, 8, 8, 7, 7, 6, 5, 4, 4, 2, 4, 3, 4, 4, 7, 6, 8], +[7, 7, 7, 6, 6, 5, 5, 4, 5, 3, 3, 2, 1, 1, 1, 2, 2, 3, 5, 5, 8, 9, 10, 9], +[9, 9, 7, 6, 3, 3, 0, 1, -1, 1, 0, 2, 1, 3, 4, 6, 5, 6, 7, 6, 7, 7, 8, 7], +[9, 7, 8, 6, 6, 4, 5, 4, 4, 4, 5, 4, 6, 6, 6, 6, 5, 5, 4, 4, 3, 4, 3, 4], +[5, 7, 6, 9, 8, 9, 9, 8, 6, 5, 4, 2, 2, 0, 1, 0, 1, 0, 1, 0, 2, 2, 3, 3], +[5, 5, 6, 7, 7, 7, 6, 7, 4, 3, 1, 0, -2, -1, -2, -1, -1, 1, 1, 3, 4, 4, 5, 5], +[5, 4, 4, 3, 4, 3, 4, 3, 4, 2, 3, 2, 2, 2, 2, 3, 4, 5, 5, 5, 4, 5, 3, 4], +[2, 2, 0, 2, 1, 2, 2, 4, 5, 6, 6, 7, 7, 6, 5, 3, 4, 3, 3, 2, 3, 2, 3, 2], +[3, 2, 3, 2, 3, 3, 4, 5, 5, 6, 5, 6, 5, 4, 3, 2, 0, 0, -2, 0, -1, 1, 2, 4], +[5, 6, 7, 5, 6, 4, 4, 2, 2, 0, 1, -1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 4, 5], +[5, 7, 5, 6, 4, 4, 3, 3, 1, 2, 1, 2, 2, 4, 6, 8, 8, 9, 9, 8, 7, 5, 5, 3], +[4, 3, 5, 4, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 8, 9, 8, 8, 7, 6, 4, 5], +[3, 4, 4, 5, 6, 8, 9, 9, 10, 9, 9, 7, 7, 5, 5, 3, 5, 4, 5, 4, 6, 7, 8, 8], +[8, 7, 6, 6, 5, 6, 5, 6, 5, 6, 4, 4, 3, 3, 2, 3, 4, 5, 5, 7, 8, 9, 10, 10], +[10, 8, 8, 6, 5, 2, 3, 2, 3, 3, 3, 4, 5, 6, 7, 7, 8, 9, 8, 8, 7, 8, 6, 8], +[7, 8, 6, 6, 4, 5, 4, 4, 5, 5, 6, 7, 8, 7, 8, 7, 8, 6, 6, 4, 5, 3, 4, 4], +[6, 6, 7, 7, 8, 8, 7, 7, 6, 5, 4, 4, 3, 3, 2, 3, 1, 2, 0, 2, 1, 2, 3, 4], +[5, 5, 6, 6, 7, 5, 5, 3, 3, 0, 0, -2, -2, -2, -2, -1, 1, 2, 4, 3, 5, 5, 4, 5], +[5, 5, 4, 5, 3, 4, 2, 2, 1, 1, 1, 2, 1, 2, 2, 4, 5, 5, 7, 6, 7, 5, 6, 4], +[5, 2, 3, 2, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5, 4, 4, 3, 3, 2, 3, 3, 4, 3, 4], +[4, 4, 4, 5, 5, 6, 6, 5, 5, 5, 5, 3, 3, 1, 2, -1, -1, -1, -1, -1, 1, 2, 3, 5], +[7, 8, 7, 8, 6, 7, 4, 4, 2, 2, 0, 0, -1, 0, -1, 1, 1, 1, 2, 2, 2, 3, 4, 4], +[7, 6, 8, 6, 7, 5, 6, 4, 3, 2, 2, 2, 2, 3, 4, 5, 6, 7, 6, 6, 5, 5, 2, 3], +[2, 4, 3, 4, 5, 6, 7, 8, 8, 9, 9, 8, 9, 7, 7, 6, 6, 5, 6, 5, 5, 3, 3, 2], +[3, 3, 3, 4, 5, 6, 8, 9, 9, 10, 8, 8, 6, 6, 4, 4, 3, 2, 2, 3, 3, 5, 5, 6], +[7, 6, 6, 5, 5, 4, 5, 3, 4, 3, 4, 3, 5, 4, 4, 4, 4, 5, 6, 7, 7, 8, 8, 9], +[8, 9, 7, 6, 4, 3, 2, 2, 2, 2, 3, 4, 6, 7, 9, 8, 10, 9, 10, 8, 8, 7, 8, 7], +[8, 6, 7, 5, 5, 5, 5, 5, 5, 6, 6, 8, 7, 9, 10, 10, 9, 9, 7, 7, 5, 5, 4, 5], +[5, 5, 6, 8, 9, 8, 9, 8, 9, 6, 7, 5, 5, 4, 4, 4, 5, 4, 5, 4, 4, 4, 5, 6], +[6, 6, 6, 7, 7, 7, 6, 6, 5, 4, 2, 1, 1, 1, 1, 2, 3, 5, 7, 6, 8, 6, 8, 6], +[6, 4, 4, 3, 4, 3, 3, 2, 3, 4, 4, 4, 4, 4, 5, 6, 7, 8, 7, 9, 8, 8, 7, 7], +[5, 4, 2, 2, 1, 1, 2, 3, 5, 5, 7, 7, 8, 6, 7, 5, 5, 4, 5, 4, 5, 4, 5, 5], +[4, 5, 3, 4, 3, 3, 3, 4, 2, 4, 3, 4, 2, 3, 2, 2, 1, 1, -1, 0, 1, 3, 5, 6], +[8, 8, 9, 7, 7, 5, 4, 1, 1, -1, -1, -2, -1, 0, 0, 2, 2, 3, 3, 4, 4, 5, 5, 7], +[6, 7, 6, 7, 5, 5, 4, 2, 1, 0, 0, 0, 1, 2, 4, 5, 7, 7, 8, 7, 7, 5, 5, 4], +[4, 4, 4, 4, 6, 6, 7, 8, 7, 8, 6, 7, 6, 6, 6, 7, 5, 6, 5, 6, 5, 5, 5, 4], +[4, 5, 6, 6, 7, 8, 9, 10, 10, 8, 8, 6, 5, 3, 2, 1, 1, 1, 2, 2, 4, 5, 6, 8], +[8, 9, 8, 8, 7, 7, 5, 6, 5, 5, 4, 3, 2, 2, 2, 1, 2, 3, 4, 4, 6, 7, 9, 9], +[10, 8, 9, 7, 6, 5, 4, 4, 3, 4, 4, 4, 5, 6, 6, 7, 6, 7, 5, 6, 5, 6, 5, 6], +[5, 6, 6, 7, 6, 6, 6, 6, 7, 6, 8, 7, 8, 7, 8, 6, 6, 5, 4, 3, 2, 1, 2, 3], +[3, 5, 6, 7, 7, 9, 8, 9, 8, 7, 6, 6, 4, 4, 3, 3, 3, 1, 1, 1, 1, 1, 3, 3], +[4, 4, 6, 5, 7, 5, 6, 5, 4, 3, 2, 1, 1, 1, 1, 2, 3, 5, 4, 7, 6, 6, 5, 5], +[3, 4, 2, 3, 1, 2, 2, 2, 3, 2, 3, 3, 5, 5, 6, 6, 8, 7, 9, 7, 8, 6, 7, 5], +[5, 4, 3, 2, 1, 2, 3, 5, 5, 6, 6, 8, 8, 9, 7, 7, 7, 6, 5, 5, 5, 5, 5, 5], +[6, 6, 7, 5, 6, 5, 6, 6, 6, 5, 5, 4, 5, 4, 4, 3, 2, 2, 2, 2, 3, 5, 5, 7], +[8, 9, 9, 9, 8, 7, 5, 4, 3, 2, 2, 1, 1, 1, 2, 3, 5, 5, 7, 6, 7, 6, 8, 7], +[8, 8, 9, 8, 7, 7, 6, 6, 4, 4, 3, 4, 4, 5, 6, 8, 8, 10, 9, 10, 8, 8, 6, 6], +[4, 4, 4, 4, 5, 5, 7, 8, 9, 9, 11, 9, 9, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 7], +[6, 6, 5, 6, 6, 7, 7, 9, 8, 9, 8, 7, 6, 5, 4, 3, 2, 3, 3, 3, 5, 5, 8, 8], +[9, 7, 8, 6, 6, 3, 3, 3, 2, 2, 2, 1, 1, 2, 2, 3, 3, 5, 4, 6, 7, 8, 8, 9], +[9, 9, 7, 6, 5, 4, 3, 2, 2, 1, 2, 3, 5, 5, 7, 7, 9, 7, 8, 6, 7, 6, 7, 7], +[7, 7, 7, 7, 6, 6, 5, 6, 5, 6, 5, 6, 5, 6, 6, 7, 7, 6, 4, 4, 2, 3, 2, 3], +[5, 4, 8, 8, 9, 9, 10, 8, 8, 6, 5, 3, 3, 1, 1, 1, 1, 2, 2, 3, 2, 3, 3, 4], +[5, 7, 6, 7, 7, 8, 7, 7, 5, 3, 2, 1, 1, 0, 0, 0, 2, 2, 5, 5, 6, 5, 7, 5], +[5, 4, 4, 3, 3, 4, 4, 4, 4, 5, 4, 5, 3, 5, 5, 5, 5, 6, 5, 7, 6, 6, 5, 5], +[4, 3, 2, 1, 2, 2, 4, 4, 7, 7, 9, 9, 9, 7, 7, 6, 4, 3, 3, 2, 2, 3, 3, 4], +[4, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 5, 5, 5, 3, 3, 2, 0, 1, -1, 2, 1, 4, 4], +[7, 7, 8, 7, 7, 5, 5, 3, 2, 2, 0, 1, 1, 2, 3, 5, 5, 6, 5, 7, 5, 6, 5, 6], +[5, 6, 6, 6, 6, 5, 5, 4, 4, 3, 4, 4, 5, 5, 8, 9, 11, 10, 11, 9, 10, 8, 7, 5], +[4, 4, 4, 4, 4, 6, 6, 8, 8, 10, 9, 10, 9, 9, 9, 10, 9, 9, 8, 9, 8, 8, 7, 6], +[7, 5, 7, 6, 8, 7, 9, 9, 9, 9, 9, 7, 7, 6, 5, 5, 3, 5, 5, 7, 7, 10, 9, 11], +[10, 11, 9, 9, 7, 6, 5, 5, 4, 4, 3, 2, 3, 3, 4, 3, 6, 6, 8, 8, 10, 10, 11, 11], +[11, 10, 9, 8, 6, 5, 4, 4, 2, 4, 3, 5, 5, 6, 7, 9, 8, 9, 9, 8, 8, 8, 8, 8], +[8, 7, 8, 7, 8, 7, 7, 6, 7, 6, 8, 6, 7, 6, 7, 6, 6, 6, 4, 4, 3, 4, 3, 5], +[4, 7, 6, 8, 7, 8, 7, 7, 7, 5, 3, 3, 2, 1, 2, 1, 1, 0, 2, 1, 3, 2, 4, 4], +[6, 5, 6, 5, 6, 6, 5, 5, 3, 3, 0, 0, -1, 0, 0, 1, 2, 4, 4, 5, 5, 6, 5, 6], +[5, 4, 3, 2, 2, 1, 1, 0, 2, 1, 3, 2, 3, 4, 5, 4, 5, 6, 6, 6, 6, 6, 6, 5], +[4, 4, 3, 3, 1, 3, 2, 4, 4, 6, 5, 7, 6, 6, 6, 6, 5, 4, 3, 3, 3, 3, 4, 4], +[6, 6, 8, 6, 8, 7, 6, 6, 5, 5, 4, 3, 2, 2, 1, 2, 0, 1, 0, 2, 1, 3, 4, 7], +[7, 9, 8, 9, 8, 8, 6, 5, 4, 2, 0, -1, 0, 0, 1, 2, 4, 3, 5, 4, 5, 5, 5, 6], +[7, 7, 7, 7, 7, 8, 7, 7, 6, 6, 5, 5, 4, 5, 5, 7, 7, 8, 8, 7, 7, 6, 5, 4], +[4, 3, 4, 4, 6, 6, 9, 9, 11, 11, 12, 11, 10, 8, 7, 7, 5, 6, 5, 6, 4, 5, 4, 5], +[4, 5, 4, 6, 6, 8, 8, 10, 10, 10, 10, 9, 8, 6, 6, 4, 3, 2, 3, 3, 5, 5, 8, 7], +[8, 8, 7, 7, 6, 6, 4, 4, 4, 5, 4, 5, 4, 5, 5, 7, 5, 7, 6, 8, 7, 8, 9, 9], +[9, 8, 8, 6, 5, 3, 4, 2, 4, 3, 6, 5, 8, 8, 10, 11, 10, 11, 10, 9, 8, 7, 7, 7], +[6, 7, 6, 8, 7, 8, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 9, 8, 6, 6, 5, 5, 4], +[6, 6, 8, 8, 10, 9, 10, 9, 8, 7, 5, 5, 4, 4, 3, 4, 4, 5, 4, 6, 5, 6, 6, 7], +[7, 7, 7, 7, 7, 8, 7, 6, 6, 3, 4, 1, 1, 1, 3, 2, 5, 6, 9, 8, 9, 9, 9, 9], +[8, 7, 6, 5, 3, 4, 3, 4, 3, 4, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 7, 8, 7], +[7, 5, 5, 2, 3, 3, 4, 4, 5, 6, 7, 7, 8, 7, 5, 5, 4, 3, 2, 4, 3, 5, 5, 7], +[7, 8, 7, 8, 8, 7, 6, 5, 6, 4, 4, 3, 3, 2, 2, 1, 1, -1, 1, -1, 2, 2, 5, 6], +[7, 8, 9, 9, 7, 7, 4, 4, 2, 2, -1, 0, -1, 0, 1, 3, 4, 5, 5, 6, 5, 5, 5, 5], +[6, 5, 6, 5, 7, 6, 6, 5, 5, 4, 5, 4, 5, 6, 7, 7, 8, 9, 9, 8, 7, 7, 5, 5], +[4, 4, 3, 5, 5, 6, 7, 9, 9, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 6, 6, 5, 6, 5], +[6, 5, 7, 6, 7, 8, 8, 9, 8, 9, 7, 7, 5, 5, 3, 3, 3, 4, 4, 5, 5, 8, 8, 10], +[10, 10, 9, 8, 7, 6, 6, 4, 5, 3, 4, 3, 4, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 10], +[10, 10, 8, 9, 6, 6, 4, 5, 4, 5, 5, 6, 6, 7, 8, 8, 9, 8, 8, 7, 7, 6, 7, 5], +[7, 6, 7, 6, 8, 7, 8, 8, 9, 9, 9, 8, 8, 8, 7, 7, 6, 6, 3, 4, 2, 2, 2, 3], +[3, 5, 5, 7, 7, 9, 9, 9, 9, 7, 7, 5, 4, 3, 3, 2, 2, 1, 3, 2, 3, 3, 4, 4], +[5, 4, 4, 5, 4, 5, 4, 5, 4, 5, 3, 4, 2, 2, 2, 4, 5, 6, 7, 7, 7, 7, 6, 5], +[6, 3, 4, 2, 2, 0, 2, 2, 3, 4, 5, 6, 8, 7, 8, 9, 8, 9, 8, 9, 7, 8, 6, 7], +[5, 5, 3, 4, 2, 3, 3, 4, 5, 6, 8, 8, 9, 9, 9, 8, 7, 5, 6, 5, 5, 4, 6, 6], +[7, 7, 8, 8, 7, 7, 6, 6, 4, 5, 4, 4, 3, 4, 4, 5, 4, 4, 4, 5, 5, 6, 8, 9], +[10, 10, 11, 9, 9, 7, 6, 4, 3, 1, 2, 0, 1, 1, 3, 5, 6, 8, 9, 9, 9, 9, 8, 8], +[7, 9, 7, 8, 7, 7, 6, 6, 6, 5, 5, 5, 5, 6, 7, 8, 9, 10, 11, 11, 11, 9, 9, 7], +[7, 5, 6, 5, 7, 7, 9, 10, 9, 10, 9, 9, 8, 7, 5, 5, 4, 6, 4, 5, 5, 7, 7, 7], +[7, 7, 6, 6, 6, 7, 7, 6, 7, 6, 6, 4, 4, 2, 2, 0, 1, 0, 1, 1, 4, 5, 8, 9], +[10, 10, 9, 9, 7, 6, 4, 4, 2, 3, 2, 2, 2, 2, 2, 3, 3, 4, 5, 5, 6, 6, 8, 8], +[9, 8, 8, 6, 7, 5, 4, 2, 2, 2, 3, 4, 5, 6, 6, 7, 7, 7, 5, 6, 4, 5, 3, 5]] diff --git a/Shared/DataModel/DataClass.swift b/Shared/DataModel/DataClass.swift index 60db57a..095b40d 100644 --- a/Shared/DataModel/DataClass.swift +++ b/Shared/DataModel/DataClass.swift @@ -25,25 +25,6 @@ extension CGColor { } } -extension CGPoint { - func encode() -> String { - return "x: \(x), y: \(y)" - } - - init?(from str: String?) { - self.init() - guard let str = str else { return nil } - let regex = /x:\s*([\-0-9\.]+)\s*,\s*y:\s*([\-0-9\.]+)/ - let matches = try? regex.firstMatch(in: str)?.output - if let matches = matches, let x = Double(matches.1), let y = Double(matches.2) { - self.x = x - self.y = y - } else { - return nil - } - } -} - protocol OptionalType { associatedtype Wrapped var optional: Wrapped? { get } @@ -76,7 +57,7 @@ extension String { return Int(string) } } - + var floatValue: CGFloat? { let string = trimmingCharacters(in: .whitespaces) if string.isEmpty { @@ -134,7 +115,7 @@ extension String { } } -fileprivate func extract(from str: String, inner: Bool = false) -> [String: String] { +private func extract(from str: String, inner: Bool = false) -> [String: String] { let regex = if inner { /([a-zA-Z_0-9]+)\s*:[\s"]*([^\s"#][^"#]*)[\s"#]*(#*.*)$/ } else { @@ -167,7 +148,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr private let _locations: [CGFloat] private let _colors: [CGColor] let isLoop: Bool - + init(locations: [CGFloat], colors: [CGColor], loop: Bool) { guard locations.count == colors.count else { fatalError("Gradient locations count does not equal colors count") @@ -180,7 +161,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr _colors = colorAndLocation.map { $0.0 } isLoop = loop } - + func interpolate(at: CGFloat) -> CGColor { let locations = self.locations let colors = self.colors @@ -204,7 +185,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr return colors.last! } } - + var locations: [CGFloat] { if isLoop { return _locations + [1] @@ -220,7 +201,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr return _colors } } - + func encode() -> String { var encoded = "" let locationString = _locations.map { "\($0)" }.joined(separator: ", ") @@ -230,7 +211,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr encoded += "loop: \(isLoop)" return encoded } - + init?(from str: String?) { guard let str = str else { return nil } let values = extract(from: str, inner: true) @@ -243,16 +224,16 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr self.isLoop = isLoop } } - + struct StartingPhase { var zeroRing: CGFloat = 0.0 var firstRing: CGFloat = 0.0 var secondRing: CGFloat = 0.0 var thirdRing: CGFloat = 0.0 var fourthRing: CGFloat = 0.0 - + init() { } - + func encode() -> String { var encoded = "" encoded += "zeroRing: \(zeroRing)\n" @@ -262,7 +243,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr encoded += "fourthRing: \(fourthRing)\n" return encoded } - + init?(from str: String?) { guard let str = str else { return nil } let values = extract(from: str, inner: true) @@ -296,9 +277,9 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr var fontColorDark = CGColor(gray: 0, alpha: 1) var evenSolarTermTickColorDark = CGColor(gray: 1, alpha: 1) var oddSolarTermTickColorDark = CGColor(gray: 0.67, alpha: 1) - var planetIndicator: [CGColor] = [CGColor(gray: 0.2, alpha: 1), CGColor(gray: 0.3, alpha: 1), CGColor(gray: 0.4, alpha: 1), CGColor(gray: 0.5, alpha: 1), CGColor(gray: 0.6, alpha: 1), CGColor(gray: 0.7, alpha: 1)] - var sunPositionIndicator: [CGColor] = [CGColor(gray: 0.3, alpha: 1), CGColor(gray: 0.4, alpha: 1), CGColor(gray: 0.5, alpha: 1), CGColor(gray: 0.6, alpha: 1)] - var moonPositionIndicator: [CGColor] = [CGColor(gray: 0.4, alpha: 1), CGColor(gray: 0.5, alpha: 1), CGColor(gray: 0.6, alpha: 1)] + var planetIndicator = Planets(moon: CGColor(gray: 0.3, alpha: 1), mercury: CGColor(gray: 0.4, alpha: 1), venus: CGColor(gray: 0.5, alpha: 1), mars: CGColor(gray: 0.6, alpha: 1), jupiter: CGColor(gray: 0.7, alpha: 1), saturn: CGColor(gray: 0.8, alpha: 1)) + var sunPositionIndicator = Solar(midnight: CGColor(gray: 0.3, alpha: 1), sunrise: CGColor(gray: 0.4, alpha: 1), noon: CGColor(gray: 0.5, alpha: 1), sunset: CGColor(gray: 0.6, alpha: 1)) + var moonPositionIndicator = Lunar(moonrise: CGColor(gray: 0.4, alpha: 1), highMoon: CGColor(gray: 0.5, alpha: 1), moonset: CGColor(gray: 0.6, alpha: 1)) var eclipseIndicator = CGColor(gray: 0.3, alpha: 1) var fullmoonIndicator = CGColor(gray: 0.4, alpha: 1) var oddStermIndicator = CGColor(gray: 0.5, alpha: 1) @@ -311,7 +292,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr var horizontalTextOffset: CGFloat = 0 var watchSize: CGSize = .zero var cornerRadiusRatio: CGFloat = 0 - + func encode(includeOffset: Bool = true, includeColor: Bool = true) -> String { var encoded = "" if includeColor { @@ -335,13 +316,13 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr encoded += "fontColorDark: \(fontColorDark.hexCode)\n" encoded += "evenSolarTermTickColorDark: \(evenSolarTermTickColorDark.hexCode)\n" encoded += "oddSolarTermTickColorDark: \(oddSolarTermTickColorDark.hexCode)\n" - encoded += "planetIndicator: \(planetIndicator.map { $0.hexCode }.joined(separator: ", "))\n" + encoded += "planetIndicator: \(planetIndicator.encode([\.mercury, \.venus, \.mars, \.jupiter, \.saturn, \.moon]))\n" encoded += "eclipseIndicator: \(eclipseIndicator.hexCode)\n" encoded += "fullmoonIndicator: \(fullmoonIndicator.hexCode)\n" encoded += "oddStermIndicator: \(oddStermIndicator.hexCode)\n" encoded += "evenStermIndicator: \(evenStermIndicator.hexCode)\n" - encoded += "sunPositionIndicator: \(sunPositionIndicator.map { $0.hexCode }.joined(separator: ", "))\n" - encoded += "moonPositionIndicator: \(moonPositionIndicator.map { $0.hexCode }.joined(separator: ", "))\n" + encoded += "sunPositionIndicator: \(sunPositionIndicator.encode([\.midnight, \.sunrise, \.noon, \.sunset]))\n" + encoded += "moonPositionIndicator: \(moonPositionIndicator.encode([\.moonrise, \.highMoon, \.moonset]))\n" encoded += "shadeAlpha: \(shadeAlpha)\n" encoded += "shadowSize: \(shadowSize)\n" } @@ -357,26 +338,14 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr encoded += "startingPhase: \(startingPhase.encode().replacingOccurrences(of: "\n", with: "; "))\n" return encoded } - + func update(from values: [String: String], updateSize: Bool = true) { let seperatorRegex = /(\s*;|\{\})/ func expand(value: String?) -> String? { guard let value = value else { return nil } return value.replacing(seperatorRegex) { _ in "\n" } } - - func readColorList(_ list: String?) -> [CGColor]? { - var colors = [CGColor?]() - if let colorValues = list { - for color in colorValues.split(separator: ",") { - colors.append(String(color).colorValue) - } - return colors.flattened() - } else { - return nil - } - } - + initialized = true self.withMutation(keyPath: \.firstRing) { _firstRing = Gradient(from: expand(value: values["firstRing"])) ?? _firstRing @@ -400,15 +369,9 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr _fontColorDark = values["fontColorDark"]?.colorValue ?? _fontColorDark _evenSolarTermTickColorDark = values["evenSolarTermTickColorDark"]?.colorValue ?? _evenSolarTermTickColorDark _oddSolarTermTickColorDark = values["oddSolarTermTickColorDark"]?.colorValue ?? _oddSolarTermTickColorDark - if let colourList = readColorList(values["planetIndicator"]), colourList.count == _planetIndicator.count { - _planetIndicator = colourList - } - if let colourList = readColorList(values["sunPositionIndicator"]), colourList.count == _sunPositionIndicator.count { - _sunPositionIndicator = colourList - } - if let colourList = readColorList(values["moonPositionIndicator"]), colourList.count == _moonPositionIndicator.count { - _moonPositionIndicator = colourList - } + _planetIndicator.read(string: values["planetIndicator"], to: [\.mercury, \.venus, \.mars, \.jupiter, \.saturn, \.moon]) + _sunPositionIndicator.read(string: values["sunPositionIndicator"], to: [\.midnight, \.sunrise, \.noon, \.sunset]) + _moonPositionIndicator.read(string: values["moonPositionIndicator"], to: [\.moonrise, \.highMoon, \.moonset]) _eclipseIndicator = values["eclipseIndicator"]?.colorValue ?? _eclipseIndicator _fullmoonIndicator = values["fullmoonIndicator"]?.colorValue ?? _fullmoonIndicator _oddStermIndicator = values["oddStermIndicator"]?.colorValue ?? _oddStermIndicator @@ -427,18 +390,18 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr _cornerRadiusRatio = values["cornerRadiusRatio"]?.floatValue ?? _cornerRadiusRatio } } - + func update(from str: String, updateSize: Bool = true) { let values = extract(from: str) update(from: values, updateSize: updateSize) } - + func loadStatic() { let filePath = Bundle.main.path(forResource: "layout", ofType: "txt")! let defaultLayout = try! String(contentsOfFile: filePath) self.update(from: defaultLayout) } - + func loadDefault(context: ModelContext, local: Bool = false) { let defaultName = AppInfo.defaultName let predicate = { @@ -452,7 +415,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } }() let descriptor = FetchDescriptor(predicate: predicate, sortBy: [SortDescriptor(\.modifiedDate, order: .reverse)]) - + var found = false do { let themes = try context.fetch(descriptor) @@ -473,12 +436,12 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr self.update(from: defaultLayout) } } - + @MainActor func saveDefault(context: ModelContext) { let defaultName = AppInfo.defaultName let deviceName = AppInfo.deviceName try? LocalData.write(context: LocalSchema.container.mainContext, deviceName: deviceName) - + let predicate = #Predicate { data in data.name == defaultName && data.deviceName == deviceName } @@ -497,13 +460,13 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } catch { print(error.localizedDescription) } - + if !found { let defaultTheme = ThemeData(name: AppInfo.defaultName, code: self.encode()) context.insert(defaultTheme) } } - + func autoSave() { withObservationTracking { _ = self.encode() @@ -518,9 +481,9 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } @Observable final class CalendarConfigure { - + #if os(iOS) - @ObservationIgnored var watchConnectivity: WatchConnectivityManager? = nil + @ObservationIgnored var watchConnectivity: WatchConnectivityManager? #endif @ObservationIgnored var initialized = false var name: String = AppInfo.defaultName @@ -528,25 +491,25 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr var apparentTime: Bool = false var largeHour: Bool = false var locationEnabled: Bool = true - var customLocation: CGPoint? = nil - var timezone: TimeZone? = nil + var customLocation: GeoLocation? + var timezone: TimeZone? var effectiveTimezone: TimeZone { timezone ?? Calendar.current.timeZone } - + convenience init(from code: String, name: String? = nil) { self.init() self.update(from: code, newName: name) } - - func location(locationManager: LocationManager?) -> CGPoint? { + + func location(locationManager: LocationManager?) -> GeoLocation? { if locationEnabled, let locationManager = locationManager { return locationManager.location ?? customLocation } else { return customLocation } } - + func encode(withName: Bool = false) -> String { var encoded = "" if withName { @@ -564,7 +527,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } return encoded } - + private func update(from values: [String: String], newName: String?) { initialized = true self.withMutation(keyPath: \.name) { @@ -573,7 +536,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr _apparentTime = values["apparentTime"]?.boolValue ?? _apparentTime _largeHour = values["largeHour"]?.boolValue ?? _largeHour _locationEnabled = values["locationEnabled"]?.boolValue ?? _locationEnabled - _customLocation = CGPoint(from: values["customLocation"]) + _customLocation = GeoLocation(from: values["customLocation"]) if let tzStr = values["timezone"], let tz = TimeZone(identifier: tzStr) { _timezone = tz } else { @@ -581,12 +544,12 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } } } - + func update(from str: String, newName: String? = nil) { let values = extract(from: str) update(from: values, newName: newName) } - + func load(name: String?, context: ModelContext) { let descriptor: FetchDescriptor if let name = name { @@ -611,7 +574,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr print(error.localizedDescription) } } - + func save(context: ModelContext) { let name = name let predicate = #Predicate { data in @@ -632,13 +595,13 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } catch { print(error.localizedDescription) } - + if !found { let config = ConfigData(name: self.name, code: self.encode()) context.insert(config) } } - + func sendToWatch() { #if os(iOS) self.watchConnectivity?.send(messages: [ @@ -646,7 +609,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr ]) #endif } - + @MainActor func saveName() { do { try LocalData.write(context: LocalSchema.container.mainContext, configName: self.name) @@ -654,7 +617,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr print(error.localizedDescription) } } - + func autoSaveName() { withObservationTracking { _ = self.name @@ -665,7 +628,7 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } } } - + func autoSave() { withObservationTracking { _ = self.encode(withName: true) @@ -679,3 +642,30 @@ func applyGradient(gradient: WatchLayout.Gradient, startingAngle: CGFloat) -> Gr } } } + +private protocol ReadWrite { + mutating func read(string list: String?, to properties: [WritableKeyPath]) + func encode(_ properties: [KeyPath]) -> String +} + +private extension ReadWrite { + mutating func read(string list: String?, to properties: [WritableKeyPath]) { + if let colorValues = list { + let colorList = colorValues.split(separator: ",").compactMap { color in + String(color).colorValue + } + guard colorList.count == properties.count else { return } + for i in 0..]) -> String { + properties.map { self[keyPath: $0].hexCode }.joined(separator: ", ") + } +} + +extension Planets : ReadWrite {} +extension Solar : ReadWrite {} +extension Lunar : ReadWrite {} diff --git a/Shared/DataModel/DataModel.swift b/Shared/DataModel/DataModel.swift index c83d69d..8a6ef90 100644 --- a/Shared/DataModel/DataModel.swift +++ b/Shared/DataModel/DataModel.swift @@ -20,7 +20,7 @@ import VisionKit #endif private func intVersion(_ version: Schema.Version) -> Int { - version.major * 100_0000 + version.minor * 1_0000 + version.patch * 100 + 0 + version.major * 100_0000 + version.minor * 1_0000 + version.patch * 100 + 1 } private func createContainer(schema: Schema, migrationPlan: SchemaMigrationPlan.Type? = nil, configurations: [ModelConfiguration]) -> ModelContainer { @@ -49,8 +49,7 @@ struct AppInfo { typealias DataSchema = DataSchemaV4 extension DataSchema { - - static let container = { + static func migrateData(to context: ModelContext) { #if os(macOS) let containerPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "28HU5A7B46.ChineseTime")!.appendingPathComponent("ChineseTime") #elseif os(iOS) || os(visionOS) @@ -59,10 +58,63 @@ extension DataSchema { let containerPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.ChineseTime.Watch")!.appendingPathComponent("ChineseTime.sqlite") #endif let fullSchema = Schema(versionedSchema: DataSchema.self) - let modelConfig = ModelConfiguration("ChineseTime", schema: fullSchema, url: containerPath, cloudKitDatabase: .automatic) - return createContainer(schema: fullSchema, migrationPlan: DataMigrationPlan.self, configurations: [modelConfig]) - }() + let sourceConfig = ModelConfiguration("Chinendar", schema: fullSchema, url: containerPath, cloudKitDatabase: .automatic) + let sourceContainer = createContainer(schema: fullSchema, migrationPlan: DataMigrationPlan.self, configurations: [sourceConfig]) + let sourceContext = ModelContext(sourceContainer) + + let themeDescriptor = FetchDescriptor() + let configDescriptor = FetchDescriptor() + do { + for data in try sourceContext.fetch(themeDescriptor) { + let newData = ThemeData(name: data.name!, code: data.code!) + newData.deviceName = data.deviceName + newData.modifiedDate = data.modifiedDate + newData.version = data.version + context.insert(newData) + } + for data in try sourceContext.fetch(configDescriptor) { + let newData = Config(name: data.name!, code: data.code!) + newData.modifiedDate = data.modifiedDate + newData.version = data.version + context.insert(newData) + } + try context.save() + } catch { + print(error.localizedDescription) + } + } + static func removeOld() { +#if os(macOS) + let containerPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "28HU5A7B46.ChineseTime")!.appendingPathComponent("ChineseTime") +#elseif os(iOS) || os(visionOS) + let containerPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.ChineseTime")!.appendingPathComponent("ChineseTime.sqlite") +#elseif os(watchOS) + let containerPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.ChineseTime.Watch")!.appendingPathComponent("ChineseTime.sqlite") +#endif + do { + try FileManager.default.removeItem(at: containerPath) + let ext = containerPath.pathExtension + try FileManager.default.removeItem(at: containerPath.deletingPathExtension().appendingPathExtension("\(ext)-shm")) + try FileManager.default.removeItem(at: containerPath.deletingPathExtension().appendingPathExtension("\(ext)-wal")) + } catch { + print(error.localizedDescription) + } + } + + static let container = { + let fullSchema = Schema(versionedSchema: DataSchema.self) + let modelConfig = ModelConfiguration("Chinendar", schema: fullSchema, groupContainer: .automatic, cloudKitDatabase: .automatic) + if let exist = try? modelConfig.url.checkResourceIsReachable(), exist { + removeOld() + return createContainer(schema: fullSchema, migrationPlan: DataMigrationPlan.self, configurations: [modelConfig]) + } else { + let modelContainer = createContainer(schema: fullSchema, migrationPlan: DataMigrationPlan.self, configurations: [modelConfig]) + migrateData(to: ModelContext(modelContainer)) + return modelContainer + } + }() + static let context = ModelContext(container) } @@ -71,16 +123,24 @@ extension ThemeData { static var version: Int { intVersion(DataSchema.versionIdentifier) } - - static func latestVersion() -> Int { + + static func notLatest() -> Bool { let deviceName = AppInfo.deviceName let predicate = #Predicate { data in data.deviceName == deviceName && data.version != nil } var descriptor = FetchDescriptor(predicate: predicate, sortBy: [SortDescriptor(\.modifiedDate, order: .reverse)]) descriptor.fetchLimit = 1 - let version = try? DataSchema.context.fetch(descriptor).first?.version - return version ?? 0 + if let latestEntry = try? DataSchema.context.fetch(descriptor).first { + if (latestEntry.version ?? 0) < Self.version { + latestEntry.version = Self.version + return true + } else { + return false + } + } else { + return true + } } static func experienced() -> Bool { let predicate = #Predicate { data in @@ -90,18 +150,18 @@ extension ThemeData { let counts = try? DataSchema.context.fetchCount(descriptor) descriptor.fetchLimit = 1 let date = try? DataSchema.context.fetch(descriptor).first?.modifiedDate - + if let date = date, let counts = counts, counts > 1, date.distance(to: .now) > 3600 * 24 * 5 { return true } else { return false } } - + var isNil: Bool { return code == nil || name == nil || deviceName == nil || modifiedDate == nil } - + func update(code: String) { if self.code != code { self.code = code @@ -118,11 +178,11 @@ extension ConfigData { static var version: Int { intVersion(DataSchema.versionIdentifier) } - + var isNil: Bool { return code == nil || name == nil || modifiedDate == nil } - + func update(code: String, name: String? = nil) { if self.code != code { self.code = code @@ -139,13 +199,13 @@ enum DataSchemaV4: VersionedSchema { static var models: [any PersistentModel.Type] { [DataSchemaV3.Layout.self, Config.self] } - + @Model final class Config { @Attribute(.allowsCloudEncryption) var code: String? var modifiedDate: Date? @Attribute(.allowsCloudEncryption) var name: String? var version: Int? - + init(name: String, code: String) { self.name = name self.code = code @@ -160,14 +220,14 @@ enum DataSchemaV3: VersionedSchema { static var models: [any PersistentModel.Type] { [Layout.self] } - + @Model final class Layout { var code: String? var deviceName: String? var modifiedDate: Date? @Attribute(hashModifier: "v3") var name: String? var version: Int? - + init(name: String, code: String) { self.name = name self.deviceName = AppInfo.deviceName @@ -183,14 +243,14 @@ enum DataSchemaV2: VersionedSchema { static var models: [any PersistentModel.Type] { [Layout.self] } - + @Model final class Layout { var code: String? var deviceName: String? var modifiedDate: Date? var name: String? var version: Int? - + init(name: String, code: String) { self.name = name self.deviceName = AppInfo.deviceName @@ -206,13 +266,13 @@ enum DataSchemaV1: VersionedSchema { static var models: [any PersistentModel.Type] { [Layout.self] } - + @Model final class Layout { var code: String? var deviceName: String? var modifiedDate: Date? var name: String? - + init(name: String, deviceName: String, code: String) { self.name = name self.deviceName = deviceName @@ -226,9 +286,9 @@ enum DataMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [DataSchemaV1.self, DataSchemaV2.self, DataSchemaV3.self, DataSchemaV4.self] } - + static var stages: [MigrationStage] { [migrateV1toV2, migrateV2toV3, migrateV3toV4] } - + static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: DataSchemaV1.self, toVersion: DataSchemaV2.self) static let migrateV2toV3 = MigrationStage.custom( fromVersion: DataSchemaV2.self, toVersion: DataSchemaV3.self, @@ -256,13 +316,53 @@ enum DataMigrationPlan: SchemaMigrationPlan { typealias LocalSchema = LocalSchemaV2 extension LocalSchema { + + static func migrateData(to context: ModelContext) { + let localSchema = Schema(versionedSchema: LocalSchema.self) + let sourceConfig = ModelConfiguration("ChineseTimeLocal", schema: localSchema, groupContainer: .automatic, cloudKitDatabase: .none) + let sourceContainer = createContainer(schema: localSchema, migrationPlan: DataMigrationPlan.self, configurations: [sourceConfig]) + let sourceContext = ModelContext(sourceContainer) + + let localDescriptor = FetchDescriptor() + do { + for data in try sourceContext.fetch(localDescriptor) { + let newData = LocalData(deviceName: data.deviceName, configName: data.configName) + newData.modifiedDate = data.modifiedDate + newData.version = data.version + context.insert(newData) + } + try context.save() + } catch { + print(error.localizedDescription) + } + } + + static func removeOld() { + let localSchema = Schema(versionedSchema: LocalSchema.self) + let sourceConfig = ModelConfiguration("ChineseTimeLocal", schema: localSchema, groupContainer: .automatic, cloudKitDatabase: .none) + do { + try FileManager.default.removeItem(at: sourceConfig.url) + let ext = sourceConfig.url.pathExtension + try FileManager.default.removeItem(at: sourceConfig.url.deletingPathExtension().appendingPathExtension("\(ext)-shm")) + try FileManager.default.removeItem(at: sourceConfig.url.deletingPathExtension().appendingPathExtension("\(ext)-wal")) + } catch { + print(error.localizedDescription) + } + } static let container = { let localSchema = Schema(versionedSchema: LocalSchema.self) - let modelConfig = ModelConfiguration("ChineseTimeLocal", schema: localSchema, groupContainer: .automatic, cloudKitDatabase: .none) - return createContainer(schema: localSchema, migrationPlan: LocalDataMigrationPlan.self, configurations: [modelConfig]) + let modelConfig = ModelConfiguration("ChinendarLocal", schema: localSchema, groupContainer: .automatic, cloudKitDatabase: .none) + if let exist = try? modelConfig.url.checkResourceIsReachable(), exist { + removeOld() + return createContainer(schema: localSchema, migrationPlan: LocalDataMigrationPlan.self, configurations: [modelConfig]) + } else { + let modelContainer = createContainer(schema: localSchema, migrationPlan: LocalDataMigrationPlan.self, configurations: [modelConfig]) + migrateData(to: ModelContext(modelContainer)) + return modelContainer + } }() - + static let context = ModelContext(container) } @@ -271,7 +371,7 @@ extension LocalData: Identifiable, Hashable { static var version: Int { intVersion(LocalSchema.versionIdentifier) } - + func update(deviceName: String) { if self.deviceName != deviceName { self.deviceName = deviceName @@ -279,7 +379,7 @@ extension LocalData: Identifiable, Hashable { self.version = Self.version } } - + func update(configName: String) { if self.configName != configName { self.configName = configName @@ -287,7 +387,7 @@ extension LocalData: Identifiable, Hashable { self.version = Self.version } } - + static func read(context: ModelContext) -> LocalData? { let descriptor = FetchDescriptor(sortBy: [SortDescriptor(\LocalData.modifiedDate, order: .reverse)]) do { @@ -300,7 +400,7 @@ extension LocalData: Identifiable, Hashable { } return nil } - + static func write(context: ModelContext, deviceName: String? = nil, configName: String? = nil) throws { let descriptor = FetchDescriptor(sortBy: [SortDescriptor(\LocalData.modifiedDate, order: .reverse)]) let records = try context.fetch(descriptor) @@ -326,19 +426,18 @@ extension LocalData: Identifiable, Hashable { } } - enum LocalSchemaV2: VersionedSchema { static let versionIdentifier: Schema.Version = .init(2, 1, 0) static var models: [any PersistentModel.Type] { [LocalData.self] } - + @Model final class LocalData { var deviceName: String? var configName: String? var modifiedDate: Date? var version: Int? - + init(deviceName: String?, configName: String?) { self.deviceName = deviceName self.configName = configName @@ -353,12 +452,12 @@ enum LocalSchemaV1: VersionedSchema { static var models: [any PersistentModel.Type] { [LocalData.self] } - + @Model final class LocalData { var deviceName: String? var modifiedDate: Date? var version: Int? - + init(deviceName: String) { self.deviceName = deviceName self.modifiedDate = Date.now @@ -371,7 +470,7 @@ enum LocalDataMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [LocalSchemaV1.self, LocalSchemaV2.self] } - + static var stages: [MigrationStage] { [migrateV1toV2] } static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: LocalSchemaV1.self, toVersion: LocalSchemaV2.self) } diff --git a/Shared/DataModel/LocationManager.swift b/Shared/DataModel/LocationManager.swift index 4348434..66fbda2 100644 --- a/Shared/DataModel/LocationManager.swift +++ b/Shared/DataModel/LocationManager.swift @@ -8,10 +8,36 @@ import CoreLocation import Observation +struct GeoLocation: Equatable { + let lat: Double + let lon: Double + + func encode() -> String { + return "lat: \(lat), lon: \(lon)" + } + + init(lat: Double, lon: Double) { + self.lat = lat + self.lon = lon + } + + init?(from str: String?) { + guard let str = str else { return nil } + let regex = /(x|lat):\s*([\-0-9\.]+)\s*,\s*(y|lon):\s*([\-0-9\.]+)/ + let matches = try? regex.firstMatch(in: str)?.output + if let matches = matches, let lat = Double(matches.2), let lon = Double(matches.4) { + self.lat = lat + self.lon = lon + } else { + return nil + } + } +} + @Observable final class LocationManager: NSObject, CLLocationManagerDelegate { - - private var _location: CGPoint? = nil - private(set) var location: CGPoint? { + + private var _location: GeoLocation? + private(set) var location: GeoLocation? { get { _location } set { @@ -26,7 +52,7 @@ import Observation @ObservationIgnored let manager = CLLocationManager() @ObservationIgnored private var lastUpdated = Date.distantPast - @ObservationIgnored private var continuation: CheckedContinuation? + @ObservationIgnored private var continuation: CheckedContinuation? var enabled: Bool { get { @@ -53,7 +79,7 @@ import Observation } } } - + override init() { super.init() manager.delegate = self @@ -78,8 +104,8 @@ import Observation } } } - - func getLocation() async -> CGPoint? { + + func getLocation() async -> GeoLocation? { if lastUpdated.distance(to: .now) > 3600 { #if os(watchOS) let authorized = [.authorizedWhenInUse, .authorizedAlways].contains(manager.authorizationStatus) @@ -98,7 +124,7 @@ import Observation func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { if let location = locations.last { - let locationPoint = CGPoint(x: location.coordinate.latitude, y: location.coordinate.longitude) + let locationPoint = GeoLocation(lat: location.coordinate.latitude, lon: location.coordinate.longitude) self.location = locationPoint continuation?.resume(with: .success(locationPoint)) } else { @@ -106,7 +132,7 @@ import Observation } continuation = nil } - + func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { switch manager.authorizationStatus { #if os(macOS) @@ -116,18 +142,18 @@ import Observation case .authorizedWhenInUse, .authorizedAlways: // Location services are available. requestLocation() #endif - + case .restricted, .denied: break - + case .notDetermined: // Authorization not determined yet. manager.requestWhenInUseAuthorization() - + @unknown default: print("Unhandled Location Authorization Case") } } - + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { if let continuation = continuation { continuation.resume(with: .success(nil)) diff --git a/Shared/DataModel/PlanetModel.swift b/Shared/DataModel/PlanetModel.swift index 4cf5722..d99eca9 100644 --- a/Shared/DataModel/PlanetModel.swift +++ b/Shared/DataModel/PlanetModel.swift @@ -7,383 +7,364 @@ import Foundation -let planetNames = ["辰", "太白", "熒惑", "歲", "填", "月"] +struct SolarSystem { + private static let earthRadiiInAU: Double = 1 / 23455 + static let aeroAdj = 29 / 60 / 180 * Double.pi + + struct SphericalLoc { + let ra: Double + let decl: Double + let r: Double + } -func % (lhs: T, rhs: T) -> T { - lhs - rhs*floor(lhs / rhs) -} + struct Planet { + let loc: SphericalLoc + let diameter: Double + } -private struct Matrix { - var p11 = 0.0, p12 = 0.0, p13 = 0.0, p21 = 0.0, p22 = 0.0, p23 = 0.0, p31 = 0.0, p32 = 0.0, p33 = 0.0 -} + struct Planets { + let sun: Planet + let moon: Planet + let mercury: Planet + let venus: Planet + let mars: Planet + let jupiter: Planet + let saturn: Planet + } -private func precessionMatrixVondrak(T: Double) -> Matrix { - let omega = [0.01559490024120026, 0.0244719973015758, 0.02151775790129995, 0.01169573974755144, 0.02602271819084525, 0.01674533688817117, 0.0397997422384214, 0.02291460724719032, 0.03095165175950535, 0.01427996660722633, 0.03680403764749055, 0.008807750966790847, 0.02007407446383254, 0.0489420883874403, 0.03110487775831478, 0.01994662002279234, 0.04609144151393476, 0.01282282715750936] - let cPsiA = [-0.1076593062579846, 0.05932495062847037, -0.007703729840835942, 0.01203357586861691, 0.000728786082003343, -6.609012098588148e-05, 0.001888045891520004, 0.009848668946298234, 0.001763501537747769, -0.004347554865592219, -0.004494201976897112, 0.000179723665294558, -0.002897646374457124, 0.0003213481408001133, 0, 0, 0, 0] - let sPsiA = [-0.01572365411244583, -0.01924576393436911, 0.03441793111567203, -0.009229382101760265, 0.0007099369818066644, 0.00630563269451746, 0.008375146833970948, 0.001453733482001713, -0.005900793277074788, -0.002285254065278213, -0.002141335465978059, -0.0004177599299066708, -0.001494779621447613, -0.002049868015261339, 0, 0, 0, 0] - let cOmgA = [0.00614611792998422, 0.008253100851149026, -0.01440165141619654, 0.003363590350788535, -7.138615291626988e-05, -0.002504786979418468, -0.00172978832643207, -0.0006280861013429611, 0.001241749955604002, 0.0009224361511874661, 0.0004610771596491818, -0.001613979006196489, 0.0006367428132294327, 0.0004010956619564596, 0, 0, 0, 0] - let sOmgA = [-0.04155568953790275, 0.0257426196723017, -0.002959273392809311, 0.004475809265755418, 1.822441292043207e-05, -0.0001972760876678778, 0.000389971927172294, 0.003913904086152674, 0.0004058488092230152, -0.001787289168266385, -0.0009302656497305446, -2.067134029104406e-05, -0.0013107116813526, 5.625225752812272e-05, 0, 0, 0, 0] - let cChiA = [-0.06673908312554792, 0.06550733801292973, -0.007055149797375992, 0.005111848628877972, 0, -0.0005444464620177098, 0.0009830562551572195, 0.009386235733694169, 0, -0.003177877146985308, -0.004324046613805478, 0, 0, -0.001615990759958801, 0.001587849478343136, -0.002398762740975183, 0.002838548328494804, 0.0005357813386138708] - let sChiA = [-0.01069967856443793, -0.02029794993715239, 0.03266650186037179, -0.0041544791939612, 0, 0.004640389727239152, 0.008287602553739408, 0.0007486759753624905, 0, -0.00118062300801947, -0.001970956729830991, 0, 0, -0.002165451504436122, -0.005086043543188153, -0.001461733557390353, 0.0002004643484864111, 0.000690981600754813] - - var psiA = 0.04107992866630529 + T*(0.02444817476355586 + T*(-3.592047589119096e-08 + 1.401111538406559e-12*T)) - var omgA = 0.4086163677095374 + T*(-2.150908863572772e-06 + T*(7.078279744199225e-12 + 7.320686584753994e-13*T)) - var chiA = -9.530113429264049e-05 + T*(3.830798934518299e-07 + T*(7.13645738593237e-11 - 2.957363454768169e-13*T)) - for i in 0..<18 { - let ang = omega[i]*T - let cosAng = cos(ang), sinAng = sin(ang) - psiA += cPsiA[i]*cosAng + sPsiA[i]*sinAng - omgA += cOmgA[i]*cosAng + sOmgA[i]*sinAng - chiA += cChiA[i]*cosAng + sChiA[i]*sinAng + enum Targets { + case sun, sunMoon, all + var list: [Int] { + switch self { + case .sun: [0] + case .sunMoon: [0, 1] + case .all: [0, 1, 2, 3, 4, 5, 6] + } + } } - let cEps = 0.9174821430652418, sEps = 0.397776969112606 - let sPsi = sin(psiA), cPsi = cos(psiA) - let sOmg = sin(omgA), cOmg = cos(omgA) - let sChi = sin(chiA), cChi = cos(chiA) - - var p = Matrix() - p.p11 = cChi*cPsi + sChi*cOmg*sPsi - p.p12 = (-cChi*sPsi + sChi*cOmg*cPsi)*cEps + sChi*sOmg*sEps - p.p13 = (-cChi*sPsi + sChi*cOmg*cPsi)*sEps - sChi*sOmg*cEps - p.p21 = -sChi*cPsi + cChi*cOmg*sPsi - p.p22 = (sChi*sPsi + cChi*cOmg*cPsi)*cEps + cChi*sOmg*sEps - p.p23 = (sChi*sPsi + cChi*cOmg*cPsi)*sEps - cChi*sOmg*cEps - p.p31 = sOmg*sPsi - p.p32 = sOmg*cPsi*cEps - cOmg*sEps - p.p33 = sOmg*cPsi*sEps + cOmg*cEps - - return p -} -private func precession_matrix(T0: Double, T: Double) -> Matrix { - if T0==0 { - return precessionMatrixVondrak(T: T) - } else { - let p0 = precessionMatrixVondrak(T: T0) - let p1 = precessionMatrixVondrak(T: T0 + T) - var p = Matrix() - // Inverse of p0 is the transpose of p0 - p.p11 = p1.p11*p0.p11 + p1.p12*p0.p12 + p1.p13*p0.p13 - p.p12 = p1.p11*p0.p21 + p1.p12*p0.p22 + p1.p13*p0.p23 - p.p13 = p1.p11*p0.p31 + p1.p12*p0.p32 + p1.p13*p0.p33 - p.p21 = p1.p21*p0.p11 + p1.p22*p0.p12 + p1.p23*p0.p13 - p.p22 = p1.p21*p0.p21 + p1.p22*p0.p22 + p1.p23*p0.p23 - p.p23 = p1.p21*p0.p31 + p1.p22*p0.p32 + p1.p23*p0.p33 - p.p31 = p1.p31*p0.p11 + p1.p32*p0.p12 + p1.p33*p0.p13 - p.p32 = p1.p31*p0.p21 + p1.p32*p0.p22 + p1.p33*p0.p23 - p.p33 = p1.p31*p0.p31 + p1.p32*p0.p32 + p1.p33*p0.p33 - return p + let time: Date + let loc: GeoLocation? + let planets: Planets + let localSiderialTime: Double? // in radian + + init(time: Date, loc: GeoLocation?, targets: Targets) { + self.time = time + self.loc = loc + + let (lst, ra, dec, r, d) = Self.planetPos(T: Self.fromJD2000(date: time), Loc: loc, selection: targets.list) + localSiderialTime = lst + planets = .init(sun: .init(loc: .init(ra: ra[0], decl: dec[0], r: r[0]), diameter: d[0]), + moon: .init(loc: .init(ra: ra[1], decl: dec[1], r: r[1]), diameter: d[1]), + mercury: .init(loc: .init(ra: ra[2], decl: dec[2], r: r[2]), diameter: d[2]), + venus: .init(loc: .init(ra: ra[3], decl: dec[3], r: r[3]), diameter: d[3]), + mars: .init(loc: .init(ra: ra[4], decl: dec[4], r: r[4]), diameter: d[4]), + jupiter: .init(loc: .init(ra: ra[5], decl: dec[5], r: r[5]), diameter: d[5]), + saturn: .init(loc: .init(ra: ra[6], decl: dec[6], r: r[6]), diameter: d[6])) } -} -// Solve the Kepler's equation M = - e sin E -private func kepler(M: Double, e: Double) -> Double { - // mean anomaly -> [-pi, pi) - let n2pi = floor(M / (2.0*Double.pi) + 0.5)*(2.0*Double.pi) - let Mp = M - n2pi - - // Solve Kepler's equation E - e sin E = M using Newton's iteration method - var E = Mp // initial guess - if e > 0.8 { - E = Double.pi - } // need another initial guess for very eccentric orbit - var E0 = E*1.01 - let tol = 1e-15 - var iter = 0, maxit = 100 - while abs(E - E0) > tol && iter < maxit { - E0 = E - E = E0 - (E0 - e*sin(E0) - Mp) / (1.0 - e*cos(E0)) - iter += 1 + static func normalize(radian: Double) -> Double { + let arcLength = radian / Double.pi + let normalized = (arcLength + 1) %% 2 - 1 + return normalized * Double.pi } - if iter==maxit { - // Newton's iteration doesn't converge after 100 iterations, use bisection instead. - iter = 0 - maxit = 60 - if Mp > 0.0 { - E0 = 0.0 - E = Double.pi - } else { - E = 0.0 - E0 = -Double.pi +} + +private extension SolarSystem { + private static func planetPos(T: Double, Loc: GeoLocation?, selection: [Int]) -> (lst: Double?, ra: [Double], dec: [Double], r: [Double], d: [Double]) { + // https://www.stjarnhimlen.se/comp/ppcomp.html + + // [Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn] + let N0 = [0, 125.1228, 48.3313, 76.6799, 49.5574, 100.4542, 113.6634] + let Ndot = [0, -0.0529538083, 3.24587e-5, 2.46590e-5, 2.11081e-5, 2.76854e-5, 2.38980e-5] + let i0 = [0, 5.1454, 7.0047, 3.3946, 1.8497, 1.3030, 2.4886] + let idot = [0, 0, 5.00e-8, 2.75e-8, -1.78e-8, -1.557e-7, -1.081e-7] + let w0 = [282.9404, 318.0634, 29.1241, 54.8910, 286.5016, 273.8777, 339.3939] + let wdot = [4.70935e-5, 0.1643573223, 1.01444e-5, 1.38374e-5, 2.92961e-5, 1.64505e-5, 2.97661e-5] + let a = [1, 60.2666, 0.387098, 0.723330, 1.523688, 5.20256, 9.55475] + let e0 = [0.016709, 0.054900, 0.205635, 0.006773, 0.093405, 0.048498, 0.055546] + let edot = [-1.151e-9, 0, 5.59e-10, -1.302e-9, 2.516e-9, 4.469e-9, -9.499e-9] + let M0 = [356.0470, 115.3654, 168.6562, 48.0052, 18.6021, 19.8950, 316.9670] + let Mdot = [0.9856002585, 13.0649929509, 4.0923344368, 1.6021302244, 0.5240207766, 0.0830853001, 0.0334442282] + let d0 = [0.533128, 32.228, 0.00187, 0.004700, 0.00259, 0.05306, 0.0439] + + var N: [Double] = .init(repeating: 0, count: 7) // longitude of the ascending node + var I: [Double] = .init(repeating: 0, count: 7) // inclination to the ecliptic (plane of the Earth's orbit) + var w: [Double] = .init(repeating: 0, count: 7) // argument of perihelion + var e: [Double] = .init(repeating: 0, count: 7) // eccentricity (0=circle, 0-1=ellipse, 1=parabola) + var M: [Double] = .init(repeating: 0, count: 7) // mean anomaly (0 at perihelion; increases uniformly with time) + var E: [Double] = .init(repeating: 0, count: 7) // eccentric anomaly + var xv: [Double] = .init(repeating: 0, count: 7) + var yv: [Double] = .init(repeating: 0, count: 7) + var v: [Double] = .init(repeating: 0, count: 7) + var r: [Double] = .init(repeating: 0, count: 7) + + let ecl = (23.4393 - 3.563e-7 * T) * Double.pi / 180 + + for i in selection { + N[i] = (N0[i] + T * Ndot[i]) * Double.pi / 180 // radian + I[i] = (i0[i] + T * idot[i]) * Double.pi / 180 // radian + w[i] = (w0[i] + T * wdot[i]) * Double.pi / 180 // radian + e[i] = e0[i] + T * edot[i] + M[i] = (M0[i] + T * Mdot[i]) * Double.pi / 180 // radian + + // First, compute the eccentric anomaly E from the mean anomaly M and from the eccentricity e + E[i] = M[i] + e[i] * sin(M[i]) * (1 + e[i] * cos(M[i])) // radian + var iterE = E[i] - (E[i] - e[i] * sin(E[i]) - M[i]) / (1 - e[i] * cos(E[i])) + while abs(E[i] - iterE) > 1e-5 { + E[i] = iterE + iterE = E[i] - (E[i] - e[i] * sin(E[i]) - M[i]) / (1 - e[i] * cos(E[i])) + } + + // Then compute the Sun's distance r and its true anomaly v from: + xv[i] = a[i] * (cos(E[i]) - e[i]) + yv[i] = a[i] * sqrt(1 - e[i] * e[i]) * sin(E[i]) + v[i] = atan2(yv[i], xv[i]) + r[i] = sqrt(xv[i] * xv[i] + yv[i] * yv[i]) + } + + var xh: [Double] = .init(repeating: 0, count: 7) + var yh: [Double] = .init(repeating: 0, count: 7) + var zh: [Double] = .init(repeating: 0, count: 7) + var lonecl: [Double] = .init(repeating: 0, count: 7) + var latecl: [Double] = .init(repeating: 0, count: 7) + + for i in selection { + // Compute the planet's position in 3-dimensional space: + xh[i] = r[i] * (cos(N[i]) * cos(v[i] + w[i]) - sin(N[i]) * sin(v[i] + w[i]) * cos(I[i])) + yh[i] = r[i] * (sin(N[i]) * cos(v[i] + w[i]) + cos(N[i]) * sin(v[i] + w[i]) * cos(I[i])) + zh[i] = r[i] * (sin(v[i] + w[i]) * sin(I[i])) + + // For the Moon, this is the geocentric (Earth-centered) position in the ecliptic coordinate system. For the planets, this is the heliocentric (Sun-centered) position, also in the ecliptic coordinate system. + lonecl[i] = atan2(yh[i], xh[i]) + latecl[i] = atan2(zh[i], sqrt(xh[i] * xh[i] + yh[i] * yh[i])) } - while E - E0 > tol && iter < maxit { - let E1 = 0.5*(E + E0) - let z = E1 - e*sin(E1) - Mp - if z > 0.0 { - E = E1 + + // Moon perturbations + let Ls = M[0] + w[0] // Mean Longitude of the Sun (Ns=0) + if selection.contains(1) { + let Lm = M[1] + w[1] + N[1] // Mean longitude of the Moon + let D = Lm - Ls // Mean elongation of the Moon + let F = Lm - N[1] // Argument of latitude for the Moon + var lonAdj = 1.274 * sin(M[1] - 2 * D) // the Evection + lonAdj -= 1.274 * sin(M[1] - 2 * D) // the Evection + lonAdj += 0.658 * sin(2 * D) // the Variation + lonAdj -= 0.186 * sin(M[0]) // the Yearly Equation + lonAdj -= 0.059 * sin(2 * M[1] - 2 * D) + lonAdj -= 0.057 * sin(M[1] - 2 * D + M[0]) + lonAdj += 0.053 * sin(M[1] + 2 * D) + lonAdj += 0.046 * sin(2 * D - M[0]) + lonAdj += 0.041 * sin(M[1] - M[0]) + lonAdj -= 0.035 * sin(D) // the Parallactic Equation + lonAdj -= 0.031 * sin(M[1] + M[0]) + lonAdj -= 0.015 * sin(2 * F - 2 * D) + lonAdj += 0.011 * sin(M[1] - 4 * D) + var latAdj = -0.173 * sin(F - 2 * D) + latAdj -= 0.055 * sin(M[1] - F - 2 * D) + latAdj -= 0.046 * sin(M[1] + F - 2 * D) + latAdj += 0.033 * sin(F + 2 * D) + latAdj += 0.017 * sin(2 * M[1] + F) + lonecl[1] += lonAdj * Double.pi / 180 + latecl[1] += latAdj * Double.pi / 180 + r[1] -= 0.58 * cos(M[1] - 2 * D) + r[1] -= 0.46 * cos(2 * D) + } + + // Jupiter perterbations + if selection.contains([5, 6]) { + var lonAdjJ = -0.332 * sin(2 * M[5] - 5 * M[6] - 67.6 / 180 * Double.pi) + lonAdjJ -= 0.056 * sin(2 * M[5] - 2 * M[6] + 21 / 180 * Double.pi) + lonAdjJ += 0.042 * sin(3 * M[5] - 5 * M[6] + 21 / 180 * Double.pi) + lonAdjJ -= 0.036 * sin(M[5] - 2 * M[6]) + lonAdjJ += 0.022 * cos(M[5] - M[6]) + lonAdjJ += 0.023 * sin(2 * M[5] - 3 * M[6] + 52 / 180 * Double.pi) + lonAdjJ -= 0.016 * sin(M[5] - 5 * M[6] - 69 / 180 * Double.pi) + var lonAdjS = 0.812 * sin(2 * M[5] - 5 * M[6] - 67.6 / 180 * Double.pi) + lonAdjS -= 0.229 * cos(2 * M[5] - 4 * M[6] - 2 / 180 * Double.pi) + lonAdjS += 0.119 * sin(M[5] - 2 * M[6] - 3 / 180 * Double.pi) + lonAdjS += 0.046 * sin(2 * M[5] - 6 * M[6] - 69 / 180 * Double.pi) + lonAdjS += 0.014 * sin(M[5] - 3 * M[6] + 32 / 180 * Double.pi) + var latAdjS = -0.020 * cos(2 * M[5] - 4 * M[6] - 2 / 180 * Double.pi) + latAdjS += 0.018 * sin(2 * M[5] - 6 * M[6] - 49 / 180 * Double.pi) + lonecl[5] += lonAdjJ * Double.pi / 180 + lonecl[6] += lonAdjS * Double.pi / 180 + latecl[6] += latAdjS * Double.pi / 180 + } + + var xg: [Double] = .init(repeating: 0, count: 7) + var yg: [Double] = .init(repeating: 0, count: 7) + var zg: [Double] = .init(repeating: 0, count: 7) + var xe: [Double] = .init(repeating: 0, count: 7) + var ye: [Double] = .init(repeating: 0, count: 7) + var ze: [Double] = .init(repeating: 0, count: 7) + var ra: [Double] = .init(repeating: 0, count: 7) + var dec: [Double] = .init(repeating: 0, count: 7) + var rho: [Double] = .init(repeating: 0, count: 7) + + for i in selection { + xh[i] = r[i] * cos(lonecl[i]) * cos(latecl[i]) + yh[i] = r[i] * sin(lonecl[i]) * cos(latecl[i]) + zh[i] = r[i] * sin(latecl[i]) + + // Earth centered + if i > 1 { + xg[i] = xh[i] + xh[0] + yg[i] = yh[i] + yh[0] + zg[i] = zh[i] + zh[0] } else { - E0 = E1 + xg[i] = xh[i] + yg[i] = yh[i] + zg[i] = zh[i] } - iter += 1 - } - } - return E -} + // Equatorial + xe[i] = xg[i] + ye[i] = yg[i] * cos(ecl) - zg[i] * sin(ecl) + ze[i] = yg[i] * sin(ecl) + zg[i] * cos(ecl) -// Planet positions at T -// The planet data are stored in an array in this order: -// Mercury, Venus, Mars, Jupiter, Saturn -// The second argument, calculate, is a logical -// vector of length 8, true if the planet position -// is to be calculated. For example, to calculate -// the position of Mars only, set calculate to -// [false,false,false,true,false,false,false,false] -// -// output: Ra's amd Dec's in radians -// For planets whose positions are not calculated, as indicated -// in the variable 'calculate', ra and dec are not defined. -func planetPos(T: Double) -> [Double] { - let pi2 = 2*Double.pi - // 1/light speed in century/AU - let f1oc = 1.58125073358306e-07 - let cosEps = cos(eps) - let sinEps = sin(eps) - - // Angles have been converted to radians - let a0: [Double], adot: [Double], e0: [Double], edot: [Double], I0: [Double], Idot: [Double], L0: [Double], Ldot: [Double], pom0: [Double], pomdot: [Double], Omg0: [Double], Omgdot: [Double] - let b: [Double], c: [Double], s: [Double], f: [Double] - if T > -2, T < 0.5 { - // use the parameters for 1800 AD - 2050 AD - a0 = [1.00000261, 0.38709927, 0.72333566, 1.52371034, 5.202887, 9.53667594] - adot = [0.00000562, 0.00000037, 0.0000039, 0.00001847, -0.00011607, -0.0012506] - e0 = [0.01671123, 0.20563593, 0.00677672, 0.09339410, 0.04838624, 0.05386179] - edot = [-0.00004392, 0.00001906, -0.00004107, 0.00007882, -0.00013253, -0.00050991] - I0 = [-2.67209908480332e-07, 0.122259947932126, 0.0592482741110957, 0.0322832054248893, 0.0227660215304719, 0.0433887433093108] - Idot = [-0.000225962193202099, -0.000103803282729438, -1.37689024689833e-05, -0.00014191813200034, -3.20641418200886e-05, 3.3791145114937e-05] - L0 = [1.75343755707279, 4.40259868429583, 3.17613445608937, -0.0794723815383351, 0.600331137865858, 0.87186603715888] - Ldot = [628.307577900922, 2608.79030501053, 1021.32854958241, 334.061301681387, 52.966311891386, 21.3365387887055] - pom0 = [1.79660147404917, 1.35189357642502, 2.29689635603878, -0.41789517122344, 0.257060466847075, 1.61615531016306] - pomdot = [0.00564218940290684, 0.00280085010386076, 4.68322452858386e-05, 0.00775643308768542, 0.00370929031433238, -0.00731244366619248] - Omg0 = [0, 0.843530995489199, 1.33831572240834, 0.864977129749742, 1.75360052596996, 1.9837835429754] - Omgdot = [0, -0.00218760982161663, -0.00484667775462579, -0.00510636965735315, 0.00357253294639726, -0.00503838053087464] - b = [0, 0, 0, 0, 0, 0] - c = [0, 0, 0, 0, 0, 0] - s = [0, 0, 0, 0, 0, 0] - f = [0, 0, 0, 0, 0, 0] - } else { - // use the parameters for 3000 BC - 3000 AD - a0 = [1.00000018, 0.38709843, 0.72332102, 1.52371243, 5.20248019, 9.54149883] - adot = [-0.00000003, 0, -0.00000026, 0.00000097, -0.00002864, -0.00003065] - e0 = [0.01673163, 0.20563661, 0.00676399, 0.09336511, 0.0485359, 0.05550825] - edot = [-0.00003661, 0.00002123, -0.00005107, 0.00009149, 0.00018026, -0.00032044] - I0 = [-9.48516635288838e-06, 0.122270686943013, 0.059302368845932, 0.0323203332904682, 0.0226650928050204, 0.0435327181373017] - Idot = [-0.000233381587852327, -0.000103002002069847, 7.59113504862414e-06, -0.000126493959268765, -5.63216004289318e-05, 7.88834716694625e-05] - L0 = [1.75347846863765, 4.40262213698312, 3.17614508514451, -0.0797289377825283, 0.599255160009829, 0.873986072195182] - Ldot = [628.307588608167, 2608.79031817869, 1021.32855334028, 334.061243342709, 52.9690623526126, 21.3299296671748] - pom0 = [1.79646842620403, 1.35189222676191, 2.29977771922823, -0.417438213482006, 0.249144920643598, 1.62073649087534] - pomdot = [0.00554931973527652, 0.00278205709660699, 0.000991285579543109, 0.00789301155937221, 0.00317635891415782, 0.00945610278111832] - Omg0 = [-0.08923177123077, 0.843685496572442, 1.33818957716586, 0.867659193442843, 1.75044003925455, 1.98339193542262] - Omgdot = [-0.00421040715476989, -0.00213177691337826, -0.00476024137061832, -0.00468663333114593, 0.00227322485367811, -0.00436594147292966] - b = [0, 0, 0, 0, -2.17328398458334e-06, 4.52022822974011e-06] - c = [0, 0, 0, 0, 0.00105837813038487, -0.0023447571730711] - s = [0, 0, 0, 0, -0.00621955723490303, 0.0152402406847545] - f = [0, 0, 0, 0, 0.669355584755475, 0.669355584755475] - } + ra[i] = atan2(ye[i], xe[i]) + dec[i] = atan2(ze[i], sqrt(xe[i] * xe[i] + ye[i] * ye[i])) + rho[i] = sqrt(xe[i] * xe[i] + ye[i] * ye[i] + ze[i] * ze[i]) + } - var xp: Double, yp: Double, zp: Double - var x: [Double] = [0, 0, 0, 0, 0, 0] - var y: [Double] = [0, 0, 0, 0, 0, 0] - var z: [Double] = [0, 0, 0, 0, 0, 0] - var rGeo: [Double] = [0, 0, 0, 0, 0, 0] - var vx: [Double] = [0, 0, 0, 0, 0, 0] - var vy: [Double] = [0, 0, 0, 0, 0, 0] - var vz: [Double] = [0, 0, 0, 0, 0, 0] - - for i in 0..<6 { - let a = a0[i] + adot[i]*T - let e = e0[i] + edot[i]*T - let I = I0[i] + Idot[i]*T - let L = L0[i] + (Ldot[i]*T % pi2) - let pom = pom0[i] + pomdot[i]*T - let Omg = Omg0[i] + Omgdot[i]*T - let omg = pom - Omg - var M = L - pom - M += b[i]*T*T + c[i]*cos(f[i]*T) + s[i]*sin(f[i]*T) - let E = kepler(M: M, e: e) - let bb = a*sqrt(1 - e*e) - let Edot = Ldot[i] / (1 - e*cos(E)) - xp = a*(cos(E) - e) - yp = bb*sin(E) - let vxp = -a*sin(E)*Edot - let vyp = bb*cos(E)*Edot - let m11 = cos(omg)*cos(Omg) - sin(omg)*sin(Omg)*cos(I) - let m12 = -sin(omg)*cos(Omg) - cos(omg)*sin(Omg)*cos(I) - x[i] = m11*xp + m12*yp - vx[i] = m11*vxp + m12*vyp - let m21 = cos(omg)*sin(Omg) + sin(omg)*cos(Omg)*cos(I) - let m22 = cos(omg)*cos(Omg)*cos(I) - sin(omg)*sin(Omg) - y[i] = m21*xp + m22*yp - vy[i] = m21*vxp + m22*vyp - let m31 = sin(omg)*sin(I) - let m32 = cos(omg)*sin(I) - z[i] = m31*xp + m32*yp - vz[i] = m31*vxp + m32*vyp - } + var lst: Double? + if let location = Loc { + let gclat = (location.lat - 0.1924 * sin(2 * location.lat * Double.pi / 180)) * Double.pi / 180 + let rEarth = 0.99883 + 0.00167 * cos(2 * location.lat * Double.pi / 180) + let gmst0 = Ls + Double.pi + lst = gmst0 + (T - floor(T)) * 2 * Double.pi + location.lon * Double.pi / 180 + + // Topocentric correction for moon + if selection.contains(1) { + let ha = lst! - ra[1] + let mpar = asin(1 / (rho[1])) + let g = atan(tan(gclat) / cos(ha)) + let topRa = ra[1] - mpar * rEarth * cos(gclat) * sin(ha) / cos(dec[1]) + let topDec = if abs(g) > 1e-5 { + dec[1] - mpar * rEarth * sin(gclat) * sin(g - dec[1]) / sin(g) + } else { + dec[1] - mpar * rEarth * sin(-dec[1]) * cos(ha) + } + ra[1] = topRa + dec[1] = topDec + } + } - // heliocentric position -> geocentric position - // index 2 becomes Sun's geocentric position - x[0] = -x[0]; y[0] = -y[0]; z[0] = -z[0] - // let dT; - for i in 1..<6 { - x[i] = x[i] + x[0] - y[i] = y[i] + y[0] - z[i] = z[i] + z[0] - rGeo[i] = sqrt(x[i]*x[i] + y[i]*y[i] + z[i]*z[i]) - // correct for light time - let dT = rGeo[i]*f1oc - x[i] -= vx[i]*dT - y[i] -= vy[i]*dT - z[i] -= vz[i]*dT - } + var d: [Double] = .init(repeating: 0, count: 7) + for i in selection { + ra[i] = normalize(radian: ra[i]) + dec[i] = normalize(radian: dec[i]) + d[i] = (d0[i] * Double.pi / 180) / rho[i] + } + rho[1] *= earthRadiiInAU - // RA and Dec with respect to J2000 - let p = precession_matrix(T0: 0, T: T) - - var output = [Double]() - for i in 1..<6 { - // equatorial coordinates - let xeq = x[i] - let yeq = cosEps*y[i] - sinEps*z[i] - let zeq = sinEps*y[i] + cosEps*z[i] - - // precessed to the mean equator and equinox of the date - xp = p.p11*xeq + p.p12*yeq + p.p13*zeq - yp = p.p21*xeq + p.p22*yeq + p.p23*zeq - zp = p.p31*xeq + p.p32*yeq + p.p33*zeq - - // to eliptic coordinates - let xel = xp - let yel = cosEps*yp + sinEps*zp - // let zel = - sinEps*yp + cosEps*zp - output.append(atan2(yel, xel)) + return (lst: lst, ra: ra, dec: dec, r: rho, d: d) } - return output -} -func moonCoordinate(D: Double) -> (Double, Double, Double) { - var l = 0.606434 + 0.03660110129*D - var m = 0.374897 + 0.03629164709*D - var f = 0.259091 + 0.03674819520*D - var d = 0.827362 + 0.03386319198*D - var n = 0.347343 - 0.00014709391*D - var g = 0.993126 + 0.00273777850*D - - l = 2*Double.pi*(l - floor(l)) - m = 2*Double.pi*(m - floor(m)) - f = 2*Double.pi*(f - floor(f)) - d = 2*Double.pi*(d - floor(d)) - n = 2*Double.pi*(n - floor(n)) - g = 2*Double.pi*(g - floor(g)) - - var v: Double, u: Double, w: Double - v = 0.39558*sin(f + n) - + 0.08200*sin(f) - + 0.03257*sin(m - f - n) - + 0.01092*sin(m + f + n) - + 0.00666*sin(m - f) - - 0.00644*sin(m + f - 2*d + n) - - 0.00331*sin(f - 2*d + n) - - 0.00304*sin(f - 2*d) - - 0.00240*sin(m - f - 2*d - n) - + 0.00226*sin(m + f) - - 0.00108*sin(m + f - 2*d) - - 0.00079*sin(f - n) - + 0.00078*sin(f + 2*d + n) - - u = 1 - - 0.10828*cos(m) - - 0.01880*cos(m - 2*d) - - 0.01479*cos(2*d) - + 0.00181*cos(2*m - 2*d) - - 0.00147*cos(2*m) - - 0.00105*cos(2*d - g) - - 0.00075*cos(m - 2*d + g) - - w = 0.10478*sin(m) - - 0.04105*sin(2*f + 2*n) - - 0.02130*sin(m - 2*d) - - 0.01779*sin(2*f + n) - + 0.01774*sin(n) - + 0.00987*sin(2*d) - - 0.00338*sin(m - 2*f - 2*n) - - 0.00309*sin(g) - - 0.00190*sin(2*f) - - 0.00144*sin(m + n) - - 0.00144*sin(m - 2*f - n) - - 0.00113*sin(m + 2*f + 2*n) - - 0.00094*sin(m - 2*d + g) - - 0.00092*sin(2*m - 2*d) - - var s: Double - s = w / sqrt(u - v*v) - let rightAscension = l + atan(s / sqrt(1 - s*s)) - - s = v / sqrt(u) - let declination = atan(s / sqrt(1 - s*s)) - - let distance = 60.40974*sqrt(u) - - let x = cos(rightAscension)*cos(declination)*distance - let y = sin(rightAscension)*cos(declination)*distance - let z = sin(declination)*distance - - // RA and Dec with respect to J2000 - let p = precession_matrix(T0: 0, T: D / 36525) - // precessed to the mean equator and equinox of the date - let x_new = p.p11*x + p.p12*y + p.p13*z - let y_new = p.p21*x + p.p22*y + p.p23*z - let z_new = p.p31*x + p.p32*y + p.p33*z - - return (x: x_new, y: y_new, z: z_new) + private static func fromJD2000(date: Date) -> Double { + let dateComponents = Calendar.utcCalendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond], from: date) + let (year, month, day, hour, minute, second, nanosecond) = (dateComponents.year!, dateComponents.month!, dateComponents.day!, dateComponents.hour!, dateComponents.minute!, dateComponents.second!, dateComponents.nanosecond!) + let dayNumber = 367 * year - 7 * (year + (month + 9) / 12) / 4 - 3 * ((year + (month - 9) / 7) / 100 + 1) / 4 + 275 * month / 9 + day - 730515 + let timeComponent = Double(hour) + Double(minute) / 60 + (Double(second) + Double(nanosecond) / 1e9) / 3600 + return Double(dayNumber) + timeComponent / 24 + } } -func moonElipticPosition(D: Double) -> Double { - let (x, y, z) = moonCoordinate(D: D) - // Back to eliptic - let yel = cos(eps)*y + sin(eps)*z - return atan2(yel, x) +enum RiseSetType { + case sunrise, sunset, moonrise, moonset } - -func moonEquatorPosition(D: Double) -> (Double, Double, Double) { - let (x, y, z) = moonCoordinate(D: D) - return (ra: atan2(y, x), dec: atan2(z, sqrt(x*x + y*y)), sqrt(x*x + y*y + z*z)) +enum MeridianType { + case noon, midnight, highMoon, lowMoon } -func equationOfTime(D: Double) -> Double { - let d = D / 36525 - let epsilon = (23.4393 - 0.013*d - 2e-7*pow(d, 2) + 5e-7*pow(d, 3)) / 180*Double.pi - let e = 1.6709e-2 - 4.193e-5*d - 1.26e-7*pow(d, 2) - let lambdaP = (282.93807 + 1.7195*d + 3.025e-4*pow(d, 2)) / 180*Double.pi - let y = pow(tan(epsilon / 2), 2) - let m = 6.24004077 + 0.01720197*D - var deltaT = -2*e*sin(m) + y*sin(2*(m + lambdaP)) - deltaT += -1.25*pow(e, 2)*sin(2*m) + 4*e*y*sin(m)*cos(2*(m + lambdaP)) - 0.5*pow(y, 2)*sin(4*(m + lambdaP)) - return deltaT +func riseSetTime(around time: Date, at loc: GeoLocation, type: RiseSetType, iteration: Int = 0) -> Date? { + let solarSystem: SolarSystem + let planet: SolarSystem.Planet + switch type { + case .sunrise, .sunset: + solarSystem = SolarSystem(time: time, loc: loc, targets: .sun) + planet = solarSystem.planets.sun + case .moonrise, .moonset: + solarSystem = SolarSystem(time: time, loc: loc, targets: .sunMoon) + planet = solarSystem.planets.moon + } + let timeUntilNoon = SolarSystem.normalize(radian: planet.loc.ra - solarSystem.localSiderialTime!) + let solarHeight = -planet.diameter / 2 - SolarSystem.aeroAdj + let localHourAngle = (sin(solarHeight) - sin(loc.lat / 180 * Double.pi) * sin(planet.loc.decl)) / (cos(loc.lat / 180 * Double.pi) * cos(planet.loc.decl)) + + if abs(localHourAngle) < 1 || iteration < 3 { + let netTime = switch type { + case .sunrise, .moonrise: + timeUntilNoon - acos(min(1, max(-1, localHourAngle))) + case .sunset, .moonset: + timeUntilNoon + acos(min(1, max(-1, localHourAngle))) + } + let dTime = netTime / Double.pi * 43082.04 + if abs(dTime) < 14.4 && abs(localHourAngle) < 1 { + return time + } else { + return riseSetTime(around: time + dTime, at: loc, type: type, iteration: iteration + 1) + } + } else { + return nil + } } -func daytimeOffset(latitude: Double, progressInYear: Double) -> Double { - let denominator = sqrt(pow(cos(eps), 2) + pow(sin(eps)*sin(progressInYear), 2))*cos(latitude) - let numerator = sin(latitude)*sin(eps)*cos(progressInYear) - sin(aeroAdj) - let cosValue = numerator / denominator - if cosValue >= 1 { - return -Double.infinity - } else if cosValue <= -1 { - return Double.infinity +func meridianTime(around time: Date, at loc: GeoLocation, type: MeridianType, iteration: Int = 0) -> Date? { + let solarSystem: SolarSystem + let planet: SolarSystem.Planet + switch type { + case .noon, .midnight: + solarSystem = SolarSystem(time: time, loc: loc, targets: .sun) + planet = solarSystem.planets.sun + case .highMoon, .lowMoon: + solarSystem = SolarSystem(time: time, loc: loc, targets: .sunMoon) + planet = solarSystem.planets.moon + } + let offset = switch type { + case .noon, .highMoon: + 0.0 + case .midnight, .lowMoon: + Double.pi + } + let timeUntilNoon = SolarSystem.normalize(radian: planet.loc.ra - solarSystem.localSiderialTime! + offset) + + let dTime = timeUntilNoon / Double.pi * 43082.04 + if abs(dTime) < 14.4 { + let latInRadian = loc.lat * Double.pi / 180 + let localHourAngle = solarSystem.localSiderialTime! - planet.loc.ra + let solarHeightSin = sin(latInRadian) * sin(planet.loc.decl) + cos(latInRadian) * cos(planet.loc.decl) * cos(localHourAngle) + let solarHeight = asin(solarHeightSin) + let solarHeightMin = -planet.diameter / 2 - SolarSystem.aeroAdj + switch type { + case .noon, .highMoon: + if solarHeight >= solarHeightMin { + return time + } else { + return nil + } + case .midnight, .lowMoon: + if solarHeight < solarHeightMin { + return time + } else { + return nil + } + } } else { - return acos(cosValue) + return meridianTime(around: time + dTime, at: loc, type: type, iteration: iteration + 1) } } -func lunarTimeOffset(latitude: Double, jdTime: Double, light: Bool) -> Double { - let (_, dec, dist) = moonEquatorPosition(D: jdTime) - let parallaxAdj = asin((1 - 0.273) / dist) - let cosValue = (sin(latitude)*sin(dec) - sin(aeroAdj - parallaxAdj)) / (cos(dec)*cos(latitude))*(light ? 1 : -1) - if cosValue >= 1 { - return Double.infinity - } else if cosValue <= -1 { - return -Double.infinity +func dayStart(around time: Date, at loc: GeoLocation, iteration: Int = 0) -> Date { + let solarSystem = SolarSystem(time: time, loc: loc, targets: .sun) + let planet = solarSystem.planets.sun + let offset = Double.pi + let timeUntilMidnight = SolarSystem.normalize(radian: planet.loc.ra - solarSystem.localSiderialTime! + offset) + + let dTime = timeUntilMidnight / Double.pi * 43082.04 + if abs(dTime) < 1 { + return time } else { - return Double.pi - acos(cosValue) + return dayStart(around: time + dTime, at: loc, iteration: iteration + 1) } } diff --git a/Shared/Locale.swift b/Shared/Locale.swift index 1ddd624..0cfe42c 100644 --- a/Shared/Locale.swift +++ b/Shared/Locale.swift @@ -23,8 +23,8 @@ extension Locale { } return isEastAsian } - - static let translation: [String : String] = [ + + static let translation: [String: String] = [ "夜中": NSLocalizedString("夜中", comment: ""), "日出": NSLocalizedString("日出", comment: ""), "日中": NSLocalizedString("日中", comment: ""), "日入": NSLocalizedString("日入", comment: ""), "月出": NSLocalizedString("月出", comment: ""), "月中": NSLocalizedString("月中", comment: ""), "月入": NSLocalizedString("月入", comment: ""), "朔": NSLocalizedString("朔", comment: ""), "望": NSLocalizedString("望", comment: ""), diff --git a/Shared/Localizable.xcstrings b/Shared/Localizable.xcstrings index 73924b7..551fce2 100644 --- a/Shared/Localizable.xcstrings +++ b/Shared/Localizable.xcstrings @@ -656,9 +656,6 @@ } } } - }, - "你好" : { - }, "僅時" : { "localizations" : { @@ -1294,6 +1291,7 @@ } }, "填" : { + "comment" : "Planet Name", "localizations" : { "en" : { "stringUnit" : { @@ -1636,7 +1634,7 @@ } }, "太白" : { - "comment" : "Venus Indicator", + "comment" : "Planet Name", "localizations" : { "en" : { "stringUnit" : { @@ -4038,7 +4036,7 @@ } }, "月" : { - "comment" : "Moon position Indicator", + "comment" : "Planet Name", "localizations" : { "en" : { "stringUnit" : { @@ -4641,7 +4639,7 @@ } }, "歲" : { - "comment" : "Jupiter Indicator", + "comment" : "Planet Name", "localizations" : { "en" : { "stringUnit" : { @@ -5016,7 +5014,7 @@ } }, "熒惑" : { - "comment" : "Mars Indicator", + "comment" : "Planet Name", "localizations" : { "en" : { "stringUnit" : { @@ -6845,7 +6843,7 @@ } }, "辰" : { - "comment" : "Mercury Indicator", + "comment" : "Planet Name", "localizations" : { "en" : { "stringUnit" : { @@ -7388,4 +7386,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/Shared/Setting/CalendarConfig.swift b/Shared/Setting/CalendarConfig.swift index f06c1fb..9d22d1d 100644 --- a/Shared/Setting/CalendarConfig.swift +++ b/Shared/Setting/CalendarConfig.swift @@ -26,7 +26,7 @@ struct ConfigList: View { #endif @State private var newName = "" @State private var errorMsg = "" - @State private var target: ConfigData? = nil + @State private var target: ConfigData? private var invalidName: Bool { return !validateName(newName) } @@ -41,7 +41,7 @@ struct ConfigList: View { return "" } } - + var body: some View { let newConfig = Button { newName = validName(NSLocalizedString("佚名", comment: "unnamed")) @@ -49,7 +49,7 @@ struct ConfigList: View { } label: { Label("謄錄", systemImage: "square.and.pencil") } - + let newConfigConfirm = Button(NSLocalizedString("此名甚善", comment: "Confirm adding Settings"), role: .destructive) { let newConfig = ConfigData(name: newName, code: calendarConfigure.encode()) modelContext.insert(newConfig) @@ -61,7 +61,7 @@ struct ConfigList: View { errorAlert = true } } - + let renameConfirm = Button(NSLocalizedString("此名甚善", comment: "Confirm adding Settings"), role: .destructive) { if let target = target, !target.isNil { let isChangingCurrent = target.name == calendarConfigure.name @@ -88,7 +88,7 @@ struct ConfigList: View { } label: { Label("讀入", systemImage: "square.and.arrow.down") } - + let moreMenu = Menu { VStack { newConfig @@ -100,7 +100,7 @@ struct ConfigList: View { } .menuIndicator(.hidden) .menuStyle(.automatic) - + Form { if configs.count > 0 { Section { @@ -125,17 +125,17 @@ struct ConfigList: View { displayText.append(calendar.hourString + calendar.quarterString) return displayText.joined(separator: " ") }() - + let dateLabel = Text(String(chineseDate.reversed())) .foregroundStyle(.secondary) - + let nameLabel = Label { Text(config.name! == AppInfo.defaultName ? NSLocalizedString("常用", comment: "") : config.name!) } icon: { Image(systemName: config.name! == calendarConfigure.name ? "circle.inset.filled" : "circle") .foregroundStyle(Color.blue) } - + let saveButton = Button { #if os(macOS) if !config.isNil { @@ -148,14 +148,14 @@ struct ConfigList: View { } label: { Label("寫下", systemImage: "square.and.arrow.up") } - + let deleteButton = Button(role: .destructive) { target = config deleteAlert = true } label: { Label("刪", systemImage: "trash") } - + let renameButton = Button { target = config newName = validName(targetName) @@ -274,7 +274,7 @@ struct ConfigList: View { } #endif } - + func switchTo(config: ConfigData) { if config.name != calendarConfigure.name { calendarConfigure.update(from: config.code!, newName: config.name!) @@ -292,7 +292,7 @@ struct ConfigList: View { return false } } - + func validName(_ name: String) -> String { var (baseName, i) = reverseNumberedName(name) while !validateName(numberedName(baseName, number: i)) { @@ -300,7 +300,7 @@ struct ConfigList: View { } return numberedName(baseName, number: i) } - + func removeDuplicates() { var records = Set() for data in configs { @@ -315,7 +315,7 @@ struct ConfigList: View { } } } - + #if os(macOS) @MainActor func handleFile(_ file: URL) throws { diff --git a/Shared/Setting/ColorSetting.swift b/Shared/Setting/ColorSetting.swift index 333af0f..16404d2 100644 --- a/Shared/Setting/ColorSetting.swift +++ b/Shared/Setting/ColorSetting.swift @@ -10,7 +10,7 @@ import SwiftUI struct ColorSettingCell: View { let text: Text @Binding var color: CGColor - + var body: some View { HStack { text @@ -26,27 +26,27 @@ struct ColorSettingCell: View { struct ColorSetting: View { @Environment(WatchLayout.self) var watchLayout @Environment(WatchSetting.self) var watchSetting - + var body: some View { Form { Section(header: Text("五星", comment: "Planets")) { HStack(spacing: 20) { - ColorSettingCell(text: Text("辰", comment: ""), color: watchLayout.binding(\.planetIndicator[0])) + ColorSettingCell(text: Text("辰", comment: ""), color: watchLayout.binding(\.planetIndicator.mercury)) Divider() - ColorSettingCell(text: Text("太白", comment: ""), color: watchLayout.binding(\.planetIndicator[1])) + ColorSettingCell(text: Text("太白", comment: ""), color: watchLayout.binding(\.planetIndicator.venus)) } HStack(spacing: 20) { - ColorSettingCell(text: Text("熒惑", comment: ""), color: watchLayout.binding(\.planetIndicator[2])) + ColorSettingCell(text: Text("熒惑", comment: ""), color: watchLayout.binding(\.planetIndicator.mars)) Divider() - ColorSettingCell(text: Text("歲", comment: ""), color: watchLayout.binding(\.planetIndicator[3])) + ColorSettingCell(text: Text("歲", comment: ""), color: watchLayout.binding(\.planetIndicator.jupiter)) } HStack(spacing: 20) { - ColorSettingCell(text: Text("填", comment: ""), color: watchLayout.binding(\.planetIndicator[4])) + ColorSettingCell(text: Text("填", comment: ""), color: watchLayout.binding(\.planetIndicator.saturn)) Divider() - ColorSettingCell(text: Text("月", comment: ""), color: watchLayout.binding(\.planetIndicator[5])) + ColorSettingCell(text: Text("月", comment: ""), color: watchLayout.binding(\.planetIndicator.moon)) } } - + Section(header: Text("朔望節氣", comment: "Moon phase and Solor terms")) { HStack(spacing: 20) { ColorSettingCell(text: Text("朔", comment: ""), color: watchLayout.binding(\.eclipseIndicator)) @@ -59,28 +59,28 @@ struct ColorSetting: View { ColorSettingCell(text: Text("中氣", comment: ""), color: watchLayout.binding(\.evenStermIndicator)) } } - + Section(header: Text("日出入", comment: "Sunrise & Sunset Indicators")) { HStack(spacing: 20) { - ColorSettingCell(text: Text("日出", comment: ""), color: watchLayout.binding(\.sunPositionIndicator[1])) + ColorSettingCell(text: Text("日出", comment: ""), color: watchLayout.binding(\.sunPositionIndicator.sunrise)) Divider() - ColorSettingCell(text: Text("日中", comment: ""), color: watchLayout.binding(\.sunPositionIndicator[2])) + ColorSettingCell(text: Text("日中", comment: ""), color: watchLayout.binding(\.sunPositionIndicator.noon)) } HStack(spacing: 20) { - ColorSettingCell(text: Text("日入", comment: ""), color: watchLayout.binding(\.sunPositionIndicator[3])) + ColorSettingCell(text: Text("日入", comment: ""), color: watchLayout.binding(\.sunPositionIndicator.sunset)) Divider() - ColorSettingCell(text: Text("夜中", comment: ""), color: watchLayout.binding(\.sunPositionIndicator[0])) + ColorSettingCell(text: Text("夜中", comment: ""), color: watchLayout.binding(\.sunPositionIndicator.midnight)) } } - + Section(header: Text("月出入", comment: "Moonrise & Moonset")) { HStack(spacing: 20) { - ColorSettingCell(text: Text("月出", comment: ""), color: watchLayout.binding(\.moonPositionIndicator[0])) + ColorSettingCell(text: Text("月出", comment: ""), color: watchLayout.binding(\.moonPositionIndicator.moonrise)) Divider() - ColorSettingCell(text: Text("月中", comment: ""), color: watchLayout.binding(\.moonPositionIndicator[1])) + ColorSettingCell(text: Text("月中", comment: ""), color: watchLayout.binding(\.moonPositionIndicator.highMoon)) } HStack(spacing: 20) { - ColorSettingCell(text: Text("月入", comment: ""), color: watchLayout.binding(\.moonPositionIndicator[2])) + ColorSettingCell(text: Text("月入", comment: ""), color: watchLayout.binding(\.moonPositionIndicator.moonset)) } } } diff --git a/Shared/Setting/Datetime.swift b/Shared/Setting/Datetime.swift index b9fea5b..65e13ef 100644 --- a/Shared/Setting/Datetime.swift +++ b/Shared/Setting/Datetime.swift @@ -8,11 +8,71 @@ import SwiftUI import Observation -fileprivate struct TimeZoneSelection: Equatable { +final class DataTree: CustomStringConvertible { + var nodeName: String + private var offsprings: [DataTree] + private var registry: [String: Int] + + init(name: String) { + nodeName = name + offsprings = [] + registry = [:] + } + + var nextLevel: [DataTree] { + get { + offsprings + } + } + + func add(element: String) -> DataTree { + let data: DataTree + if let index = registry[element] { + data = offsprings[index] + } else { + registry[element] = offsprings.count + offsprings.append(DataTree(name: element)) + data = offsprings.last! + } + return data + } + + var count: Int { + offsprings.count + } + + subscript(element: String) -> DataTree? { + if let index = registry[element] { + return offsprings[index] + } else { + return nil + } + } + + var description: String { + var string: String + if offsprings.count > 0 { + string = "{\(nodeName): " + } else { + string = "\(nodeName)" + } + for offspring in offsprings { + string += offspring.description + } + if offsprings.count > 0 { + string += "}, " + } else { + string += "," + } + return string + } +} + +private struct TimeZoneSelection: Equatable { static func == (lhs: TimeZoneSelection, rhs: TimeZoneSelection) -> Bool { lhs.primary == rhs.primary && lhs.secondary == rhs.secondary && lhs.tertiary == rhs.tertiary } - + let timeZones = populateTimezones() var primary: String { didSet { @@ -33,14 +93,14 @@ fileprivate struct TimeZoneSelection: Equatable { } } var tertiary: String - + init(timezone: TimeZone) { let components = timezone.identifier.split(separator: "/") primary = if components.count > 0 { String(components[0]) } else { "" } secondary = if components.count > 1 { String(components[1]) } else { "" } tertiary = if components.count > 2 { String(components[2]) } else { "" } } - + var timezone: TimeZone? { var identifier = primary if secondary != "" { @@ -53,7 +113,7 @@ fileprivate struct TimeZoneSelection: Equatable { } } -@Observable fileprivate class DateManager { +@Observable private class DateManager { var chineseCalendar: ChineseCalendar? var watchSetting: WatchSetting? var calendarConfigure: CalendarConfigure? @@ -68,7 +128,7 @@ fileprivate struct TimeZoneSelection: Equatable { } } } - + var time: Date { get { watchSetting?.displayTime ?? chineseCalendar?.time ?? .now @@ -77,13 +137,13 @@ fileprivate struct TimeZoneSelection: Equatable { update() } } - + var timezone: TimeZone { get { calendarConfigure?.timezone ?? chineseCalendar?.calendar.timeZone ?? Calendar.current.timeZone } } - + var isCurrent: Bool { get { watchSetting?.displayTime == nil @@ -96,7 +156,7 @@ fileprivate struct TimeZoneSelection: Equatable { update() } } - + var isTimezoneCurrent: Bool { get { calendarConfigure?.timezone == nil @@ -109,7 +169,7 @@ fileprivate struct TimeZoneSelection: Equatable { update() } } - + var globalMonth: Bool { get { calendarConfigure?.globalMonth ?? false @@ -118,7 +178,7 @@ fileprivate struct TimeZoneSelection: Equatable { update() } } - + var apparentTime: Bool { get { calendarConfigure?.apparentTime ?? false @@ -127,7 +187,7 @@ fileprivate struct TimeZoneSelection: Equatable { update() } } - + var largeHour: Bool { get { calendarConfigure?.largeHour ?? false @@ -136,13 +196,13 @@ fileprivate struct TimeZoneSelection: Equatable { update() } } - + func setup(watchSetting: WatchSetting, calendarConfigure: CalendarConfigure, chineseCalendar: ChineseCalendar) { self.calendarConfigure = calendarConfigure self.watchSetting = watchSetting self.chineseCalendar = chineseCalendar } - + private func update() { chineseCalendar?.update(time: watchSetting?.displayTime ?? .now, timezone: calendarConfigure?.effectiveTimezone, globalMonth: calendarConfigure?.globalMonth, apparentTime: calendarConfigure?.apparentTime, largeHour: calendarConfigure?.largeHour) @@ -168,7 +228,7 @@ struct Datetime: View { @Environment(LocationManager.self) var locationManager @Environment(CalendarConfigure.self) var calendarConfigure @Environment(WatchSetting.self) var watchSetting - + var body: some View { Form { Section(header: Text("算法", comment: "Methodology setting")) { @@ -183,7 +243,7 @@ struct Datetime: View { } } } - + HStack { Picker("太陽時", selection: $dateManager.apparentTime) { let choice = if calendarConfigure.location(locationManager: locationManager) != nil { @@ -200,7 +260,7 @@ struct Datetime: View { } } } - + HStack { Picker("時辰", selection: $dateManager.largeHour) { ForEach([true, false], id: \.self) { largeHour in @@ -214,13 +274,13 @@ struct Datetime: View { } } .pickerStyle(.menu) - + Section(header: Text(NSLocalizedString("日時:", comment: "Date & time section") + dateManager.time.formatted(date: .abbreviated, time: .shortened))) { Toggle("今", isOn: $dateManager.isCurrent) DatePicker("擇時", selection: $dateManager.time, in: ChineseCalendar.start...ChineseCalendar.end, displayedComponents: [.date, .hourAndMinute]) .environment(\.timeZone, dateManager.timezone) } - + let timezoneTitle = if let desp = dateManager.timezone.localizedName(for: .standard, locale: Locale.current) { NSLocalizedString("時區:", comment: "Timezone section") + desp } else { @@ -232,7 +292,7 @@ struct Datetime: View { Picker("大區", selection: $dateManager.timeZoneSelection.primary) { ForEach(dateManager.timeZoneSelection.timeZones.nextLevel.map { $0.nodeName }, id: \.self) { tz in Text(tz.replacingOccurrences(of: "_", with: " ")) - + } } .lineLimit(1) diff --git a/Shared/Setting/Decoration.swift b/Shared/Setting/Decoration.swift index 0b03bc6..247053b 100644 --- a/Shared/Setting/Decoration.swift +++ b/Shared/Setting/Decoration.swift @@ -13,14 +13,14 @@ struct SliderView: View { let min: CGFloat let max: CGFloat let label: Text - + var body: some View { #if os(iOS) || os(visionOS) VStack { HStack { label Spacer() - + let formatter: NumberFormatter = { let formatter = NumberFormatter() formatter.maximumFractionDigits = 2 @@ -50,7 +50,7 @@ struct SliderView: View { } } .labelsHidden() - + let formatter: NumberFormatter = { let formatter = NumberFormatter() formatter.maximumFractionDigits = 2 @@ -71,7 +71,7 @@ struct ThemedColorSettingCell: View { let text: Text @Binding var color: CGColor @Binding var darkColor: CGColor - + var body: some View { HStack { text @@ -100,7 +100,7 @@ struct ThemedColorSettingCell: View { struct DecorationSetting: View { @Environment(WatchLayout.self) var watchLayout @Environment(WatchSetting.self) var watchSetting - + var body: some View { Form { Section(header: Text("透明度", comment: "Transparency sliders")) { diff --git a/Shared/Setting/Documentation.swift b/Shared/Setting/Documentation.swift index 3ab363d..6bf613c 100644 --- a/Shared/Setting/Documentation.swift +++ b/Shared/Setting/Documentation.swift @@ -7,8 +7,54 @@ import SwiftUI +let helpString: String = NSLocalizedString("介紹全文", comment: "Markdown formatted Wiki") + +enum MarkdownElement { + case heading(_: AttributedString) + case paragraph(_: [AttributedString]) +} + +final class MarkdownParser { + func parse(_ markdownString: String) -> [MarkdownElement] { + var elements: [MarkdownElement] = [] + var currentParagraph: [AttributedString] = [] + let scanner = Scanner(string: markdownString) + while !scanner.isAtEnd { + if let line = scanner.scanUpToCharacters(from: .newlines), let attrLine = try? AttributedString(markdown: line) { + if headingLevel(for: line) > 0 { + if !currentParagraph.isEmpty { + elements.append(.paragraph(currentParagraph)) + currentParagraph = [] + } + elements.append(.heading(attrLine)) + } else { + currentParagraph.append(attrLine) + } + } + } + + if !currentParagraph.isEmpty { + elements.append(.paragraph(currentParagraph)) + } + + return elements + } + + private func headingLevel(for line: String) -> Int { + let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines) + guard trimmedLine.count > 0 else { return 0 } + var index = trimmedLine.startIndex + var count = 0 + while index < trimmedLine.endIndex && trimmedLine[index] == "#" { + count += 1 + index = trimmedLine.index(after: index) + } + return min(count, 6) + } +} + extension MarkdownElement { - + var attributeContainer: AttributeContainer { var container = AttributeContainer() switch self { @@ -21,7 +67,7 @@ extension MarkdownElement { } } -fileprivate struct Paragraph: Identifiable { +private struct Paragraph: Identifiable { var id = UUID() let title: AttributedString let body: [AttributedString] @@ -30,7 +76,7 @@ fileprivate struct Paragraph: Identifiable { struct ParagraphView: View { @State fileprivate var article: Paragraph - + var body: some View { Section { Button { @@ -70,7 +116,7 @@ struct Documentation: View { private let parser = MarkdownParser() @State fileprivate var articles: [Paragraph] = [] @Environment(WatchSetting.self) var watchSetting - + var body: some View { Form { ForEach(articles) { article in @@ -95,7 +141,7 @@ struct Documentation: View { } #endif } - + func prepareArticle(markdown: String) { let elements = parser.parse(markdown) var articleInWork = [Paragraph]() diff --git a/Shared/Setting/LayoutSetting.swift b/Shared/Setting/LayoutSetting.swift index e7bf439..1b88d81 100644 --- a/Shared/Setting/LayoutSetting.swift +++ b/Shared/Setting/LayoutSetting.swift @@ -15,7 +15,7 @@ struct LayoutSettingCell: View { let completion: (() -> Void)? @State var tempValue: V @FocusState var isFocused: Bool - + init(text: Text, value: Binding, validation: ((V) -> V)? = nil, completion: (() -> Void)? = nil) { self.text = text self._value = value @@ -23,7 +23,7 @@ struct LayoutSettingCell: View { self.completion = completion self._tempValue = State(initialValue: value.wrappedValue) } - + var body: some View { HStack { text @@ -68,7 +68,7 @@ struct LayoutSettingCell: View { #endif } } - + func commit() { if let validation = validation { tempValue = validation(tempValue) @@ -103,7 +103,7 @@ struct LayoutSettingCell: View { } } var centerFontMemberSelection: String = "" - + var textFont: NSFont? { get { readFont(family: textFontSelection, style: textFontMemberSelection) @@ -118,7 +118,7 @@ struct LayoutSettingCell: View { } } } - + var centerFont: NSFont? { get { readFont(family: centerFontSelection, style: centerFontMemberSelection) @@ -133,7 +133,7 @@ struct LayoutSettingCell: View { } } } - + func populateFontMembers(for fontFamily: String) -> [String] { var allMembers = [String]() let members = NSFontManager.shared.availableMembers(ofFontFamily: fontFamily) @@ -144,7 +144,7 @@ struct LayoutSettingCell: View { } return allMembers } - + func readFont(family: String, style: String) -> NSFont? { let size = NSFont.systemFontSize if let font = NSFont(name: "\(family.filter { !$0.isWhitespace })-\(style.filter { !$0.isWhitespace })", size: size) { @@ -154,8 +154,7 @@ struct LayoutSettingCell: View { for i in 0..: View { } return nil } - + func getFontFamilyAndMember(font: NSFont) -> (String?, String?) { let family = font.familyName let member = font.fontName.split(separator: "-").last.map {String($0)} @@ -186,7 +185,7 @@ struct LayoutSetting: View { #if os(macOS) @State var fontHandler = FontHandler() #endif - + var body: some View { Form { #if os(macOS) || os(visionOS) @@ -211,28 +210,28 @@ struct LayoutSetting: View { Section(header: Text("字體", comment: "Font selection")) { HStack(spacing: 20) { Picker("小字", selection: $fontHandler.textFontSelection) { - ForEach(fontHandler.allFonts, id:\.self) { family in + ForEach(fontHandler.allFonts, id: \.self) { family in Text(family) } } Divider() Picker("麤細", selection: $fontHandler.textFontMemberSelection) { - ForEach(fontHandler.textFontMembers, id:\.self) { member in + ForEach(fontHandler.textFontMembers, id: \.self) { member in Text(member) } } .labelsHidden() } - + HStack(spacing: 20) { Picker("大字", selection: $fontHandler.centerFontSelection) { - ForEach(fontHandler.allFonts, id:\.self) { family in + ForEach(fontHandler.allFonts, id: \.self) { family in Text(family) } } Divider() Picker("麤細", selection: $fontHandler.centerFontMemberSelection) { - ForEach(fontHandler.centerFontMembers, id:\.self) { member in + ForEach(fontHandler.centerFontMembers, id: \.self) { member in Text(member) } } diff --git a/Shared/Setting/Location.swift b/Shared/Setting/Location.swift index 45adf94..db13954 100644 --- a/Shared/Setting/Location.swift +++ b/Shared/Setting/Location.swift @@ -7,35 +7,35 @@ import SwiftUI -internal func coordinateDesp(coordinate: CGPoint) -> (lat: String, lon: String) { +internal func coordinateDesp(coordinate: GeoLocation) -> (lat: String, lon: String) { var latitudeLabel = "" - if coordinate.x > 0 { + if coordinate.lat > 0 { latitudeLabel = NSLocalizedString("北緯", comment: "N") - } else if coordinate.x < 0 { + } else if coordinate.lat < 0 { latitudeLabel = NSLocalizedString("南緯", comment: "S") } - let latitude = Int(round(abs(coordinate.x) * 3600)) + let latitude = Int(round(abs(coordinate.lat) * 3600)) var latitudeString = "\(latitude / 3600)°\((latitude % 3600) / 60)\'\(latitude % 60)\"" if Locale.isEastAsian { latitudeString = "\(latitudeLabel) \(latitudeString)" } else { latitudeString = "\(latitudeString) \(latitudeLabel)" } - + var longitudeLabel = "" - if coordinate.y > 0 { + if coordinate.lon > 0 { longitudeLabel = NSLocalizedString("東經", comment: "E") - } else if coordinate.y < 0 { + } else if coordinate.lon < 0 { longitudeLabel = NSLocalizedString("西經", comment: "W") } - let longitude = Int(round(abs(coordinate.y) * 3600)) + let longitude = Int(round(abs(coordinate.lon) * 3600)) var longitudeString = "\(longitude / 3600)°\((longitude % 3600) / 60)\'\(longitude % 60)\"" if Locale.isEastAsian { longitudeString = "\(longitudeLabel) \(longitudeString)" } else { longitudeString = "\(longitudeString) \(longitudeLabel)" } - + return (latitudeString, longitudeString) } @@ -44,7 +44,7 @@ struct LocationSelection: Equatable { var degree: Int = 0 var minute: Int = 0 var second: Int = 0 - + var value: CGFloat { var locationValue = CGFloat(degree) locationValue += CGFloat(minute) / 60 @@ -52,7 +52,7 @@ struct LocationSelection: Equatable { locationValue *= positive ? 1.0 : -1.0 return locationValue } - + static func from(value: CGFloat) -> Self { var values: [Int] = [0, 0, 0] let tempValue = Int(round(abs(value) * 3600)) @@ -63,30 +63,30 @@ struct LocationSelection: Equatable { } } -@Observable fileprivate class LocationData { +@Observable private class LocationData { var locationManager: LocationManager? var calendarConfigure: CalendarConfigure? var locationUnavailable = false - + var timezoneLongitude: CGFloat { let timezone = calendarConfigure?.timezone ?? Calendar.current.timeZone let logitude = (CGFloat(timezone.secondsFromGMT()) - timezone.daylightSavingTimeOffset()) / 240 return ((logitude + 180) %% 360) - 180 } - + var locationEnabled: Bool { get { calendarConfigure?.location(locationManager: locationManager) != nil } set { if newValue { - calendarConfigure?.customLocation = calendarConfigure?.customLocation ?? CGPoint(x: 0.0, y: timezoneLongitude) + calendarConfigure?.customLocation = calendarConfigure?.customLocation ?? GeoLocation(lat: 0.0, lon: timezoneLongitude) } else { calendarConfigure?.locationEnabled = false calendarConfigure?.customLocation = nil } } } - + var gpsEnabled: Bool { get { if let locationManager = locationManager, let calendarConfigure = calendarConfigure { @@ -104,35 +104,35 @@ struct LocationSelection: Equatable { } } else { calendarConfigure?.locationEnabled = false - calendarConfigure?.customLocation = calendarConfigure?.customLocation ?? locationManager?.location ?? CGPoint(x: 0.0, y: timezoneLongitude) + calendarConfigure?.customLocation = calendarConfigure?.customLocation ?? locationManager?.location ?? GeoLocation(lat: 0.0, lon: timezoneLongitude) } } } - - var manualLocation: CGPoint? { + + var manualLocation: GeoLocation? { calendarConfigure?.customLocation } - + var latitudeSelection: LocationSelection { get { - LocationSelection.from(value: manualLocation?.x ?? 0) + LocationSelection.from(value: manualLocation?.lat ?? 0) } set { - calendarConfigure?.customLocation?.x = newValue.value + calendarConfigure?.customLocation = GeoLocation(lat: newValue.value, lon: calendarConfigure?.customLocation?.lon ?? 0) } } - + var longitudeSelection: LocationSelection { get { - LocationSelection.from(value: manualLocation?.y ?? CGFloat(Calendar.current.timeZone.secondsFromGMT()) / 240) + LocationSelection.from(value: manualLocation?.lon ?? CGFloat(Calendar.current.timeZone.secondsFromGMT()) / 240) } set { - calendarConfigure?.customLocation?.y = newValue.value + calendarConfigure?.customLocation? = GeoLocation(lat: calendarConfigure?.customLocation?.lat ?? 0, lon: newValue.value) } } - - var location: CGPoint? { + + var location: GeoLocation? { calendarConfigure?.location(locationManager: locationManager) } - + func setup(locationManager: LocationManager, calendarConfigure: CalendarConfigure) { self.locationManager = locationManager self.calendarConfigure = calendarConfigure @@ -146,14 +146,14 @@ struct OnSubmitTextField: View { @Binding var value: V @State var tempValue: V @FocusState var isFocused: Bool - + init(_ title: LocalizedStringKey, value: Binding, formatter: NumberFormatter) { self.title = title self.formatter = formatter self._value = value self._tempValue = State(initialValue: value.wrappedValue) } - + var body: some View { HStack { Text(title) @@ -198,7 +198,7 @@ struct Location: View { @Environment(LocationManager.self) var locationManager @Environment(CalendarConfigure.self) var calendarConfigure @Environment(ChineseCalendar.self) var chineseCalendar - + var body: some View { Form { Section { diff --git a/Shared/Setting/RingSetting.swift b/Shared/Setting/RingSetting.swift index c06bba9..dd220e9 100644 --- a/Shared/Setting/RingSetting.swift +++ b/Shared/Setting/RingSetting.swift @@ -18,13 +18,13 @@ class ColorPanelObserver { object: nil ) } - + @objc private func colorPanelWillClose(notification: Notification) { guard let closingWindow = notification.object as? NSWindow, closingWindow == NSColorPanel.shared else { return } - + NSColorPanel.shared.setTarget(nil) NSColorPanel.shared.setAction(nil) } @@ -39,7 +39,7 @@ class ColorNode: NSControl, NSColorChanging { } } } - + init(frame frameRect: NSRect, color: NSColor, action: @escaping (NSColor) -> Void) { self.color = color self.callBack = action @@ -52,11 +52,11 @@ class ColorNode: NSControl, NSColorChanging { let clickGesture = NSClickGestureRecognizer(target: self, action: #selector(onTap(sender:))) self.addGestureRecognizer(clickGesture) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + @objc func onTap(sender: NSClickGestureRecognizer) { let colorPanel = NSColorPanel.shared colorPanel.setTarget(nil) @@ -74,7 +74,7 @@ class ColorNode: NSControl, NSColorChanging { colorPanel.setTarget(self) colorPanel.setAction(#selector(changeColor(_:))) } - + @objc func changeColor(_ sender: NSColorPanel?) { if let newColor = sender?.color { color = newColor @@ -86,11 +86,11 @@ class ColorNode: NSControl, NSColorChanging { struct ColorNodeView: NSViewRepresentable { let size: CGSize @Binding var color: CGColor - + func makeNSView(context: Context) -> ColorNode { return ColorNode(frame: NSRect(origin: .zero, size: size), color: NSColor(cgColor: color)!, action: { color = $0.cgColor }) } - + func updateNSView(_ nsView: ColorNode, context: Context) { nsView.color = NSColor(cgColor: color)! } @@ -101,7 +101,7 @@ struct ColorNodeView: NSViewRepresentable { private var colors: [CGColor] = [] private var values: [CGFloat] = [] var isLoop: Bool = false - + var gradientStops: [Gradient.Stop] { var stops = [Gradient.Stop]() for (value, color) in zip(values, colors) { @@ -116,11 +116,11 @@ struct ColorNodeView: NSViewRepresentable { } return stops } - + var count: Int { colors.count } - + func bindColor(at index: Int) -> Binding { Binding(get: { self.color(at: index) @@ -130,7 +130,7 @@ struct ColorNodeView: NSViewRepresentable { } }) } - + func color(at index: Int) -> CGColor { if index >= 0 && index < self.colors.count { self.colors[index] @@ -138,7 +138,7 @@ struct ColorNodeView: NSViewRepresentable { CGColor(gray: 0, alpha: 0) } } - + func value(at index: Int) -> CGFloat { if index >= 0 && index < self.values.count { self.values[index] @@ -146,32 +146,32 @@ struct ColorNodeView: NSViewRepresentable { 0 } } - + func updateValue(at index: Int, with newValue: CGFloat) { if index >= 0 && index < self.values.count { self.values[index] = newValue } } - + func add(color: CGColor, at value: CGFloat) { let index = values.insertionIndex(of: value, comparison: { $0 < $1 }) colors.insert(color, at: index) values.insert(value, at: index) } - + func remove(at index: Int) { if index >= 0 && index < colors.count { colors.remove(at: index) values.remove(at: index) } } - + func export(allowLoop: Bool = true) -> WatchLayout.Gradient { return WatchLayout.Gradient(locations: values, colors: colors, loop: allowLoop && isLoop) } - + init() {} - + init(from gradient: WatchLayout.Gradient, allowLoop: Bool = true) { isLoop = allowLoop && gradient.isLoop if isLoop { @@ -201,14 +201,14 @@ struct GradientSliderView: View { let text: Text @Binding var gradient: WatchLayout.Gradient let allowLoop: Bool - + @State private var viewGradient = ViewGradient() - @State private var position: (index: Int, pos: CGPoint)? = nil - + @State private var position: (index: Int, pos: CGPoint)? + var body: some View { GeometryReader { proxy in let size: CGSize = proxy.size - + let tapGesture = SpatialTapGesture() .onEnded { value in var newPosition = valueForPosition(value.location, in: size) @@ -216,7 +216,7 @@ struct GradientSliderView: View { let interpolateColor = gradient.interpolate(at: newPosition) viewGradient.add(color: interpolateColor, at: newPosition) } - + VStack { HStack { text @@ -236,7 +236,7 @@ struct GradientSliderView: View { } } ZStack { - + // Gradient background LinearGradient(gradient: Gradient(stops: viewGradient.gradientStops), startPoint: .leading, endPoint: .trailing) .frame(height: barHeight) @@ -250,7 +250,7 @@ struct GradientSliderView: View { .hoverEffect() #endif .gesture(tapGesture) - + ForEach(0.. CGPoint { var boundedPoint = point #if os(iOS) @@ -339,11 +339,11 @@ struct GradientSliderView: View { boundedPoint.y = max(min(boundedPoint.y, bound.height + verticalOffset), verticalOffset) return boundedPoint } - + private func positionForValue(_ value: CGFloat, in size: CGSize) -> CGPoint { return CGPoint(x: (size.width - (pickerSize + padding) * 2) * value + pickerSize, y: slideHeight) } - + private func valueForPosition(_ position: CGPoint, in size: CGSize) -> CGFloat { let value = (position.x - pickerSize) / (size.width - (pickerSize + padding) * 2) return max(0.0, min(1.0, value)) @@ -353,7 +353,7 @@ struct GradientSliderView: View { struct RingSetting: View { @Environment(WatchLayout.self) var watchLayout @Environment(WatchSetting.self) var watchSetting - + var body: some View { Form { Section(header: Text("漸變色", comment: "Gradient Pickers")) { @@ -373,7 +373,7 @@ struct RingSetting: View { GradientSliderView(text: Text("大字", comment: "Day Ring Gradient"), gradient: watchLayout.binding(\.centerFontColor), allowLoop: false) .frame(height: height - loopSize) } - + Section(header: Text("起始角", comment: "Starting Phase")) { SliderView(value: watchLayout.binding(\.startingPhase.zeroRing), min: -1, max: 1, label: Text("節氣")) SliderView(value: watchLayout.binding(\.startingPhase.firstRing), min: -1, max: 1, label: Text("年輪")) diff --git a/Shared/Setting/StatusState.swift b/Shared/Setting/StatusState.swift index 2bcdfcc..28a12b7 100644 --- a/Shared/Setting/StatusState.swift +++ b/Shared/Setting/StatusState.swift @@ -8,12 +8,12 @@ import Foundation class StatusState: Equatable { - var location: CGPoint? + var location: GeoLocation? var date: Date? var timezone: TimeZone? var statusBar: WatchLayout.StatusBar var calendarSetting: Int - + init(locationManager: LocationManager, watchLayout: WatchLayout, calendarConfigure: CalendarConfigure, watchSetting: WatchSetting) { location = calendarConfigure.location(locationManager: locationManager) date = watchSetting.displayTime diff --git a/Shared/Setting/ThemesList.swift b/Shared/Setting/ThemesList.swift index e39f4b3..fe3f923 100644 --- a/Shared/Setting/ThemesList.swift +++ b/Shared/Setting/ThemesList.swift @@ -14,7 +14,7 @@ struct DynamicButtonStyle: ButtonStyle { var prominent: Bool @Environment(\.isEnabled) var isEnabled @ScaledMetric(relativeTo: .body) var size: CGFloat = 4 - + func makeBody(configuration: Configuration) -> some View { let color = isEnabled ? Color.primary : Color.secondary configuration.label @@ -35,7 +35,7 @@ struct HighlightButton: View { let action: () -> Void @ViewBuilder let label: () -> Label @State var hover = false - + var body: some View { let button = Button { action() @@ -61,14 +61,14 @@ struct TextDocument: FileDocument { text = String(decoding: data, as: UTF8.self) } } - + func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { let data = Data(text.utf8) return FileWrapper(regularFileWithContents: data) } - + static let readableContentTypes: [UTType] = [.text] - + var text: String = "" init?(_ text: String?) { if let text = text { @@ -81,13 +81,11 @@ struct TextDocument: FileDocument { private func loadThemes(data: [ThemeData]) -> [String: [ThemeData]] { var newThemes = [String: [ThemeData]]() - for data in data { - if !data.isNil { - if newThemes[data.deviceName!] == nil { - newThemes[data.deviceName!] = [data] - } else { - newThemes[data.deviceName!]!.append(data) - } + for data in data where !data.isNil { + if newThemes[data.deviceName!] == nil { + newThemes[data.deviceName!] = [data] + } else { + newThemes[data.deviceName!]!.append(data) } } for deviceName in newThemes.keys { @@ -161,7 +159,7 @@ func writeFile(name: String, code: String) { } @MainActor -func readFile(handler: @escaping (URL) throws -> ()) { +func readFile(handler: @escaping (URL) throws -> Void) { let panel = NSOpenPanel() panel.level = NSWindow.Level.floating panel.allowsMultipleSelection = false @@ -204,7 +202,7 @@ struct ThemesList: View { #endif @State private var newName = "" @State private var errorMsg = "" - @State private var target: ThemeData? = nil + @State private var target: ThemeData? var targetName: String { if let name = target?.name { if name == AppInfo.defaultName { @@ -224,7 +222,7 @@ struct ThemesList: View { loadThemes(data: dataStack) } let currentDeviceName = AppInfo.deviceName - + var body: some View { let newTheme = Button { newName = validName(NSLocalizedString("佚名", comment: "unnamed")) @@ -237,7 +235,7 @@ struct ThemesList: View { } label: { Label("復原", systemImage: "arrow.clockwise") } - + let newThemeConfirm = Button(NSLocalizedString("此名甚善", comment: "Confirm adding Settings"), role: .destructive) { let newTheme = ThemeData(name: newName, code: watchLayout.encode()) modelContext.insert(newTheme) @@ -248,7 +246,7 @@ struct ThemesList: View { errorAlert = true } } - + let renameConfirm = Button(NSLocalizedString("此名甚善", comment: "Confirm adding Settings"), role: .destructive) { if let target = target, !target.isNil { target.name = newName @@ -271,7 +269,7 @@ struct ThemesList: View { } label: { Label("讀入", systemImage: "square.and.arrow.down") } - + let moreMenu = Menu { VStack { newTheme @@ -284,7 +282,7 @@ struct ThemesList: View { } .menuIndicator(.hidden) .menuStyle(.automatic) - + Form { if dataStack.count > 0 { let deviceNames = themes.keys.sorted(by: {$0 > $1}).sorted(by: {prev, _ in prev == currentDeviceName}) @@ -306,7 +304,7 @@ struct ThemesList: View { Text(theme.modifiedDate!, style: .date) .foregroundStyle(.secondary) } - + let saveButton = Button { #if os(macOS) if !theme.isNil { @@ -319,14 +317,14 @@ struct ThemesList: View { } label: { Label("寫下", systemImage: "square.and.arrow.up") } - + let deleteButton = Button(role: .destructive) { target = theme deleteAlert = true } label: { Label("刪", systemImage: "trash") } - + let renameButton = Button { target = theme newName = validName(theme.name!, device: theme.deviceName!) @@ -334,7 +332,7 @@ struct ThemesList: View { } label: { Label("更名", systemImage: "rectangle.and.pencil.and.ellipsis.rtl") } - + let nameLabel = if theme.name! != AppInfo.defaultName { Text(theme.name!) } else { @@ -492,7 +490,7 @@ struct ThemesList: View { } #endif } - + func validateName(_ name: String, onDevice deviceName: String) -> Bool { if name.count > 0 { let currentDeviceThemes = themes[deviceName] @@ -501,7 +499,7 @@ struct ThemesList: View { return false } } - + func validName(_ name: String, device: String? = nil) -> String { var (baseName, i) = reverseNumberedName(name) while !validateName(numberedName(baseName, number: i), onDevice: device ?? currentDeviceName) { @@ -509,7 +507,7 @@ struct ThemesList: View { } return numberedName(baseName, number: i) } - + func removeDuplicates() { var records = Set() for data in dataStack { @@ -524,7 +522,7 @@ struct ThemesList: View { } } } - + #if os(macOS) @MainActor func handleFile(_ file: URL) throws { @@ -539,18 +537,12 @@ struct ThemesList: View { #endif } -//#Preview("Themes") { -// let watchLayout = WatchLayout() -// let watchSetting = WatchSetting() -// watchLayout.loadStatic() -// return ThemesList() -// .modelContainer(DataSchema.container) -// .environment(watchLayout) -// .environment(watchSetting) -//} - -#Preview("Button") { - HighlightButton(action: {}) { - Text("你好") - } +#Preview("Themes") { + let watchLayout = WatchLayout() + let watchSetting = WatchSetting() + watchLayout.loadStatic() + return ThemesList() + .modelContainer(DataSchema.container) + .environment(watchLayout) + .environment(watchSetting) } diff --git a/Shared/Utilities.swift b/Shared/Utilities.swift index 2d15e1d..3f2d3d6 100644 --- a/Shared/Utilities.swift +++ b/Shared/Utilities.swift @@ -7,108 +7,119 @@ import Foundation -let helpString: String = NSLocalizedString("介紹全文", comment: "Markdown formatted Wiki") +func +(lhs: CGPoint, rhs: CGPoint) -> CGPoint { + return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y) +} -enum MarkdownElement { - case heading(_: AttributedString) - case paragraph(_: [AttributedString]) +func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint { + return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y) } -final class MarkdownParser { - func parse(_ markdownString: String) -> [MarkdownElement] { - var elements: [MarkdownElement] = [] - var currentParagraph: [AttributedString] = [] - let scanner = Scanner(string: markdownString) - while !scanner.isAtEnd { - if let line = scanner.scanUpToCharacters(from: .newlines), let attrLine = try? AttributedString(markdown: line) { - if headingLevel(for: line) > 0 { - if !currentParagraph.isEmpty { - elements.append(.paragraph(currentParagraph)) - currentParagraph = [] - } - elements.append(.heading(attrLine)) - } else { - currentParagraph.append(attrLine) - } - } - } - - if !currentParagraph.isEmpty { - elements.append(.paragraph(currentParagraph)) - } - - return elements - } - - private func headingLevel(for line: String) -> Int { - let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines) - guard trimmedLine.count > 0 else { return 0 } - var index = trimmedLine.startIndex - var count = 0 - while index < trimmedLine.endIndex && trimmedLine[index] == "#" { - count += 1 - index = trimmedLine.index(after: index) - } - return min(count, 6) - } +func *(lhs: CGPoint, rhs: CGFloat) -> CGPoint { + return CGPoint(x: lhs.x * rhs, y: lhs.y * rhs) } -final class DataTree: CustomStringConvertible { - var nodeName: String - private var offsprings: [DataTree] - private var registry: [String: Int] - - init(name: String) { - nodeName = name - offsprings = [] - registry = [:] +func /(lhs: CGPoint, rhs: CGFloat) -> CGPoint { + return CGPoint(x: lhs.x / rhs, y: lhs.y / rhs) +} + +infix operator %%: MultiplicationPrecedence +infix operator /%: MultiplicationPrecedence + +extension BinaryInteger { + static func %%(_ left: Self, _ right: Self) -> Self { + let mod = left % right + return mod >= 0 ? mod : mod + right } - - var nextLevel: [DataTree] { - get { - offsprings - } +} + +extension FloatingPoint { + static func %%(_ left: Self, _ right: Self) -> Self { + let mod = left.truncatingRemainder(dividingBy: right) + return mod >= 0 ? mod : mod + right } - - func add(element: String) -> DataTree { - let data: DataTree - if let index = registry[element] { - data = offsprings[index] +} + +extension BinaryInteger { + static func /%(_ left: Self, _ right: Self) -> Self { + if left < 0 { + return (left - right + 1) / right } else { - registry[element] = offsprings.count - offsprings.append(DataTree(name: element)) - data = offsprings.last! + return left / right } - return data } - - var count: Int { - offsprings.count - } - - subscript(element: String) -> DataTree? { - if let index = registry[element] { - return offsprings[index] - } else { - return nil +} + +extension Array { + func insertionIndex(of value: Element, comparison: (Element, Element) -> Bool) -> Index { + var slice: SubSequence = self[...] + + while !slice.isEmpty { + let middle = slice.index(slice.startIndex, offsetBy: slice.count / 2) + if comparison(value, slice[middle]) { + slice = slice[.. 0 { - string = "{\(nodeName): " - } else { - string = "\(nodeName)" - } - for offspring in offsprings { - string += offspring.description + + func slice(from: Int = 0, to: Int? = nil, step: Int = 1) -> Self { + var sliced = Self() + var i = from + let limit = to ?? count + while i < limit { + sliced.append(self[i]) + i += step } - if offsprings.count > 0 { - string += "}, " + return sliced + } +} + +extension Int { + func quotient(rhs: Int) -> Int { + if self < 0 { + return (self - (rhs - 1)) / rhs } else { - string += "," + return self / rhs } - return string } } + +protocol NamedPoint { + var name: String { get } + var pos: Double { get } +} + +protocol NamedArray { + func getValues(_ properties: [KeyPath]) -> [S] +} + +extension NamedArray { + func getValues(_ properties: [KeyPath]) -> [S] { + properties.map { self[keyPath: $0] } + } +} + +struct Planets: NamedArray { + var moon: S + var mercury: S + var venus: S + var mars: S + var jupiter: S + var saturn: S +} + +struct Solar: NamedArray { + var midnight: S + var sunrise: S + var noon: S + var sunset: S +} + +struct Lunar: NamedArray { + var moonrise: S + var highMoon: S + var moonset: S +} diff --git a/Shared/Views/HoverView.swift b/Shared/Views/HoverView.swift index 06043fe..70e4e42 100644 --- a/Shared/Views/HoverView.swift +++ b/Shared/Views/HoverView.swift @@ -10,7 +10,7 @@ import Observation @Observable final class EntitySelection { @ObservationIgnored var entityNotes = EntityNotes() - @ObservationIgnored var timer: Timer? = nil + @ObservationIgnored var timer: Timer? @ObservationIgnored var _activeNote: [EntityNotes.EntityNote] = [] { didSet { timer?.invalidate() @@ -60,9 +60,9 @@ struct Hover: View { @Binding var tapPos: CGPoint? @State var isEastAsian = Locale.isEastAsian @State var prepared = true - + var body: some View { - + let shortEdge = min(watchLayout.watchSize.width, watchLayout.watchSize.height) let longEdge = min(watchLayout.watchSize.width, watchLayout.watchSize.height) let fontSize: CGFloat = min(shortEdge * 0.04, longEdge * 0.032) diff --git a/Shared/Views/Icon.swift b/Shared/Views/Icon.swift index e6980f6..97d5342 100644 --- a/Shared/Views/Icon.swift +++ b/Shared/Views/Icon.swift @@ -13,7 +13,7 @@ struct Icon: View { let watchLayout: WatchLayout let widthScale: CGFloat let preview: Bool - + init(watchLayout: WatchLayout, preview: Bool = false) { self.watchLayout = watchLayout self.preview = preview @@ -23,15 +23,15 @@ struct Icon: View { widthScale = 1.5 } } - + var body: some View { let coreColor = colorScheme == .dark ? watchLayout.innerColorDark : watchLayout.innerColor let backColor = colorScheme == .dark ? watchLayout.backColorDark : watchLayout.backColor let clearColor = CGColor(gray: 0, alpha: 0) let shadowDirection = 0.62 - + GeometryReader { proxy in - + let size = proxy.size let shortEdge = min(size.width, size.height) let cornerSize = watchLayout.cornerRadiusRatio * shortEdge @@ -44,7 +44,7 @@ struct Icon: View { } else { secondRingOuter.shrink(by: Ring.paddedWidth * shortEdge * widthScale) } - + ZStack { Ring(width: Ring.paddedWidth * widthScale, viewSize: size, compact: false, ticks: ChineseCalendar.Ticks(), startingAngle: 0, angle: preview ? 0.9 : 0.3, textFont: WatchFont(watchLayout.textFont), textColor: clearColor, alpha: watchLayout.shadeAlpha, majorTickAlpha: 1, minorTickAlpha: 1, majorTickColor: clearColor, minorTickColor: clearColor, backColor: backColor, gradientColor: watchLayout.firstRing, outerRing: firstRingOuter, marks: [], shadowDirection: shadowDirection, entityNotes: nil, shadowSize: watchLayout.shadowSize, highlightType: .flicker, offset: .zero) diff --git a/Shared/Views/RoundedRect.swift b/Shared/Views/RoundedRect.swift index 4a31240..ddb358c 100644 --- a/Shared/Views/RoundedRect.swift +++ b/Shared/Views/RoundedRect.swift @@ -12,17 +12,17 @@ final class RoundedRect { let _boundBox: CGRect let _nodePos: CGFloat let _ankorPos: CGFloat - + init(rect: CGRect, nodePos: CGFloat, ankorPos: CGFloat) { _boundBox = rect _nodePos = nodePos _ankorPos = ankorPos } - + func copy() -> RoundedRect { return RoundedRect(rect: _boundBox, nodePos: _nodePos, ankorPos: _ankorPos) } - + private func drawPath(vertex: [CGPoint]) -> CGMutablePath { let path = CGMutablePath() var previousPoint = vertex[vertex.count - 1] @@ -64,7 +64,7 @@ final class RoundedRect { path.closeSubpath() return path } - + var path: CGMutablePath { let vertex: [CGPoint] = [CGPoint(x: _boundBox.minX, y: _boundBox.minY), CGPoint(x: _boundBox.minX, y: _boundBox.maxY), @@ -72,7 +72,7 @@ final class RoundedRect { CGPoint(x: _boundBox.maxX, y: _boundBox.minY)] return drawPath(vertex: vertex) } - + func shrink(by diameterChange: CGFloat) -> RoundedRect { let shortEdgeLength = min(_boundBox.width, _boundBox.height) let horizontalShift = diameterChange * (shortEdgeLength - _nodePos)/max(_boundBox.width, _boundBox.height) @@ -85,36 +85,36 @@ final class RoundedRect { newBoundBox.size.height -= 2 * diameterChange return RoundedRect(rect: newBoundBox, nodePos: newNodePos, ankorPos: newAnkorPos) } - + func bezierLength(t: CGFloat) -> CGFloat { guard _nodePos > 0 else { return 0 } let alpha = _ankorPos/_nodePos - + var length = pow(t, 2) * (-1 - 2 * alpha+9 * pow(alpha, 2)) - 5 * t * alpha * (1 - alpha) length *= 0.3 * (-1+2 * alpha+pow(alpha, 2)) length += pow(1 - alpha, 2) * (1 - 4 * alpha+5 * pow(alpha, 2)) length *= pow(t/(1 - alpha), 3) length += 3 * t * ((1 - alpha)+t * (2 * alpha - 1)) - + return length * _nodePos } - + struct OrientedPoint { var name: String var position: CGPoint var direction: CGFloat } - + func arcPoints(lambdas: [CGFloat]) -> [OrientedPoint] { return arcPoints(lambdas: lambdas.map { ChineseCalendar.NamedPosition(name: "", pos: Double($0)) }) } - + func arcPoints(lambdas: [T]) -> [OrientedPoint] { let arcLength = bezierLength(t: 0.5) * 2 let innerWidth = _boundBox.width - 2 * _nodePos let innerHeight = _boundBox.height - 2 * _nodePos let totalLength = 2 * (innerWidth+innerHeight)+4 * arcLength - + func bezierNorm(l: CGFloat) -> (CGPoint, CGFloat) { var t: CGFloat = 0.0 var otherSide = false @@ -123,7 +123,7 @@ final class RoundedRect { effectiveL = 1.0 - effectiveL otherSide = true } - + let stepSize: CGFloat = 0.1 var currL: CGFloat = 0.0 var prevL: CGFloat = -stepSize @@ -148,10 +148,10 @@ final class RoundedRect { let midPoint = CGPoint(x: xt * _nodePos, y: yt * _nodePos) return (midPoint, angle) } - + var firstLine = [(CGFloat, Int)](), secondLine = [(CGFloat, Int)](), thirdLine = [(CGFloat, Int)](), fourthLine = [(CGFloat, Int)](), fifthLine = [(CGFloat, Int)]() var firstArc = [(CGFloat, Int)](), secondArc = [(CGFloat, Int)](), thirdArc = [(CGFloat, Int)](), fourthArc = [(CGFloat, Int)]() - + var i = 0 for lambdaPoint in lambdas { let lambda = lambdaPoint.pos @@ -179,69 +179,69 @@ final class RoundedRect { } i += 1 } - + var points = [(OrientedPoint, Int)]() - + for (lambda, i) in firstLine { let start = CGPoint(x: _boundBox.midX+lambda, y: _boundBox.maxY) let normAngle: CGFloat = 0 points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in firstArc { var (start, normAngle) = bezierNorm(l: lambda) start = CGPoint(x: _boundBox.maxX - start.y, y: _boundBox.maxY - start.x) points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in secondLine { let start = CGPoint(x: _boundBox.maxX, y: _boundBox.maxY - _nodePos - lambda) let normAngle = CGFloat.pi/2 points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in secondArc { var (start, normAngle) = bezierNorm(l: lambda) start = CGPoint(x: _boundBox.maxX - start.x, y: _boundBox.minY+start.y) normAngle += CGFloat.pi/2 points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in thirdLine { let start = CGPoint(x: _boundBox.maxX - _nodePos - lambda, y: _boundBox.minY) let normAngle = CGFloat.pi points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in thirdArc { var (start, normAngle) = bezierNorm(l: lambda) normAngle += CGFloat.pi start = CGPoint(x: _boundBox.minX+start.y, y: _boundBox.minY+start.x) points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in fourthLine { let start = CGPoint(x: _boundBox.minX, y: _boundBox.minY+_nodePos+lambda) let normAngle = CGFloat.pi * 3/2 points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in fourthArc { var (start, normAngle) = bezierNorm(l: lambda) normAngle += CGFloat.pi * 3/2 start = CGPoint(x: _boundBox.minX+start.x, y: _boundBox.maxY - start.y) points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + for (lambda, i) in fifthLine { let start = CGPoint(x: _boundBox.minX+_nodePos+lambda, y: _boundBox.maxY) let normAngle: CGFloat = 0 points.append((OrientedPoint(name: lambdas[i].name, position: start, direction: normAngle), i)) } - + return points.sorted { $0.1 < $1.1 }.map { $0.0 } } - + func arcPosition(lambdas: [CGFloat], width: CGFloat) -> CGPath { let center = CGPoint(x: _boundBox.midX, y: _boundBox.midY) func getEnd(start: CGPoint, center: CGPoint, width: CGFloat) -> CGPoint { @@ -259,7 +259,7 @@ final class RoundedRect { path.addLine(to: end) } } - + return path } } diff --git a/Shared/Views/WatchFaceBasics.swift b/Shared/Views/WatchFaceBasics.swift index 001287e..2e59986 100644 --- a/Shared/Views/WatchFaceBasics.swift +++ b/Shared/Views/WatchFaceBasics.swift @@ -9,11 +9,14 @@ import SwiftUI private func changePhase(phase: CGFloat, angle: CGFloat) -> CGFloat { if phase >= 0 { - return (angle + phase) % 1.0 + return (angle + phase) %% 1.0 } else { - return (-angle + phase) % 1.0 + return (-angle + phase) %% 1.0 } } +private func changePhase(phase: CGFloat, angles: [CGFloat]) -> [CGFloat] { + return angles.map { changePhase(phase: phase, angle: $0) } +} class EntityNotes { struct EntityNote: Hashable, Identifiable { @@ -21,14 +24,14 @@ class EntityNotes { let position: CGPoint let color: CGColor let id = UUID() - + func hash(into hasher: inout Hasher) { hasher.combine(name) } } var entities = Set() - + func reset() { entities = Set() } @@ -63,23 +66,23 @@ struct ZeroRing: View { let oddTicksPath: CGPath let evenTicksPath: CGPath fileprivate let drawableTexts: [DrawableText] - + init(width: CGFloat, viewSize: CGSize, compact: Bool, textFont: WatchFont, outerRing: RoundedRect, startingAngle: CGFloat, oddTicks: [CGFloat], evenTicks: [CGFloat], oddColor: CGColor, evenColor: CGColor, oddTexts: [String], evenTexts: [String], offset: CGSize = .zero) { self.shortEdge = min(viewSize.width, viewSize.height) let longEdge = max(viewSize.width, viewSize.height) self.oddColor = oddColor self.evenColor = evenColor - + let textRing = outerRing.shrink(by: (width + 0.003)/2 * shortEdge) let ringBoundPath = outerRing.path self.ringBoundPath = ringBoundPath self.oddTicksPath = outerRing.arcPosition(lambdas: changePhase(phase: startingAngle, angles: oddTicks), width: 0.15 * shortEdge) self.evenTicksPath = outerRing.arcPosition(lambdas: changePhase(phase: startingAngle, angles: evenTicks), width: 0.15 * shortEdge) - + let fontSize: CGFloat = min(shortEdge * 0.03, longEdge * 0.025) * (compact ? 1.5 : 1.0) let font = textFont.font.withSize(fontSize) var drawableTexts = [DrawableText]() - + let oddPoints = textRing.arcPoints(lambdas: oddTicks.map { changePhase(phase: startingAngle, angle: $0) }) for i in 0.. ([ChineseCalendar.NamedPosition], [CGColor]) { var newPositions = [ChineseCalendar.NamedPosition]() var newColors = [CGColor]() @@ -385,7 +388,7 @@ struct Marks { } return (pos: newPositions, color: newColors) } - + init(outer: Bool, locations: [ChineseCalendar.NamedPosition?], colors: [CGColor], radius: CGFloat) { self.outer = outer let (pos, col) = Marks.pairMarkPositionColor(rawPositions: locations, rawColors: colors) @@ -420,7 +423,7 @@ private func prepareText(tickName: String, at point: RoundedRect.OrientedPoint, string = tickName } let attrStr = NSMutableAttributedString(string: string) - attrStr.addAttributes([.font: font.font, .foregroundColor: color], range: NSMakeRange(0, attrStr.length)) + attrStr.addAttributes([.font: font.font, .foregroundColor: color], range: NSRange(location: 0, length: attrStr.length)) var boxTransform = CGAffineTransform(translationX: -point.position.x, y: -point.position.y) let transform: CGAffineTransform @@ -437,14 +440,14 @@ private func prepareText(tickName: String, at point: RoundedRect.OrientedPoint, } boxTransform = boxTransform.concatenating(transform) boxTransform = boxTransform.concatenating(CGAffineTransform(translationX: point.position.x, y: point.position.y)) - + let characters = string.map { NSMutableAttributedString(string: String($0), attributes: attrStr.attributes(at: 0, effectiveRange: nil)) } let mean = CGFloat(characters.count - 1)/2 var text = [DrawableText]() for i in 0.. CGFloat.pi/4 && point.direction < CGFloat.pi * 3/4) || (point.direction > CGFloat.pi * 5/4 && point.direction < CGFloat.pi * 7/4) { @@ -460,7 +463,7 @@ private func prepareText(tickName: String, at point: RoundedRect.OrientedPoint, return text } -fileprivate func prepareCoreText(text: String, offsetRatio: CGFloat, centerOffset: CGFloat, outerBound: RoundedRect, maxLength: Int, viewSize: CGSize, font: WatchFont) -> [DrawableText] { +private func prepareCoreText(text: String, offsetRatio: CGFloat, centerOffset: CGFloat, outerBound: RoundedRect, maxLength: Int, viewSize: CGSize, font: WatchFont) -> [DrawableText] { let centerTextShortSize = min(outerBound._boundBox.width, outerBound._boundBox.height) * 0.31 let centerTextLongSize = max(outerBound._boundBox.width, outerBound._boundBox.height) * 0.17 let centerTextSize = min(centerTextShortSize, centerTextLongSize) * sqrt(5/CGFloat(maxLength)) @@ -469,18 +472,18 @@ fileprivate func prepareCoreText(text: String, offsetRatio: CGFloat, centerOffse var offset = min(centerTextSize * abs(offsetRatio) * sqrt(CGFloat(maxLength)/3), minSeparation) offset *= offsetRatio >= 0 ? 1.0 : -1.0 offset += centerTextSize * centerOffset * sqrt(CGFloat(maxLength)/3) - + var drawableTexts = [DrawableText]() let centerFont = font.font.withSize(centerTextSize) - + let attrStr = NSMutableAttributedString(string: text) - attrStr.addAttributes([.font: centerFont, .foregroundColor: CGColor(gray: 1, alpha: 1)], range: NSMakeRange(0, attrStr.length)) + attrStr.addAttributes([.font: centerFont, .foregroundColor: CGColor(gray: 1, alpha: 1)], range: NSRange(location: 0, length: attrStr.length)) var characters = attrStr.string.map { NSMutableAttributedString(string: String($0), attributes: attrStr.attributes(at: 0, effectiveRange: nil)) } if characters.count > maxLength { characters = Array(characters[.. [CGFloat] { - return angles.map { angle in - if phase >= 0 { - return (angle + phase) % 1.0 - } else { - return (-angle + phase) % 1.0 - } - } -} diff --git a/Shared/Views/WatchFaceView.swift b/Shared/Views/WatchFaceView.swift index 4b32919..7c22dfb 100644 --- a/Shared/Views/WatchFaceView.swift +++ b/Shared/Views/WatchFaceView.swift @@ -31,8 +31,8 @@ private func calSubhourGradient(watchLayout: WatchLayout, chineseCalendar: Chine let startOfDay = chineseCalendar.startOfDay let lengthOfDay = startOfDay.distance(to: chineseCalendar.startOfNextDay) let fourthRingColor = WatchLayout.Gradient(locations: [0, 1], colors: [ - watchLayout.thirdRing.interpolate(at: (startOfDay.distance(to: chineseCalendar.startHour) / lengthOfDay) % 1.0), - watchLayout.thirdRing.interpolate(at: (startOfDay.distance(to: chineseCalendar.endHour) / lengthOfDay) % 1.0) + watchLayout.thirdRing.interpolate(at: (startOfDay.distance(to: chineseCalendar.startHour) / lengthOfDay) %% 1.0), + watchLayout.thirdRing.interpolate(at: (startOfDay.distance(to: chineseCalendar.endHour) / lengthOfDay) %% 1.0) ], loop: false) return fourthRingColor } @@ -45,8 +45,10 @@ private enum Rings { private func ringMarks(for ring: Rings, watchLayout: WatchLayout, chineseCalendar: ChineseCalendar, radius: CGFloat) -> ([Marks], [Marks]) { switch ring { case .date: + let planets = chineseCalendar.planetPosition.getValues([\.mercury, \.venus, \.mars, \.jupiter, \.saturn, \.moon]) + let planetColors = watchLayout.planetIndicator.getValues([\.mercury, \.venus, \.mars, \.jupiter, \.saturn, \.moon]) let eventInMonth = chineseCalendar.eventInMonth - let firstRingMarks = [Marks(outer: true, locations: chineseCalendar.planetPosition, colors: watchLayout.planetIndicator, radius: radius)] + let firstRingMarks = [Marks(outer: true, locations: planets, colors: planetColors, radius: radius)] let secondRingMarks = [ Marks(outer: true, locations: eventInMonth.eclipse, colors: [watchLayout.eclipseIndicator], radius: radius), Marks(outer: true, locations: eventInMonth.fullMoon, colors: [watchLayout.fullmoonIndicator], radius: radius), @@ -54,27 +56,33 @@ private func ringMarks(for ring: Rings, watchLayout: WatchLayout, chineseCalenda Marks(outer: true, locations: eventInMonth.evenSolarTerm, colors: [watchLayout.evenStermIndicator], radius: radius) ] return (firstRingMarks, secondRingMarks) - + case .time: let eventInDay = chineseCalendar.eventInDay let sunMoonPositions = chineseCalendar.sunMoonPositions + let sunTimes = sunMoonPositions.solar.getValues([\.midnight, \.sunrise, \.noon, \.sunset]) + let sunColors = watchLayout.sunPositionIndicator.getValues([\.midnight, \.sunrise, \.noon, \.sunset]) + let moonTimes = sunMoonPositions.lunar.getValues([\.moonrise, \.highMoon, \.moonset]) + let moonColors = watchLayout.moonPositionIndicator.getValues([\.moonrise, \.highMoon, \.moonset]) let thirdRingMarks = [ Marks(outer: true, locations: eventInDay.eclipse, colors: [watchLayout.eclipseIndicator], radius: radius), Marks(outer: true, locations: eventInDay.fullMoon, colors: [watchLayout.fullmoonIndicator], radius: radius), Marks(outer: true, locations: eventInDay.oddSolarTerm, colors: [watchLayout.oddStermIndicator], radius: radius), Marks(outer: true, locations: eventInDay.evenSolarTerm, colors: [watchLayout.evenStermIndicator], radius: radius), - Marks(outer: false, locations: sunMoonPositions.solar, colors: watchLayout.sunPositionIndicator, radius: radius), - Marks(outer: false, locations: sunMoonPositions.lunar, colors: watchLayout.moonPositionIndicator, radius: radius) + Marks(outer: false, locations: sunTimes, colors: sunColors, radius: radius), + Marks(outer: false, locations: moonTimes, colors: moonColors, radius: radius) ] let eventInHour = chineseCalendar.eventInHour let sunMoonSubhourPositions = chineseCalendar.sunMoonSubhourPositions + let sunTimesSubhour = sunMoonSubhourPositions.solar.getValues([\.midnight, \.sunrise, \.noon, \.sunset]) + let moonTimesSubhour = sunMoonSubhourPositions.lunar.getValues([\.moonrise, \.highMoon, \.moonset]) let fourthRingMarks = [ Marks(outer: true, locations: eventInHour.eclipse, colors: [watchLayout.eclipseIndicator], radius: radius), Marks(outer: true, locations: eventInHour.fullMoon, colors: [watchLayout.fullmoonIndicator], radius: radius), Marks(outer: true, locations: eventInHour.oddSolarTerm, colors: [watchLayout.oddStermIndicator], radius: radius), Marks(outer: true, locations: eventInHour.evenSolarTerm, colors: [watchLayout.evenStermIndicator], radius: radius), - Marks(outer: false, locations: sunMoonSubhourPositions.solar, colors: watchLayout.sunPositionIndicator, radius: radius), - Marks(outer: false, locations: sunMoonSubhourPositions.lunar, colors: watchLayout.moonPositionIndicator, radius: radius) + Marks(outer: false, locations: sunTimesSubhour, colors: sunColors, radius: radius), + Marks(outer: false, locations: moonTimesSubhour, colors: moonColors, radius: radius) ] return (thirdRingMarks, fourthRingMarks) } @@ -129,7 +137,7 @@ struct PressState { } func pressAnchor(pos: CGPoint?, size: CGSize, proxy: GeometryProxy) -> UnitPoint { - let center = CGPointMake(size.width / 2, size.height / 2) + let center = CGPoint(x: size.width / 2, y: size.height / 2) let tapPosition: CGPoint if var tapPos = pos { tapPos.x -= (proxy.size.width - size.width) / 2 @@ -145,7 +153,7 @@ func pressAnchor(pos: CGPoint?, size: CGSize, proxy: GeometryProxy) -> UnitPoint struct Watch: View { static let frameOffset: CGFloat = 0.03 - + @Environment(\.colorScheme) var colorScheme #if !os(visionOS) @Environment(\.showsWidgetContainerBackground) var showsWidgetContainerBackground @@ -166,7 +174,7 @@ struct Watch: View { let entityNotes: EntityNotes? let shift: CGSize let highlightType: HighlightType - + init(displaySubquarter: Bool, displaySolarTerms: Bool, compact: Bool, watchLayout: WatchLayout, markSize: CGFloat, chineseCalendar: ChineseCalendar, highlightType: HighlightType, widthScale: CGFloat = 1, centerOffset: CGFloat = 0.05, entityNotes: EntityNotes? = nil, textShift: Bool = false, shrink: Bool = true) { self.shrink = shrink self.displayZeroRing = displaySolarTerms @@ -180,14 +188,14 @@ struct Watch: View { self.entityNotes = entityNotes self.highlightType = highlightType self.shift = if textShift { - CGSizeMake(watchLayout.horizontalTextOffset, watchLayout.verticalTextOffset) + CGSize(width: watchLayout.horizontalTextOffset, height: watchLayout.verticalTextOffset) } else { CGSize.zero } } - + var body: some View { - + #if !os(visionOS) let watchLayout = switch widgetRenderingMode { case .fullColor: @@ -198,18 +206,18 @@ struct Watch: View { #else let watchLayout = self.watchLayout #endif - + let fourthRingColor = calSubhourGradient(watchLayout: watchLayout, chineseCalendar: chineseCalendar) - + let textColor = colorScheme == .dark ? watchLayout.fontColorDark : watchLayout.fontColor let majorTickColor = colorScheme == .dark ? watchLayout.majorTickColorDark : watchLayout.majorTickColor let minorTickColor = colorScheme == .dark ? watchLayout.minorTickColorDark : watchLayout.minorTickColor let coreColor = colorScheme == .dark ? watchLayout.innerColorDark : watchLayout.innerColor let backColor = colorScheme == .dark ? watchLayout.backColorDark : watchLayout.backColor let shadowDirection = chineseCalendar.currentHourInDay - + GeometryReader { proxy in - + let size = proxy.size let shortEdge = min(size.width, size.height) let cornerSize = watchLayout.cornerRadiusRatio * shortEdge @@ -221,7 +229,7 @@ struct Watch: View { let innerBound = fourthRingOuter.shrink(by: Ring.paddedWidth * shortEdge * widthScale) let (firstRingMarks, secondRingMarks) = ringMarks(for: .date, watchLayout: watchLayout, chineseCalendar: chineseCalendar, radius: Marks.markSize * shortEdge * markSize) let (thirdRingMarks, fourthRingMarks) = ringMarks(for: .time, watchLayout: watchLayout, chineseCalendar: chineseCalendar, radius: Marks.markSize * shortEdge * markSize) - + ZStack { if displayZeroRing { let oddSTColor = colorScheme == .dark ? watchLayout.oddSolarTermTickColorDark : watchLayout.oddSolarTermTickColor @@ -252,7 +260,7 @@ struct Watch: View { struct DateWatch: View { static let frameOffset: CGFloat = 0.03 - + @Environment(\.directedScale) var directedScale @Environment(\.colorScheme) var colorScheme #if !os(visionOS) @@ -271,7 +279,7 @@ struct DateWatch: View { let centerOffset: CGFloat let entityNotes: EntityNotes? let highlightType: HighlightType - + init(displaySolarTerms: Bool, compact: Bool, watchLayout: WatchLayout, markSize: CGFloat, chineseCalendar: ChineseCalendar, highlightType: HighlightType, widthScale: CGFloat = 1, centerOffset: CGFloat = 0.05, entityNotes: EntityNotes? = nil, shrink: Bool = true) { self.shrink = shrink self.displayZeroRing = displaySolarTerms @@ -284,9 +292,9 @@ struct DateWatch: View { self.entityNotes = entityNotes self.highlightType = highlightType } - + var body: some View { - + #if !os(visionOS) let watchLayout = switch widgetRenderingMode { case .fullColor: @@ -304,9 +312,9 @@ struct DateWatch: View { let coreColor = colorScheme == .dark ? watchLayout.innerColorDark : watchLayout.innerColor let backColor = colorScheme == .dark ? watchLayout.backColorDark : watchLayout.backColor let shadowDirection = chineseCalendar.currentHourInDay - + GeometryReader { proxy in - + let size = proxy.size let shortEdge = min(size.width, size.height) let cornerSize = watchLayout.cornerRadiusRatio * shortEdge @@ -314,9 +322,9 @@ struct DateWatch: View { let firstRingOuter = displayZeroRing ? outerBound.shrink(by: ZeroRing.width * shortEdge * widthScale) : outerBound let secondRingOuter = firstRingOuter.shrink(by: Ring.paddedWidth * shortEdge * widthScale) let innerBound = secondRingOuter.shrink(by: Ring.paddedWidth * shortEdge * widthScale) - + let (firstRingMarks, secondRingMarks) = ringMarks(for: .date, watchLayout: watchLayout, chineseCalendar: chineseCalendar, radius: Marks.markSize * shortEdge * markSize) - + ZStack { if displayZeroRing { let oddSTColor = colorScheme == .dark ? watchLayout.oddSolarTermTickColorDark : watchLayout.oddSolarTermTickColor @@ -341,7 +349,7 @@ struct DateWatch: View { struct TimeWatch: View { static let frameOffset: CGFloat = 0.03 - + @Environment(\.directedScale) var directedScale @Environment(\.colorScheme) var colorScheme #if !os(visionOS) @@ -361,7 +369,7 @@ struct TimeWatch: View { let centerOffset: CGFloat let entityNotes: EntityNotes? let highlightType: HighlightType - + init(matchZeroRingGap: Bool, displaySubquarter: Bool, compact: Bool, watchLayout: WatchLayout, markSize: CGFloat, chineseCalendar: ChineseCalendar, highlightType: HighlightType, widthScale: CGFloat = 1, centerOffset: CGFloat = 0.05, entityNotes: EntityNotes? = nil, shrink: Bool = true) { self.shrink = shrink self.displayZeroRing = matchZeroRingGap @@ -375,9 +383,9 @@ struct TimeWatch: View { self.entityNotes = entityNotes self.highlightType = highlightType } - + var body: some View { - + #if !os(visionOS) let watchLayout = switch widgetRenderingMode { case .fullColor: @@ -388,18 +396,18 @@ struct TimeWatch: View { #else let watchLayout = self.watchLayout #endif - + let fourthRingColor = calSubhourGradient(watchLayout: watchLayout, chineseCalendar: chineseCalendar) - + let textColor = colorScheme == .dark ? watchLayout.fontColorDark : watchLayout.fontColor let majorTickColor = colorScheme == .dark ? watchLayout.majorTickColorDark : watchLayout.majorTickColor let minorTickColor = colorScheme == .dark ? watchLayout.minorTickColorDark : watchLayout.minorTickColor let coreColor = colorScheme == .dark ? watchLayout.innerColorDark : watchLayout.innerColor let backColor = colorScheme == .dark ? watchLayout.backColorDark : watchLayout.backColor let shadowDirection = chineseCalendar.currentHourInDay - + GeometryReader { proxy in - + let size = proxy.size let shortEdge = min(size.width, size.height) let cornerSize = watchLayout.cornerRadiusRatio * shortEdge @@ -408,7 +416,7 @@ struct TimeWatch: View { let secondRingOuter = firstRingOuter.shrink(by: Ring.paddedWidth * shortEdge * widthScale) let innerBound = secondRingOuter.shrink(by: Ring.paddedWidth * shortEdge * widthScale) let (thirdRingMarks, fourthRingMarks) = ringMarks(for: .time, watchLayout: watchLayout, chineseCalendar: chineseCalendar, radius: Marks.markSize * shortEdge * markSize) - + ZStack { let _ = entityNotes?.reset() Ring(width: Ring.paddedWidth * widthScale, viewSize: size, compact: compact, ticks: chineseCalendar.hourTicks, startingAngle: watchLayout.startingPhase.thirdRing, angle: chineseCalendar.currentHourInDay, textFont: WatchFont(watchLayout.textFont), textColor: textColor, alpha: watchLayout.shadeAlpha, majorTickAlpha: watchLayout.majorTickAlpha, minorTickAlpha: watchLayout.minorTickAlpha, majorTickColor: majorTickColor, minorTickColor: minorTickColor, backColor: backColor, gradientColor: watchLayout.thirdRing, outerRing: firstRingOuter, marks: thirdRingMarks, shadowDirection: shadowDirection, entityNotes: entityNotes, shadowSize: showsWidgetContainerBackground ? watchLayout.shadowSize : 0.0, highlightType: highlightType) @@ -417,7 +425,7 @@ struct TimeWatch: View { Ring(width: Ring.paddedWidth * widthScale, viewSize: size, compact: compact, ticks: chineseCalendar.subhourTicks, startingAngle: watchLayout.startingPhase.fourthRing, angle: chineseCalendar.subhourInHour, textFont: WatchFont(watchLayout.textFont), textColor: textColor, alpha: watchLayout.shadeAlpha, majorTickAlpha: watchLayout.majorTickAlpha, minorTickAlpha: watchLayout.minorTickAlpha, majorTickColor: majorTickColor, minorTickColor: minorTickColor, backColor: backColor, gradientColor: fourthRingColor, outerRing: secondRingOuter, marks: fourthRingMarks, shadowDirection: shadowDirection, entityNotes: entityNotes, shadowSize: watchLayout.shadowSize, highlightType: highlightType) .scaleEffect(1 + directedScale.value * 0.75, anchor: directedScale.anchor) .animation(.spring(duration: 0.5, bounce: 0.7, blendDuration: 0.2), value: directedScale) - + let timeString = displaySubquarter ? chineseCalendar.quarterString : chineseCalendar.shortQuarterString Core(viewSize: size, dateString: chineseCalendar.hourString, timeString: timeString, font: WatchFont(watchLayout.centerFont), maxLength: 3, textColor: watchLayout.centerFontColor, outerBound: innerBound, innerColor: coreColor, backColor: backColor, centerOffset: centerOffset, shadowDirection: shadowDirection, shadowSize: watchLayout.shadowSize) .scaleEffect(1 + directedScale.value, anchor: directedScale.anchor) @@ -427,12 +435,11 @@ struct TimeWatch: View { } } - #Preview("Watch") { let chineseCalendar = ChineseCalendar() let watchLayout = WatchLayout() watchLayout.loadStatic() - + return Watch(displaySubquarter: true, displaySolarTerms: true, compact: false, watchLayout: watchLayout, markSize: 1.0, chineseCalendar: chineseCalendar, highlightType: .flicker) .frame(width: watchLayout.watchSize.width, height: watchLayout.watchSize.height) } diff --git a/Shared/WatchConnectivity.swift b/Shared/WatchConnectivity.swift index 960deda..ee152dc 100644 --- a/Shared/WatchConnectivity.swift +++ b/Shared/WatchConnectivity.swift @@ -13,7 +13,7 @@ final class WatchConnectivityManager: NSObject, WCSessionDelegate { @ObservationIgnored let watchLayout: WatchLayout @ObservationIgnored let calendarConfigure: CalendarConfigure @ObservationIgnored let locationManager: LocationManager - + init(watchLayout: WatchLayout, calendarConfigure: CalendarConfigure, locationManager: LocationManager) { self.watchLayout = watchLayout self.calendarConfigure = calendarConfigure @@ -24,7 +24,7 @@ final class WatchConnectivityManager: NSObject, WCSessionDelegate { WCSession.default.activate() } } - + func session(_ session: WCSession, didReceiveMessage message: [String: Any]) { #if os(watchOS) if let newLayout = message["layout"] as? String { @@ -56,18 +56,18 @@ final class WatchConnectivityManager: NSObject, WCSessionDelegate { } #endif } - + func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {} - + #if os(iOS) func sessionDidBecomeInactive(_ session: WCSession) {} func sessionDidDeactivate(_ session: WCSession) { session.activate() } #endif - + func send(messages: [String: String]) { guard WCSession.default.activationState == .activated else { return } #if os(iOS) @@ -81,7 +81,7 @@ final class WatchConnectivityManager: NSObject, WCSessionDelegate { } } } - + #if os(watchOS) func requestLayout() { Task(priority: .background) { @@ -92,4 +92,3 @@ final class WatchConnectivityManager: NSObject, WCSessionDelegate { } #endif } - diff --git a/Vision/Layout.swift b/Vision/Layout.swift index f3a824c..21c4cf8 100644 --- a/Vision/Layout.swift +++ b/Vision/Layout.swift @@ -9,9 +9,9 @@ import SwiftUI import Observation @Observable final class WatchLayout: MetaWatchLayout { - + struct StatusBar: Equatable { - + enum Separator: String, CaseIterable { case space, dot, none var symbol: String { @@ -22,23 +22,23 @@ import Observation } } } - + var date: Bool var time: Bool var holiday: Int var separator: Separator - + func encode() -> String { "date: \(date.description), time: \(time.description), holiday: \(holiday.description), separator: \(separator.rawValue)" } - + init(date: Bool = true, time: Bool = true, holiday: Int = 0, separator: Separator = .space) { self.date = date self.time = time self.holiday = holiday self.separator = separator } - + init?(from str: String?) { guard let str = str else { return nil } let regex = /([a-zA-Z_0-9]+)\s*:[\s"]*([^\s"#][^"#]*)[\s"#]*(#*.*)$/ @@ -58,28 +58,28 @@ import Observation var textFont = UIFont.systemFont(ofSize: UIFont.systemFontSize, weight: .regular) var centerFont = UIFont(name: "SourceHanSansKR-Heavy", size: UIFont.systemFontSize)! - + var statusBar = StatusBar() - + override func encode(includeOffset: Bool = true, includeColor: Bool = true) -> String { var encoded = super.encode(includeOffset: includeOffset, includeColor: includeColor) encoded += "statusBar: \(statusBar.encode())\n" return encoded } - + override func update(from values: [String: String], updateSize: Bool = true) { super.update(from: values, updateSize: updateSize) if let value = values["statusBar"] { statusBar = StatusBar(from: value) ?? statusBar } } - + var monochrome: Self { let emptyLayout = Self.init() emptyLayout.update(from: self.encode(includeColor: false)) return emptyLayout } - + func binding(_ keyPath: ReferenceWritableKeyPath) -> Binding { return Binding(get: { self[keyPath: keyPath] }, set: { self[keyPath: keyPath] = $0 }) } @@ -92,18 +92,18 @@ import Observation enum TabSelection: String, CaseIterable { case spaceTime, design, documentation } - - var displayTime: Date? = nil + + var displayTime: Date? var vertical = true var settingIsOpen = false var timeDisplay = "" - @ObservationIgnored var previousSelectionSpaceTime: Selection? = nil - @ObservationIgnored var previousSelectionDesign: Selection? = nil - @ObservationIgnored var previousTabSelection: TabSelection? = nil + @ObservationIgnored var previousSelectionSpaceTime: Selection? + @ObservationIgnored var previousSelectionDesign: Selection? + @ObservationIgnored var previousTabSelection: TabSelection? var effectiveTime: Date { displayTime ?? .now } - + func binding(_ keyPath: ReferenceWritableKeyPath) -> Binding { return Binding(get: { self[keyPath: keyPath] }, set: { self[keyPath: keyPath] = $0 }) } diff --git a/Vision/Views/Setting.swift b/Vision/Views/Setting.swift index 86d1327..68a30fc 100644 --- a/Vision/Views/Setting.swift +++ b/Vision/Views/Setting.swift @@ -16,8 +16,8 @@ struct Setting: View { @State private var selection: WatchSetting.Selection? @State private var selectedTab: WatchSetting.TabSelection = .spaceTime let spaceTimePages: [WatchSetting.Selection] = [.datetime, .location, .configs] - let designPages: [WatchSetting.Selection] = [.ringColor, .decoration, .markColor,.layout, .themes] - + let designPages: [WatchSetting.Selection] = [.ringColor, .decoration, .markColor, .layout, .themes] + var body: some View { TabView(selection: $selectedTab) { NavigationSplitView { @@ -57,7 +57,7 @@ struct Setting: View { Label("時空", systemImage: "globe.desk") } .navigationSplitViewColumnWidth(ideal: 200) - + NavigationSplitView { List(selection: $selection) { ForEach(designPages, id: \.self) { selection in @@ -103,7 +103,7 @@ struct Setting: View { Label("設計", systemImage: "paintbrush") } .navigationSplitViewColumnWidth(ideal: 200) - + NavigationStack { Documentation() } @@ -125,7 +125,7 @@ struct Setting: View { } } } - + func buildView(selection: WatchSetting.Selection) -> some View { let sel = switch selection { case .datetime: @@ -156,7 +156,7 @@ struct Setting: View { let calendarConfigure = CalendarConfigure() let watchSetting = WatchSetting() watchLayout.loadStatic() - + return Setting() .modelContainer(DataSchema.container) .environment(chineseCalendar) diff --git a/Vision/Views/WatchFace.swift b/Vision/Views/WatchFace.swift index 41c5a8a..b05dd9f 100644 --- a/Vision/Views/WatchFace.swift +++ b/Vision/Views/WatchFace.swift @@ -15,10 +15,10 @@ struct WatchFace: View { @Environment(\.modelContext) private var modelContext @State var showWelcome = false @State var entityPresenting = EntitySelection() - @State var tapPos: CGPoint? = nil + @State var tapPos: CGPoint? @State var hoverBounds: CGRect = .zero @State var touchState = PressState() - + func tapped(tapPosition: CGPoint, proxy: GeometryProxy, size: CGSize) { var tapPosition = tapPosition tapPos = tapPosition @@ -33,7 +33,7 @@ struct WatchFace: View { } } } - + func mainSize(proxy: GeometryProxy) -> CGSize { var idealSize = watchLayout.watchSize if proxy.size.height < proxy.size.width { @@ -53,7 +53,7 @@ struct WatchFace: View { } return idealSize } - + var body: some View { GeometryReader { proxy in @@ -68,21 +68,21 @@ struct WatchFace: View { touchState.pressing = true touchState.location = value.location } - .onEnded { value in + .onEnded { _ in if touchState.tapped { tapped(tapPosition: touchState.location!, proxy: proxy, size: size) } touchState.pressing = false touchState.location = nil } - + ZStack { Watch(displaySubquarter: true, displaySolarTerms: true, compact: false, watchLayout: watchLayout, markSize: 1.0, chineseCalendar: chineseCalendar, highlightType: .flicker, widthScale: 0.9, centerOffset: centerOffset, entityNotes: entityPresenting.entityNotes, textShift: true) .frame(width: size.width, height: size.height) .position(CGPoint(x: proxy.size.width / 2, y: proxy.size.height / 2)) .environment(\.directedScale, DirectedScale(value: touchState.pressing ? -0.1 : 0.0, anchor: pressAnchor(pos: touchState.location, size: size, proxy: proxy))) .gesture(gesture) - + Hover(entityPresenting: entityPresenting, bounds: $hoverBounds, tapPos: $tapPos) } .onChange(of: proxy.size) { @@ -92,10 +92,10 @@ struct WatchFace: View { .animation(.easeInOut(duration: 0.2), value: entityPresenting.activeNote) } .sheet(isPresented: $showWelcome) { - Welcome(size: CGSizeMake(watchLayout.watchSize.width * 0.8, watchLayout.watchSize.height * 0.8)) + Welcome(size: CGSize(width: watchLayout.watchSize.width * 0.8, height: watchLayout.watchSize.height * 0.8)) } .task(priority: .background) { - showWelcome = ThemeData.latestVersion() < ThemeData.version + showWelcome = ThemeData.notLatest() } } } @@ -105,7 +105,7 @@ struct WatchFace: View { let watchLayout = WatchLayout() let watchSetting = WatchSetting() watchLayout.loadStatic() - + return WatchFace() .modelContainer(DataSchema.container) .environment(chineseCalendar) diff --git a/Vision/Views/Welcome.swift b/Vision/Views/Welcome.swift index 84c2183..505c6ae 100644 --- a/Vision/Views/Welcome.swift +++ b/Vision/Views/Welcome.swift @@ -11,7 +11,7 @@ struct Welcome: View { let size: CGSize @Environment(\.dismiss) var dismiss @Environment(WatchLayout.self) var watchLayout - + var body: some View { let baseLength = min(size.width, size.height) VStack { @@ -76,7 +76,7 @@ struct Welcome: View { } Spacer(minLength: baseLength / 50) .frame(maxHeight: baseLength / 25) - + Button { dismiss() } label: { @@ -91,10 +91,9 @@ struct Welcome: View { } } - #Preview("Welcome") { let watchLayout = WatchLayout() watchLayout.loadStatic() - return Welcome(size: CGSizeMake(396, 484)) + return Welcome(size: CGSize(width: 396, height: 484)) .environment(watchLayout) } diff --git a/Vision/visionApp.swift b/Vision/visionApp.swift index 22aab59..9d39c32 100644 --- a/Vision/visionApp.swift +++ b/Vision/visionApp.swift @@ -20,7 +20,7 @@ struct Chinendar: App { private var statusState: StatusState { StatusState(locationManager: locationManager, watchLayout: watchLayout, calendarConfigure: calendarConfigure, watchSetting: watchSetting) } - + init() { watchLayout.loadDefault(context: DataSchema.container.mainContext) calendarConfigure.load(name: LocalData.read(context: LocalSchema.container.mainContext)?.configName, context: DataSchema.container.mainContext) @@ -29,7 +29,7 @@ struct Chinendar: App { calendarConfigure.autoSave() calendarConfigure.autoSaveName() } - + var body: some Scene { WindowGroup(id: "WatchFace") { WatchFace() @@ -78,7 +78,7 @@ struct Chinendar: App { } .defaultSize(width: watchLayout.watchSize.width + 30, height: watchLayout.watchSize.height + 30) .windowResizability(.contentSize) - + WindowGroup(id: "Settings") { Setting() .modelContainer(DataSchema.container) @@ -93,7 +93,7 @@ struct Chinendar: App { } .defaultSize(width: 900, height: 700) } - + func statusBar(from chineseCalendar: ChineseCalendar, options watchLayout: WatchLayout) -> String { var displayText = [String]() if watchLayout.statusBar.date { @@ -108,7 +108,7 @@ struct Chinendar: App { } return displayText.joined(separator: watchLayout.statusBar.separator.symbol) } - + func update() { chineseCalendar.update(time: watchSetting.effectiveTime, timezone: calendarConfigure.effectiveTimezone, diff --git a/Watch/Layout.swift b/Watch/Layout.swift index 9a06422..b06045d 100644 --- a/Watch/Layout.swift +++ b/Watch/Layout.swift @@ -9,11 +9,11 @@ import SwiftUI import Observation @Observable final class WatchLayout: MetaWatchLayout { - + var textFont = UIFont.systemFont(ofSize: 14, weight: .regular) var centerFont = UIFont(name: "SourceHanSansKR-Heavy", size: 14)! var dualWatch = false - + override func encode(includeOffset: Bool = true, includeColor: Bool = true) -> String { var encoded = super.encode(includeOffset: includeOffset, includeColor: includeColor) encoded += "dualWatch: \(dualWatch)\n" @@ -26,22 +26,22 @@ import Observation dualWatch = dual } } - + var monochrome: Self { let emptyLayout = Self.init() emptyLayout.update(from: self.encode(includeColor: false)) return emptyLayout } - + func binding(_ keyPath: ReferenceWritableKeyPath) -> Binding { return Binding(get: { self[keyPath: keyPath] }, set: { self[keyPath: keyPath] = $0 }) } } @Observable final class WatchSetting { - + var size: CGSize = .zero - var displayTime: Date? = nil + var displayTime: Date? var effectiveTime: Date { displayTime ?? .now } diff --git a/Watch/Views/ContentView.swift b/Watch/Views/ContentView.swift index 666c82a..fb877a7 100644 --- a/Watch/Views/ContentView.swift +++ b/Watch/Views/ContentView.swift @@ -12,12 +12,12 @@ struct WatchFaceTab: View { @Environment(WatchSetting.self) var watchSetting let proxy: GeometryProxy let tab: Tab - + init(proxy: GeometryProxy, @ViewBuilder content: () -> Tab) { self.proxy = proxy self.tab = content() } - + var body: some View { TabView { tab diff --git a/Watch/Views/DateTimeAdjust.swift b/Watch/Views/DateTimeAdjust.swift index c567106..c962fea 100644 --- a/Watch/Views/DateTimeAdjust.swift +++ b/Watch/Views/DateTimeAdjust.swift @@ -8,10 +8,10 @@ import SwiftUI import Observation -@Observable fileprivate class TimeManager { +@Observable private class TimeManager { var chineseCalendar: ChineseCalendar? var watchSetting: WatchSetting? - + var time: Date { get { watchSetting?.displayTime ?? chineseCalendar?.time ?? .now @@ -24,7 +24,7 @@ import Observation chineseCalendar?.update(time: watchSetting?.displayTime ?? .now) } } - + var isCurrent: Bool { get { watchSetting?.displayTime == nil @@ -37,7 +37,7 @@ import Observation chineseCalendar?.update(time: watchSetting?.displayTime ?? .now) } } - + func setup(watchSetting: WatchSetting, chineseCalendar: ChineseCalendar) { self.watchSetting = watchSetting self.chineseCalendar = chineseCalendar @@ -48,7 +48,7 @@ struct DateTimeAdjust: View { @Environment(WatchSetting.self) var watchSetting @Environment(ChineseCalendar.self) var chineseCalendar @State private var timeManager = TimeManager() - + var body: some View { VStack(spacing: 10) { DatePicker(selection: $timeManager.time, in: ChineseCalendar.start...ChineseCalendar.end, displayedComponents: [.date]) { @@ -88,7 +88,6 @@ struct DateTimeAdjust: View { } } - #Preview("Datetime Adjust") { let chineseCalendar = ChineseCalendar(compact: true) let watchSetting = WatchSetting() diff --git a/Watch/Views/Setting.swift b/Watch/Views/Setting.swift index 05fc420..4c154f0 100644 --- a/Watch/Views/Setting.swift +++ b/Watch/Views/Setting.swift @@ -22,7 +22,7 @@ struct Setting: View { watchLayout.cornerRadiusRatio = newValue }) } - + var body: some View { List { Section { @@ -35,7 +35,7 @@ struct Setting: View { } header: { Text("圓角比例", comment: "Corner radius ratio") } - + Section { NavigationLink { DateTimeAdjust() diff --git a/Watch/Views/SwitchConfig.swift b/Watch/Views/SwitchConfig.swift index 2874058..2e5fb24 100644 --- a/Watch/Views/SwitchConfig.swift +++ b/Watch/Views/SwitchConfig.swift @@ -17,7 +17,7 @@ struct SwitchConfig: View { @State private var deleteAlert = false @State private var errorAlert = false @State private var errorMsg = "" - @State private var target: ConfigData? = nil + @State private var target: ConfigData? var body: some View { List { @@ -37,11 +37,11 @@ struct SwitchConfig: View { displayText.append(calendar.hourString + calendar.quarterString) return displayText.joined(separator: " ") }() - + let dateLabel = Text(String(chineseDate.reversed())) .foregroundStyle(.secondary) .font(.caption) - + let nameLabel = switch (config.name! == AppInfo.defaultName, config.name! == calendarConfigure.name) { case (true, true): Label("常用", systemImage: "checkmark.circle.fill") @@ -56,7 +56,7 @@ struct SwitchConfig: View { Label(config.name!, systemImage: "circle") .foregroundStyle(Color.primary) } - + Button { calendarConfigure.update(from: config.code!, newName: config.name!) chineseCalendar.update(timezone: calendarConfigure.effectiveTimezone, @@ -64,7 +64,7 @@ struct SwitchConfig: View { globalMonth: calendarConfigure.globalMonth, apparentTime: calendarConfigure.apparentTime, largeHour: calendarConfigure.largeHour) } label: { - VStack() { + VStack { nameLabel .frame(maxWidth: .infinity, alignment: .leading) dateLabel @@ -105,7 +105,7 @@ struct SwitchConfig: View { } } } - + #Preview("SwitchConfig") { let chineseCalendar = ChineseCalendar(compact: true) let locationManager = LocationManager() diff --git a/Watch/Views/WatchFace.swift b/Watch/Views/WatchFace.swift index 7511555..db4933a 100644 --- a/Watch/Views/WatchFace.swift +++ b/Watch/Views/WatchFace.swift @@ -9,11 +9,11 @@ import SwiftUI struct WatchFace: View { @Binding var entityPresenting: EntitySelection - @State var tapPos: CGPoint? = nil + @State var tapPos: CGPoint? @State var hoverBounds: CGRect = .zero @ViewBuilder let content: () -> Content @State var touchState = PressState() - + func tapped(tapPosition: CGPoint, proxy: GeometryProxy, size: CGSize) { var tapPosition = tapPosition tapPos = tapPosition @@ -28,7 +28,7 @@ struct WatchFace: View { } } } - + var body: some View { GeometryReader { proxy in let gesture = DragGesture(minimumDistance: 0, coordinateSpace: .local) @@ -36,14 +36,14 @@ struct WatchFace: View { touchState.pressing = true touchState.location = value.location } - .onEnded { value in + .onEnded { _ in if touchState.tapped { tapped(tapPosition: touchState.location!, proxy: proxy, size: proxy.size) } touchState.pressing = false touchState.location = nil } - + ZStack { content() .environment(\.directedScale, DirectedScale(value: touchState.pressing ? -0.1 : 0.0, anchor: pressAnchor(pos: touchState.location, size: proxy.size, proxy: proxy))) @@ -60,7 +60,7 @@ struct WatchFaceDate: View { @Environment(WatchSetting.self) var watchSetting @Environment(ChineseCalendar.self) var chineseCalendar @State var entityPresenting = EntitySelection() - + var body: some View { WatchFace(entityPresenting: $entityPresenting) { DateWatch(displaySolarTerms: false, compact: true, @@ -75,7 +75,7 @@ struct WatchFaceTime: View { @Environment(WatchSetting.self) var watchSetting @Environment(ChineseCalendar.self) var chineseCalendar @State var entityPresenting = EntitySelection() - + var body: some View { WatchFace(entityPresenting: $entityPresenting) { TimeWatch(matchZeroRingGap: false, displaySubquarter: true, compact: true, watchLayout: watchLayout, markSize: 1.5, chineseCalendar: chineseCalendar, highlightType: .flicker, widthScale: 1.5, entityNotes: entityPresenting.entityNotes, shrink: false) @@ -89,7 +89,7 @@ struct WatchFaceFull: View { @Environment(WatchSetting.self) var watchSetting @Environment(ChineseCalendar.self) var chineseCalendar @State var entityPresenting = EntitySelection() - + var body: some View { WatchFace(entityPresenting: $entityPresenting) { Watch(displaySubquarter: true, displaySolarTerms: false, compact: true, @@ -104,10 +104,10 @@ struct WatchFaceFull: View { let watchLayout = WatchLayout() let watchSetting = WatchSetting() watchLayout.loadStatic() - + return GeometryReader { proxy in WatchFaceDate() - .onAppear{ + .onAppear { watchSetting.size = proxy.size } } @@ -122,10 +122,10 @@ struct WatchFaceFull: View { let watchLayout = WatchLayout() let watchSetting = WatchSetting() watchLayout.loadStatic() - + return GeometryReader { proxy in WatchFaceTime() - .onAppear{ + .onAppear { watchSetting.size = proxy.size } } @@ -143,7 +143,7 @@ struct WatchFaceFull: View { return GeometryReader { proxy in WatchFaceFull() - .onAppear{ + .onAppear { watchSetting.size = proxy.size } } diff --git a/Watch/watchApp.swift b/Watch/watchApp.swift index 9a998d2..214efa1 100644 --- a/Watch/watchApp.swift +++ b/Watch/watchApp.swift @@ -16,7 +16,7 @@ struct Chinendar: App { let calendarConfigure = CalendarConfigure() let watchSetting = WatchSetting() let timer = Timer.publish(every: ChineseCalendar.updateInterval, on: .main, in: .common).autoconnect() - + init() { watchConnectivity = .init(watchLayout: watchLayout, calendarConfigure: calendarConfigure, locationManager: locationManager) watchLayout.loadDefault(context: DataSchema.container.mainContext) @@ -46,7 +46,7 @@ struct Chinendar: App { } } } - + func update() { chineseCalendar.update(time: watchSetting.effectiveTime, timezone: calendarConfigure.effectiveTimezone, diff --git a/Widget/Dual.swift b/Widget/Dual.swift index 212abc0..b54f516 100644 --- a/Widget/Dual.swift +++ b/Widget/Dual.swift @@ -13,9 +13,9 @@ enum DisplayOrder: String, AppEnum { case dateFirst, timeFirst static let typeDisplayRepresentation: TypeDisplayRepresentation = .init(name: "日時之順序") - static let caseDisplayRepresentations: [DisplayOrder : DisplayRepresentation] = [ + static let caseDisplayRepresentations: [DisplayOrder: DisplayRepresentation] = [ .dateFirst: .init(title: "日左時右"), - .timeFirst: .init(title: "時左日右"), + .timeFirst: .init(title: "時左日右") ] } @@ -26,13 +26,13 @@ struct MediumConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigratedApp @Parameter(title: "選日曆") var calendarConfig: ConfigIntent - + @Parameter(title: "順序", default: .dateFirst) var order: DisplayOrder - + @Parameter(title: "背景灰度", default: 0, controlStyle: .slider, inclusiveRange: (0, 1)) var backAlpha: Double - + static var parameterSummary: some ParameterSummary { Summary { \.$calendarConfig @@ -47,11 +47,11 @@ struct MediumProvider: ChinendarAppIntentTimelineProvider { typealias Intent = MediumConfiguration let modelContext = DataSchema.context let locationManager = LocationManager() - + func compactCalendar(context: Context) -> Bool { return context.family != .systemExtraLarge } - + func nextEntryDates(chineseCalendar: ChineseCalendar, config: MediumConfiguration, context: Context) -> [Date] { return chineseCalendar.nextQuarters(count: 10) } @@ -63,7 +63,7 @@ struct MediumEntry: TimelineEntry, ChinendarEntry { let chineseCalendar: ChineseCalendar let watchLayout: WatchLayout let relevance: TimelineEntryRelevance? - + init(configuration: MediumProvider.Intent, chineseCalendar: ChineseCalendar, watchLayout: WatchLayout) { date = chineseCalendar.time self.configuration = configuration @@ -80,7 +80,7 @@ struct MediumWidgetEntryView: View { init(entry: MediumProvider.Entry) { self.entry = entry } - + func backColor() -> Color { return Color.gray.opacity(entry.configuration.backAlpha) } @@ -106,7 +106,6 @@ struct MediumWidgetEntryView: View { } } - struct MediumWidget: Widget { static let kind: String = "Medium" diff --git a/Widget/Full.swift b/Widget/Full.swift index 8e04046..f970564 100644 --- a/Widget/Full.swift +++ b/Widget/Full.swift @@ -13,13 +13,13 @@ struct LargeConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigratedAppI static let intentClassName = "LargeIntent" static let title: LocalizedStringResource = "全錶" static let description = IntentDescription("完整錶面") - + @Parameter(title: "選日曆") var calendarConfig: ConfigIntent - + @Parameter(title: "背景灰度", default: 0, controlStyle: .slider, inclusiveRange: (0, 1)) var backAlpha: Double - + static var parameterSummary: some ParameterSummary { Summary { \.$calendarConfig @@ -33,11 +33,11 @@ struct LargeProvider: ChinendarAppIntentTimelineProvider { typealias Intent = LargeConfiguration let modelContext = DataSchema.context let locationManager = LocationManager() - + func compactCalendar(context: Context) -> Bool { return context.family != .systemLarge } - + func nextEntryDates(chineseCalendar: ChineseCalendar, config: LargeConfiguration, context: Context) -> [Date] { return chineseCalendar.nextQuarters(count: 10) } @@ -49,7 +49,7 @@ struct LargeEntry: TimelineEntry, ChinendarEntry { let chineseCalendar: ChineseCalendar let watchLayout: WatchLayout let relevance: TimelineEntryRelevance? - + init(configuration: LargeProvider.Intent, chineseCalendar: ChineseCalendar, watchLayout: WatchLayout) { date = chineseCalendar.time self.configuration = configuration @@ -66,7 +66,7 @@ struct LargeWidgetEntryView: View { init(entry: LargeProvider.Entry) { self.entry = entry } - + func backColor() -> Color { return Color.gray.opacity(entry.configuration.backAlpha) } diff --git a/Widget/Protocols.swift b/Widget/Protocols.swift index f4d56b4..b41c80f 100644 --- a/Widget/Protocols.swift +++ b/Widget/Protocols.swift @@ -12,7 +12,7 @@ import SwiftData protocol ChinendarAppIntentTimelineProvider: AppIntentTimelineProvider where Entry: ChinendarEntry { var modelContext: ModelContext { get } var locationManager: LocationManager { get } - + func nextEntryDates(chineseCalendar: ChineseCalendar, config: Entry.Intent, context: Context) -> [Date] func compactCalendar(context: Context) -> Bool } @@ -25,7 +25,7 @@ extension ChinendarAppIntentTimelineProvider { let chineseCalendar = ChineseCalendar(timezone: calendarConfigure.effectiveTimezone, location: calendarConfigure.location(locationManager: nil), compact: compactCalendar(context: context), globalMonth: calendarConfigure.globalMonth, apparentTime: calendarConfigure.apparentTime, largeHour: calendarConfigure.largeHour) return Entry(configuration: Entry.Intent(), chineseCalendar: chineseCalendar, watchLayout: watchLayout) } - + func snapshot(for configuration: Entry.Intent, in context: Context) async -> Entry { let watchLayout = WatchLayout() watchLayout.loadDefault(context: modelContext, local: true) @@ -35,18 +35,18 @@ extension ChinendarAppIntentTimelineProvider { let entry = Entry(configuration: configuration, chineseCalendar: chineseCalendar, watchLayout: watchLayout) return entry } - + func timeline(for configuration: Entry.Intent, in context: Context) async -> Timeline { let watchLayout = WatchLayout() watchLayout.loadDefault(context: modelContext, local: true) let calendarConfigure = CalendarConfigure() calendarConfigure.load(name: configuration.calendarConfig.name, context: modelContext) - let _ = await locationManager.getLocation() + _ = await locationManager.getLocation() let chineseCalendar = ChineseCalendar(timezone: calendarConfigure.effectiveTimezone, location: calendarConfigure.location(locationManager: locationManager), compact: compactCalendar(context: context), globalMonth: calendarConfigure.globalMonth, apparentTime: calendarConfigure.apparentTime, largeHour: calendarConfigure.largeHour) let originalChineseCalendar = chineseCalendar.copy let entryDates = nextEntryDates(chineseCalendar: chineseCalendar, config: configuration, context: context) - + var chineseCalendars = [chineseCalendar.copy] for entryDate in entryDates { chineseCalendar.update(time: entryDate, location: calendarConfigure.location(locationManager: locationManager)) @@ -60,7 +60,7 @@ extension ChinendarAppIntentTimelineProvider { #endif return Timeline(entries: entries, policy: .atEnd) } - + func compactCalendar(context: Context) -> Bool { return true } diff --git a/Widget/Single.swift b/Widget/Single.swift index 2b425b7..658f47f 100644 --- a/Widget/Single.swift +++ b/Widget/Single.swift @@ -13,9 +13,9 @@ enum DisplayMode: String, AppEnum { case date, time static let typeDisplayRepresentation: TypeDisplayRepresentation = .init(name: "日時之擇一") - static let caseDisplayRepresentations: [DisplayMode : DisplayRepresentation] = [ + static let caseDisplayRepresentations: [DisplayMode: DisplayRepresentation] = [ .date: .init(title: "日"), - .time: .init(title: "時"), + .time: .init(title: "時") ] } @@ -26,13 +26,13 @@ struct SmallConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigratedAppI @Parameter(title: "選日曆") var calendarConfig: ConfigIntent - + @Parameter(title: "型制", default: .time) var mode: DisplayMode - + @Parameter(title: "背景灰度", default: 0, controlStyle: .slider, inclusiveRange: (0, 1)) var backAlpha: Double - + static var parameterSummary: some ParameterSummary { Summary { \.$calendarConfig @@ -47,7 +47,7 @@ struct SmallProvider: ChinendarAppIntentTimelineProvider { typealias Intent = SmallConfiguration let modelContext = DataSchema.context let locationManager = LocationManager() - + func nextEntryDates(chineseCalendar: ChineseCalendar, config: SmallConfiguration, context: Context) -> [Date] { return switch config.mode { case .time: @@ -64,7 +64,7 @@ struct SmallEntry: TimelineEntry, ChinendarEntry { let chineseCalendar: ChineseCalendar let watchLayout: WatchLayout let relevance: TimelineEntryRelevance? - + init(configuration: SmallProvider.Intent, chineseCalendar: ChineseCalendar, watchLayout: WatchLayout) { date = chineseCalendar.time self.configuration = configuration @@ -84,7 +84,7 @@ struct SmallWidgetEntryView: View { var backColor: Color { Color.gray.opacity(entry.configuration.backAlpha) } - + var body: some View { switch entry.configuration.mode { case .time: @@ -114,7 +114,6 @@ struct SmallWidget: Widget { } } - #Preview("Small Date", as: .systemSmall, using: { let intent = SmallProvider.Intent() intent.calendarConfig = .init(id: AppInfo.defaultName) diff --git a/Widget/TaskGroup.swift b/Widget/TaskGroup.swift index 7fb8a46..2e9c585 100644 --- a/Widget/TaskGroup.swift +++ b/Widget/TaskGroup.swift @@ -12,10 +12,10 @@ import SwiftData struct ConfigIntent: AppEntity { let id: String var name: String { id } - + static let typeDisplayRepresentation: TypeDisplayRepresentation = "選日曆" static var defaultQuery = ConfigQuery() - + var displayRepresentation: DisplayRepresentation { if name != AppInfo.defaultName { DisplayRepresentation(title: "\(name)") @@ -29,16 +29,14 @@ struct ConfigQuery: EntityQuery { func entities(for identifiers: [String]) async throws -> [ConfigIntent] { try await suggestedEntities().filter { identifiers.contains($0.name) } } - + func suggestedEntities() async throws -> [ConfigIntent] { var allConfigs = [ConfigIntent]() let context = DataSchema.context let descriptor = FetchDescriptor(sortBy: [SortDescriptor(\.modifiedDate, order: .reverse)]) let configs = try context.fetch(descriptor) - for config in configs { - if !config.isNil { - allConfigs.append(ConfigIntent(id: config.name!)) - } + for config in configs where !config.isNil { + allConfigs.append(ConfigIntent(id: config.name!)) } if allConfigs.count > 0 { return allConfigs @@ -46,7 +44,7 @@ struct ConfigQuery: EntityQuery { return [ConfigIntent(id: AppInfo.defaultName)] } } - + func defaultResult() async -> ConfigIntent? { let name = LocalData.read(context: LocalSchema.context)?.configName ?? AppInfo.defaultName return ConfigIntent(id: name) diff --git a/Widget/WatchWidgets/Card.swift b/Widget/WatchWidgets/Card.swift index 16bbb34..0e04eb4 100644 --- a/Widget/WatchWidgets/Card.swift +++ b/Widget/WatchWidgets/Card.swift @@ -13,10 +13,10 @@ struct CardConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigratedAppIn static let intentClassName = "TextCardIntent" static let title: LocalizedStringResource = "文字片" static let description = IntentDescription("華曆文字片") - + @Parameter(title: "選日曆") var calendarConfig: ConfigIntent - + static var parameterSummary: some ParameterSummary { Summary { \.$calendarConfig @@ -29,14 +29,14 @@ struct CardProvider: ChinendarAppIntentTimelineProvider { typealias Entry = CardEntry let modelContext = DataSchema.context let locationManager = LocationManager() - + func nextEntryDates(chineseCalendar: ChineseCalendar, config: CardConfiguration, context: Context) -> [Date] { return chineseCalendar.nextQuarters(count: 12) } - + func recommendations() -> [AppIntentRecommendation] { return [ - AppIntentRecommendation(intent: Intent(), description: "華曆"), + AppIntentRecommendation(intent: Intent(), description: "華曆") ] } } @@ -46,7 +46,7 @@ struct CardEntry: TimelineEntry, ChinendarEntry { let chineseCalendar: ChineseCalendar let watchLayout: WatchLayout let relevance: TimelineEntryRelevance? - + init(configuration: CardProvider.Intent, chineseCalendar: ChineseCalendar, watchLayout: WatchLayout) { self.date = chineseCalendar.time self.chineseCalendar = chineseCalendar diff --git a/Widget/WatchWidgets/Circular.swift b/Widget/WatchWidgets/Circular.swift index fe79148..82e5dd0 100644 --- a/Widget/WatchWidgets/Circular.swift +++ b/Widget/WatchWidgets/Circular.swift @@ -13,9 +13,9 @@ enum CircularMode: String, AppEnum { case daylight, monthDay static let typeDisplayRepresentation: TypeDisplayRepresentation = .init(name: "圓輪掛件選項") - static let caseDisplayRepresentations: [CircularMode : DisplayRepresentation] = [ + static let caseDisplayRepresentations: [CircularMode: DisplayRepresentation] = [ .daylight: .init(title: "日月光華"), - .monthDay: .init(title: "歲月之輪"), + .monthDay: .init(title: "歲月之輪") ] } @@ -26,10 +26,10 @@ struct CircularConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigratedA @Parameter(title: "選日曆") var calendarConfig: ConfigIntent - + @Parameter(title: "型制", default: .daylight) var mode: CircularMode - + static var parameterSummary: some ParameterSummary { Summary { \.$calendarConfig @@ -43,7 +43,7 @@ struct CircularProvider: ChinendarAppIntentTimelineProvider { typealias Intent = CircularConfiguration let modelContext = DataSchema.context let locationManager = LocationManager() - + func nextEntryDates(chineseCalendar: ChineseCalendar, config: CircularConfiguration, context: Context) -> [Date] { return switch config.mode { case .monthDay: @@ -65,50 +65,38 @@ struct CircularProvider: ChinendarAppIntentTimelineProvider { } } -private func sunTimes(times: [ChineseCalendar.NamedPosition?]) -> (start: CGFloat, end: CGFloat)? { - guard times.count == 5 else { return nil } - if let sunrise = times[1]?.pos, let sunset = times[3]?.pos { - return (start: CGFloat(sunrise), end: CGFloat(sunset)) - } else if times[1] == nil && times[3] == nil { - if let _ = times[2]?.pos { - return (start: 0, end: 1) +private func sunTimes(times: Solar) -> (start: Double, end: Double)? { + if let sunrise = times.sunrise?.pos { + if let sunset = times.sunset?.pos { + return (start: sunrise, end: sunset) } else { - return (start: 0, end: 1e-7) + return (start: sunrise, end: 1) } } else { - if let sunrise = times[1]?.pos { - return (start: CGFloat(sunrise), end: 1.0) - } else if let sunset = times[3]?.pos { - return (start: 0, end: CGFloat(sunset)) + if let sunset = times.sunset?.pos { + return (start: 0, end: sunset) } else { - return (start: 0, end: 1e-7) + if times.noon != nil { + return (start: 0, end: 1) + } else { + return (start: 0, end: 1e-7) + } } } } -private func moonTimes(times: [ChineseCalendar.NamedPosition?]) -> ((start: CGFloat, end: CGFloat)?, CGFloat?) { - guard times.count == 6 else { return (nil, nil) } - if let firstMoonRise = times[0]?.pos { - if let firstMoonSet = times[2]?.pos { - return ((start: CGFloat(firstMoonRise), end: CGFloat(firstMoonSet)), times[1].flatMap { CGFloat($0.pos) }) +private func moonTimes(times: Lunar) -> ((start: Double, end: Double)?, Double?) { + if let moonrise = times.moonrise?.pos { + if let moonset = times.moonset?.pos { + return ((start: moonrise, end: moonset), times.highMoon?.pos) } else { - return ((start: CGFloat(firstMoonRise), end: 1.0), times[1].flatMap { CGFloat($0.pos) } ?? 1.0) + return ((start: moonrise, end: 1), times.highMoon?.pos ?? 1) } - } else if let secondMoonSet = times[5]?.pos { - if let secondMoonRise = times[3]?.pos { - return ((start: CGFloat(secondMoonRise), end: CGFloat(secondMoonSet)), times[4].flatMap { CGFloat($0.pos) }) - } else { - return ((start: 0.0, end: CGFloat(secondMoonSet)), times[4].flatMap { CGFloat($0.pos) } ?? 0.0) - } - } else if let firstMoonSet = times[2]?.pos, let secondMoonRise = times[3]?.pos { - return ((start: CGFloat(secondMoonRise), end: CGFloat(firstMoonSet)), (times[1] ?? times[4]).flatMap { CGFloat($0.pos) }) } else { - if let firstMoonSet = times[2]?.pos { - return ((start: 0, end: CGFloat(firstMoonSet)), times[1].flatMap { CGFloat($0.pos) } ?? 0.0) - } else if let secondMoonRise = times[3]?.pos { - return ((start: CGFloat(secondMoonRise), end: 1.0), times[4].flatMap { CGFloat($0.pos) } ?? 1.0) + if let moonset = times.moonset?.pos { + return ((start: 0, end: moonset), times.highMoon?.pos ?? 0) } else { - if times[1] != nil || times[4] != nil { + if times.highMoon != nil { return ((start: 0, end: 1), nil) } else { return ((start: 0, end: 1e-7), nil) @@ -131,14 +119,14 @@ struct CircularEntry: TimelineEntry, ChinendarEntry { let currentColor: Color? let relevance: TimelineEntryRelevance? let phase: (CGFloat, CGFloat) - + init(configuration: CircularProvider.Intent, chineseCalendar: ChineseCalendar, watchLayout: WatchLayout) { date = chineseCalendar.time self.configuration = configuration self.chineseCalendar = chineseCalendar self.watchLayout = watchLayout let phase = watchLayout.startingPhase - + switch configuration.mode { case .monthDay: outer = (start: 0, end: chineseCalendar.currentDayInYear) @@ -150,13 +138,13 @@ struct CircularEntry: TimelineEntry, ChinendarEntry { currentColor = nil self.phase = (phase.firstRing, phase.secondRing) relevance = TimelineEntryRelevance(score: 5, duration: 3600) - + case .daylight: let (inner, innerDirection) = moonTimes(times: chineseCalendar.sunMoonPositions.lunar) let outer = sunTimes(times: chineseCalendar.sunMoonPositions.solar) - self.inner = inner ?? (start: 0, end: 1e-7) - self.innerDirection = innerDirection - self.outer = outer ?? (start: 0, end: 1e-7) + self.inner = inner.map { (start: CGFloat($0.start), end: CGFloat($0.end)) } ?? (start: 0, end: 1e-7) + self.innerDirection = innerDirection.map { CGFloat($0) } + self.outer = outer.map { (start: CGFloat($0.start), end: CGFloat($0.end)) } ?? (start: 0, end: 1e-7) outerGradient = applyGradient(gradient: watchLayout.thirdRing, startingAngle: 0) innerGradient = applyGradient(gradient: watchLayout.secondRing, startingAngle: 0) current = chineseCalendar.currentHourInDay diff --git a/Widget/WatchWidgets/CountDown.swift b/Widget/WatchWidgets/CountDown.swift index 624a393..57004eb 100644 --- a/Widget/WatchWidgets/CountDown.swift +++ b/Widget/WatchWidgets/CountDown.swift @@ -80,7 +80,7 @@ struct CountDownEntry: TimelineEntry, ChinendarEntry { let color: CGColor let barColor: CGColor let relevance: TimelineEntryRelevance? - + init(configuration: CountDownProvider.Intent, chineseCalendar: ChineseCalendar, watchLayout: WatchLayout) { self.configuration = configuration self.chineseCalendar = chineseCalendar @@ -90,8 +90,12 @@ struct CountDownEntry: TimelineEntry, ChinendarEntry { self.date = chineseCalendar.startOfNextDay (previousDate, nextDate) = find(in: chineseCalendar.moonPhases, at: chineseCalendar.time) if let next = nextDate { - color = next.name == ChineseCalendar.moonPhases[0] ? watchLayout.eclipseIndicator : watchLayout.fullmoonIndicator - barColor = if next.name == ChineseCalendar.moonPhases[0] { // New moon + color = if next.name == ChineseCalendar.moonPhases.newmoon { + watchLayout.eclipseIndicator + } else { + watchLayout.fullmoonIndicator + } + barColor = if next.name == ChineseCalendar.moonPhases.newmoon { // New moon watchLayout.secondRing.interpolate(at: chineseCalendar.eventInMonth.eclipse.first?.pos ?? 0.0) } else { // Full moon watchLayout.secondRing.interpolate(at: chineseCalendar.eventInMonth.fullMoon.first?.pos ?? 0.5) @@ -102,7 +106,7 @@ struct CountDownEntry: TimelineEntry, ChinendarEntry { barColor = CGColor(gray: 0, alpha: 0) relevance = TimelineEntryRelevance(score: 0) } - + case .solarTerms: self.date = chineseCalendar.startOfNextDay (previousDate, nextDate) = find(in: chineseCalendar.solarTerms, at: chineseCalendar.time) @@ -119,39 +123,53 @@ struct CountDownEntry: TimelineEntry, ChinendarEntry { barColor = CGColor(gray: 0, alpha: 0) relevance = TimelineEntryRelevance(score: 0) } - + case .moonriseSet: self.date = chineseCalendar.time + 1800 // Half Hour - let moonriseAndSet = chineseCalendar.moonTimes.filter { $0.name == ChineseCalendar.moonTimeName[0] || $0.name == ChineseCalendar.moonTimeName[2] } + let current = chineseCalendar.getMoonTimes(for: .current) + let previous = chineseCalendar.getMoonTimes(for: .previous) + let next = chineseCalendar.getMoonTimes(for: .next) + let moonriseAndSet = [previous.moonrise, previous.moonset, current.moonrise, current.moonset, next.moonrise, next.moonset].compactMap { $0 } (previousDate, nextDate) = find(in: moonriseAndSet, at: chineseCalendar.time) if let next = nextDate { - color = next.name == ChineseCalendar.moonTimeName[0] ? watchLayout.moonPositionIndicator[0] : watchLayout.moonPositionIndicator[2] - barColor = if next.name == ChineseCalendar.moonTimeName[0] { // Moonrise - watchLayout.secondRing.interpolate(at: chineseCalendar.sunMoonPositions.lunar[0]?.pos ?? chineseCalendar.sunMoonPositions.lunar[3]?.pos ?? 0.25) + color = if next.name == ChineseCalendar.moonTimeName.moonrise { + watchLayout.moonPositionIndicator.moonrise + } else { + watchLayout.moonPositionIndicator.moonset + } + barColor = if next.name == ChineseCalendar.moonTimeName.moonrise { // Moonrise + watchLayout.secondRing.interpolate(at: chineseCalendar.sunMoonPositions.lunar.moonrise?.pos ?? 0.25) } else { // Moonset - watchLayout.secondRing.interpolate(at: chineseCalendar.sunMoonPositions.lunar[2]?.pos ?? chineseCalendar.sunMoonPositions.lunar[5]?.pos ?? 0.75) + watchLayout.secondRing.interpolate(at: chineseCalendar.sunMoonPositions.lunar.moonset?.pos ?? 0.75) } relevance = TimelineEntryRelevance(score: 10, duration: date.distance(to: next.date)) } else { - color = watchLayout.moonPositionIndicator[1] + color = watchLayout.moonPositionIndicator.highMoon barColor = CGColor(gray: 0, alpha: 0) relevance = TimelineEntryRelevance(score: 0) } - + case .sunriseSet: self.date = chineseCalendar.time + 1800 // Half Hour - let sunriseAndSet = chineseCalendar.sunTimes.filter { $0.name == ChineseCalendar.dayTimeName[1] || $0.name == ChineseCalendar.dayTimeName[3] } + let current = chineseCalendar.getSunTimes(for: .current) + let previous = chineseCalendar.getSunTimes(for: .previous) + let next = chineseCalendar.getSunTimes(for: .next) + let sunriseAndSet = [previous.sunrise, previous.sunset, current.sunrise, current.sunset, next.sunrise, next.sunset].compactMap { $0 } (previousDate, nextDate) = find(in: sunriseAndSet, at: chineseCalendar.time) if let next = nextDate { - color = next.name == ChineseCalendar.dayTimeName[1] ? watchLayout.sunPositionIndicator[1] : watchLayout.sunPositionIndicator[3] - barColor = if next.name == ChineseCalendar.dayTimeName[1] { // Sunrise - watchLayout.thirdRing.interpolate(at: chineseCalendar.sunMoonPositions.solar[1]?.pos ?? 0.25) + color = if next.name == ChineseCalendar.dayTimeName.sunrise { + watchLayout.sunPositionIndicator.sunrise + } else { + watchLayout.sunPositionIndicator.sunset + } + barColor = if next.name == ChineseCalendar.dayTimeName.sunrise { // Sunrise + watchLayout.thirdRing.interpolate(at: chineseCalendar.sunMoonPositions.solar.sunrise?.pos ?? 0.25) } else { // Sunset - watchLayout.thirdRing.interpolate(at: chineseCalendar.sunMoonPositions.solar[3]?.pos ?? 0.75) + watchLayout.thirdRing.interpolate(at: chineseCalendar.sunMoonPositions.solar.sunset?.pos ?? 0.75) } relevance = TimelineEntryRelevance(score: 10, duration: date.distance(to: next.date)) } else { - color = watchLayout.sunPositionIndicator[2] + color = watchLayout.sunPositionIndicator.noon barColor = CGColor(gray: 0, alpha: 0) relevance = TimelineEntryRelevance(score: 0) } @@ -170,7 +188,7 @@ struct CountDownEntryView: View { let index = findSolarTerm(next.name) if index >= 0 { let icon = IconType.solarTerm(view: SolarTerm(angle: CGFloat(index) / 24.0, color: entry.color)) - + switch family { case .accessoryRectangular: let name = String(next.name.replacingOccurrences(of: " ", with: "")) @@ -184,11 +202,11 @@ struct CountDownEntryView: View { } case .lunarPhases: if let next = entry.nextDate, let previous = entry.previousDate { - let icon = IconType.moon(view: MoonPhase(angle: next.name == ChineseCalendar.moonPhases[0] ? 0.05 : 0.5, color: entry.color)) - + let icon = IconType.moon(view: MoonPhase(angle: next.name == ChineseCalendar.moonPhases.newmoon ? 0.05 : 0.5, color: entry.color)) + switch family { case .accessoryRectangular: - RectanglePanel(icon: icon, name: Text(Locale.translation[next.name]! ?? ""), color: entry.color, barColor: entry.barColor, start: previous.date, end: next.date) + RectanglePanel(icon: icon, name: Text(Locale.translation[next.name] ?? ""), color: entry.color, barColor: entry.barColor, start: previous.date, end: next.date) case .accessoryCorner: Curve(icon: icon, barColor: entry.barColor, start: previous.date, end: next.date) @@ -196,12 +214,12 @@ struct CountDownEntryView: View { EmptyView() } } - + case .sunriseSet: - let noonTimes = entry.chineseCalendar.sunTimes.filter { $0.name == ChineseCalendar.dayTimeName[2]} + let noonTime = entry.chineseCalendar.getSunTimes(for: .current).noon if let next = entry.nextDate, let previous = entry.previousDate { - let icon = IconType.sunrise(view: Sun(color: entry.color, rise: next.name == ChineseCalendar.dayTimeName[1])) - + let icon = IconType.sunrise(view: Sun(color: entry.color, rise: next.name == ChineseCalendar.dayTimeName.sunrise)) + switch family { case .accessoryRectangular: RectanglePanel(icon: icon, name: Text(Locale.translation[next.name] ?? ""), color: entry.color, barColor: entry.barColor, start: previous.date, end: next.date) @@ -210,14 +228,14 @@ struct CountDownEntryView: View { default: EmptyView() } - + } else { let icon = IconType.sunrise(view: Sun(color: entry.color, rise: nil)) - + switch family { case .accessoryRectangular: let sunDescription = if entry.chineseCalendar.location != nil { - if noonTimes.count > 0 { + if noonTime != nil { Text("永日", comment: "Sun never set") } else { Text("永夜", comment: "Sun never rise") @@ -233,10 +251,10 @@ struct CountDownEntryView: View { } } case .moonriseSet: - let moonNoonTimes = entry.chineseCalendar.moonTimes.filter { $0.name == ChineseCalendar.moonTimeName[1]} + let highMoonTime = entry.chineseCalendar.getMoonTimes(for: .current).highMoon if let next = entry.nextDate, let previous = entry.previousDate { - let icon = IconType.moon(view: MoonPhase(angle: entry.chineseCalendar.currentDayInMonth, color: entry.color, rise: next.name == ChineseCalendar.moonTimeName[0])) - + let icon = IconType.moon(view: MoonPhase(angle: entry.chineseCalendar.currentDayInMonth, color: entry.color, rise: next.name == ChineseCalendar.moonTimeName.moonrise)) + switch family { case .accessoryRectangular: RectanglePanel(icon: icon, name: Text(Locale.translation[next.name] ?? ""), color: entry.color, barColor: entry.barColor, start: previous.date, end: next.date) @@ -248,11 +266,11 @@ struct CountDownEntryView: View { } } else { let icon = IconType.moon(view: MoonPhase(angle: entry.chineseCalendar.currentDayInMonth, color: entry.color, rise: nil)) - + switch family { case .accessoryRectangular: let moonDescription = if entry.chineseCalendar.location != nil { - if moonNoonTimes.count > 0 { + if highMoonTime != nil { Text("永月", comment: "Moon never set") } else { Text("永無月", comment: "Moon never rise") @@ -270,7 +288,7 @@ struct CountDownEntryView: View { } } } - + private func findSolarTerm(_ solarTerm: String) -> Int { if let even = ChineseCalendar.evenSolarTermChinese.firstIndex(of: solarTerm) { return even * 2 diff --git a/Widget/WatchWidgets/IconView.swift b/Widget/WatchWidgets/IconView.swift index 17ebbed..2a1f422 100644 --- a/Widget/WatchWidgets/IconView.swift +++ b/Widget/WatchWidgets/IconView.swift @@ -16,11 +16,11 @@ enum IconType { struct SolarTerm: View { var angle: CGFloat var color: CGColor - + func pointOnCircle(center: CGPoint, radius: CGFloat, angle: CGFloat) -> CGPoint { return CGPoint(x: sin(angle) * radius + center.x, y: cos(angle) * radius + center.y) } - + var body: some View { Canvas { context, size in let minEdge = min(size.width, size.height) @@ -29,7 +29,7 @@ struct SolarTerm: View { let ringRadius = minEdge * 0.42 let starRadius = minEdge * 0.08 let smallStarRadius = minEdge * 0.06 - + let connectionPath = CGMutablePath() connectionPath.move(to: pointOnCircle(center: center, radius: centerRadius, angle: 0.4 * CGFloat.pi)) connectionPath.addLine(to: pointOnCircle(center: center, radius: centerRadius, angle: 0.6 * CGFloat.pi)) @@ -41,14 +41,15 @@ struct SolarTerm: View { control1: CGPoint(x: ringRadius - starRadius * 1.2, y: 0) + center, control2: CGPoint(x: centerRadius, y: 0) + center) connectionPath.closeSubpath() - + let circlesPath = CGMutablePath() circlesPath.addEllipse(in: CGRect(origin: center - CGPoint(x: centerRadius, y: centerRadius), size: CGSize(width: centerRadius * 2, height: centerRadius * 2))) circlesPath.addEllipse(in: CGRect(origin: center - CGPoint(x: starRadius - ringRadius, y: starRadius), size: CGSize(width: starRadius * 2, height: starRadius * 2))) - + let dotsPath = CGMutablePath() for i in 1...11 { - dotsPath.addEllipse(in: CGRect(origin: pointOnCircle(center: center, radius: ringRadius, angle: CGFloat(i) * CGFloat.pi * 2 / 12 + 0.5 * CGFloat.pi) - CGPoint(x: smallStarRadius, y: smallStarRadius), size: CGSize(width: smallStarRadius * 2, height: smallStarRadius * 2))) + let center = pointOnCircle(center: center, radius: ringRadius, angle: CGFloat(i) * CGFloat.pi * 2 / 12 + 0.5 * CGFloat.pi) - CGPoint(x: smallStarRadius, y: smallStarRadius) + dotsPath.addEllipse(in: CGRect(origin: center, size: CGSize(width: smallStarRadius * 2, height: smallStarRadius * 2))) } context.fill(Path(connectionPath), with: .color(Color(cgColor: color))) @@ -75,7 +76,7 @@ private func starPath(x: CGFloat, y: CGFloat, radius: CGFloat, sides: Int, point } return points } - + let adjustment = 0.5 / CGFloat(sides) let path = CGMutablePath() let points = polygonPointArray(sides: sides, x: x, y: y, radius: radius) @@ -93,11 +94,11 @@ struct MoonPhase: View { var angle: CGFloat var color: CGColor var rise: Bool? - + func pointOnCircle(center: CGPoint, radius: CGFloat, angle: CGFloat) -> CGPoint { return CGPoint(x: sin(angle) * radius + center.x, y: cos(angle) * radius + center.y) } - + var body: some View { Canvas { context, size in let minEdge = min(size.width, size.height) @@ -105,19 +106,19 @@ struct MoonPhase: View { let centerRadius = minEdge * 0.3 let ringRadius = minEdge * 0.42 let starRadius = minEdge * 0.1 - + context.clip(to: Path(ellipseIn: CGRect(x: center.x - minEdge * 0.5, y: center.y - minEdge * 0.5, width: minEdge, height: minEdge))) var moonContext = context - + if rise != nil { let groundMaskPath = CGMutablePath() groundMaskPath.addArc(center: center, radius: minEdge * 0.5, startAngle: 0.2 * CGFloat.pi, endAngle: 0.80 * CGFloat.pi, clockwise: false) groundMaskPath.closeSubpath() - + let groundPath = CGMutablePath() groundPath.addArc(center: center, radius: minEdge * 0.5, startAngle: 0.23 * CGFloat.pi, endAngle: 0.77 * CGFloat.pi, clockwise: false) groundPath.closeSubpath() - + let groundContext = context groundContext.fill(Path(groundPath), with: .color(.brown)) moonContext.clip(to: Path(groundMaskPath), options: .inverse) @@ -132,7 +133,7 @@ struct MoonPhase: View { } else { moonContext.fill(Path(ellipse), with: .color(Color(cgColor: color))) } - + let halfMoon = CGMutablePath() if sin(2.0 * CGFloat.pi * angle) >= 0 { halfMoon.addArc(center: center, radius: centerRadius, startAngle: -0.5 * CGFloat.pi, endAngle: 0.5 * CGFloat.pi, clockwise: true) @@ -141,16 +142,16 @@ struct MoonPhase: View { } halfMoon.closeSubpath() moonContext.fill(Path(halfMoon), with: .color(Color(cgColor: color))) - + let circle = CGMutablePath(ellipseIn: CGRect(x: center.x - centerRadius, y: center.y - centerRadius, width: centerRadius * 2, height: centerRadius * 2), transform: nil) backContext.fill(Path(circle), with: .color(Color(cgColor: color).opacity(0.2 * color.alpha))) - + for position in [0.2, 0.4, 0.76] { let direction = pointOnCircle(center: center, radius: ringRadius, angle: (position + angle * 0.02) * CGFloat.pi * 2.0) let star = starPath(x: direction.x, y: direction.y, radius: starRadius * (0.75 + 0.25 * cos(angle * CGFloat.pi * 2.0)), sides: 5, pointyness: 0.5) moonContext.fill(Path(star), with: .color(.yellow.opacity(0.75 + 0.25 * cos(angle * CGFloat.pi * 2.0)))) } - + if let rise = rise { var arrow = context arrow.clipToLayer { ctx in @@ -170,11 +171,11 @@ struct MoonPhase: View { struct Sun: View { var color: CGColor var rise: Bool? - + func pointOnCircle(center: CGPoint, radius: CGFloat, angle: CGFloat) -> CGPoint { return CGPoint(x: sin(angle) * radius + center.x, y: cos(angle) * radius + center.y) } - + var body: some View { Canvas { context, size in let minEdge = min(size.width, size.height) @@ -182,27 +183,27 @@ struct Sun: View { let centerRadius = minEdge * 0.3 let ringRadius = minEdge * 0.42 let smallStarRadius = minEdge * 0.08 - + context.clip(to: Path(ellipseIn: CGRect(x: center.x - minEdge * 0.5, y: center.y - minEdge * 0.5, width: minEdge, height: minEdge))) var sunContext = context - + if rise != nil { let groundMaskPath = CGMutablePath() groundMaskPath.addArc(center: center, radius: minEdge * 0.5, startAngle: 0.20 * CGFloat.pi, endAngle: 0.80 * CGFloat.pi, clockwise: false) groundMaskPath.closeSubpath() - + let groundPath = CGMutablePath() groundPath.addArc(center: center, radius: minEdge * 0.5, startAngle: 0.23 * CGFloat.pi, endAngle: 0.77 * CGFloat.pi, clockwise: false) groundPath.closeSubpath() - + let groundContext = context groundContext.fill(Path(groundPath), with: .color(.brown)) sunContext.clip(to: Path(groundMaskPath), options: .inverse) sunContext.translateBy(x: 0, y: minEdge * 0.1) } - + let mainCircle = CGMutablePath(ellipseIn: CGRect(x: center.x - centerRadius, y: center.y - centerRadius, width: centerRadius * 2, height: centerRadius * 2), transform: nil) - + let radiationPath = CGMutablePath() for i in 0...11 { radiationPath.move(to: pointOnCircle(center: center, radius: ringRadius - smallStarRadius, angle: CGFloat(i) / 12.0 * CGFloat.pi * 2.0)) @@ -214,7 +215,7 @@ struct Sun: View { sunContext.fill(Path(mainCircle), with: .color(Color(cgColor: color))) sunContext.fill(Path(radiationPath), with: .color(.yellow)) - + if let rise = rise { var arrow = context arrow.clipToLayer { ctx in diff --git a/Widget/WatchWidgets/Relevance.swift b/Widget/WatchWidgets/Relevance.swift index 67c9357..1f8b991 100644 --- a/Widget/WatchWidgets/Relevance.swift +++ b/Widget/WatchWidgets/Relevance.swift @@ -11,11 +11,11 @@ enum EventType: String, AppEnum { case solarTerms, lunarPhases, sunriseSet, moonriseSet static let typeDisplayRepresentation: TypeDisplayRepresentation = .init(name: "時計掛件選項") - static let caseDisplayRepresentations: [EventType : DisplayRepresentation] = [ + static let caseDisplayRepresentations: [EventType: DisplayRepresentation] = [ .solarTerms: .init(title: "節氣"), .lunarPhases: .init(title: "月相"), .sunriseSet: .init(title: "日躔"), - .moonriseSet: .init(title: "月離"), + .moonriseSet: .init(title: "月離") ] } @@ -28,7 +28,7 @@ struct CountDownConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigrated var calendarConfig: ConfigIntent @Parameter(title: "目的", default: .solarTerms) var target: EventType - + static var parameterSummary: some ParameterSummary { Summary { \.$calendarConfig @@ -44,9 +44,9 @@ func updateCountDownRelevantIntents(chineseCalendar: ChineseCalendar) async { async let moonTimes = nextMoonTimes(chineseCalendar: chineseCalendar) async let solarTerms = nextSolarTerm(chineseCalendar: chineseCalendar) async let moonPhases = nextMoonPhase(chineseCalendar: chineseCalendar) - + var relevantIntents = [RelevantIntent]() - + for date in await sunTimes { let config = CountDownConfiguration() config.target = .sunriseSet @@ -54,7 +54,7 @@ func updateCountDownRelevantIntents(chineseCalendar: ChineseCalendar) async { let relevantIntent = RelevantIntent(config, widgetKind: rectWidgetKind, relevance: relevantContext) relevantIntents.append(relevantIntent) } - + for date in await moonTimes { let config = CountDownConfiguration() config.target = .moonriseSet @@ -62,7 +62,7 @@ func updateCountDownRelevantIntents(chineseCalendar: ChineseCalendar) async { let relevantIntent = RelevantIntent(config, widgetKind: rectWidgetKind, relevance: relevantContext) relevantIntents.append(relevantIntent) } - + for date in await solarTerms { let config = CountDownConfiguration() config.target = .solarTerms @@ -72,7 +72,7 @@ func updateCountDownRelevantIntents(chineseCalendar: ChineseCalendar) async { let relevantIntent = RelevantIntent(config, widgetKind: rectWidgetKind, relevance: relevantContext) relevantIntents.append(relevantIntent) } - + for date in await moonPhases { let config = CountDownConfiguration() config.target = .lunarPhases @@ -82,7 +82,7 @@ func updateCountDownRelevantIntents(chineseCalendar: ChineseCalendar) async { let relevantIntent = RelevantIntent(config, widgetKind: rectWidgetKind, relevance: relevantContext) relevantIntents.append(relevantIntent) } - + do { try await RelevantIntentManager.shared.updateRelevantIntents(relevantIntents) } catch { @@ -91,17 +91,25 @@ func updateCountDownRelevantIntents(chineseCalendar: ChineseCalendar) async { } func nextMoonTimes(chineseCalendar: ChineseCalendar) -> [Date] { - let moonTimes = chineseCalendar.moonTimes.filter { - ($0.name == ChineseCalendar.moonTimeName[0] || $0.name == ChineseCalendar.moonTimeName[2]) && ($0.date > chineseCalendar.time) - }.map{ $0.date } - return moonTimes + let current = chineseCalendar.getMoonTimes(for: .current) + let next = chineseCalendar.getMoonTimes(for: .next) + let allTimes = [current.moonrise, current.moonset, next.moonrise, next.moonset] + let nextTimes = allTimes.compactMap { (time: ChineseCalendar.NamedDate?) -> Date? in + guard let time = time, time.date > chineseCalendar.time else { return nil } + return time.date + } + return nextTimes } func nextSunTimes(chineseCalendar: ChineseCalendar) -> [Date] { - let sunTimes = chineseCalendar.sunTimes.filter { - ($0.name == ChineseCalendar.dayTimeName[1] || $0.name == ChineseCalendar.dayTimeName[3]) && ($0.date > chineseCalendar.time) - }.map{ $0.date } - return sunTimes + let current = chineseCalendar.getSunTimes(for: .current) + let next = chineseCalendar.getSunTimes(for: .next) + let allTimes = [current.sunrise, current.sunset, next.sunrise, next.sunset] + let nextTimes = allTimes.compactMap { (time: ChineseCalendar.NamedDate?) -> Date? in + guard let time = time, time.date > chineseCalendar.time else { return nil } + return time.date + } + return nextTimes } func nextSolarTerm(chineseCalendar: ChineseCalendar) -> [Date] { diff --git a/Widget/WatchWidgets/TextDesp.swift b/Widget/WatchWidgets/TextDesp.swift index 7cd1b1c..8d6482a 100644 --- a/Widget/WatchWidgets/TextDesp.swift +++ b/Widget/WatchWidgets/TextDesp.swift @@ -12,20 +12,20 @@ import SwiftUI enum TextWidgetSeparator: String, AppEnum { static let typeDisplayRepresentation: TypeDisplayRepresentation = .init(name: "讀號選項") case space = " ", dot = "・", none = "" - static let caseDisplayRepresentations: [TextWidgetSeparator : DisplayRepresentation] = [ + static let caseDisplayRepresentations: [TextWidgetSeparator: DisplayRepresentation] = [ .none: .init(title: "無"), .dot: .init(title: "・"), - .space: .init(title: "空格"), + .space: .init(title: "空格") ] } enum TextWidgetTime: String, AppEnum { static let typeDisplayRepresentation: TypeDisplayRepresentation = .init(name: "讀號選項") case none, hour, hourAndQuarter - static let caseDisplayRepresentations: [TextWidgetTime : DisplayRepresentation] = [ + static let caseDisplayRepresentations: [TextWidgetTime: DisplayRepresentation] = [ .none: .init(title: "無"), .hour: .init(title: "僅時"), - .hourAndQuarter: .init(title: "時刻"), + .hourAndQuarter: .init(title: "時刻") ] } @@ -33,7 +33,7 @@ struct TextConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigratedAppIn static let intentClassName = "SingleLineIntent" static let title: LocalizedStringResource = "文字" static let description = IntentDescription("簡單華曆文字") - + @Parameter(title: "選日曆") var calendarConfig: ConfigIntent @Parameter(title: "日", default: true) @@ -44,7 +44,7 @@ struct TextConfiguration: ChinendarWidgetConfigIntent, CustomIntentMigratedAppIn var holidays: Int @Parameter(title: "讀號", default: .dot) var separator: TextWidgetSeparator - + static var parameterSummary: some ParameterSummary { Summary { \.$calendarConfig @@ -61,7 +61,7 @@ struct TextProvider: ChinendarAppIntentTimelineProvider { typealias Entry = TextEntry let modelContext = DataSchema.context let locationManager = LocationManager() - + func nextEntryDates(chineseCalendar: ChineseCalendar, config: TextConfiguration, context: Context) -> [Date] { switch config.time { case .hour, .none: @@ -70,7 +70,7 @@ struct TextProvider: ChinendarAppIntentTimelineProvider { return chineseCalendar.nextQuarters(count: 12) } } - + func recommendations() -> [AppIntentRecommendation] { let datetimeHoliday = Intent() let datetime = Intent() @@ -81,7 +81,7 @@ struct TextProvider: ChinendarAppIntentTimelineProvider { return [ AppIntentRecommendation(intent: datetimeHoliday, description: "日時、節日"), AppIntentRecommendation(intent: datetime, description: "日時"), - AppIntentRecommendation(intent: dateholiday, description: "日、節日"), + AppIntentRecommendation(intent: dateholiday, description: "日、節日") ] } } @@ -95,7 +95,7 @@ struct TextEntry: TimelineEntry, ChinendarEntry { let chineseCalendar: ChineseCalendar let watchLayout: WatchLayout let relevance: TimelineEntryRelevance? - + init(configuration: TextProvider.Intent, chineseCalendar: ChineseCalendar, watchLayout: WatchLayout) { self.date = chineseCalendar.time self.displayDate = configuration.date diff --git a/Widget/WatchWidgets/WatchWidgetBasic.swift b/Widget/WatchWidgets/WatchWidgetBasic.swift index 769253f..314b530 100644 --- a/Widget/WatchWidgets/WatchWidgetBasic.swift +++ b/Widget/WatchWidgets/WatchWidgetBasic.swift @@ -83,7 +83,7 @@ struct Circular: View { var body: some View { let fullColor = widgetRenderingMode == .fullColor let whiteGradient = Gradient(colors: [.white, .white]) - + GeometryReader { proxy in let size = proxy.size ZStack { @@ -120,7 +120,7 @@ struct Circular: View { private struct RectIconStyle: ViewModifier { let size: CGSize - + func body(content: Content) -> some View { content .scaledToFit() @@ -143,7 +143,7 @@ struct RectanglePanel: View { var body: some View { let fullColor = widgetRenderingMode == .fullColor - + GeometryReader { proxy in HStack(alignment: .center) { switch icon { @@ -188,12 +188,12 @@ struct RectanglePanel: View { private struct CurveIconStyle: ViewModifier { let size: CGSize let bar: Bar - + init(size: CGSize, @ViewBuilder bar: () -> Bar) { self.size = size self.bar = bar() } - + func body(content: Content) -> some View { content .widgetAccentable() @@ -211,7 +211,7 @@ struct Curve: View { var body: some View { let fullColor = widgetRenderingMode == .fullColor - + GeometryReader { proxy in let curveStyle = CurveIconStyle(size: proxy.size) { if let start = start, let end = end { @@ -239,27 +239,27 @@ struct Curve: View { } struct CalendarBadge: View { - + let dateString: String let timeString: String let color: Gradient let backGround: Color let centerFont: UIFont @Environment(\.widgetRenderingMode) var widgetRenderingMode - + private func prepareText(_ text: String, size: CGFloat) -> Text { let attrStr = NSMutableAttributedString(string: String(text.reversed())) let centerFont = centerFont.withSize(size) - attrStr.addAttributes([.font: centerFont, .foregroundColor: CGColor(gray: 1, alpha: 1)], range: NSMakeRange(0, attrStr.length)) + attrStr.addAttributes([.font: centerFont, .foregroundColor: CGColor(gray: 1, alpha: 1)], range: NSRange(location: 0, length: attrStr.length)) return Text(AttributedString(attrStr)) } - + var body: some View { let fullColor = widgetRenderingMode == .fullColor let whiteGradient = Gradient(colors: [.white, .white]) - + GeometryReader { proxy in - VStack{ + VStack { let fontSize = min(proxy.size.width / 8, proxy.size.height / 3) prepareText(dateString, size: fontSize) .multilineTextAlignment(.center) diff --git a/iOS/Layout.swift b/iOS/Layout.swift index e58e525..990da37 100644 --- a/iOS/Layout.swift +++ b/iOS/Layout.swift @@ -11,16 +11,16 @@ import SwiftData @Observable final class WatchLayout: MetaWatchLayout { - @ObservationIgnored var watchConnectivity: WatchConnectivityManager? = nil + @ObservationIgnored var watchConnectivity: WatchConnectivityManager? var textFont = UIFont.systemFont(ofSize: UIFont.systemFontSize, weight: .regular) var centerFont = UIFont(name: "SourceHanSansKR-Heavy", size: UIFont.systemFontSize)! - + func sendToWatch() { self.watchConnectivity?.send(messages: [ "layout": self.encode(includeOffset: false) ]) } - + override func autoSave() { withObservationTracking { _ = self.encode() @@ -33,21 +33,21 @@ import SwiftData } } } - + var monochrome: Self { let emptyLayout = Self.init() emptyLayout.update(from: self.encode(includeColor: false)) return emptyLayout } - + func binding(_ keyPath: ReferenceWritableKeyPath) -> Binding { return Binding(get: { self[keyPath: keyPath] }, set: { self[keyPath: keyPath] = $0 }) } } @Observable class WatchSetting { - - var displayTime: Date? = nil + + var displayTime: Date? var presentSetting = false var vertical = true var effectiveTime: Date { diff --git a/iOS/Views/Setting.swift b/iOS/Views/Setting.swift index e0507c4..c756f05 100644 --- a/iOS/Views/Setting.swift +++ b/iOS/Views/Setting.swift @@ -32,9 +32,9 @@ struct Setting: View { Label("日曆墻", systemImage: "globe") } } - + Section("設計") { - NavigationLink{ + NavigationLink { RingSetting() } label: { Label("輪色", systemImage: "pencil.and.outline") diff --git a/iOS/Views/WatchFace.swift b/iOS/Views/WatchFace.swift index da93ce7..b2cfb6a 100644 --- a/iOS/Views/WatchFace.swift +++ b/iOS/Views/WatchFace.swift @@ -35,7 +35,7 @@ struct WatchFace: View { } }) } - + func tapped(tapPosition: CGPoint, proxy: GeometryProxy, size: CGSize) { var tapPosition = tapPosition tapPos = tapPosition @@ -50,7 +50,7 @@ struct WatchFace: View { } } } - + func mainSize(proxy: GeometryProxy) -> CGSize { var idealSize = watchLayout.watchSize if proxy.size.height < proxy.size.width { @@ -70,7 +70,7 @@ struct WatchFace: View { } return idealSize } - + var body: some View { GeometryReader { proxy in let size = mainSize(proxy: proxy) @@ -87,14 +87,14 @@ struct WatchFace: View { touchState.pressing = true touchState.location = value.location } - + ZStack { Watch(displaySubquarter: true, displaySolarTerms: true, compact: false, watchLayout: watchLayout, markSize: 1.0, chineseCalendar: chineseCalendar, highlightType: .flicker, widthScale: 0.9, centerOffset: centerOffset, entityNotes: entityPresenting.entityNotes, textShift: true) .frame(width: size.width, height: size.height) .position(CGPoint(x: proxy.size.width / 2, y: proxy.size.height / 2)) .environment(\.directedScale, DirectedScale(value: touchState.pressing ? -0.1 : 0.0, anchor: pressAnchor(pos: touchState.location, size: size, proxy: proxy))) .gesture(gesture) - + Hover(entityPresenting: entityPresenting, bounds: $hoverBounds, tapPos: $tapPos) } .onChange(of: dragging) { _, newValue in @@ -132,7 +132,7 @@ struct WatchFace: View { .inspectorColumnWidth(min: 350, ideal: 400, max: 500) } .task(priority: .background) { - showWelcome = ThemeData.latestVersion() < ThemeData.version + showWelcome = ThemeData.notLatest() } .onChange(of: scenePhase) { switch scenePhase { @@ -152,7 +152,7 @@ struct WatchFace: View { let calendarConfigure = CalendarConfigure() let watchSetting = WatchSetting() watchLayout.loadStatic() - + return WatchFace() .modelContainer(DataSchema.container) .environment(chineseCalendar) diff --git a/iOS/Views/Welcome.swift b/iOS/Views/Welcome.swift index 9f161e1..9bdc174 100644 --- a/iOS/Views/Welcome.swift +++ b/iOS/Views/Welcome.swift @@ -10,7 +10,7 @@ import SwiftUI struct Welcome: View { @Environment(\.dismiss) var dismiss @Environment(WatchLayout.self) var watchLayout - + var body: some View { VStack { ScrollView(showsIndicators: false) { @@ -74,7 +74,7 @@ struct Welcome: View { } Spacer(minLength: 15) .frame(maxHeight: 25) - + Button { dismiss() } label: { @@ -89,7 +89,6 @@ struct Welcome: View { } } - #Preview("Welcome") { let watchLayout = WatchLayout() watchLayout.loadStatic() diff --git a/iOS/iOSApp.swift b/iOS/iOSApp.swift index 2e4e978..f736ed6 100644 --- a/iOS/iOSApp.swift +++ b/iOS/iOSApp.swift @@ -16,7 +16,7 @@ struct Chinendar: App { let watchSetting = WatchSetting() let watchConnectivity: WatchConnectivityManager let timer = Timer.publish(every: ChineseCalendar.updateInterval, on: .main, in: .common).autoconnect() - + init() { watchConnectivity = .init(watchLayout: watchLayout, calendarConfigure: calendarConfigure, locationManager: locationManager) watchLayout.watchConnectivity = watchConnectivity @@ -47,7 +47,7 @@ struct Chinendar: App { } } } - + func update() { chineseCalendar.update(time: watchSetting.effectiveTime, timezone: calendarConfigure.effectiveTimezone, diff --git a/iOSWidget/iOSWidgetBundle.swift b/iOSWidget/iOSWidgetBundle.swift index 3ac17e6..7634c8d 100644 --- a/iOSWidget/iOSWidgetBundle.swift +++ b/iOSWidget/iOSWidgetBundle.swift @@ -9,7 +9,7 @@ import SwiftUI @main struct iOSWidgetBundle: WidgetBundle { - + var body: some Widget { SmallWidget() MediumWidget() diff --git a/macOS/Layout.swift b/macOS/Layout.swift index 8dd5094..7f621ce 100644 --- a/macOS/Layout.swift +++ b/macOS/Layout.swift @@ -9,9 +9,9 @@ import SwiftUI import Observation @Observable final class WatchLayout: MetaWatchLayout { - + struct StatusBar: Equatable { - + enum Separator: String, CaseIterable { case space, dot, none var symbol: String { @@ -22,23 +22,23 @@ import Observation } } } - + var date: Bool var time: Bool var holiday: Int var separator: Separator - + func encode() -> String { "date: \(date.description), time: \(time.description), holiday: \(holiday.description), separator: \(separator.rawValue)" } - + init(date: Bool = true, time: Bool = true, holiday: Int = 0, separator: Separator = .space) { self.date = date self.time = time self.holiday = holiday self.separator = separator } - + init?(from str: String?) { guard let str = str else { return nil } let regex = /([a-zA-Z_0-9]+)\s*:[\s"]*([^\s"#][^"#]*)[\s"#]*(#*.*)$/ @@ -81,13 +81,13 @@ import Observation statusBar = StatusBar(from: value) ?? statusBar } } - + var monochrome: Self { let emptyLayout = Self.init() emptyLayout.update(from: self.encode(includeColor: false)) return emptyLayout } - + func binding(_ keyPath: ReferenceWritableKeyPath) -> Binding { return Binding(get: { self[keyPath: keyPath] }, set: { self[keyPath: keyPath] = $0 }) } @@ -97,9 +97,9 @@ import Observation enum Selection: String, CaseIterable { case datetime, location, configs, ringColor, decoration, markColor, layout, themes, documentation } - - var displayTime: Date? = nil - @ObservationIgnored var previousSelection: Selection? = nil + + var displayTime: Date? + @ObservationIgnored var previousSelection: Selection? var effectiveTime: Date { displayTime ?? .now } diff --git a/macOS/Views/Setting.swift b/macOS/Views/Setting.swift index f6cc5f1..0cd5197 100644 --- a/macOS/Views/Setting.swift +++ b/macOS/Views/Setting.swift @@ -19,11 +19,11 @@ struct Setting: View { @State private var columnVisibility = NavigationSplitViewVisibility.automatic @Environment(\.modelContext) private var modelContext @Environment(\.requestReview) var requestReview - + private var statusState: StatusState { StatusState(locationManager: locationManager, watchLayout: watchLayout, calendarConfigure: calendarConfigure, watchSetting: watchSetting) } - + var body: some View { NavigationSplitView(columnVisibility: $columnVisibility) { List(selection: $selection) { @@ -113,7 +113,7 @@ struct Setting: View { cleanColorPanel() } } - + func buildView(selection: WatchSetting.Selection) -> some View { let sel = switch selection { case .datetime: @@ -137,7 +137,7 @@ struct Setting: View { } return sel } - + @MainActor func cleanColorPanel() { NSColorPanel.shared.setTarget(nil) NSColorPanel.shared.setAction(nil) diff --git a/macOS/Views/WatchFace.swift b/macOS/Views/WatchFace.swift index 6a725fa..ba2da49 100644 --- a/macOS/Views/WatchFace.swift +++ b/macOS/Views/WatchFace.swift @@ -11,12 +11,12 @@ struct WatchFace: View { @Environment(WatchLayout.self) var watchLayout @Environment(ChineseCalendar.self) var chineseCalendar @State var entityPresenting = EntitySelection() - @State var tapPos: CGPoint? = nil + @State var tapPos: CGPoint? @State var hoverBounds: CGRect = .zero @State var touchState = PressState() @Environment(\.openWindow) private var openWindow @Environment(\.modelContext) private var modelContext - + func tapped(tapPosition: CGPoint, proxy: GeometryProxy, size: CGSize) { var tapPosition = tapPosition tapPos = tapPosition @@ -31,36 +31,36 @@ struct WatchFace: View { } } } - + var body: some View { GeometryReader { proxy in - let size: CGSize = watchLayout.watchSize + let size: CGSize = watchLayout.watchSize let centerOffset = if size.height >= size.width { watchLayout.centerTextOffset } else { watchLayout.centerTextHOffset } - + let gesture = DragGesture(minimumDistance: 0, coordinateSpace: .local) .onChanged { value in touchState.pressing = true touchState.location = value.location } - .onEnded { value in + .onEnded { _ in if touchState.tapped { tapped(tapPosition: touchState.location!, proxy: proxy, size: size) } touchState.pressing = false touchState.location = nil } - + ZStack { Watch(displaySubquarter: true, displaySolarTerms: true, compact: false, watchLayout: watchLayout, markSize: 1.0, chineseCalendar: chineseCalendar, highlightType: .flicker, widthScale: 0.9, centerOffset: centerOffset, entityNotes: entityPresenting.entityNotes, textShift: true) .frame(width: size.width, height: size.height) .position(CGPoint(x: proxy.size.width / 2, y: proxy.size.height / 2)) .environment(\.directedScale, DirectedScale(value: touchState.pressing ? -0.1 : 0.0, anchor: pressAnchor(pos: touchState.location, size: size, proxy: proxy))) .gesture(gesture) - + Hover(entityPresenting: entityPresenting, bounds: $hoverBounds, tapPos: $tapPos) } .animation(.easeInOut(duration: 0.2), value: entityPresenting.activeNote) @@ -73,7 +73,7 @@ struct WatchFace: View { let chineseCalendar = ChineseCalendar() let watchLayout = WatchLayout() watchLayout.loadStatic() - + return WatchFace() .modelContainer(DataSchema.container) .environment(chineseCalendar) diff --git a/macOS/Views/Welcome.swift b/macOS/Views/Welcome.swift index 36333ab..32a80be 100644 --- a/macOS/Views/Welcome.swift +++ b/macOS/Views/Welcome.swift @@ -10,7 +10,7 @@ import SwiftUI struct Welcome: View { @Environment(\.dismiss) var dismiss @Environment(WatchLayout.self) var watchLayout - + var body: some View { ScrollView(showsIndicators: false) { VStack(spacing: 20) { @@ -67,7 +67,6 @@ struct Welcome: View { } } - #Preview("Welcome") { let watchLayout = WatchLayout() watchLayout.loadStatic() diff --git a/macOS/macApp.swift b/macOS/macApp.swift index 143a909..db909e5 100644 --- a/macOS/macApp.swift +++ b/macOS/macApp.swift @@ -36,7 +36,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { var watchPanel: WatchPanel! private var _timer: Timer? var lastReloaded = Date.distantPast - + func applicationWillFinishLaunching(_ aNotification: Notification) { statusItem = NSStatusBar.system.statusItem(withLength: 0) statusItem.button?.action = #selector(self.toggleDisplay(sender:)) @@ -49,7 +49,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { calendarConfigure.autoSaveName() AppDelegate.instance = self } - + func applicationDidFinishLaunching(_ aNotification: Notification) { update() watchPanel = { @@ -65,7 +65,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { .environment(watchLayout) .environment(calendarConfigure) .environment(watchSetting) - + return WatchPanelHosting(watch: watchFace, setting: setting, statusItem: statusItem, watchLayout: watchLayout, isPresented: false) }() _timer = Timer.scheduledTimer(withTimeInterval: ChineseCalendar.updateInterval, repeats: true) { _ in @@ -74,11 +74,11 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } } } - + func applicationWillResignActive(_ notification: Notification) { watchPanel.isPresented = false } - + func applicationWillTerminate(_ aNotification: Notification) { if lastReloaded.distance(to: .now) > 1800 { // Half Hour WidgetCenter.shared.reloadAllTimelines() @@ -87,7 +87,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { _timer = nil statusItem = nil } - + @objc func toggleDisplay(sender: NSStatusItem) { watchPanel.isPresented.toggle() if watchPanel.isPresented && lastReloaded.distance(to: .now) > 7200 { // 2 Hours @@ -95,7 +95,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { lastReloaded = .now } } - + func updateStatusBar(dateText: String) { if let button = statusItem.button { if dateText.count > 0 { @@ -104,13 +104,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } else { button.title = "" let image = NSImage(resource: .image) - image.size = NSMakeSize(NSStatusBar.system.thickness, NSStatusBar.system.thickness) + image.size = NSSize(width: NSStatusBar.system.thickness, height: NSStatusBar.system.thickness) button.image = image } statusItem.length = button.intrinsicContentSize.width } } - + func statusBar(from chineseCalendar: ChineseCalendar, options watchLayout: WatchLayout) -> String { var displayText = [String]() if watchLayout.statusBar.date { @@ -125,7 +125,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } return displayText.joined(separator: watchLayout.statusBar.separator.symbol) } - + func update() { chineseCalendar.update(time: watchSetting.effectiveTime, timezone: calendarConfigure.effectiveTimezone, diff --git a/macOS/watchPanel.swift b/macOS/watchPanel.swift index 39944bd..300300f 100644 --- a/macOS/watchPanel.swift +++ b/macOS/watchPanel.swift @@ -17,7 +17,7 @@ class WatchPanel: NSPanel { fileprivate var settingWindow: NSWindow? private var buttonSize: NSSize { let ratio = 80 * 2.3 / (watchLayout.watchSize.width / 2) - return NSMakeSize(80 / ratio, 30 / ratio) + return NSSize(width: 80 / ratio, height: 30 / ratio) } var isPresented: Bool { @@ -28,27 +28,27 @@ class WatchPanel: NSPanel { self.present() } } - + init(statusItem: NSStatusItem, watchLayout: WatchLayout, isPresented: Bool) { self._isPresented = isPresented self.statusItem = statusItem self.watchLayout = watchLayout - + let blurView = NSVisualEffectView() blurView.blendingMode = .behindWindow blurView.material = .hudWindow blurView.state = .active blurView.wantsLayer = true backView = blurView - + self.settingButton = { - let view = OptionView(frame: NSZeroRect) + let view = OptionView(frame: NSRect.zero) view.button.image = NSImage(systemSymbolName: "gearshape", accessibilityDescription: "Setting") view.button.contentTintColor = .controlTextColor return view }() self.closeButton = { - let view = OptionView(frame: NSZeroRect) + let view = OptionView(frame: NSRect.zero) view.button.image = NSImage(systemSymbolName: "xmark", accessibilityDescription: "Quit") view.button.contentTintColor = .systemRed return view @@ -77,19 +77,18 @@ class WatchPanel: NSPanel { self.close() } } - + func panelPosition() { if let statusItemFrame = statusItem.button?.window?.frame { let windowRect = getCurrentScreen() - var frame = NSMakeRect( - statusItemFrame.midX - watchLayout.watchSize.width / 2, - statusItemFrame.minY - watchLayout.watchSize.height - buttonSize.height * 1.7 - 6, - watchLayout.watchSize.width, - watchLayout.watchSize.height + buttonSize.height * 1.7) - if NSMaxX(frame) >= NSMaxX(windowRect) { - frame.origin.x = NSMaxX(windowRect) - frame.width - } else if NSMinX(frame) <= NSMinX(windowRect) { - frame.origin.x = NSMinX(windowRect) + var frame = NSRect(x: statusItemFrame.midX - watchLayout.watchSize.width / 2, + y: statusItemFrame.minY - watchLayout.watchSize.height - buttonSize.height * 1.7 - 6, + width: watchLayout.watchSize.width, + height: watchLayout.watchSize.height + buttonSize.height * 1.7) + if frame.maxX >= windowRect.maxX { + frame.origin.x = windowRect.maxX - frame.width + } else if frame.minX <= windowRect.minX { + frame.origin.x = windowRect.minX } setFrame(frame, display: true) var bounds = contentView!.bounds @@ -100,26 +99,26 @@ class WatchPanel: NSPanel { backView.layer?.mask = mask bounds.origin.y += buttonSize.height * 1.7 backView.frame = bounds - settingButton.frame = NSMakeRect(bounds.width / 2 - buttonSize.width * 1.5, buttonSize.height / 2, buttonSize.width, buttonSize.height) + settingButton.frame = NSRect(x: bounds.width / 2 - buttonSize.width * 1.5, y: buttonSize.height / 2, width: buttonSize.width, height: buttonSize.height) settingButton.button.font = settingButton.button.font?.withSize(buttonSize.height / 2) - closeButton.frame = NSMakeRect(bounds.width / 2 + buttonSize.width * 0.5, buttonSize.height / 2, buttonSize.width, buttonSize.height) + closeButton.frame = NSRect(x: bounds.width / 2 + buttonSize.width * 0.5, y: buttonSize.height / 2, width: buttonSize.width, height: buttonSize.height) closeButton.button.font = closeButton.button.font?.withSize(buttonSize.height / 2) } } - + private func getCurrentScreen() -> NSRect { var screenRect = NSScreen.main!.frame let screens = NSScreen.screens for i in 0 ..< screens.count { let rect = screens[i].frame - if let statusBarFrame = statusItem.button?.window?.frame, NSPointInRect(NSMakePoint(statusBarFrame.midX, statusBarFrame.midY), rect) { + if let statusBarFrame = statusItem.button?.window?.frame, rect.contains(NSPoint(x: statusBarFrame.midX, y: statusBarFrame.midY)) { screenRect = rect break } } return screenRect } - + @objc func closeApp(_ sender: NSButton) { NSApp.terminate(sender) } @@ -128,7 +127,7 @@ class WatchPanel: NSPanel { internal final class WatchPanelHosting: WatchPanel { private let watchView: NSHostingView private let settingView: NSHostingController - + init(watch: WatchView, setting: SettingView, statusItem: NSStatusItem, watchLayout: WatchLayout, isPresented: Bool) { watchView = NSHostingView(rootView: watch) settingView = NSHostingController(rootView: setting) @@ -136,12 +135,12 @@ internal final class WatchPanelHosting: Watc settingButton.button.action = #selector(openSetting(_:)) contentView?.addSubview(watchView) } - + override func panelPosition() { super.panelPosition() watchView.frame = backView.frame } - + @objc func openSetting(_ sender: NSButton) { if settingWindow == nil || !settingWindow!.isVisible { settingWindow?.close() @@ -160,7 +159,7 @@ internal final class WatchPanelHosting: Watc } } -fileprivate final class OptionView: NSView { +private final class OptionView: NSView { let background: NSVisualEffectView let button: NSButton override var frame: NSRect { @@ -180,18 +179,18 @@ fileprivate final class OptionView: NSView { let optionMask = CAShapeLayer() optionMask.path = RoundedRect(rect: background.bounds, nodePos: background.bounds.height / 2, ankorPos: background.bounds.height / 2 * 0.2).path background.layer?.mask = optionMask - + let button = NSButton(frame: frameRect) button.alignment = .center button.isBordered = false - + self.background = background self.button = button super.init(frame: frameRect) addSubview(self.background) addSubview(self.button) } - + required init?(coder: NSCoder) { fatalError("Not implemented") }