using System;

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

namespace CumulusMX
{
	internal static class MoonriseMoonset
	{
		// JavaScript by Peter Hayes http://www.aphayes.pwp.blueyonder.co.uk/
		// Copyright 2001-2010
		// Unless otherwise stated this code is based on the methods in
		// Astronomical Algorithms, first edition, by Jean Meeus
		// Published by Willmann-Bell, Inc.
		// This code is made freely available but please keep this notice.
		// The calculations are approximate but should be good enough for general use,
		// I accept no responsibility for errors in astronomy or coding.

		// WARNING moonrise code changed on 6 May 2003 to correct a systematic error
		// these are now local times NOT UTC as the original code did.

		// Meeus first edition table 45.A Longitude and distance of the moon

		private static readonly int[] T45AD =
		[
			0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2, 2, 4, 2, 0, 2, 2, 1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1,
			2, 0, 1, 3, 4, 2, 0, 1, 2, 2
		];

		private static readonly int[] T45AM =
		[
			0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0,
			0, -1, 0, 1, 0, 1, 0, 0, -1, 2, 1, 0, 0
		];

		private static readonly int[] T45AMP =
		[
			1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0, -1, 0, 1, 2, 0, -3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1,
			-2, 0, 1, 4, 0, -2, 0, 2, 1, -2, -3, 2, 1, -1, 3, -1
		];

		private static readonly int[] T45AF =
		[
			0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0,
			0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2
		];

		private static readonly int[] T45AL =
		[
			6288774, 1274027, 658314, 213618, -185116, -114332, 58793, 57066, 53322, 45758, -40923, -34720, -30383, 15327, -12528, 10980, 10675, 10034, 8548,
			-7888, -6766, -5163, 4987, 4036, 3994, 3861, 3665, -2689, -2602, 2390, -2348, 2236, -2120, -2069, 2048, -1773, -1595, 1215, -1110, -892, -810, 759,
			-713, -700, 691, 596, 549, 537, 520, -487, -399, -381, 351, -340, 330, 327, -323, 299, 294, 0
		];

		private static readonly int[] T45AR =
		[
			-20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138, -170733, -204586, -129620, 108743, 104755, 10321, 0, 79661, -34782, -23210,
			-21636, 24208, 30824, -8379, -16675, -12831, -10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0, 3258, 2616,
			-1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752
		];

		// Meeus table 45B latitude of the moon

		private static readonly int[] T45BD =
		[
			0, 0, 0, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 4, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 4, 0, 4, 2, 2, 2, 2, 0, 2, 2, 2, 2, 4, 2, 2, 0, 2, 1, 1, 0, 2,
			1, 2, 0, 4, 4, 1, 4, 1, 4, 2
		];

		private static readonly int[] T45BM =
		[
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, -1, -1, -1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 1, 0, -1, -2, 0, 1, 1, 1,
			1, 1, 0, -1, 1, 0, -1, 0, 0, 0, -1, -2
		];

		private static readonly int[] T45BMP =
		[
			0, 1, 1, 0, -1, -1, 0, 2, 1, 2, 0, -2, 1, 0, -1, 0, -1, -1, -1, 0, 0, -1, 0, 1, 1, 0, 0, 3, 0, -1, 1, -2, 0, 2, 1, -2, 3, 2, -3, -1, 0, 0, 1, 0, 1,
			1, 0, 0, -2, -1, 1, -2, 2, -2, -1, 1, 1, -1, 0, 0
		];

		private static readonly int[] T45BF =
		[
			1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 3, 1, 1, 1, -1, -1, -1, 1, -1, 1, -3, 1, -3, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1,
			-1, 3, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1
		];

		private static readonly int[] T45BL =
		[
			5128122, 280602, 277693, 173237, 55413, 46271, 32573, 17198, 9266, 8822, 8216, 4324, 4200, -3359, 2463, 2211, 2065, -1870, 1828, -1794, -1749, -1565,
			-1491, -1475, -1410, -1344, -1335, 1107, 1021, 833, 777, 671, 607, 596, 491, -451, 439, 422, 421, -366, -351, 331, 315, 302, -283, -229, 223, 223,
			-220, -220, -185, 181, -177, 176, 166, -164, 132, -119, 115, 107
		];

		// Tabulate the New Moons in UT - expensive to calculate these accurately
		private static readonly string[] NewMoons =
		[
			"2024-01-11 11:57 +0000",
			"2024-02-09 22:58 +0000",
			"2024-03-10 09:00 +0000",
			"2024-04-08 18:21 +0000",
			"2024-05-08 03:21 +0000",
			"2024-06-06 12:37 +0000",
			"2024-07-05 22:57 +0000",
			"2024-08-04 11:12 +0000",
			"2024-09-03 01:55 +0000",
			"2024-10-02 18:48 +0000",
			"2024-11-01 12:46 +0000",
			"2024-12-01 06:20 +0000",
			"2024-12-30 22:26 +0000",
			"2025-01-29 12:36 +0000",
			"2025-02-28 00:44 +0000",
			"2025-03-29 10:58 +0000",
			"2025-04-27 19:31 +0000",
			"2025-05-27 03:02 +0000",
			"2025-06-25 10:32 +0000",
			"2025-07-24 19:11 +0000",
			"2025-08-23 06:06 +0000",
			"2025-09-21 19:53 +0000",
			"2025-10-21 12:24 +0000",
			"2025-11-20 06:46 +0000",
			"2025-12-20 01:42 +0000",
			"2026-01-18 19:51 +0000",
			"2026-02-17 12:00 +0000",
			"2026-03-19 01:23 +0000",
			"2026-04-17 11:52 +0000",
			"2026-05-16 20:01 +0000",
			"2026-06-15 02:54 +0000",
			"2026-07-14 09:44 +0000",
			"2026-08-12 17:36 +0000",
			"2026-09-11 03:26 +0000",
			"2026-10-10 15:49 +0000",
			"2026-11-09 07:01 +0000",
			"2026-12-09 00:51 +0000",
			"2027-01-07 20:23 +0000",
			"2027-02-06 15:55 +0000",
			"2027-03-08 09:28 +0000",
			"2027-04-06 23:50 +0000",
			"2027-05-06 10:58 +0000",
			"2027-06-04 19:40 +0000",
			"2027-07-04 03:01 +0000",
			"2027-08-02 10:05 +0000",
			"2027-08-31 17:41 +0000",
			"2027-09-30 02:35 +0000",
			"2027-10-29 13:36 +0000",
			"2027-11-28 03:24 +0000",
			"2027-12-27 20:11 +0000",
			"2028-01-26 15:11 +0000",
			"2028-02-25 10:36 +0000",
			"2028-03-26 04:30 +0000",
			"2028-04-24 19:46 +0000",
			"2028-05-24 08:16 +0000",
			"2028-06-22 18:27 +0000",
			"2028-07-22 03:01 +0000",
			"2028-08-20 10:44 +0000",
			"2028-09-18 18:24 +0000",
			"2028-10-18 02:56 +0000",
			"2028-11-16 13:18 +0000",
			"2028-12-16 02:05 +0000",
			"2029-01-14 17:24 +0000",
			"2029-02-13 10:30 +0000",
			"2029-03-15 04:18 +0000",
			"2029-04-13 21:39 +0000",
			"2029-05-13 13:41 +0000",
			"2029-06-12 03:50 +0000",
			"2029-07-11 15:50 +0000",
			"2029-08-10 01:55 +0000",
			"2029-09-08 10:44 +0000",
			"2029-10-07 19:14 +0000",
			"2029-11-06 04:24 +0000",
			"2029-12-05 14:52 +0000",
			"2030-01-04 02:49 +0000",
			"2030-02-02 16:07 +0000",
			"2030-03-04 06:34 +0000",
			"2030-04-02 22:02 +0000",
			"2030-05-02 14:11 +0000",
			"2030-06-01 06:20 +0000",
			"2030-06-30 21:33 +0000",
			"2030-07-30 11:10 +0000",
			"2030-08-28 23:06 +0000",
			"2030-09-27 09:54 +0000",
			"2030-10-26 20:16 +0000",
			"2030-11-25 06:46 +0000",
			"2030-12-24 17:32 +0000",
			"2031-01-23 04:30 +0000",
			"2031-02-21 15:49 +0000",
			"2031-03-23 03:48 +0000",
			"2031-04-21 16:56 +0000",
			"2031-05-21 07:16 +0000",
			"2031-06-19 22:24 +0000",
			"2031-07-19 13:39 +0000",
			"2031-08-18 04:31 +0000",
			"2031-09-16 18:46 +0000",
			"2031-10-16 08:20 +0000",
			"2031-11-14 21:09 +0000",
			"2031-12-14 09:05 +0000",
			"2032-01-12 20:06 +0000",
			"2032-02-11 06:24 +0000",
			"2032-03-11 16:25 +0000",
			"2032-04-10 02:39 +0000",
			"2032-05-09 13:35 +0000",
			"2032-06-08 01:31 +0000",
			"2032-07-07 14:40 +0000",
			"2032-08-06 05:10 +0000",
			"2032-09-04 20:55 +0000",
			"2032-10-04 13:25 +0000",
			"2032-11-03 05:44 +0000",
			"2032-12-02 20:52 +0000",
			"2033-01-01 10:17 +0000",
			"2033-01-30 21:59 +0000",
			"2033-03-01 08:23 +0000",
			"2033-03-30 17:52 +0000",
			"2033-04-29 02:45 +0000",
			"2033-05-28 11:36 +0000",
			"2033-06-26 21:06 +0000",
			"2033-07-26 08:12 +0000",
			"2033-08-24 21:39 +0000",
			"2033-09-23 13:38 +0000",
			"2033-10-23 07:27 +0000",
			"2033-11-22 01:38 +0000",
			"2033-12-21 18:45 +0000",
			"2034-01-20 10:01 +0000",
			"2034-02-18 23:09 +0000",
			"2034-03-20 10:14 +0000",
			"2034-04-18 19:26 +0000",
			"2034-05-18 03:12 +0000",
			"2034-06-16 10:26 +0000",
			"2034-07-15 18:15 +0000",
			"2034-08-14 03:52 +0000",
			"2034-09-12 16:13 +0000",
			"2034-10-12 07:31 +0000",
			"2034-11-11 01:15 +0000",
			"2034-12-10 20:13 +0000",
			"2035-01-09 15:02 +0000",
			"2035-02-08 08:21 +0000",
			"2035-03-09 23:08 +0000",
			"2035-04-08 10:57 +0000",
			"2035-05-07 20:03 +0000",
			"2035-06-06 03:20 +0000",
			"2035-07-05 09:59 +0000",
			"2035-08-03 17:12 +0000",
			"2035-09-02 01:59 +0000",
			"2035-10-01 13:06 +0000",
			"2035-10-31 02:58 +0000",
			"2035-11-29 19:36 +0000",
			"2035-12-29 14:30 +0000",
			"2036-01-28 10:16 +0000",
			"2036-02-27 04:58 +0000",
			"2036-03-27 20:56 +0000",
			"2036-04-26 09:32 +0000",
			"2036-05-25 19:16 +0000",
			"2036-06-24 03:09 +0000",
			"2036-07-23 10:17 +0000",
			"2036-08-21 17:35 +0000",
			"2036-09-20 01:51 +0000",
			"2036-10-19 11:50 +0000",
			"2036-11-18 00:13 +0000",
			"2036-12-17 15:33 +0000",
			"2037-01-16 09:33 +0000",
			"2037-02-15 04:53 +0000",
			"2037-03-16 23:35 +0000",
			"2037-04-15 16:07 +0000",
			"2037-05-15 05:53 +0000",
			"2037-06-13 17:09 +0000",
			"2037-07-13 02:31 +0000",
			"2037-08-11 10:41 +0000",
			"2037-09-09 18:25 +0000",
			"2037-10-09 02:34 +0000",
			"2037-11-07 12:03 +0000",
			"2037-12-06 23:37 +0000",
			"2038-01-05 13:40 +0000",
			"2038-02-04 05:51 +0000",
			"2038-03-05 23:14 +0000",
			"2038-04-04 16:42 +0000",
			"2038-05-04 09:18 +0000",
			"2038-06-03 00:23 +0000",
			"2038-07-02 13:31 +0000",
			"2038-08-01 00:39 +0000",
			"2038-08-30 10:12 +0000",
			"2038-09-28 18:57 +0000",
			"2038-10-28 03:52 +0000",
			"2038-11-26 13:47 +0000",
			"2038-12-26 01:01 +0000",
			"2039-01-24 13:36 +0000",
			"2039-02-23 03:16 +0000",
			"2039-03-24 17:58 +0000",
			"2039-04-23 09:33 +0000",
			"2039-05-23 01:37 +0000",
			"2039-06-21 17:20 +0000",
			"2039-07-21 07:53 +0000",
			"2039-08-19 20:49 +0000",
			"2039-09-18 08:22 +0000",
			"2039-10-17 19:08 +0000",
			"2039-11-16 05:45 +0000",
			"2039-12-15 16:32 +0000",
			"2040-01-14 03:25 +0000",
			"2040-02-12 14:24 +0000",
			"2040-03-13 01:45 +0000",
			"2040-04-11 13:59 +0000",
			"2040-05-11 03:27 +0000",
			"2040-06-09 18:02 +0000",
			"2040-07-09 09:13 +0000",
			"2040-08-08 00:25 +0000",
			"2040-09-06 15:12 +0000",
			"2040-10-06 05:25 +0000",
			"2040-11-04 18:55 +0000",
			"2040-12-04 07:32 +0000",
			"2041-01-02 19:07 +0000",
			"2041-02-01 05:42 +0000",
			"2041-03-02 15:39 +0000",
			"2041-04-01 01:28 +0000",
			"2041-04-30 11:46 +0000",
			"2041-05-29 22:55 +0000",
			"2041-06-28 11:16 +0000",
			"2041-07-28 01:01 +0000",
			"2041-08-26 16:15 +0000",
			"2041-09-25 08:40 +0000",
			"2041-10-25 01:29 +0000",
			"2041-11-23 17:36 +0000",
			"2041-12-23 08:05 +0000",
			"2042-01-21 20:41 +0000",
			"2042-02-20 07:39 +0000",
			"2042-03-21 17:23 +0000",
			"2042-04-20 02:18 +0000",
			"2042-05-19 10:54 +0000",
			"2042-06-17 19:47 +0000",
			"2042-07-17 05:51 +0000",
			"2042-08-15 18:00 +0000",
			"2042-09-14 08:49 +0000",
			"2042-10-14 02:02 +0000",
			"2042-11-12 20:27 +0000",
			"2042-12-12 14:28 +0000",
			"2043-01-11 06:52 +0000",
			"2043-02-09 21:07 +0000",
			"2043-03-11 09:09 +0000",
			"2043-04-09 19:06 +0000",
			"2043-05-09 03:20 +0000",
			"2043-06-07 10:35 +0000",
			"2043-07-06 17:51 +0000",
			"2043-08-05 02:22 +0000",
			"2043-09-03 13:16 +0000",
			"2043-10-03 03:11 +0000",
			"2043-11-01 19:56 +0000",
			"2043-12-01 14:36 +0000",
			"2043-12-31 09:47 +0000",
			"2044-01-30 04:03 +0000",
			"2044-02-28 20:11 +0000",
			"2044-03-29 09:25 +0000",
			"2044-04-27 19:41 +0000",
			"2044-05-27 03:39 +0000",
			"2044-06-25 10:24 +0000",
			"2044-07-24 17:10 +0000",
			"2044-08-23 01:05 +0000",
			"2044-09-21 11:03 +0000",
			"2044-10-20 23:35 +0000",
			"2044-11-19 14:57 +0000",
			"2044-12-19 08:52 +0000",
			"2045-01-18 04:24 +0000",
			"2045-02-16 23:50 +0000",
			"2045-03-18 17:14 +0000",
			"2045-04-17 07:26 +0000",
			"2045-05-16 18:26 +0000",
			"2045-06-15 03:04 +0000",
			"2045-07-14 10:28 +0000",
			"2045-08-12 17:39 +0000",
			"2045-09-11 01:27 +0000",
			"2045-10-10 10:36 +0000",
			"2045-11-08 21:48 +0000",
			"2045-12-08 11:40 +0000",
			"2046-01-07 04:23 +0000",
			"2046-02-05 23:08 +0000",
			"2046-03-07 18:14 +0000",
			"2046-04-06 11:50 +0000",
			"2046-05-06 02:55 +0000",
			"2046-06-04 15:21 +0000",
			"2046-07-04 01:38 +0000",
			"2046-08-02 10:25 +0000",
			"2046-08-31 18:25 +0000",
			"2046-09-30 02:25 +0000",
			"2046-10-29 11:17 +0000",
			"2046-11-27 21:49 +0000",
			"2046-12-27 10:38 +0000",
			"2047-01-26 01:43 +0000",
			"2047-02-24 18:25 +0000",
			"2047-03-26 11:43 +0000",
			"2047-04-25 04:38 +0000",
			"2047-05-24 20:26 +0000",
			"2047-06-23 10:34 +0000",
			"2047-07-22 22:48 +0000",
			"2047-08-21 09:15 +0000",
			"2047-09-19 18:31 +0000",
			"2047-10-19 03:27 +0000",
			"2047-11-17 12:59 +0000",
			"2047-12-16 23:37 +0000",
			"2048-01-15 11:32 +0000",
			"2048-02-14 00:30 +0000",
			"2048-03-14 14:27 +0000",
			"2048-04-13 05:18 +0000",
			"2048-05-12 20:57 +0000",
			"2048-06-11 12:48 +0000",
			"2048-07-11 04:03 +0000",
			"2048-08-09 17:58 +0000",
			"2048-09-08 06:23 +0000",
			"2048-10-07 17:44 +0000",
			"2048-11-06 04:37 +0000",
			"2048-12-05 15:30 +0000",
			"2049-01-04 02:23 +0000",
			"2049-02-02 13:16 +0000",
			"2049-03-04 00:10 +0000",
			"2049-04-02 11:38 +0000",
			"2049-05-02 00:10 +0000",
			"2049-05-31 13:59 +0000",
			"2049-06-30 04:49 +0000",
			"2049-07-29 20:06 +0000",
			"2049-08-28 11:17 +0000",
			"2049-09-27 02:04 +0000",
			"2049-10-26 16:14 +0000",
			"2049-11-25 05:35 +0000",
			"2049-12-24 17:51 +0000",
			"2050-01-23 04:56 +0000",
			"2050-02-21 15:03 +0000",
			"2050-03-23 00:40 +0000",
			"2050-04-21 10:25 +0000",
			"2050-05-20 20:50 +0000",
			"2050-06-19 08:21 +0000",
			"2050-07-18 21:15 +0000",
			"2050-08-17 11:46 +0000",
			"2050-09-16 03:48 +0000",
			"2050-10-15 20:47 +0000",
			"2050-11-14 13:40 +0000",
			"2050-12-14 05:17 +0000",
			"2051-01-12 18:57 +0000",
			"2051-02-11 06:41 +0000",
			"2051-03-12 16:52 +0000",
			"2051-04-11 01:58 +0000",
			"2051-05-10 10:29 +0000",
			"2051-06-08 18:56 +0000",
			"2051-07-08 04:08 +0000",
			"2051-08-06 15:04 +0000",
			"2051-09-05 04:32 +0000",
			"2051-10-04 20:45 +0000",
			"2051-11-03 14:58 +0000",
			"2051-12-03 09:35 +0000",
			"2052-01-02 03:04 +0000",
			"2052-01-31 18:29 +0000",
			"2052-03-01 07:35 +0000",
			"2052-03-30 18:26 +0000",
			"2052-04-29 03:20 +0000",
			"2052-05-28 10:50 +0000",
			"2052-06-26 17:50 +0000",
			"2052-07-26 01:30 +0000",
			"2052-08-24 11:06 +0000",
			"2052-09-22 23:31 +0000",
			"2052-10-22 15:02 +0000",
			"2052-11-21 09:01 +0000",
			"2052-12-21 04:14 +0000",
			"2053-01-19 23:11 +0000",
			"2053-02-18 16:30 +0000",
			"2053-03-20 07:10 +0000",
			"2053-04-18 18:47 +0000",
			"2053-05-18 03:42 +0000",
			"2053-06-16 10:51 +0000",
			"2053-07-15 17:26 +0000",
			"2053-08-14 00:40 +0000",
			"2053-09-12 09:35 +0000",
			"2053-10-11 20:53 +0000",
			"2053-11-10 10:54 +0000",
			"2053-12-10 03:39 +0000",
			"2054-01-08 22:33 +0000",
			"2054-02-07 18:12 +0000",
			"2054-03-09 12:44 +0000",
			"2054-04-08 04:31 +0000",
			"2054-05-07 17:00 +0000",
			"2054-06-06 02:39 +0000",
			"2054-07-05 10:34 +0000",
			"2054-08-03 17:48 +0000",
			"2054-09-02 01:17 +0000",
			"2054-10-01 09:49 +0000",
			"2054-10-30 20:01 +0000",
			"2054-11-29 08:33 +0000",
			"2054-12-28 23:51 +0000",
			"2055-01-27 17:38 +0000",
			"2055-02-26 12:38 +0000",
			"2055-03-28 06:59 +0000",
			"2055-04-26 23:16 +0000",
			"2055-05-26 12:56 +0000",
			"2055-06-25 00:14 +0000",
			"2055-07-24 09:47 +0000",
			"2055-08-22 18:14 +0000",
			"2055-09-21 02:19 +0000",
			"2055-10-20 10:50 +0000",
			"2055-11-18 20:34 +0000",
			"2055-12-18 08:15 +0000",
			"2056-01-16 22:09 +0000",
			"2056-02-15 13:58 +0000",
			"2056-03-16 06:51 +0000",
			"2056-04-14 23:49 +0000",
			"2056-05-14 16:05 +0000",
			"2056-06-13 07:03 +0000",
			"2056-07-12 20:19 +0000",
			"2056-08-11 07:47 +0000",
			"2056-09-09 17:47 +0000",
			"2056-10-09 03:00 +0000",
			"2056-11-07 12:21 +0000",
			"2056-12-06 22:30 +0000",
			"2057-01-05 09:49 +0000",
			"2057-02-03 22:09 +0000",
			"2057-03-05 11:24 +0000",
			"2057-04-04 01:30 +0000",
			"2057-05-03 16:31 +0000",
			"2057-06-02 08:10 +0000",
			"2057-07-01 23:46 +0000",
			"2057-07-31 14:31 +0000",
			"2057-08-30 03:53 +0000",
			"2057-09-28 15:59 +0000",
			"2057-10-28 03:18 +0000",
			"2057-11-26 14:22 +0000",
			"2057-12-26 01:21 +0000",
			"2058-01-24 12:14 +0000",
			"2058-02-22 22:56 +0000",
			"2058-03-24 09:49 +0000",
			"2058-04-22 21:28 +0000",
			"2058-05-22 10:22 +0000",
			"2058-06-21 00:34 +0000",
			"2058-07-20 15:38 +0000",
			"2058-08-19 07:02 +0000",
			"2058-09-17 22:16 +0000",
			"2058-10-17 13:04 +0000",
			"2058-11-16 03:08 +0000",
			"2058-12-15 16:11 +0000",
			"2059-01-14 03:56 +0000",
			"2059-02-12 14:27 +0000",
			"2059-03-14 00:04 +0000",
			"2059-04-12 09:28 +0000",
			"2059-05-11 19:14 +0000",
			"2059-06-10 05:56 +0000",
			"2059-07-09 17:57 +0000",
			"2059-08-08 07:36 +0000",
			"2059-09-06 23:00 +0000",
			"2059-10-06 15:48 +0000",
			"2059-11-05 09:10 +0000",
			"2059-12-05 01:48 +0000",
			"2060-01-03 16:39 +0000",
			"2060-02-02 05:22 +0000",
			"2060-03-02 16:11 +0000",
			"2060-04-01 01:37 +0000",
			"2060-04-30 10:11 +0000",
			"2060-05-29 18:23 +0000",
			"2060-06-28 02:57 +0000",
			"2060-07-27 12:49 +0000",
			"2060-08-26 00:55 +0000",
			"2060-09-24 15:52 +0000",
			"2060-10-24 09:24 +0000",
			"2060-11-23 04:15 +0000",
			"2060-12-22 22:38 +0000",
			"2061-01-21 15:15 +0000",
			"2061-02-20 05:30 +0000",
			"2061-03-21 17:23 +0000",
			"2061-04-20 03:04 +0000",
			"2061-05-19 11:03 +0000",
			"2061-06-17 18:03 +0000",
			"2061-07-17 01:09 +0000",
			"2061-08-15 09:39 +0000",
			"2061-09-13 20:36 +0000",
			"2061-10-13 10:40 +0000",
			"2061-11-12 03:39 +0000",
			"2061-12-11 22:31 +0000",
			"2062-01-10 17:51 +0000",
			"2062-02-09 12:09 +0000",
			"2062-03-11 04:12 +0000",
			"2062-04-09 17:16 +0000",
			"2062-05-09 03:22 +0000",
			"2062-06-07 11:12 +0000",
			"2062-07-06 17:53 +0000",
			"2062-08-05 00:39 +0000",
			"2062-09-03 08:42 +0000",
			"2062-10-02 18:49 +0000",
			"2062-11-01 07:32 +0000",
			"2062-11-30 23:00 +0000",
			"2062-12-30 16:56 +0000",
			"2063-01-29 12:22 +0000",
			"2063-02-28 07:36 +0000",
			"2063-03-30 00:48 +0000",
			"2063-04-28 14:51 +0000",
			"2063-05-28 01:46 +0000",
			"2063-06-26 10:25 +0000",
			"2063-07-25 17:55 +0000",
			"2063-08-24 01:17 +0000",
			"2063-09-22 09:21 +0000",
			"2063-10-21 18:46 +0000",
			"2063-11-20 06:09 +0000",
			"2063-12-19 20:03 +0000",
			"2064-01-18 12:36 +0000",
			"2064-02-17 07:02 +0000",
			"2064-03-18 01:44 +0000",
			"2064-04-16 19:00 +0000",
			"2064-05-16 09:54 +0000",
			"2064-06-14 22:20 +0000",
			"2064-07-14 08:45 +0000",
			"2064-08-12 17:48 +0000",
			"2064-09-11 02:10 +0000",
			"2064-10-10 10:34 +0000",
			"2064-11-08 19:45 +0000",
			"2064-12-08 06:28 +0000",
			"2065-01-06 19:14 +0000",
			"2065-02-05 10:01 +0000",
			"2065-03-07 02:14 +0000",
			"2065-04-05 19:00 +0000",
			"2065-05-05 11:29 +0000",
			"2065-06-04 03:04 +0000",
			"2065-07-03 17:14 +0000",
			"2065-08-02 05:45 +0000",
			"2065-08-31 16:39 +0000",
			"2065-09-30 02:23 +0000",
			"2065-10-29 11:48 +0000",
			"2065-11-27 21:39 +0000",
			"2065-12-27 08:27 +0000",
			"2066-01-25 20:14 +0000",
			"2066-02-24 08:50 +0000",
			"2066-03-25 22:13 +0000",
			"2066-04-24 12:28 +0000",
			"2066-05-24 03:37 +0000",
			"2066-06-22 19:14 +0000",
			"2066-07-22 10:32 +0000",
			"2066-08-21 00:49 +0000",
			"2066-09-19 13:47 +0000",
			"2066-10-19 01:42 +0000",
			"2066-11-17 13:06 +0000",
			"2066-12-17 00:17 +0000",
			"2067-01-15 11:17 +0000",
			"2067-02-13 21:57 +0000",
			"2067-03-15 08:29 +0000",
			"2067-04-13 19:23 +0000",
			"2067-05-13 07:20 +0000",
			"2067-06-11 20:40 +0000",
			"2067-07-11 11:15 +0000",
			"2067-08-10 02:36 +0000",
			"2067-09-08 18:08 +0000",
			"2067-10-08 09:27 +0000",
			"2067-11-07 00:13 +0000",
			"2067-12-06 14:04 +0000",
			"2068-01-05 02:37 +0000",
			"2068-02-03 13:45 +0000",
			"2068-03-03 23:37 +0000",
			"2068-04-02 08:51 +0000",
			"2068-05-01 18:06 +0000",
			"2068-05-31 04:02 +0000",
			"2068-06-29 15:10 +0000",
			"2068-07-29 03:54 +0000",
			"2068-08-27 18:27 +0000",
			"2068-09-26 10:47 +0000",
			"2068-10-26 04:16 +0000",
			"2068-11-24 21:41 +0000",
			"2068-12-24 13:43 +0000",
			"2069-01-23 03:35 +0000",
			"2069-02-21 15:17 +0000",
			"2069-03-23 01:12 +0000",
			"2069-04-21 09:59 +0000",
			"2069-05-20 18:06 +0000",
			"2069-06-19 02:13 +0000",
			"2069-07-18 11:12 +0000",
			"2069-08-16 22:02 +0000",
			"2069-09-15 11:34 +0000",
			"2069-10-15 04:02 +0000",
			"2069-11-13 22:37 +0000",
			"2069-12-13 17:37 +0000",
			"2070-01-12 11:22 +0000",
			"2070-02-11 02:51 +0000",
			"2070-03-12 15:52 +0000",
			"2070-04-11 02:30 +0000",
			"2070-05-10 11:08 +0000",
			"2070-06-08 18:24 +0000",
			"2070-07-08 01:14 +0000",
			"2070-08-06 08:51 +0000",
			"2070-09-04 18:28 +0000",
			"2070-10-04 07:00 +0000",
			"2070-11-02 22:42 +0000",
			"2070-12-02 16:52 +0000",
			"2071-01-01 12:14 +0000",
			"2071-01-31 07:15 +0000",
			"2071-03-02 00:30 +0000",
			"2071-03-31 15:02 +0000",
			"2071-04-30 02:29 +0000",
			"2071-05-29 11:17 +0000",
			"2071-06-27 18:21 +0000",
			"2071-07-27 00:55 +0000",
			"2071-08-25 08:16 +0000",
			"2071-09-23 17:21 +0000",
			"2071-10-23 04:49 +0000",
			"2071-11-21 18:59 +0000",
			"2071-12-21 11:46 +0000",
			"2072-01-20 06:34 +0000",
			"2072-02-19 02:02 +0000",
			"2072-03-19 20:20 +0000",
			"2072-04-18 11:56 +0000",
			"2072-05-18 00:17 +0000",
			"2072-06-16 09:57 +0000",
			"2072-07-15 17:56 +0000",
			"2072-08-14 01:20 +0000",
			"2072-09-12 09:07 +0000",
			"2072-10-11 17:55 +0000",
			"2072-11-10 04:20 +0000",
			"2072-12-09 16:58 +0000",
			"2073-01-08 08:10 +0000",
			"2073-02-07 01:39 +0000",
			"2073-03-08 20:14 +0000",
			"2073-04-07 14:13 +0000",
			"2073-05-07 06:14 +0000",
			"2073-06-05 19:50 +0000",
			"2073-07-05 07:15 +0000",
			"2073-08-03 17:03 +0000",
			"2073-09-02 01:52 +0000",
			"2073-10-01 10:21 +0000",
			"2073-10-30 19:13 +0000",
			"2073-11-29 05:12 +0000",
			"2073-12-28 16:55 +0000",
			"2074-01-27 06:37 +0000",
			"2074-02-25 21:59 +0000",
			"2074-03-27 14:18 +0000",
			"2074-04-26 06:46 +0000",
			"2074-05-25 22:43 +0000",
			"2074-06-24 13:37 +0000",
			"2074-07-24 03:06 +0000",
			"2074-08-22 14:58 +0000",
			"2074-09-21 01:28 +0000",
			"2074-10-20 11:12 +0000",
			"2074-11-18 20:56 +0000",
			"2074-12-18 07:20 +0000",
			"2075-01-16 18:37 +0000",
			"2075-02-15 06:40 +0000",
			"2075-03-16 19:24 +0000",
			"2075-04-15 08:55 +0000",
			"2075-05-14 23:21 +0000",
			"2075-06-13 14:38 +0000",
			"2075-07-13 06:10 +0000",
			"2075-08-11 21:10 +0000",
			"2075-09-10 11:01 +0000",
			"2075-10-09 23:42 +0000",
			"2075-11-08 11:35 +0000",
			"2075-12-07 23:03 +0000",
			"2076-01-06 10:15 +0000",
			"2076-02-04 21:01 +0000",
			"2076-03-05 07:24 +0000",
			"2076-04-03 17:47 +0000",
			"2076-05-03 04:51 +0000",
			"2076-06-01 17:13 +0000",
			"2076-07-01 07:03 +0000",
			"2076-07-30 22:04 +0000",
			"2076-08-29 13:42 +0000",
			"2076-09-28 05:26 +0000",
			"2076-10-27 20:50 +0000",
			"2076-11-26 11:28 +0000",
			"2076-12-26 00:52 +0000",
			"2077-01-24 12:45 +0000",
			"2077-02-22 23:06 +0000",
			"2077-03-24 08:24 +0000",
			"2077-04-22 17:20 +0000",
			"2077-05-22 02:37 +0000",
			"2077-06-20 12:54 +0000",
			"2077-07-20 00:40 +0000",
			"2077-08-18 14:16 +0000",
			"2077-09-17 05:52 +0000",
			"2077-10-16 23:06 +0000",
			"2077-11-15 16:59 +0000",
			"2077-12-15 10:05 +0000",
			"2078-01-14 01:13 +0000",
			"2078-02-12 13:59 +0000",
			"2078-03-14 00:37 +0000",
			"2078-04-12 09:45 +0000",
			"2078-05-11 17:56 +0000",
			"2078-06-10 01:48 +0000",
			"2078-07-09 10:08 +0000",
			"2078-08-07 19:51 +0000",
			"2078-09-06 07:58 +0000",
			"2078-10-05 23:05 +0000",
			"2078-11-04 16:55 +0000",
			"2078-12-04 12:07 +0000",
			"2079-01-03 06:49 +0000",
			"2079-02-01 23:35 +0000",
			"2079-03-03 13:48 +0000",
			"2079-04-02 01:29 +0000",
			"2079-05-01 10:57 +0000",
			"2079-05-30 18:41 +0000",
			"2079-06-29 01:31 +0000",
			"2079-07-28 08:33 +0000",
			"2079-08-26 17:02 +0000",
			"2079-09-25 04:05 +0000",
			"2079-10-24 18:19 +0000",
			"2079-11-23 11:28 +0000",
			"2079-12-23 06:30 +0000",
			"2080-01-22 01:55 +0000",
			"2080-02-20 20:10 +0000",
			"2080-03-21 12:05 +0000",
			"2080-04-20 00:59 +0000",
			"2080-05-19 10:56 +0000",
			"2080-06-17 18:40 +0000",
			"2080-07-17 01:20 +0000",
			"2080-08-15 08:13 +0000",
			"2080-09-13 16:25 +0000",
			"2080-10-13 02:43 +0000",
			"2080-11-11 15:36 +0000",
			"2080-12-11 07:09 +0000",
			"2081-01-10 01:01 +0000",
			"2081-02-08 20:16 +0000",
			"2081-03-10 15:16 +0000",
			"2081-04-09 08:14 +0000",
			"2081-05-08 22:08 +0000",
			"2081-06-07 09:01 +0000",
			"2081-07-06 17:44 +0000",
			"2081-08-05 01:23 +0000",
			"2081-09-03 09:02 +0000",
			"2081-10-02 17:23 +0000",
			"2081-11-01 03:03 +0000",
			"2081-11-30 14:36 +0000",
			"2081-12-30 04:28 +0000",
			"2082-01-28 20:46 +0000",
			"2082-02-27 14:47 +0000",
			"2082-03-29 09:04 +0000",
			"2082-04-28 02:01 +0000",
			"2082-05-27 16:46 +0000",
			"2082-06-26 05:15 +0000",
			"2082-07-25 15:54 +0000",
			"2082-08-24 01:17 +0000",
			"2082-09-22 10:04 +0000",
			"2082-10-21 18:51 +0000",
			"2082-11-20 04:19 +0000",
			"2082-12-19 15:11 +0000",
			"2083-01-18 03:49 +0000",
			"2083-02-16 18:15 +0000",
			"2083-03-18 09:56 +0000",
			"2083-04-17 02:09 +0000",
			"2083-05-16 18:13 +0000",
			"2083-06-15 09:37 +0000",
			"2083-07-14 23:54 +0000",
			"2083-08-13 12:44 +0000",
			"2083-09-12 00:06 +0000",
			"2083-10-11 10:23 +0000",
			"2083-11-09 20:15 +0000",
			"2083-12-09 06:25 +0000",
			"2084-01-07 17:17 +0000",
			"2084-02-06 04:52 +0000",
			"2084-03-06 17:03 +0000",
			"2084-04-05 05:52 +0000",
			"2084-05-04 19:32 +0000",
			"2084-06-03 10:12 +0000",
			"2084-07-03 01:37 +0000",
			"2084-08-01 17:03 +0000",
			"2084-08-31 07:44 +0000",
			"2084-09-29 21:16 +0000",
			"2084-10-29 09:47 +0000",
			"2084-11-27 21:39 +0000",
			"2084-12-27 09:07 +0000",
			"2085-01-25 20:07 +0000",
			"2085-02-24 06:32 +0000",
			"2085-03-25 16:37 +0000",
			"2085-04-24 02:58 +0000",
			"2085-05-23 14:22 +0000",
			"2085-06-22 03:17 +0000",
			"2085-07-21 17:42 +0000",
			"2085-08-20 09:10 +0000",
			"2085-09-19 01:06 +0000",
			"2085-10-18 16:59 +0000",
			"2085-11-17 08:20 +0000",
			"2085-12-16 22:37 +0000",
			"2086-01-15 11:24 +0000",
			"2086-02-13 22:26 +0000",
			"2086-03-15 08:04 +0000",
			"2086-04-13 16:53 +0000",
			"2086-05-13 01:41 +0000",
			"2086-06-11 11:12 +0000",
			"2086-07-10 22:01 +0000",
			"2086-08-09 10:37 +0000",
			"2086-09-08 01:16 +0000",
			"2086-10-07 17:55 +0000",
			"2086-11-06 11:52 +0000",
			"2086-12-06 05:47 +0000",
			"2087-01-04 22:10 +0000",
			"2087-02-03 12:10 +0000",
			"2087-03-04 23:44 +0000",
			"2087-04-03 09:26 +0000",
			"2087-05-02 17:51 +0000",
			"2087-06-01 01:38 +0000",
			"2087-06-30 09:31 +0000",
			"2087-07-29 18:20 +0000",
			"2087-08-28 05:07 +0000",
			"2087-09-26 18:46 +0000",
			"2087-10-26 11:28 +0000",
			"2087-11-25 06:23 +0000",
			"2087-12-25 01:42 +0000",
			"2088-01-23 19:38 +0000",
			"2088-02-22 11:08 +0000",
			"2088-03-23 00:00 +0000",
			"2088-04-21 10:25 +0000",
			"2088-05-20 18:49 +0000",
			"2088-06-19 01:53 +0000",
			"2088-07-18 08:39 +0000",
			"2088-08-16 16:15 +0000",
			"2088-09-15 01:57 +0000",
			"2088-10-14 14:39 +0000",
			"2088-11-13 06:31 +0000",
			"2088-12-13 00:51 +0000",
			"2089-01-11 20:17 +0000",
			"2089-02-10 15:15 +0000",
			"2089-03-12 08:23 +0000",
			"2089-04-10 22:45 +0000",
			"2089-05-10 10:03 +0000",
			"2089-06-08 18:44 +0000",
			"2089-07-08 01:47 +0000",
			"2089-08-06 08:28 +0000",
			"2089-09-04 15:58 +0000",
			"2089-10-04 01:14 +0000",
			"2089-11-02 12:55 +0000",
			"2089-12-02 03:11 +0000",
			"2089-12-31 19:56 +0000",
			"2090-01-30 14:33 +0000",
			"2090-03-01 09:45 +0000",
			"2090-03-31 03:47 +0000",
			"2090-04-29 19:11 +0000",
			"2090-05-29 07:29 +0000",
			"2090-06-27 17:11 +0000",
			"2090-07-27 01:18 +0000",
			"2090-08-25 08:59 +0000",
			"2090-09-23 17:03 +0000",
			"2090-10-23 02:09 +0000",
			"2090-11-21 12:49 +0000",
			"2090-12-21 01:28 +0000",
			"2091-01-19 16:30 +0000",
			"2091-02-18 09:37 +0000",
			"2091-03-20 03:45 +0000",
			"2091-04-18 21:19 +0000",
			"2091-05-18 13:06 +0000",
			"2091-06-17 02:40 +0000",
			"2091-07-16 14:15 +0000",
			"2091-08-15 00:21 +0000",
			"2091-09-13 09:34 +0000",
			"2091-10-12 18:29 +0000",
			"2091-11-11 03:42 +0000",
			"2091-12-10 13:54 +0000",
			"2092-01-09 01:36 +0000",
			"2092-02-07 15:02 +0000",
			"2092-03-08 05:56 +0000",
			"2092-04-06 21:40 +0000",
			"2092-05-06 13:38 +0000",
			"2092-06-05 05:17 +0000",
			"2092-07-04 20:10 +0000",
			"2092-08-03 09:53 +0000",
			"2092-09-01 22:13 +0000",
			"2092-10-01 09:15 +0000",
			"2092-10-30 19:29 +0000",
			"2092-11-29 05:36 +0000",
			"2092-12-28 16:11 +0000",
			"2093-01-27 03:22 +0000",
			"2093-02-25 15:06 +0000",
			"2093-03-27 03:17 +0000",
			"2093-04-25 16:12 +0000",
			"2093-05-25 06:06 +0000",
			"2093-06-23 21:04 +0000",
			"2093-07-23 12:35 +0000",
			"2093-08-22 03:53 +0000",
			"2093-09-20 18:16 +0000",
			"2093-10-20 07:33 +0000",
			"2093-11-18 19:57 +0000",
			"2093-12-18 07:47 +0000",
			"2094-01-16 19:06 +0000",
			"2094-02-15 05:43 +0000",
			"2094-03-16 15:45 +0000",
			"2094-04-15 01:37 +0000",
			"2094-05-14 12:09 +0000",
			"2094-06-13 00:03 +0000",
			"2094-07-12 13:36 +0000",
			"2094-08-11 04:36 +0000",
			"2094-09-09 20:30 +0000",
			"2094-10-09 12:43 +0000",
			"2094-11-08 04:41 +0000",
			"2094-12-07 19:50 +0000",
			"2095-01-06 09:33 +0000",
			"2095-02-04 21:28 +0000",
			"2095-03-06 07:39 +0000",
			"2095-04-04 16:36 +0000",
			"2095-05-04 01:05 +0000",
			"2095-06-02 09:58 +0000",
			"2095-07-01 19:54 +0000",
			"2095-07-31 07:28 +0000",
			"2095-08-29 21:05 +0000",
			"2095-09-28 12:53 +0000",
			"2095-10-28 06:31 +0000",
			"2095-11-27 00:53 +0000",
			"2095-12-26 18:24 +0000",
			"2096-01-25 09:44 +0000",
			"2096-02-23 22:28 +0000",
			"2096-03-24 08:55 +0000",
			"2096-04-22 17:44 +0000",
			"2096-05-22 01:35 +0000",
			"2096-06-20 09:12 +0000",
			"2096-07-19 17:21 +0000",
			"2096-08-18 03:00 +0000",
			"2096-09-16 15:10 +0000",
			"2096-10-16 06:28 +0000",
			"2096-11-15 00:35 +0000",
			"2096-12-14 20:05 +0000",
			"2097-01-13 14:59 +0000",
			"2097-02-12 07:48 +0000",
			"2097-03-13 21:56 +0000",
			"2097-04-12 09:26 +0000",
			"2097-05-11 18:40 +0000",
			"2097-06-10 02:13 +0000",
			"2097-07-09 08:58 +0000",
			"2097-08-07 16:00 +0000",
			"2097-09-06 00:33 +0000",
			"2097-10-05 11:45 +0000",
			"2097-11-04 02:08 +0000",
			"2097-12-03 19:26 +0000",
			"2098-01-02 14:31 +0000",
			"2098-02-01 09:53 +0000",
			"2098-03-03 04:02 +0000",
			"2098-04-01 19:46 +0000",
			"2098-05-01 08:31 +0000",
			"2098-05-30 18:23 +0000",
			"2098-06-29 02:06 +0000",
			"2098-07-28 08:51 +0000",
			"2098-08-26 15:53 +0000",
			"2098-09-25 00:16 +0000",
			"2098-10-24 10:49 +0000",
			"2098-11-22 23:50 +0000",
			"2098-12-22 15:24 +0000",
			"2099-01-21 09:07 +0000",
			"2099-02-20 04:05 +0000",
			"2099-03-21 22:46 +0000",
			"2099-04-20 15:29 +0000",
			"2099-05-20 05:16 +0000",
			"2099-06-18 16:10 +0000",
			"2099-07-18 01:00 +0000",
			"2099-08-16 08:55 +0000",
			"2099-09-14 16:51 +0000",
			"2099-10-14 01:32 +0000",
			"2099-11-12 11:30 +0000",
			"2099-12-11 23:09 +0000"
		];

		private static double rev(double angle)
		{
			return angle - Math.Floor(angle / 360.0) * 360.0;
		}

		private static double sind(double angle)
		{
			return Math.Sin((angle * Math.PI) / 180.0);
		}

		private static double cosd(double angle)
		{
			return Math.Cos((angle * Math.PI) / 180.0);
		}

		private static double tand(double angle)
		{
			return Math.Tan((angle * Math.PI) / 180.0);
		}

		private static double asind(double c)
		{
			return (180.0 / Math.PI) * Math.Asin(c);
		}

		private static double atan2d(double y, double x)
		{
			double num = x < 0 ? 1 : 0;
			return (180.0 / Math.PI) * Math.Atan(y / x) - 180.0 * num;
		}

		private static double DayNum(int year, int month, int day, double hours)
		{
			// Day number is a modified Julian date, day 0 is 2000 January 0.0
			// which corresponds to a Julian date of 2451543.5
			double d = (367 * year - Math.Floor(7 * (year + Math.Floor((month + 9) / 12.0)) / 4)
						  + Math.Floor((275 * month) / 9.0) + day - 730530 + hours / 24);
			return d;
		}

		private static double Julian(int year, int month, int day, double hours)
		{
			return DayNum(year, month, day, hours) + 2451543.5;
		}

		private static double LocalSidereal(int year, int month, int day, double hours, double lon)
		{
			// Compute local sidereal time in degrees
			// year, month, day and hours are the Greenwich date and time
			// lon is the observers longitude
			var d = DayNum(year, month, day, hours);
			var lst = (98.9818 + 0.985647352 * d + hours * 15 + lon);
			return rev(lst) / 15;
		}

		private static double[] RaDecToAltAz(double ra, double dec, int year, int month, int day, double hours, double lat, double lon)
		{
			// convert ra and dec to altitude and azimuth
			// year, month, day and hours are the Greenwich date and time
			// lat and lon are the observers latitude and longitude
			var lst = LocalSidereal(year, month, day, hours, lon);
			var x = cosd(15.0 * (lst - ra)) * cosd(dec);
			var y = sind(15.0 * (lst - ra)) * cosd(dec);
			var z = sind(dec);
			// rotate so z is the local zenith
			var xhor = x * sind(lat) - z * cosd(lat);
			var yhor = y;
			var zhor = x * cosd(lat) + z * sind(lat);
			var azimuth = rev(atan2d(yhor, xhor) + 180.0); // so 0 degrees is north
			var altitude = atan2d(zhor, Math.Sqrt(xhor * xhor + yhor * yhor));
			return [altitude, azimuth];
		}

		// MoonPos calculates the Moon position, based on Meeus chapter 45
		public static double[] MoonPos(int year, int month, int day, double hours)
		{
			// julian date
			var jd = Julian(year, month, day, hours);
			var T = (jd - 2451545.0) / 36525;
			var T2 = T * T;
			var T3 = T2 * T;
			var T4 = T3 * T;
			// Moons mean longitude L'
			var LP = 218.3164477 + 481267.88123421 * T - 0.0015786 * T2 + T3 / 538841.0 - T4 / 65194000.0;
			// Moons mean elongation
			var D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2 + T3 / 545868.0 - T4 / 113065000.0;
			// Suns mean anomaly
			var M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T2 + T3 / 24490000.0;
			// Moons mean anomaly M'
			var MP = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2 + T3 / 69699.0 - T4 / 14712000.0;
			// Moons argument of latitude
			var F = 93.2720950 + 483202.0175233 * T - 0.0036539 * T2 - T3 / 3526000.0 + T4 / 863310000.0;

			// Additional arguments
			var A1 = 119.75 + 131.849 * T;
			var A2 = 53.09 + 479264.290 * T;
			var A3 = 313.45 + 481266.484 * T;
			var E = 1 - 0.002516 * T - 0.0000074 * T2;
			var E2 = E * E;
			// Sums of periodic terms from table 45.A and 45.B
			var Sl = 0.0;
			var Sr = 0.0;
			for (var i = 0; i < 60; i++)
			{
				var Eterm = 1.0;
				if (Math.Abs(T45AM[i]) == 1) Eterm = E;
				if (Math.Abs(T45AM[i]) == 2) Eterm = E2;
				Sl += T45AL[i] * Eterm * sind(rev(T45AD[i] * D + T45AM[i] * M + T45AMP[i] * MP + T45AF[i] * F));
				Sr += T45AR[i] * Eterm * cosd(rev(T45AD[i] * D + T45AM[i] * M + T45AMP[i] * MP + T45AF[i] * F));
			}
			var Sb = 0.0;
			for (var i = 0; i < 60; i++)
			{
				var Eterm = 1.0;
				if (Math.Abs(T45BM[i]) == 1) Eterm = E;
				if (Math.Abs(T45BM[i]) == 2) Eterm = E2;
				Sb += T45BL[i] * Eterm * sind(rev(T45BD[i] * D + T45BM[i] * M + T45BMP[i] * MP + T45BF[i] * F));
			}
			// Additional additive terms
			Sl = Sl + 3958 * sind(rev(A1)) + 1962 * sind(rev(LP - F)) + 318 * sind(rev(A2));
			Sb = Sb - 2235 * sind(rev(LP)) + 382 * sind(rev(A3)) + 175 * sind(rev(A1 - F)) + 175 * sind(rev(A1 + F)) + 127 * sind(rev(LP - MP)) - 115 * sind(rev(LP + MP));
			// geocentric longitude, latitude and distance
			var mglong = rev(LP + Sl / 1000000.0);
			var mglat = rev(Sb / 1000000.0);
			if (mglat > 180.0) mglat -= 360;
			var mr = Math.Round(385000.56 + Sr / 1000.0);
			// Obliquity of Ecliptic
			var obl = 23.4393 - 3.563E-9 * (jd - 2451543.5);
			// RA and dec
			var ra = rev(atan2d(sind(mglong) * cosd(obl) - tand(mglat) * sind(obl), cosd(mglong))) / 15.0;
			var dec = rev(asind(sind(mglat) * cosd(obl) + cosd(mglat) * sind(obl) * sind(mglong)));
			if (dec > 180.0) dec -= 360;
			return [ra, dec, mr];
		}

		public static double[] MoonRise(int year, int month, int day, double TZ, double latitude, double longitude)
		{
			// returns an array containing rise and set times or one of the
			// following codes.
			// -1 rise or set event not found and moon was down at 00:00
			// -2 rise or set event not found and moon was up   at 00:00
			// WARNING code changes on 6/7 May 2003 these are now local times
			// NOT UTC and rise/set not found codes changed.
			var hours = 0.0;
			double[] riseset;
			// elh is the elevation at the hour elhdone is true if elh calculated
			var elh = new double[25];
			var elhdone = new bool[25];
			for (var i = 0; i <= 24; i++)
			{
				elhdone[i] = false;
			}
			// Compute the moon elevation at start and end of day
			// store elevation at the hours in an array elh to save search time
			var rad = MoonPos(year, month, day, hours - TZ);
			var altaz = RaDecToAltAz(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
			elh[0] = altaz[0];
			elhdone[0] = true;
			// set the return code to allow for always up or never rises
			if (elh[0] > 0.0)
			{
				riseset = [-2, -2];
			}
			else
			{
				riseset = [-1, -1];
			}
			hours = 24;
			rad = MoonPos(year, month, day, hours - TZ);
			altaz = RaDecToAltAz(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
			elh[24] = altaz[0];
			elhdone[24] = true;
			// search for moonrise and set
			for (var rise = 0; rise < 2; rise++)
			{
				var found = false;
				double hfirst = 0;
				double hlast = 24;
				// Try a binary chop on the hours to speed the search
				while (Math.Ceiling((hlast - hfirst) / 2.0) > 1)
				{
					int hmid = (int) (hfirst + Math.Round((hlast - hfirst) / 2.0));
					if (!elhdone[hmid])
					{
						hours = hmid;
						rad = MoonPos(year, month, day, hours - TZ);
						altaz = RaDecToAltAz(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
						elh[hmid] = altaz[0];
						elhdone[hmid] = true;
					}
					if (((rise == 0) && (elh[(int) hfirst] <= 0.0) && (elh[hmid] >= 0.0)) || ((rise == 1) && (elh[(int) hfirst] >= 0.0) && (elh[hmid] <= 0.0)))
					{
						hlast = hmid;
						found = true;
						continue;
					}
					if (((rise == 0) && (elh[hmid] <= 0.0) && (elh[(int) hlast] >= 0.0)) || ((rise == 1) && (elh[hmid] >= 0.0) && (elh[(int) hlast] <= 0.0)))
					{
						hfirst = hmid;
						found = true;
						continue;
					}
					break;
				}
				// If the binary chop did not find a 1 hour interval
				if ((hlast - hfirst) > 1)
				{
					for (int i = (int) hfirst; i < hlast; i++)
					{
						found = false;
						if (!elhdone[i + 1])
						{
							hours = i + 1;
							rad = MoonPos(year, month, day, hours - TZ);
							altaz = RaDecToAltAz(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
							elh[(int) hours] = altaz[0];
							elhdone[(int) hours] = true;
						}
						if (((rise == 0) && (elh[i] <= 0.0) && (elh[i + 1] >= 0.0)) || ((rise == 1) && (elh[i] >= 0.0) && (elh[i + 1] <= 0.0)))
						{
							hfirst = i;
							hlast = i + 1;
							found = true;
							break;
						}
					}
				}
				// simple linear interpolation for the minutes
				if (found)
				{
					var elfirst = elh[(int) hfirst];
					var ellast = elh[(int) hlast];
					hours = hfirst + 0.5;
					rad = MoonPos(year, month, day, hours - TZ);
					altaz = RaDecToAltAz(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
					if ((rise == 0) && (altaz[0] <= 0.0))
					{
						hfirst = hours;
						elfirst = altaz[0];
					}
					if ((rise == 0) && (altaz[0] > 0.0))
					{
						hlast = hours;
						ellast = altaz[0];
					}
					if ((rise == 1) && (altaz[0] <= 0.0))
					{
						hlast = hours;
						ellast = altaz[0];
					}
					if ((rise == 1) && (altaz[0] > 0.0))
					{
						hfirst = hours;
						elfirst = altaz[0];
					}
					var eld = Math.Abs(elfirst) + Math.Abs(ellast);
					riseset[rise] = hfirst + (hlast - hfirst) * Math.Abs(elfirst) / eld;
				}
			} // End of rise/set loop
			return (riseset);
		}

		public static double MoonPhase(int year, int month, int day, int hours)
		{
			// the illuminated percentage from Meeus chapter 46
			var j = Julian(year, month, day, hours);
			var T = (j - 2451545.0) / 36525;
			var T2 = T * T;
			var T3 = T2 * T;
			var T4 = T3 * T;
			// Moons mean elongation Meeus second edition
			var D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2 + T3 / 545868.0 - T4 / 113065000.0;
			// Moons mean anomaly M' Meeus second edition
			var MP = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2 + T3 / 69699.0 - T4 / 14712000.0;
			// Suns mean anomaly
			var M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T2 + T3 / 24490000.0;
			// phase angle
			var pa = 180.0 - D - 6.289 * sind(MP) + 2.1 * sind(M) - 1.274 * sind(2 * D - MP) - 0.658 * sind(2 * D) - 0.214 * sind(2 * MP) - 0.11 * sind(D);
			return (rev(pa));
		}

		/*
		private double[] MoonQuarters(int year , int month , int day )
		{
			// returns an array of Julian Ephemeris Days (JDE) for
			// new moon, first quarter, full moon and last quarter
			// Meeus first edition chapter 47 with only the most larger additional corrections
			// Meeus code calculate Terrestrial Dynamic Time
			// TDT = UTC + (number of leap seconds) + 32.184
			// At the end of June 2012 the 25th leap second was added
			//
			var quarters = new double[4];
			// k is an integer for new moon incremented by 0.25 for first quarter 0.5 for new etc.
			var k = Math.Floor((year + ((month - 1) + day/30)/12 - 2000)*12.3685);
			// Time in Julian centuries since 2000.0
			var T = k/1236.85;
			// Sun's mean anomaly
			var M = rev(2.5534 + 29.10535669*k - 0.0000218*T*T);
			// Moon's mean anomaly (M' in Meeus)
			var MP = rev(201.5643 + 385.81693528*k + 0.0107438*T*T + 0.00001239*T*T*T - 0.00000011*T*T*T);
			var E = 1 - 0.002516*T - 0.0000074*T*T;
			// Moons argument of latitude
			var F = rev(160.7108 + 390.67050274*k - 0.0016341*T*T - 0.00000227*T*T*T + 0.000000011*T*T*T*T);
			// Longitude of ascending node of lunar orbit
			var Omega = rev(124.7746 - 1.56375580*k + 0.0020691*T*T + 0.00000215*T*T*T);
			// The full planetary arguments include 14 terms, only used the 7 most significant
			var A = new double[8];
			A[1] = rev(299.77 + 0.107408*k - 0.009173*T*T);
			A[2] = rev(251.88 + 0.016321*k);
			A[3] = rev(251.83 + 26.651886*k);
			A[4] = rev(349.42 + 36.412478*k);
			A[5] = rev(84.88 + 18.206239*k);
			A[6] = rev(141.74 + 53.303771*k);
			A[7] = rev(207.14 + 2.453732*k);

			// New moon
			var JDE0 = 2451550.09765 + 29.530588853*k + 0.0001337*T*T - 0.000000150*T*T*T + 0.00000000073*T*T*T*T;
			// Correct for TDT since 1 July 2012
			JDE0 -= 57.184/(24*60*60);
			var JDE = JDE0 - 0.40720*sind(MP) + 0.17241*E*sind(M) + 0.01608*sind(2*MP) + 0.01039*sind(2*F) + 0.00739*E*sind(MP - M) - 0.00514*E*sind(MP + M) + 0.00208*E*E*sind(2*M) -
					  0.00111*sind(MP - 2*F) - 0.00057*sind(MP + 2*F) + 0.00056*E*sind(2*MP + M) - 0.00042*sind(3*MP) + 0.00042*E*sind(M + 2*F) + 0.00038*E*sind(M - 2*F) -
					  0.00024*E*sind(2*MP - M) - 0.00017*sind(Omega) - 0.00007*sind(MP + 2*M);

			quarters[0] = JDE + 0.000325*sind(A[1]) + 0.000165*sind(A[2]) + 0.000164*sind(A[3]) + 0.000126*sind(A[4]) + 0.000110*sind(A[5]) + 0.000062*sind(A[6]) +
						  0.000060*sind(A[7]);

			// The following code needs tidying up with a loop and conditionals for each quarter
			// First Quarter k=k+0.25
			JDE = JDE0 + 29.530588853*0.25;
			M = rev(M + 29.10535669*0.25);
			MP = rev(MP + 385.81693528*0.25);
			F = rev(F + 390.67050274*0.25);
			Omega = rev(Omega - 1.56375580*0.25);
			A[1] = rev(A[1] + 0.107408*0.25);
			A[2] = rev(A[2] + 0.016321*0.25);
			A[3] = rev(A[3] + 26.651886*0.25);
			A[4] = rev(A[4] + 36.412478*0.25);
			A[5] = rev(A[5] + 18.206239*0.25);
			A[6] = rev(A[6] + 53.303771*0.25);
			A[7] = rev(A[7] + 2.453732*0.25);

			JDE = JDE - 0.62801*sind(MP) + 0.17172*E*sind(M) - 0.01183*E*sind(MP + M) + 0.00862*sind(2*MP) + 0.00804*sind(2*F) + 0.00454*E*sind(MP - M) + 0.00204*E*E*sind(2*M) -
				  0.00180*sind(MP - 2*F) - 0.00070*sind(MP + 2*F) - 0.00040*sind(3*MP) - 0.00034*E*sind(2*MP - M) + 0.00032*E*sind(M + 2*F) + 0.00032*E*sind(M - 2*F) -
				  0.00028*E*E*sind(MP + 2*M) + 0.00027*E*sind(2*MP + M) - 0.00017*sind(Omega);
			// Next term is w add for first quarter & subtract for second
			JDE += (0.00306 - 0.00038*E*cosd(M) + 0.00026*cosd(MP) - 0.00002*cosd(MP - M) + 0.00002*cosd(MP + M) + 0.00002*cosd(2*F));

			quarters[1] = JDE + 0.000325*sind(A[1]) + 0.000165*sind(A[2]) + 0.000164*sind(A[3]) + 0.000126*sind(A[4]) + 0.000110*sind(A[5]) + 0.000062*sind(A[6]) +
						  0.000060*sind(A[7]);

			// Full moon k=k+0.5
			JDE = JDE0 + 29.530588853*0.5;
			// Already added 0.25 for first quarter
			M = rev(M + 29.10535669*0.25);
			MP = rev(MP + 385.81693528*0.25);
			F = rev(F + 390.67050274*0.25);
			Omega = rev(Omega - 1.56375580*0.25);
			A[1] = rev(A[1] + 0.107408*0.25);
			A[2] = rev(A[2] + 0.016321*0.25);
			A[3] = rev(A[3] + 26.651886*0.25);
			A[4] = rev(A[4] + 36.412478*0.25);
			A[5] = rev(A[5] + 18.206239*0.25);
			A[6] = rev(A[6] + 53.303771*0.25);
			A[7] = rev(A[7] + 2.453732*0.25);

			JDE = JDE - 0.40614*sind(MP) + 0.17302*E*sind(M) + 0.01614*sind(2*MP) + 0.01043*sind(2*F) + 0.00734*E*sind(MP - M) - 0.00515*E*sind(MP + M) + 0.00209*E*E*sind(2*M) -
				  0.00111*sind(MP - 2*F) - 0.00057*sind(MP + 2*F) + 0.00056*E*sind(2*MP + M) - 0.00042*sind(3*MP) + 0.00042*E*sind(M + 2*F) + 0.00038*E*sind(M - 2*F) -
				  0.00024*E*sind(2*MP - M) - 0.00017*sind(Omega) - 0.00007*sind(MP + 2*M);

			quarters[2] = JDE + 0.000325*sind(A[1]) + 0.000165*sind(A[2]) + 0.000164*sind(A[3]) + 0.000126*sind(A[4]) + 0.000110*sind(A[5]) + 0.000062*sind(A[6]) +
						  0.000060*sind(A[7]);

			// Last Quarter k=k+0.75
			JDE = JDE0 + 29.530588853*0.75;
			// Already added 0.5 for full moon
			M = rev(M + 29.10535669*0.25);
			MP = rev(MP + 385.81693528*0.25);
			F = rev(F + 390.67050274*0.25);
			Omega = rev(Omega - 1.56375580*0.25);
			A[1] = rev(A[1] + 0.107408*0.25);
			A[2] = rev(A[2] + 0.016321*0.25);
			A[3] = rev(A[3] + 26.651886*0.25);
			A[4] = rev(A[4] + 36.412478*0.25);
			A[5] = rev(A[5] + 18.206239*0.25);
			A[6] = rev(A[6] + 53.303771*0.25);
			A[7] = rev(A[7] + 2.453732*0.25);

			JDE = JDE - 0.62801*sind(MP) + 0.17172*E*sind(M) - 0.01183*E*sind(MP + M) + 0.00862*sind(2*MP) + 0.00804*sind(2*F) + 0.00454*E*sind(MP - M) + 0.00204*E*E*sind(2*M) -
				  0.00180*sind(MP - 2*F) - 0.00070*sind(MP + 2*F) - 0.00040*sind(3*MP) - 0.00034*E*sind(2*MP - M) + 0.00032*E*sind(M + 2*F) + 0.00032*E*sind(M - 2*F) -
				  0.00028*E*E*sind(MP + 2*M) + 0.00027*E*sind(2*MP + M) - 0.00017*sind(Omega);
			// Next term is w add for first quarter & subtract for second
			JDE -= (0.00306 - 0.00038*E*cosd(M) + 0.00026*cosd(MP) - 0.00002*cosd(MP - M) + 0.00002*cosd(MP + M) + 0.00002*cosd(2*F));

			quarters[3] = JDE + 0.000325*sind(A[1]) + 0.000165*sind(A[2]) + 0.000164*sind(A[3]) + 0.000126*sind(A[4]) + 0.000110*sind(A[5]) + 0.000062*sind(A[6]) +
						  0.000060*sind(A[7]);

			return quarters;
		}
		*/


		public static double MoonAge()
		{
			var now = DateTime.Now;
			DateTime lastNewMoon = new DateTime();
			foreach (var thisDate in NewMoons)
			{
				var newMoon = DateTime.Parse(thisDate);
				if (newMoon.CompareTo(now) <= 0)
				{
					// this date is older than now, save it as previous
					lastNewMoon = newMoon;
				}
				else
				{
					// this date is later than now, use previous date
					break;
				}
			}
			return (now - lastNewMoon).TotalDays;
		}

		public static bool CreateMoonImage(double phaseAngle, double latitude, int size, bool transparent)
		{
			if (!System.IO.File.Exists("./web/MoonBaseImage.png"))
			{
				Program.cumulus.LogMessage("CreateMoonImage: File not found - ./web/MoonBaseImage.png");
				return false;
			}

			// Reduce the memory allocation in ImageSharp - we only have a small image
			try
			{
				Configuration.Default.MemoryAllocator = MemoryAllocator.Create(new MemoryAllocatorOptions()
				{
					MaximumPoolSizeMegabytes = 1
				});
			}
			catch (Exception ex)
			{
				Program.cumulus.LogExceptionMessage(ex, "Error setting ImageSharp memory pool size");
			}

			var success = true;

			try
			{
				using var bmp = Image.Load<Rgba32>("./web/MoonBaseImage.png");
				bmp.ProcessPixelRows(accessor =>
				{
					// we need to reverse a couple of settings beyond full moon
					double corr = -1;

					if (phaseAngle > 180)
					{
						corr = 1;
						phaseAngle = -(phaseAngle - 360);
					}

					double phase = (1 - cosd(phaseAngle)) / 2;

					int srcSize = bmp.Width;
					int srcSize2 = srcSize / 2;
					int xPos = corr == -1 ? 0 : srcSize - 1;

					for (int yPos = 0; yPos <= srcSize2; yPos++)
					{
						// Determine the edges of the illuminated part of the moon
						double xe = 1 - (yPos / (double) srcSize2);
						xe = Math.Sqrt(1 - (xe * xe));
						var xPos2 = (int) (srcSize2 + (phase - 0.5) * xe * srcSize * (-corr));

						var pixels1 = accessor.GetRowSpan(yPos);
						var pixels2 = accessor.GetRowSpan(srcSize - 1 - yPos);


						var start = Math.Min(xPos, xPos2);
						var end = Math.Max(xPos, xPos2);

						for (int x = start; x <= end; x++)
						{
							if (transparent)
							{
								pixels1[x] = Color.Transparent;
								pixels2[x] = Color.Transparent;
							}
							else
							{
								var pixel = pixels1[x];
								pixel.R = (byte) (pixel.R * 0.3);
								pixel.G = (byte) (pixel.G * 0.3);
								pixel.B = (byte) (pixel.B * 0.3);
								pixels1[x] = pixel;

								// suppress double drawing of the last line
								if (yPos != srcSize2)
								{
									var pixel2 = pixels2[x];
									pixel2.R = (byte) (pixel2.R * 0.3);
									pixel2.G = (byte) (pixel2.G * 0.3);
									pixel2.B = (byte) (pixel2.B * 0.3);
									pixels2[x] = pixel2;
								}
							}
						}
					}

					// Rotate for southern hemisphere
					if (latitude < 0)
					{
						bmp.Mutate(x => x.Rotate(RotateMode.Rotate180));
					}

					// resize to desired output size
					bmp.Mutate(x => x.Resize(size, size));

					// add a bit of meta data
					if (bmp.Metadata.ExifProfile == null)
					{
						bmp.Metadata.ExifProfile = new ExifProfile();
					}
					bmp.Metadata.ExifProfile.SetValue<string>(ExifTag.XPAuthor, "Cumulus MX");
					bmp.Metadata.ExifProfile.SetValue<string>(ExifTag.XPTitle, DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss"));
					bmp.Metadata.ExifProfile.SetValue<string>(ExifTag.Software, "Cumulus MX");
					bmp.Metadata.ExifProfile.SetValue<string>(ExifTag.DateTimeOriginal, DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss"));

					// finally save the image and clean-up
					bmp.SaveAsPng("./web/moon.png");
				});
			}
			catch (Exception ex)
			{
				Program.cumulus.LogExceptionMessage(ex, "Error creating the Moon image");
				success = false;
			}

			return success;
		}
	}
}
