diff options
author | Andrew Cady <d@jerkface.net> | 2023-08-28 09:04:28 -0400 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2023-11-12 09:31:58 -0500 |
commit | eef9bbd2d8f52443eb9711804ba03fc00af8ee23 (patch) | |
tree | 17b49eda4c5f9ab237a2d061f8f1f2905944d098 /src | |
parent | 156772084f241f28c97303f6f92c39bcf19e9ab6 (diff) |
move *.hs to src/
Diffstat (limited to 'src')
-rw-r--r-- | src/CosmicCalendar.hs | 140 | ||||
-rw-r--r-- | src/CosmicCalendarEvents.hs | 1012 | ||||
-rwxr-xr-x | src/countdown.hs | 523 |
3 files changed, 1675 insertions, 0 deletions
diff --git a/src/CosmicCalendar.hs b/src/CosmicCalendar.hs new file mode 100644 index 0000000..db29c02 --- /dev/null +++ b/src/CosmicCalendar.hs | |||
@@ -0,0 +1,140 @@ | |||
1 | {-# OPTIONS_GHC | ||
2 | -Wall | ||
3 | -Wno-unused-imports | ||
4 | -Wno-unused-top-binds | ||
5 | -Wno-name-shadowing | ||
6 | #-} | ||
7 | {-# language NoImplicitPrelude #-} | ||
8 | {-# language RecordWildCards #-} | ||
9 | {-# language FlexibleContexts #-} | ||
10 | {-# language TemplateHaskell #-} | ||
11 | {-# language ViewPatterns #-} | ||
12 | {-# language OverloadedStrings #-} | ||
13 | {-# language QuasiQuotes #-} | ||
14 | |||
15 | module CosmicCalendar where | ||
16 | |||
17 | import Rebase.Prelude | ||
18 | import qualified Rebase.Prelude as Prelude | ||
19 | import Control.Lens hiding ((<|)) | ||
20 | import Data.Foldable (toList) | ||
21 | import Data.Ratio | ||
22 | import Text.Printf | ||
23 | import Data.Time.Calendar.OrdinalDate | ||
24 | import Data.Time.LocalTime | ||
25 | import Control.Monad.RWS | ||
26 | import Data.Time.Calendar.OrdinalDate | ||
27 | import Data.Text.Format.Numbers | ||
28 | import NeatInterpolation | ||
29 | import qualified Data.Text as Text | ||
30 | import Data.Text (Text, pack, unpack) | ||
31 | |||
32 | import Rebase.Data.Map.Strict (Map) | ||
33 | import qualified Rebase.Data.Map.Strict as Map | ||
34 | |||
35 | -- 13.787±0.020 billion years. Source: https://en.wikipedia.org/wiki/Age_of_the_universe#cite_note-Planck_2018-2 | ||
36 | ageOfUniverseInYears :: Integer | ||
37 | ageOfUniverseInYears = 13787 * 1000 * 1000 | ||
38 | |||
39 | -- The point of the cosmic calendar is to mentally visualize or model the scale | ||
40 | -- of cosmic/geologic/evolutionary events using the existing internal mental | ||
41 | -- model of the year. This internal mental model of the year is NOT a 365.2422 | ||
42 | -- day earth rotation, but a 365 day calendar year. | ||
43 | -- | ||
44 | -- In order to make the math of the calendar work out, the functions that look | ||
45 | -- up calendary entries (and take as input the LocalTime) must check for leap | ||
46 | -- year, and subtract one day from the input if it is later than February. | ||
47 | daysPerYear :: NominalDiffTime | ||
48 | daysPerYear = 365 -- NOT 365.2422 | ||
49 | |||
50 | lengthOfDay :: NominalDiffTime | ||
51 | lengthOfDay = 24 * 60 * 60 | ||
52 | |||
53 | lengthOfYear :: NominalDiffTime | ||
54 | lengthOfYear = daysPerYear * lengthOfDay | ||
55 | |||
56 | ageOfUniverse :: NominalDiffTime | ||
57 | ageOfUniverse = fromIntegral ageOfUniverseInYears * lengthOfYear | ||
58 | |||
59 | data CalendarEntry = CalendarEntry { | ||
60 | calBeginTime :: NominalDiffTime, | ||
61 | calEndTime :: Maybe NominalDiffTime, | ||
62 | calTitle :: Text, | ||
63 | calSubtitle :: Text, | ||
64 | calDescription :: Text, | ||
65 | calReferences :: Text | ||
66 | } deriving (Show) | ||
67 | |||
68 | -- TODO: Encode the input times like so: | ||
69 | -- | ||
70 | -- data CosmicTime = YearsAgo Rational | YearsAfterBigBang Rational | YearsBCE Rational | YearsCE Rational | ||
71 | -- | ||
72 | -- The absolute time values (YearsBCE and YearsCE) will be computed using the | ||
73 | -- year at program start: | ||
74 | |||
75 | currentYear :: Integer | ||
76 | currentYear = unsafePerformIO $ getZonedTime <&> toGregorian . localDay . zonedTimeToLocalTime <&> view _1 | ||
77 | |||
78 | years :: Rational -> NominalDiffTime | ||
79 | years = (* lengthOfYear) . fromRational | ||
80 | |||
81 | yearsAgo :: Rational -> NominalDiffTime | ||
82 | yearsAgo (fromRational -> n) = lengthOfYear * (1 - (n / fromIntegral ageOfUniverseInYears)) | ||
83 | |||
84 | afterBigBang :: NominalDiffTime -> NominalDiffTime | ||
85 | afterBigBang = (/ ageOfUniverse) . (* lengthOfYear) | ||
86 | |||
87 | thousandYears :: Rational -> NominalDiffTime | ||
88 | thousandYears = years . (* 1000) | ||
89 | |||
90 | millionYears :: Rational -> NominalDiffTime | ||
91 | millionYears = thousandYearsAgo . (* 1000) | ||
92 | |||
93 | billionYears :: Rational -> NominalDiffTime | ||
94 | billionYears = millionYearsAgo . (* 1000) | ||
95 | |||
96 | thousandYearsAgo :: Rational -> NominalDiffTime | ||
97 | thousandYearsAgo = yearsAgo . (* 1000) | ||
98 | |||
99 | millionYearsAgo :: Rational -> NominalDiffTime | ||
100 | millionYearsAgo = thousandYearsAgo . (* 1000) | ||
101 | |||
102 | billionYearsAgo :: Rational -> NominalDiffTime | ||
103 | billionYearsAgo = millionYearsAgo . (* 1000) | ||
104 | |||
105 | yearStart :: LocalTime -> LocalTime | ||
106 | yearStart (LocalTime d _) = LocalTime d' t' | ||
107 | where | ||
108 | d' = fromGregorian y 1 1 | ||
109 | t' = TimeOfDay 0 0 0 | ||
110 | (y, _, _) = toGregorian d | ||
111 | |||
112 | localTimeToYearElapsed :: LocalTime -> NominalDiffTime | ||
113 | localTimeToYearElapsed t = t `diffLocalTime` yearStart t | ||
114 | |||
115 | getPreviousCalendarEntry :: Calendar -> LocalTime -> Maybe CalendarEntry | ||
116 | getPreviousCalendarEntry cal (localTimeToYearElapsed -> t) = snd <$> Map.lookupLT t cal | ||
117 | |||
118 | getCurrentCalendarEntry :: Calendar -> LocalTime -> Maybe CalendarEntry | ||
119 | getCurrentCalendarEntry cal (localTimeToYearElapsed -> t) = snd <$> Map.lookupLE t cal | ||
120 | |||
121 | type Calendar = Map NominalDiffTime CalendarEntry | ||
122 | |||
123 | getNextCalendarEntry :: Calendar -> LocalTime -> Maybe CalendarEntry | ||
124 | getNextCalendarEntry cal (localTimeToYearElapsed -> t) = snd <$> Map.lookupGT t cal | ||
125 | |||
126 | buildCalendar :: [CalendarEntry] -> Map NominalDiffTime CalendarEntry | ||
127 | buildCalendar ls = Map.fromList $ map (\x -> (calBeginTime x, x)) $ map unwrap ls | ||
128 | |||
129 | unwrap :: CalendarEntry -> CalendarEntry | ||
130 | unwrap x@CalendarEntry{..} = x { calDescription = unwrapText calDescription } | ||
131 | where | ||
132 | unwrapText :: Text -> Text | ||
133 | unwrapText = pack . unlines . map unwords . foldr process [] . lines . unpack | ||
134 | process line [] = [[line]] | ||
135 | process line ((x:xs):ys) | shouldMerge line x = (line:x:xs):ys | ||
136 | process line rest = [line]:rest | ||
137 | shouldMerge :: String -> String -> Bool | ||
138 | shouldMerge "" _ = False | ||
139 | shouldMerge _ "" = False | ||
140 | shouldMerge _ _ = True | ||
diff --git a/src/CosmicCalendarEvents.hs b/src/CosmicCalendarEvents.hs new file mode 100644 index 0000000..90b5848 --- /dev/null +++ b/src/CosmicCalendarEvents.hs | |||
@@ -0,0 +1,1012 @@ | |||
1 | {-# OPTIONS_GHC -Wall #-} | ||
2 | {-# language NoImplicitPrelude #-} | ||
3 | {-# language OverloadedStrings #-} | ||
4 | {-# language QuasiQuotes #-} | ||
5 | |||
6 | module CosmicCalendarEvents where | ||
7 | |||
8 | import Rebase.Prelude | ||
9 | import NeatInterpolation | ||
10 | |||
11 | import CosmicCalendar | ||
12 | |||
13 | theYear, yearsBeforeCommonEra :: Integer -> NominalDiffTime | ||
14 | theYear = yearsAgo . toRational . (currentYear -) | ||
15 | yearsBeforeCommonEra = yearsAgo . toRational . ((+) (currentYear - 1)) | ||
16 | |||
17 | theCalendar :: Map NominalDiffTime CalendarEntry | ||
18 | theCalendar = buildCalendar $ | ||
19 | [ | ||
20 | CalendarEntry 0 | ||
21 | Nothing | ||
22 | "The Big Bang" | ||
23 | "The universe begins" | ||
24 | "" | ||
25 | "", | ||
26 | |||
27 | CalendarEntry (370 & thousandYears & afterBigBang) | ||
28 | Nothing | ||
29 | "Recombination" | ||
30 | "The universe becomes transparent" | ||
31 | [text| | ||
32 | At about 370,000 years,[3][4][5][6] neutral hydrogen atoms finish forming | ||
33 | ("recombination"), and as a result the universe also became transparent for | ||
34 | the first time. The newly formed atoms—mainly hydrogen and helium with | ||
35 | traces of lithium—quickly reach their lowest energy state (ground state) by | ||
36 | releasing photons ("photon decoupling"), and these photons can still be | ||
37 | detected today as the cosmic microwave background (CMB). This is the oldest | ||
38 | direct observation we currently have of the universe. | ||
39 | |] | ||
40 | [text| | ||
41 | https://en.wikipedia.org/wiki/Chronology_of_the_universe#The_very_early_universe | ||
42 | |||
43 | 3. Tanabashi, M. 2018, p. 358, chpt. 21.4.1: "Big-Bang Cosmology" (Revised | ||
44 | September 2017) by Keith A. Olive and John A. Peacock. | ||
45 | |||
46 | 4. Notes: Edward L. Wright's Javascript Cosmology Calculator (last modified | ||
47 | 23 July 2018). With a default H 0 {\displaystyle H_{0}} H_{0} = 69.6 (based | ||
48 | on WMAP9+SPT+ACT+6dFGS+BOSS/DR11+H0/Riess) parameters, the calculated age of | ||
49 | the universe with a redshift of z = 1100 is in agreement with Olive and | ||
50 | Peacock (about 370,000 years). | ||
51 | |||
52 | 5. Hinshaw, Weiland & Hill 2009. See PDF: page 45, Table 7, Age at | ||
53 | decoupling, last column. Based on WMAP+BAO+SN parameters, the age of | ||
54 | decoupling occurred 376971+3162−3167 years after the Big Bang. | ||
55 | |||
56 | 6. Ryden 2006, pp. 194–195. "Without going into the details of the | ||
57 | non-equilibrium physics, let's content ourselves by saying, in round | ||
58 | numbers, zdec ≈ 1100, corresponding to a temperature Tdec ≈ 3000 K, when the | ||
59 | age of the universe was tdec ≈ 350,000 yr in the Benchmark Model. (...) The | ||
60 | relevant times of various events around the time of recombination are shown | ||
61 | in Table 9.1. (...) Note that all these times are approximate, and are | ||
62 | dependent on the cosmological model you choose. (I have chosen the Benchmark | ||
63 | Model in calculating these numbers.)" | ||
64 | |||
65 | https://en.wikipedia.org/wiki/Recombination_(cosmology)#cite_note-2 | ||
66 | |], | ||
67 | |||
68 | CalendarEntry (13.4 & billionYearsAgo) Nothing | ||
69 | "The first observed star" | ||
70 | "" | ||
71 | "First Light Viewed Through the Rich Cluster Abell 2218" | ||
72 | "https://sites.astro.caltech.edu/~rse/firstlight/", | ||
73 | |||
74 | CalendarEntry (4.6 & billionYearsAgo) Nothing | ||
75 | "Formation of the Sun" | ||
76 | "The formation of the solar system begins" | ||
77 | [text| | ||
78 | The formation of the Solar System began about 4.6 billion years ago with the | ||
79 | gravitational collapse of a small part of a giant molecular cloud.[1] Most | ||
80 | of the collapsing mass collected in the center, forming the Sun, while the | ||
81 | rest flattened into a protoplanetary disk out of which the planets, moons, | ||
82 | asteroids, and other small Solar System bodies formed. | ||
83 | |] | ||
84 | "https://en.wikipedia.org/wiki/Formation_and_evolution_of_the_Solar_System", | ||
85 | |||
86 | CalendarEntry (4.54 & billionYearsAgo) Nothing | ||
87 | "Formation of Earth" | ||
88 | "" | ||
89 | [text| | ||
90 | The standard model for the formation of the Solar System (including the | ||
91 | Earth) is the solar nebula hypothesis.[23] In this model, the Solar System | ||
92 | formed from a large, rotating cloud of interstellar dust and gas called the | ||
93 | solar nebula. It was composed of hydrogen and helium created shortly after | ||
94 | the Big Bang 13.8 Ga (billion years ago) and heavier elements ejected by | ||
95 | supernovae. About 4.5 Ga, the nebula began a contraction that may have been | ||
96 | triggered by the shock wave from a nearby supernova.[24] A shock wave would | ||
97 | have also made the nebula rotate. As the cloud began to accelerate, its | ||
98 | angular momentum, gravity, and inertia flattened it into a protoplanetary | ||
99 | disk perpendicular to its axis of rotation. Small perturbations due to | ||
100 | collisions and the angular momentum of other large debris created the means | ||
101 | by which kilometer-sized protoplanets began to form, orbiting the nebular | ||
102 | center.[25] | ||
103 | |||
104 | The center of the nebula, not having much angular momentum, collapsed | ||
105 | rapidly, the compression heating it until nuclear fusion of hydrogen into | ||
106 | helium began. After more contraction, a T Tauri star ignited and evolved | ||
107 | into the Sun. Meanwhile, in the outer part of the nebula gravity caused | ||
108 | matter to condense around density perturbations and dust particles, and the | ||
109 | rest of the protoplanetary disk began separating into rings. In a process | ||
110 | known as runaway accretion, successively larger fragments of dust and debris | ||
111 | clumped together to form planets.[25] Earth formed in this manner about 4.54 | ||
112 | billion years ago (with an uncertainty of 1%)[26][27][4] and was largely | ||
113 | completed within 10–20 million years.[28] The solar wind of the newly formed | ||
114 | T Tauri star cleared out most of the material in the disk that had not | ||
115 | already condensed into larger bodies. The same process is expected to | ||
116 | produce accretion disks around virtually all newly forming stars in the | ||
117 | universe, some of which yield planets.[29] | ||
118 | |] | ||
119 | "https://en.wikipedia.org/wiki/History_of_Earth#Solar_System_formation", | ||
120 | |||
121 | CalendarEntry (8.8 & billionYearsAgo) Nothing | ||
122 | "Thin disk of the Milky Way Galaxy" | ||
123 | "Our galaxy begins to form" | ||
124 | [text| | ||
125 | The age of stars in the galactic thin disk has also been estimated using | ||
126 | nucleocosmochronology. Measurements of thin disk stars yield an estimate | ||
127 | that the thin disk formed 8.8 ± 1.7 billion years ago. These measurements | ||
128 | suggest there was a hiatus of almost 5 billion years between the formation | ||
129 | of the galactic halo and the thin disk.[253] Recent analysis of the chemical | ||
130 | signatures of thousands of stars suggests that stellar formation might have | ||
131 | dropped by an order of magnitude at the time of disk formation, 10 to 8 | ||
132 | billion years ago, when interstellar gas was too hot to form new stars at | ||
133 | the same rate as before.[254] | ||
134 | |] | ||
135 | "", | ||
136 | |||
137 | CalendarEntry (4.4 & billionYearsAgo) Nothing | ||
138 | "Formation of the moon" | ||
139 | "A collision of the planet Theia with Earth creates the moon" | ||
140 | [text| | ||
141 | Astronomers think the collision between Earth and Theia happened at about | ||
142 | 4.4 to 4.45 bya; about 0.1 billion years after the Solar System began to | ||
143 | form.[15][16] In astronomical terms, the impact would have been of moderate | ||
144 | velocity. Theia is thought to have struck Earth at an oblique angle when | ||
145 | Earth was nearly fully formed. Computer simulations of this "late-impact" | ||
146 | scenario suggest an initial impactor velocity at infinity below 4 kilometres | ||
147 | per second (2.5 mi/s), increasing as it fell to over 9.3 km/s (5.8 mi/s) at | ||
148 | impact, and an impact angle of about 45°.[17] However, oxygen isotope | ||
149 | abundance in lunar rock suggests "vigorous mixing" of Theia and Earth, | ||
150 | indicating a steep impact angle.[3][18] Theia's iron core would have sunk | ||
151 | into the young Earth's core, and most of Theia's mantle accreted onto | ||
152 | Earth's mantle. However, a significant portion of the mantle material from | ||
153 | both Theia and Earth would have been ejected into orbit around Earth (if | ||
154 | ejected with velocities between orbital velocity and escape velocity) or | ||
155 | into individual orbits around the Sun (if ejected at higher velocities). | ||
156 | Modelling[19] has hypothesised that material in orbit around Earth may have | ||
157 | accreted to form the Moon in three consecutive phases; accreting first from | ||
158 | the bodies initially present outside Earth's Roche limit, which acted to | ||
159 | confine the inner disk material within the Roche limit. The inner disk | ||
160 | slowly and viscously spread back out to Earth's Roche limit, pushing along | ||
161 | outer bodies via resonant interactions. After several tens of years, the | ||
162 | disk spread beyond the Roche limit, and started producing new objects that | ||
163 | continued the growth of the Moon, until the inner disk was depleted in mass | ||
164 | after several hundreds of years. | ||
165 | |] | ||
166 | [text| | ||
167 | https://en.wikipedia.org/wiki/Giant-impact_hypothesis#Basic_model | ||
168 | https://www.psi.edu/epo/moon/moon.html | ||
169 | |], | ||
170 | |||
171 | CalendarEntry (3.77 & billionYearsAgo) Nothing | ||
172 | "Life on Earth" | ||
173 | "" | ||
174 | [text| | ||
175 | The earliest time for the origin of life on Earth is at least 3.77 billion | ||
176 | years ago, possibly as early as 4.28 billion years,[2] or even 4.41 billion | ||
177 | years[4][5]—not long after the oceans formed 4.5 billion years ago, and | ||
178 | after the formation of the Earth 4.54 billion years ago.[2][3][6][7] | ||
179 | |] | ||
180 | "https://en.wikipedia.org/wiki/Earliest_known_life_forms", | ||
181 | |||
182 | CalendarEntry (3.42 & billionYearsAgo) Nothing | ||
183 | "Earliest known life on Earth" | ||
184 | "The fossil record begins" | ||
185 | [text| | ||
186 | The earliest known life forms on Earth are putative fossilized | ||
187 | microorganisms found in hydrothermal vent precipitates, considered to be | ||
188 | about 3.42 billion years old.[1][2] The earliest time for the origin of life | ||
189 | on Earth is at least 3.77 billion years ago, possibly as early as 4.28 | ||
190 | billion years,[2] or even 4.41 billion years[4][5]—not long after the oceans | ||
191 | formed 4.5 billion years ago, and after the formation of the Earth 4.54 | ||
192 | billion years ago.[2][3][6][7] The earliest direct evidence of life on Earth | ||
193 | is from microfossils of microorganisms permineralized in | ||
194 | 3.465-billion-year-old Australian Apex chert rocks.[8][9] | ||
195 | |] | ||
196 | "https://en.wikipedia.org/wiki/Earliest_known_life_forms", | ||
197 | |||
198 | CalendarEntry (3.4 & billionYearsAgo) Nothing | ||
199 | "First photosynthetic bacteria" | ||
200 | "(Still no Oxygen)" | ||
201 | [text| | ||
202 | They absorbed near-infrared rather than visible light and produced sulfur or | ||
203 | sulfate compounds rather than oxygen. Their pigments (possibly | ||
204 | bacteriochlorophylls) were predecessors to chlorophyll. | ||
205 | |] | ||
206 | "https://www.scientificamerican.com/article/timeline-of-photosynthesis-on-earth/", | ||
207 | |||
208 | CalendarEntry (2.7 & billionYearsAgo) Nothing | ||
209 | "Oxygen from photosynthesis" | ||
210 | [text| | ||
211 | Cyanobacteria (blue-green algae) initiates "rusting of the Earth" | ||
212 | The resulting Ozone layer will make life possible on land | ||
213 | |] | ||
214 | [text| | ||
215 | These ubiquitous bacteria were the first oxygen producers. They absorb | ||
216 | visible light using a mix of pigments: phycobilins, carotenoids and several | ||
217 | forms of chlorophyll. | ||
218 | |||
219 | The Great Oxidation Event (GOE), also called the Great Oxygenation Event, | ||
220 | the Oxygen Catastrophe, the Oxygen Revolution, and the Oxygen Crisis, was a | ||
221 | time interval when the Earth's atmosphere and the shallow ocean first | ||
222 | experienced a rise in the amount of oxygen. This occurred approximately | ||
223 | 2.4–2.0 Ga (billion years) ago, during the Paleoproterozoic era.[2] | ||
224 | Geological, isotopic, and chemical evidence suggests that | ||
225 | biologically-produced molecular oxygen (dioxygen, O2) started to accumulate | ||
226 | in Earth's atmosphere and changed it from a weakly reducing atmosphere | ||
227 | practically free of oxygen into an oxidizing atmosphere containing abundant | ||
228 | oxygen.[3] | ||
229 | |||
230 | The sudden injection of toxic oxygen into an anaerobic biosphere caused the | ||
231 | extinction of many existing anaerobic species on Earth.[4] Although the event is | ||
232 | inferred to have constituted a mass extinction,[5] due in part to the great | ||
233 | difficulty in surveying microscopic species' abundances, and in part to the | ||
234 | extreme age of fossil remains from that time, the Oxygen Catastrophe is | ||
235 | typically not counted among conventional lists of "great extinctions", which are | ||
236 | implicitly limited to the Phanerozoic eon. | ||
237 | |||
238 | The event is inferred to have been caused by cyanobacteria producing the | ||
239 | oxygen, which may have enabled the subsequent development of multicellular | ||
240 | life-forms.[6] | ||
241 | |||
242 | The current scientific understanding of when and how the Earth's atmosphere | ||
243 | changed from a weakly reducing to a strongly oxidizing atmosphere largely | ||
244 | began with the work of the American geologist Preston Cloud in the 1970s.[9] | ||
245 | Cloud observed that detrital sediments older than about 2 billion years ago | ||
246 | contained grains of pyrite, uraninite,[9] and siderite,[12] all minerals | ||
247 | containing reduced forms of iron or uranium that are not found in younger | ||
248 | sediments because they are rapidly oxidized in an oxidizing atmosphere. He | ||
249 | further observed that continental redbeds, which get their color from the | ||
250 | oxidized (ferric) mineral hematite, began to appear in the geological record | ||
251 | at about this time. Banded iron formation largely disappears from the | ||
252 | geological record at 1.85 billion years ago, after peaking at about 2.5 | ||
253 | billion years ago.[14] Banded iron formation can form only when abundant | ||
254 | dissolved ferrous iron is transported into depositional basins, and an | ||
255 | oxygenated ocean blocks such transport by oxidizing the iron to form | ||
256 | insoluble ferric iron compounds.[15] The end of the deposition of banded | ||
257 | iron formation at 1.85 billion years ago is therefore interpreted as marking | ||
258 | the oxygenation of the deep ocean.[9] Heinrich Holland further elaborated | ||
259 | these ideas through the 1980s, placing the main time interval of oxygenation | ||
260 | between 2.2 and 1.9 billion years ago, and they continue to shape the | ||
261 | current scientific understanding.[10] | ||
262 | |] | ||
263 | [text| | ||
264 | https://www.scientificamerican.com/article/timeline-of-photosynthesis-on-earth/ | ||
265 | https://en.wikipedia.org/wiki/Great_Oxidation_Event | ||
266 | |], | ||
267 | |||
268 | CalendarEntry (2.05 & billionYearsAgo) Nothing | ||
269 | "Eukaryotic cells" | ||
270 | "Cells with nucleus (inner membrane holding DNA)" | ||
271 | [text| | ||
272 | Eukaryotes (/juːˈkærioʊts, -əts/) are organisms whose cells have a nucleus | ||
273 | enclosed within a nuclear envelope.[1][2][3] They belong to the group of | ||
274 | organisms Eukaryota or Eukarya; their name comes from the Greek εὖ (eu, | ||
275 | "well" or "good") and κάρυον (karyon, "nut" or "kernel").[4] The domain | ||
276 | Eukaryota makes up one of the three domains of life; bacteria and archaea | ||
277 | (both prokaryotes) make up the other two domains.[5][6] The eukaryotes are | ||
278 | usually now regarded as having emerged in the Archaea or as a sister of the | ||
279 | Asgard archaea.[7][8] This implies that there are only two domains of life, | ||
280 | Bacteria and Archaea, with eukaryotes incorporated among archaea.[9][10] | ||
281 | Eukaryotes represent a small minority of the number of organisms;[11] | ||
282 | however, due to their generally much larger size, their collective global | ||
283 | biomass is estimated to be about equal to that of prokaryotes.[11] | ||
284 | Eukaryotes emerged approximately 2.3–1.8 billion years ago, during the | ||
285 | Proterozoic eon, likely as flagellated phagotrophs.[12][13] | ||
286 | |] | ||
287 | "https://en.wikipedia.org/wiki/Eukaryote", | ||
288 | |||
289 | CalendarEntry (1.2 & billionYearsAgo) Nothing | ||
290 | "Red and brown algae" | ||
291 | "" | ||
292 | [text| | ||
293 | These organisms have more complex cellular structures than bacteria do. Like | ||
294 | cyanobacteria, they contain phycobilin pigments as well as various forms of | ||
295 | chlorophyll. | ||
296 | |] | ||
297 | "https://www.scientificamerican.com/article/timeline-of-photosynthesis-on-earth/", | ||
298 | |||
299 | CalendarEntry (0.75 & billionYearsAgo) Nothing | ||
300 | "Green algae" | ||
301 | "" | ||
302 | [text| | ||
303 | Green algae do better than red and brown algae in the strong light of | ||
304 | shallow water. They make do without phycobilins. | ||
305 | |] | ||
306 | "https://www.scientificamerican.com/article/timeline-of-photosynthesis-on-earth/", | ||
307 | |||
308 | CalendarEntry (0.475 & billionYearsAgo) Nothing | ||
309 | "First land plants" | ||
310 | "" | ||
311 | [text| | ||
312 | Mosses and liverworts descended from green algae. Lacking vascular structure | ||
313 | (stems and roots) to pull water from the soil, they are unable to grow | ||
314 | tall. | ||
315 | |] | ||
316 | "https://www.scientificamerican.com/article/timeline-of-photosynthesis-on-earth/", | ||
317 | |||
318 | CalendarEntry (0.423 & billionYearsAgo) Nothing | ||
319 | "Vascular plants" | ||
320 | "" | ||
321 | [text| | ||
322 | These are literally garden-variety plants, such as ferns, grasses, trees and | ||
323 | cacti. They are able to grow tall canopies to capture more light. | ||
324 | |] | ||
325 | "https://www.scientificamerican.com/article/timeline-of-photosynthesis-on-earth/", | ||
326 | |||
327 | CalendarEntry (750 & millionYearsAgo) Nothing | ||
328 | "Bones and shells" | ||
329 | "" | ||
330 | [text| | ||
331 | A series of spectacularly preserved, 750-million-year-old fossils represent | ||
332 | the microscopic origins of biomineralization, or the ability to convert | ||
333 | minerals into hard, physical structures. This process is what makes bones, | ||
334 | shells, teeth and hair possible, literally shaping the animal kingdom and | ||
335 | even Earth itself. | ||
336 | |||
337 | The fossils were pried from ancient rock formations in Canada's Yukon by | ||
338 | earth scientists Francis Macdonald and Phoebe Cohen of Harvard University. | ||
339 | In a June Geology paper, they describe their findings as providing "a unique | ||
340 | window into the diversity of early eukaryotes." | ||
341 | |||
342 | Using molecular clocks and genetic trees to reverse-engineer evolutionary | ||
343 | histories, previous research placed the beginning of biomineralization at | ||
344 | about 750 million years ago. Around that time, the fossil record gets | ||
345 | suggestive, turning up vase-shaped amoebas with something like scales in | ||
346 | their cell walls, algae with cell walls possibly made from calcium carbonate | ||
347 | and sponge-like creatures with seemingly mineralized bodies. | ||
348 | |] | ||
349 | "https://www.wired.com/2011/06/first-shells/", | ||
350 | |||
351 | CalendarEntry (440 & millionYearsAgo) Nothing | ||
352 | "Fish with jaws" | ||
353 | "" | ||
354 | [text| | ||
355 | Prehistoric armoured fishes called placoderms were the first fishes to have | ||
356 | jaws. They arose some time in the Silurian Period, about 440 million years | ||
357 | ago, to become the most abundant and diverse fishes of their day. | ||
358 | |||
359 | Placoderms dominated the oceans, rivers and lakes for some 80 million years, | ||
360 | before their sudden extinction around 359 million years ago. This is possibly | ||
361 | due to the depletion of trace elements in our oceans. | ||
362 | |] | ||
363 | "", | ||
364 | |||
365 | CalendarEntry (518 & millionYearsAgo) Nothing | ||
366 | "Vertebrates" | ||
367 | "Animals with backbones" | ||
368 | [text| | ||
369 | Vertebrates (/ˈvɜːrtəbrɪts, -ˌbreɪts/)[3] comprise all animal taxa within | ||
370 | the subphylum Vertebrata (/ˌvɜːrtəˈbreɪtə/)[4] (chordates with backbones), | ||
371 | including all mammals, birds, reptiles, amphibians, and fish. Vertebrates | ||
372 | represent the overwhelming majority of the phylum Chordata, with currently | ||
373 | about 69,963 species described.[5] | ||
374 | |] | ||
375 | "", | ||
376 | |||
377 | CalendarEntry (385 & millionYearsAgo) Nothing | ||
378 | "Insects" | ||
379 | "" | ||
380 | [text| | ||
381 | Comprising up to 10 million living species, insects today can be found on | ||
382 | all seven continents and inhabit every terrestrial niche imaginable. But | ||
383 | according to the fossil record, they were scarce before about 325 million | ||
384 | years ago, outnumbered by their arthropod cousins the arachnids (spiders, | ||
385 | scorpions and mites) and myriapods (centipedes and millipedes). | ||
386 | |||
387 | The oldest confirmed insect fossil is that of a wingless, silverfish-like | ||
388 | creature that lived about 385 million years ago. It’s not until about 60 | ||
389 | million years later, during a period of the Earth’s history known as the | ||
390 | Pennsylvanian, that insect fossils become abundant. | ||
391 | |] | ||
392 | "https://earth.stanford.edu/news/insects-took-when-they-evolved-wings", | ||
393 | |||
394 | CalendarEntry (368 & millionYearsAgo) Nothing | ||
395 | "Amphibians" | ||
396 | "" | ||
397 | [text| | ||
398 | The earliest well-known amphibian, Ichthyostega, was found in Late Devonian | ||
399 | deposits in Greenland, dating back about 363 million years. The earliest | ||
400 | amphibian discovered to date is Elginerpeton, found in Late Devonian rocks | ||
401 | of Scotland dating to approximately 368 million years ago. The later | ||
402 | Paleozoic saw a great diversity of amphibians, ranging from small legless | ||
403 | swimming forms (Aistopoda) to bizarre "horned" forms (Nectridea). Other | ||
404 | Paleozoic amphibians more or less resembled salamanders outwardly but | ||
405 | differed in details of skeletal structure. Exactly how to classify these | ||
406 | fossils, and how they might be related to living amphibians, is still | ||
407 | debated by paleontologists. Shown at the right is Phlegethontia, an aistopod | ||
408 | from the Pennsylvanian. | ||
409 | |||
410 | The familiar frogs, toads, and salamanders have been present since at least | ||
411 | the Jurassic Period. (The fossil frog pictured to the left is much younger, | ||
412 | coming from the Eocene, only 45 to 55 million years ago). Fossil caecilians | ||
413 | are very rare; until recently the oldest known caecilians were Cenozoic in | ||
414 | age (that is, less than 65 million years old), but recent finds have pushed | ||
415 | back the ancestry of the legless caecilians to Jurassic ancestors that had | ||
416 | short legs. The rarity of fossil caecilians is probably due to their | ||
417 | burrowing habitat and reduced skeleton, both of which lessen the chances of | ||
418 | preservation. | ||
419 | |] | ||
420 | "https://ucmp.berkeley.edu/vertebrates/tetrapods/amphibfr.html", | ||
421 | |||
422 | CalendarEntry (320 & millionYearsAgo) Nothing | ||
423 | "Reptiles" | ||
424 | "" | ||
425 | [text| | ||
426 | Reptiles, in the traditional sense of the term, are defined as animals that | ||
427 | have scales or scutes, lay land-based hard-shelled eggs, and possess | ||
428 | ectothermic metabolisms. | ||
429 | |||
430 | Though few reptiles today are apex predators, many examples of apex reptiles | ||
431 | have existed in the past. Reptiles have an extremely diverse evolutionary | ||
432 | history that has led to biological successes, such as dinosaurs, pterosaurs, | ||
433 | plesiosaurs, mosasaurs, and ichthyosaurs. | ||
434 | |] | ||
435 | [text| | ||
436 | https://en.wikipedia.org/wiki/Evolution_of_reptiles | ||
437 | https://www.thoughtco.com/the-first-reptiles-1093767 | ||
438 | |], | ||
439 | |||
440 | CalendarEntry (335 & millionYearsAgo) Nothing | ||
441 | "Pangea forms" | ||
442 | "" | ||
443 | [text| | ||
444 | Pangaea or Pangea (/pænˈdʒiː.ə/)[1] was a supercontinent that existed during | ||
445 | the late Paleozoic and early Mesozoic eras.[2] It assembled from the earlier | ||
446 | continental units of Gondwana, Euramerica and Siberia during the | ||
447 | Carboniferous approximately 335 million years ago, and began to break apart | ||
448 | about 200 million years ago, at the end of the Triassic and beginning of the | ||
449 | Jurassic.[3] In contrast to the present Earth and its distribution of | ||
450 | continental mass, Pangaea was centred on the Equator and surrounded by the | ||
451 | superocean Panthalassa and the Paleo-Tethys and subsequent Tethys Oceans. | ||
452 | Pangaea is the most recent supercontinent to have existed and the first to | ||
453 | be reconstructed by geologists. | ||
454 | |] | ||
455 | "https://en.wikipedia.org/wiki/Pangaea", | ||
456 | |||
457 | CalendarEntry (243 & millionYearsAgo) Nothing | ||
458 | "Dinosaurs" | ||
459 | "" | ||
460 | [text| | ||
461 | For the past twenty years, Eoraptor has represented the beginning of the Age | ||
462 | of Dinosaurs. This controversial little creature–found in the roughly | ||
463 | 231-million-year-old rock of Argentina–has often been cited as the earliest | ||
464 | known dinosaur. But Eoraptor has either just been stripped of that title, or | ||
465 | soon will be. A newly-described fossil found decades ago in Tanzania extends | ||
466 | the dawn of the dinosaurs more than 10 million years further back in time. | ||
467 | |||
468 | Named Nyasasaurus parringtoni, the roughly 243-million-year-old fossils | ||
469 | represent either the oldest known dinosaur or the closest known relative to | ||
470 | the earliest dinosaurs. The find was announced by University of Washington | ||
471 | paleontologist Sterling Nesbitt and colleagues in Biology Letters, and I | ||
472 | wrote a short news item about the discovery for Nature News. The paper | ||
473 | presents a significant find that is also a tribute to the work of Alan | ||
474 | Charig–who studied and named the animal, but never formally published a | ||
475 | description–but it isn’t just that. The recognition of Nyasasaurus right | ||
476 | near the base of the dinosaur family tree adds to a growing body of evidence | ||
477 | that the ancestors of dinosaurs proliferated in the wake of a catastrophic | ||
478 | mass extinction. | ||
479 | |] | ||
480 | [text| | ||
481 | https://www.smithsonianmag.com/science-nature/scientists-discover-oldest-known-dinosaur-152807497/ | ||
482 | |], | ||
483 | |||
484 | CalendarEntry (210 & millionYearsAgo) Nothing | ||
485 | "Mammals" | ||
486 | "" | ||
487 | [text| | ||
488 | The earliest known mammals were the morganucodontids, tiny shrew-size | ||
489 | creatures that lived in the shadows of the dinosaurs 210 million years ago. | ||
490 | They were one of several different mammal lineages that emerged around that | ||
491 | time. All living mammals today, including us, descend from the one line that | ||
492 | survived. | ||
493 | |] | ||
494 | "https://www.nationalgeographic.com/science/article/rise-mammals", | ||
495 | |||
496 | CalendarEntry (150 & millionYearsAgo) Nothing | ||
497 | "Birds" | ||
498 | "" | ||
499 | [text| | ||
500 | The first birds had sharp teeth, long bony tails and claws on their hands. | ||
501 | The clear distinction we see between living birds and other animals did not | ||
502 | exist with early birds. The first birds were in fact more like small | ||
503 | dinosaurs than they were like any bird today. | ||
504 | |||
505 | The earliest known (from fossils) bird is the 150-million-year-old | ||
506 | Archaeopteryx, but birds had evolved before then. A range of birds with more | ||
507 | advanced features appeared soon after Archaeopteryx. One group gave rise to | ||
508 | modern birds in the Late Cretaceous. | ||
509 | |] | ||
510 | "https://australian.museum/learn/dinosaurs/the-first-birds/", | ||
511 | |||
512 | CalendarEntry (130 & millionYearsAgo) Nothing | ||
513 | "Flowers" | ||
514 | "" | ||
515 | [text| | ||
516 | Today, plants with flowers--called angiosperms--dominate the landscape. | ||
517 | Around 80 percent of green plants alive today, from oak trees to grass, are | ||
518 | flowering plants. In all of these plants, flowers are part of the | ||
519 | reproductive system. But 130 million years ago, flowering plants were rare. | ||
520 | Most plants reproduced with spores, found today on ferns, or with seeds and | ||
521 | cones, found today on pine trees. The plant fossils found in Liaoning, | ||
522 | China, show evidence of plants with spores or seeds--and perhaps one of the | ||
523 | first flowering plants. | ||
524 | |||
525 | Researchers have found an ancient plant in Liaoning, Archaefructus, that has | ||
526 | very small, simple flowers and could be one of the first flowering plants. | ||
527 | Archaefructus lived around 130 million years ago and probably grew in or | ||
528 | near the water. | ||
529 | |] | ||
530 | "https://www.amnh.org/exhibitions/dinosaurs-ancient-fossils/liaoning-diorama/when-flowers-first-bloomed", | ||
531 | |||
532 | CalendarEntry (85 & millionYearsAgo) Nothing | ||
533 | "Tyranosaurids" | ||
534 | "The Tyrant Lizards" | ||
535 | [text| | ||
536 | The name says it all. This group of huge carnivores must have tyrannically | ||
537 | ruled the land during the last part of the Cretaceous, 85 to 65 million | ||
538 | years ago. Short but deep jaws with banana-sized sharp teeth, long hind | ||
539 | limbs, small beady eyes, and tiny forelimbs (arms) typify a tyrannosaur. The | ||
540 | Tyrannosauridae included such similar animals (in rough order of increasing | ||
541 | size) as Albertosaurus, Gorgosaurus, Daspletosaurus, Tarbosaurus, and of | ||
542 | course Tyrannosaurus rex. | ||
543 | |||
544 | T. rex was one of the largest terrestrial carnivores of all time. It stood | ||
545 | approximately 15 feet high and was about 40 feet in length, roughly six tons | ||
546 | in weight. In its large mouth were six-inch long, sharp, serrated teeth. | ||
547 | |||
548 | Just about two dozen good specimens of these animals have been found and | ||
549 | these finds are from highly restricted areas in western North America. Henry | ||
550 | Fairfield Osborn, of the American Museum of Natural History in New York | ||
551 | City, first described Tyrannosaurus rex in 1905. This first specimen of | ||
552 | Tyrannosaurus is now on display at the Carnegie Museum of Natural History in | ||
553 | Pittsburgh, Pennsylvania. | ||
554 | |] | ||
555 | "", | ||
556 | |||
557 | CalendarEntry (445 & millionYearsAgo) Nothing | ||
558 | "The first mass extinction" | ||
559 | "Fluctuating sea levels cause mass die-off of marine invertebrates" | ||
560 | [text| | ||
561 | The earliest known mass extinction, the Ordovician Extinction, took place at | ||
562 | a time when most of the life on Earth lived in its seas. Its major | ||
563 | casualties were marine invertebrates including brachiopods, trilobites, | ||
564 | bivalves and corals; many species from each of these groups went extinct | ||
565 | during this time. The cause of this extinction? It’s thought that the main | ||
566 | catalyst was the movement of the supercontinent Gondwana into Earth’s | ||
567 | southern hemisphere, which caused sea levels to rise and fall repeatedly | ||
568 | over a period of millions of years, eliminating habitats and species. The | ||
569 | onset of a late Ordovician ice age and changes in water chemistry may also | ||
570 | have been factors in this extinction. | ||
571 | |] | ||
572 | "https://www.amnh.org/shelf-life/six-extinctions", | ||
573 | |||
574 | CalendarEntry (370 & millionYearsAgo) Nothing | ||
575 | "Late Devonian Extinction" | ||
576 | "The Kellwasser Event and the Hangenberg Event combine to cause an enormous loss in biodiversity" | ||
577 | [text| | ||
578 | Given that it took place over a huge span of time—estimates range from | ||
579 | 500,000 to 25 million years—it isn’t possible to point to a single cause for | ||
580 | the Devonian extinction, though some suggest that the amazing spread of | ||
581 | plant life on land during this time may have changed the environment in ways | ||
582 | that made life harder, and eventually impossible, for the species that died | ||
583 | out. | ||
584 | |||
585 | The brunt of this extinction was borne by marine invertebrates. As in the | ||
586 | Ordovician Extinction, many species of corals, trilobites, and brachiopods | ||
587 | vanished. Corals in particular were so hard hit that they were nearly wiped | ||
588 | out, and didn’t recover until the Mesozoic Era, nearly 120 million years | ||
589 | later. Not all vertebrate species were spared, however; the early bony | ||
590 | fishes known as placoderms met their end in this extinction. | ||
591 | |] | ||
592 | "https://www.amnh.org/shelf-life/six-extinctions", | ||
593 | |||
594 | CalendarEntry (252 & millionYearsAgo) Nothing | ||
595 | "The Great Dying" | ||
596 | "Mass extinction kills more than 95 percent of marine species and 70 percent of land-dwelling vertebrates" | ||
597 | [text| | ||
598 | So many species were wiped out by this mass extinction it took more than 10 | ||
599 | million years to recover from the huge blow to global biodiversity. This | ||
600 | extinction is thought to be the result of a gradual change in climate, | ||
601 | followed by a sudden catastrophe. Causes including volcanic eruptions, | ||
602 | asteroid impacts, and a sudden release of greenhouse gasses from the | ||
603 | seafloor have been proposed, but the mechanism behind the Great Dying | ||
604 | remains a mystery. | ||
605 | |] | ||
606 | "https://www.amnh.org/shelf-life/six-extinctions", | ||
607 | |||
608 | CalendarEntry (201 & millionYearsAgo) Nothing | ||
609 | "Triassic-Jurassic Extinction" | ||
610 | "Death of more than a third of marine species and of most large amphibians" | ||
611 | [text| | ||
612 | This extinction occurred just a few millennia before the breakup of the | ||
613 | supercontinent of Pangaea. While its causes are not definitively | ||
614 | understood—researchers have suggested climate change, an asteroid impact, or | ||
615 | a spate of enormous volcanic eruptions as possible culprits—its effects are | ||
616 | indisputable. | ||
617 | |||
618 | More than a third of marine species vanished, as did most large amphibians | ||
619 | of the time, as well as many species related to crocodiles and dinosaurs. | ||
620 | |] | ||
621 | "https://www.amnh.org/shelf-life/six-extinctions", | ||
622 | |||
623 | CalendarEntry (66 & millionYearsAgo) Nothing | ||
624 | "Dinosaurs extinct" | ||
625 | "Mammals take over land & sea" | ||
626 | [text| | ||
627 | An asteroid more than 6 miles across strikes the Yucatan Peninsula, | ||
628 | triggering the fifth mass extinction in the world’s history. | ||
629 | |||
630 | Some of the debris thrown into the atmosphere returned to Earth, the | ||
631 | friction turning the air into an oven and sparking forest fires as it landed | ||
632 | all over the world. The intensity of the heat pulse gave way to a prolonged | ||
633 | impact winter, the sky blotted out by soot and ash as temperatures fell. | ||
634 | |||
635 | More than 75 percent of species known from the end of the Cretaceous period, | ||
636 | 66 million years ago, didn’t make it to the following Paleogene period. The | ||
637 | geologic break between the two is called the K-Pg boundary, and beaked birds | ||
638 | were the only dinosaurs to survive the disaster.|] | ||
639 | [text| | ||
640 | https://www.smithsonianmag.com/science-nature/why-birds-survived-and-dinosaurs-went-extinct-after-asteroid-hit-earth-180975801/, | ||
641 | https://www.amnh.org/shelf-life/six-extinctions | ||
642 | |], | ||
643 | |||
644 | CalendarEntry (27.5 & millionYearsAgo) Nothing | ||
645 | "Apes and monkeys split" | ||
646 | "" | ||
647 | [text| | ||
648 | Studies of clock-like mutations in primate DNA have indicated that the split | ||
649 | between apes and Old World monkeys occurred between 30 million and 25 | ||
650 | million years ago. | ||
651 | |] | ||
652 | "https://www.nsf.gov/news/news_summ.jsp?cntn_id=127930", | ||
653 | |||
654 | CalendarEntry (12.1 & millionYearsAgo) Nothing | ||
655 | "Humans and chimpanzees split" | ||
656 | "" | ||
657 | [text| | ||
658 | A 2016 study analyzed transitions at CpG sites in genome sequences, which | ||
659 | exhibit a more clocklike behavior than other substitutions, arriving at an | ||
660 | estimate for human and chimpanzee divergence time of 12.1 million years.[20] | ||
661 | |] | ||
662 | [text| | ||
663 | https://en.wikipedia.org/wiki/Chimpanzee%E2%80%93human_last_common_ancestor | ||
664 | |], | ||
665 | |||
666 | CalendarEntry (4.4 & millionYearsAgo) Nothing | ||
667 | "Humans first walk upright" | ||
668 | "" | ||
669 | [text| | ||
670 | The earliest hominid with the most extensive evidence for bipedalism is the 4.4-million-year-old Ardipithecus ramidus. | ||
671 | |] | ||
672 | [text| | ||
673 | https://www.smithsonianmag.com/science-nature/becoming-human-the-evolution-of-walking-upright-13837658/ | ||
674 | |], | ||
675 | |||
676 | CalendarEntry (300 & thousandYearsAgo) Nothing | ||
677 | "Modern humans evolve" | ||
678 | "" | ||
679 | [text| | ||
680 | Among the oldest known remains of Homo sapiens are those found at the | ||
681 | Omo-Kibish I archaeological site in south-western Ethiopia, dating to about | ||
682 | 233,000[2] to 196,000 years ago,[3] the Florisbad site in South Africa, | ||
683 | dating to about 259,000 years ago, and the Jebel Irhoud site in Morocco, | ||
684 | dated about 300,000 years ago. | ||
685 | |] | ||
686 | [text| | ||
687 | https://en.wikipedia.org/wiki/Early_modern_human | ||
688 | |], | ||
689 | |||
690 | CalendarEntry (100 & thousandYearsAgo) Nothing | ||
691 | "Human migration out of Africa" | ||
692 | "" | ||
693 | [text| | ||
694 | Between 70,000 and 100,000 years ago, Homo sapiens began migrating from the | ||
695 | African continent and populating parts of Europe and Asia. They reached the | ||
696 | Australian continent in canoes sometime between 35,000 and 65,000 years ago. | ||
697 | |||
698 | Map of the world showing the spread of Homo sapiens throughout the Earth | ||
699 | over time. | ||
700 | |] | ||
701 | [text| | ||
702 | https://www.khanacademy.org/humanities/world-history/world-history-beginnings/origin-humans-early-societies/a/where-did-humans-come-from | ||
703 | |], | ||
704 | |||
705 | CalendarEntry (600 & millionYearsAgo) Nothing | ||
706 | "Multicellular life" | ||
707 | "" | ||
708 | [text| | ||
709 | |] | ||
710 | "", | ||
711 | |||
712 | CalendarEntry (2.6 & millionYearsAgo) Nothing | ||
713 | "First Stone Tools" | ||
714 | [text| | ||
715 | Mode I: The Oldowan Industry | ||
716 | Stone flakes with sharp edges for cutting | ||
717 | |] | ||
718 | [text| | ||
719 | The earliest known Oldowan tools yet found date from 2.6 million years ago, | ||
720 | during the Lower Palaeolithic period, and have been uncovered at Gona in | ||
721 | Ethiopia.[16] After this date, the Oldowan Industry subsequently spread | ||
722 | throughout much of Africa, although archaeologists are currently unsure | ||
723 | which Hominan species first developed them, with some speculating that it | ||
724 | was Australopithecus garhi, and others believing that it was in fact Homo | ||
725 | habilis.[17] | ||
726 | |||
727 | Homo habilis was the hominin who used the tools for most of the Oldowan in | ||
728 | Africa, but at about 1.9-1.8 million years ago Homo erectus inherited them. | ||
729 | The Industry flourished in southern and eastern Africa between 2.6 and 1.7 | ||
730 | million years ago, but was also spread out of Africa and into Eurasia by | ||
731 | travelling bands of H. erectus, who took it as far east as Java by 1.8 | ||
732 | million years ago and Northern China by 1.6 million years ago. | ||
733 | |] | ||
734 | "", | ||
735 | |||
736 | CalendarEntry (1.8 & millionYearsAgo) Nothing | ||
737 | "First major transition in stone tool technology" | ||
738 | [text| | ||
739 | Mode II: The Acheulean Industry | ||
740 | Stone hand-axes shaped symmetrically from two sides | ||
741 | |] | ||
742 | [text| | ||
743 | From the Konso Formation of Ethiopia, Acheulean hand-axes are dated to about | ||
744 | 1.5 million years ago using radiometric dating of deposits containing | ||
745 | volcanic ashes.[6] Acheulean tools in South Asia have also been found to be | ||
746 | dated as far as 1.5 million years ago.[7] However, the earliest accepted | ||
747 | examples of the Acheulean currently known come from the West Turkana region | ||
748 | of Kenya and were first described by a French-led archaeology team.[8] These | ||
749 | particular Acheulean tools were recently dated through the method of | ||
750 | magnetostratigraphy to about 1.76 million years ago, making them the oldest | ||
751 | not only in Africa but the world.[9] The earliest user of Acheulean tools | ||
752 | was Homo ergaster, who first appeared about 1.8 million years ago. Not all | ||
753 | researchers use this formal name, and instead prefer to call these users | ||
754 | early Homo erectus.[3] | ||
755 | |] | ||
756 | "", | ||
757 | |||
758 | CalendarEntry (160 & thousandYearsAgo) Nothing | ||
759 | "Second major transition in stone tool technology" | ||
760 | [text| | ||
761 | Mode III: The Levallois technique; The Mousterian Industry | ||
762 | Stone scrapers, knives, and projectile points | ||
763 | |] | ||
764 | [text| | ||
765 | Levallois is a "prepared-core" technique: one face of a stone core is fully | ||
766 | shaped by knapping in perparation. Then a large sharp flake is created by | ||
767 | cracking off the entire prepared face in one final stroke. | ||
768 | |||
769 | The technique is first found in the Lower Palaeolithic but is most commonly | ||
770 | associated with the Neanderthal Mousterian industries of the Middle | ||
771 | Palaeolithic. In the Levant, the Levallois technique was also used by | ||
772 | anatomically modern humans during the Middle Stone Age. In North Africa, the | ||
773 | Levallois technique was used in the Middle Stone Age, most notably in the | ||
774 | Aterian industry to produce very small projectile points. While Levallois | ||
775 | cores do display some variability in their platforms, their flake production | ||
776 | surfaces show remarkable uniformity. As the Levallois technique is | ||
777 | counterintuitive, teaching the process is necessary and thus language is a | ||
778 | prerequisite for such technology.[2] | ||
779 | |||
780 | The Mousterian (or Mode III) is a techno-complex (archaeological industry) | ||
781 | of stone tools, associated primarily with the Neanderthals in Europe, and to | ||
782 | a lesser extent the earliest anatomically modern humans in North Africa and | ||
783 | West Asia. The Mousterian largely defines the latter part of the Middle | ||
784 | Paleolithic, the middle of the West Eurasian Old Stone Age. It lasted | ||
785 | roughly from 160,000 to 40,000 BP. If its predecessor, known as Levallois or | ||
786 | Levallois-Mousterian, is included, the range is extended to as early as c. | ||
787 | 300,000–200,000 BP.[2] The main following period is the Aurignacian (c. | ||
788 | 43,000–28,000 BP) of Homo sapiens. | ||
789 | |] | ||
790 | "", | ||
791 | |||
792 | CalendarEntry (115 & thousandYearsAgo) (Just $ 11.7 & thousandYearsAgo) | ||
793 | "The Ice Age begins" | ||
794 | "Glaciers cover most land on Earth, joining Asia to North America" | ||
795 | [text| | ||
796 | The Last Glacial Period (LGP), also known colloquially as the last ice age | ||
797 | or simply ice age,[1] occurred from the end of the Eemian to the end of the | ||
798 | Younger Dryas, encompassing the period c. 115,000 – c. 11,700 years ago. The | ||
799 | LGP is part of a larger sequence of glacial and interglacial periods known | ||
800 | as the Quaternary glaciation which started around 2,588,000 years ago and is | ||
801 | ongoing.[2] The definition of the Quaternary as beginning 2.58 million years | ||
802 | ago (Mya) is based on the formation of the Arctic ice cap. The Antarctic ice | ||
803 | sheet began to form earlier, at about 34 Mya, in the mid-Cenozoic | ||
804 | (Eocene–Oligocene extinction event). The term Late Cenozoic Ice Age is used | ||
805 | to include this early phase.[3] | ||
806 | |] | ||
807 | "https://en.wikipedia.org/wiki/Last_Glacial_Period", | ||
808 | |||
809 | CalendarEntry (50 & thousandYearsAgo) Nothing | ||
810 | "Third major transition in stone tool technology" | ||
811 | [text| | ||
812 | Mode IV: The Aurignacian Industry | ||
813 | Long stone blades | ||
814 | |] | ||
815 | [text| | ||
816 | The widespread use of long blades (rather than flakes) of the Upper | ||
817 | Palaeolithic Mode 4 industries appeared during the Upper Palaeolithic | ||
818 | between 50,000 and 10,000 years ago, although blades were produced in small | ||
819 | quantities much earlier by Neanderthals.[20] The Aurignacian culture seems | ||
820 | to have been the first to rely largely on blades.[21] The use of blades | ||
821 | exponentially increases the efficiency of core usage compared to the | ||
822 | Levallois flake technique, which had a similar advantage over Acheulean | ||
823 | technology which was worked from cores. | ||
824 | |] | ||
825 | "https://en.wikipedia.org/wiki/Stone_tool#Mode_IV:_The_Aurignacian_Industry", | ||
826 | |||
827 | CalendarEntry (35 & thousandYearsAgo) Nothing | ||
828 | "Last major transition in stone tool technology" | ||
829 | [text| | ||
830 | Mode V: The Microlithic Industries | ||
831 | Stone blades fastened to wood or bone handles | ||
832 | |] | ||
833 | [text| | ||
834 | Mode 5 stone tools involve the production of microliths, which were | ||
835 | used in composite tools, mainly fastened to a shaft.[22] Examples include | ||
836 | the Magdalenian culture. Such a technology makes much more efficient use of | ||
837 | available materials like flint, although required greater skill in | ||
838 | manufacturing the small flakes. Mounting sharp flint edges in a wood or bone | ||
839 | handle is the key innovation in microliths, essentially because the handle | ||
840 | gives the user protection against the flint and also improves leverage of | ||
841 | the device. | ||
842 | |] | ||
843 | "https://en.wikipedia.org/wiki/Stone_tool#Mode_V:_The_Microlithic_Industries" | ||
844 | , | ||
845 | |||
846 | CalendarEntry (12 & thousandYearsAgo) Nothing | ||
847 | "Agriculture leads to permanent settlements" | ||
848 | "Neolithic age (\"new stone age\")" | ||
849 | [text| | ||
850 | Wild grains were collected and eaten from at least 105,000 years ago.[2] | ||
851 | However, domestication did not occur until much later. The earliest evidence | ||
852 | of small-scale cultivation of edible grasses is from around 21,000 BC with | ||
853 | the Ohalo II people on the shores of the Sea of Galilee.[3] By around 9500 | ||
854 | BC, the eight Neolithic founder crops – emmer wheat, einkorn wheat, hulled | ||
855 | barley, peas, lentils, bitter vetch, chickpeas, and flax – were cultivated | ||
856 | in the Levant.[4] Rye may have been cultivated earlier, but this claim | ||
857 | remains controversial.[5] Rice was domesticated in China by 6200 BC[6] with | ||
858 | earliest known cultivation from 5700 BC, followed by mung, soy and azuki | ||
859 | beans. Rice was also independently domesticated in West Africa and | ||
860 | cultivated by 1000 BC.[7][8] Pigs were domesticated in Mesopotamia around | ||
861 | 11,000 years ago, followed by sheep. Cattle were domesticated from the wild | ||
862 | aurochs in the areas of modern Turkey and India around 8500 BC. Camels were | ||
863 | domesticated late, perhaps around 3000 BC. | ||
864 | |] | ||
865 | "https://en.wikipedia.org/wiki/History_of_agriculture", | ||
866 | |||
867 | CalendarEntry (6.5 & thousandYearsAgo) Nothing | ||
868 | "First copper tools" | ||
869 | "" | ||
870 | "" | ||
871 | "", | ||
872 | |||
873 | CalendarEntry (5.3 & thousandYearsAgo) Nothing | ||
874 | "First bronze tools, first written language" | ||
875 | "The Bronze Age" | ||
876 | "" | ||
877 | "", | ||
878 | |||
879 | CalendarEntry (3000 & yearsBeforeCommonEra) (Just $ 2350 & yearsBeforeCommonEra) | ||
880 | "Corded Ware culture" | ||
881 | "Indo-European languages spread across Europe and Asia" | ||
882 | [text| | ||
883 | The Corded Ware culture comprises a broad archaeological horizon of Europe | ||
884 | between ca. 3000 BCE – 2350 BCE, thus from the late Neolithic, through the | ||
885 | Copper Age, and ending in the early Bronze Age.[2] Corded Ware culture | ||
886 | encompassed a vast area, from the contact zone between the Yamnaya culture | ||
887 | and the Corded Ware culture in south Central Europe, to the Rhine on the | ||
888 | west and the Volga in the east, occupying parts of Northern Europe, Central | ||
889 | Europe and Eastern Europe.[2][3] The Corded Ware culture is thought to have | ||
890 | originated from the westward migration of Yamnaya-related people from the | ||
891 | steppe-forest zone into the territory of late Neolithic European cultures | ||
892 | such as the Globular Amphora and Funnelbeaker cultures,[4][5][6] and is | ||
893 | considered to be a likely vector for the spread of many of the Indo-European | ||
894 | languages in Europe and Asia.[1][7][8][9] | ||
895 | |||
896 | Corded Ware encompassed most of continental northern Europe from the Rhine | ||
897 | on the west to the Volga in the east, including most of modern-day Germany, | ||
898 | the Netherlands, Denmark, Poland, Lithuania, Latvia, Estonia, Belarus, Czech | ||
899 | Republic, Austria, Hungary, Slovakia, Switzerland, northwestern Romania, | ||
900 | northern Ukraine, and the European part of Russia, as well as coastal Norway | ||
901 | and the southern portions of Sweden and Finland.[2] In the Late | ||
902 | Eneolithic/Early Bronze Age, it encompassed the territory of nearly the | ||
903 | entire Balkan Peninsula, where Corded Ware mixed with other steppe | ||
904 | elements.[11] | ||
905 | |||
906 | Archaeologists note that Corded Ware was not a "unified culture," as Corded | ||
907 | Ware groups inhabiting a vast geographical area from the Rhine to Volga seem | ||
908 | to have regionally specific subsistence strategies and economies.[2]: 226 | ||
909 | There are differences in the material culture and in settlements and | ||
910 | society.[2] At the same time, they had several shared elements that are | ||
911 | characteristic of all Corded Ware groups, such as their burial practices, | ||
912 | pottery with "cord" decoration and unique stone-axes.[2] | ||
913 | |] | ||
914 | "", | ||
915 | |||
916 | CalendarEntry (2800 & yearsBeforeCommonEra) (Just $ 1800 & yearsBeforeCommonEra) | ||
917 | "Bell Beaker culture" | ||
918 | [text| | ||
919 | copper daggers, v-perforated buttons, stone wrist-guards | ||
920 | copper, bronze, and gold working | ||
921 | long-distance exchange networks, archery | ||
922 | social stratification and the emergence of regional elites | ||
923 | |] | ||
924 | [text| | ||
925 | The Bell Beaker culture (also described as the Bell Beaker complex or Bell | ||
926 | Beaker phenomenon) is an archaeological culture named after the | ||
927 | inverted-bell beaker drinking vessel used at the very beginning of the | ||
928 | European Bronze Age. Arising from around 2800 BC, it lasted in Britain until | ||
929 | as late as 1800 BC[1][2] but in continental Europe only until 2300 BC, when | ||
930 | it was succeeded by the Unetice culture. The culture was widely dispersed | ||
931 | throughout Western Europe, being present in many regions of Iberia and | ||
932 | stretching eastward to the Danubian plains, and northward to the islands of | ||
933 | Great Britain and Ireland, and was also present in the islands of Sicily and | ||
934 | Sardinia and some small coastal areas in north-western Africa. The Bell | ||
935 | Beaker phenomenon shows substantial regional variation, and a study[3] from | ||
936 | 2018 found that it was associated with genetically diverse populations. | ||
937 | |||
938 | In its mature phase, the Bell Beaker culture is understood as not only a | ||
939 | collection of characteristic artefact types, but a complex cultural | ||
940 | phenomenon involving metalwork in copper and gold, long-distance exchange | ||
941 | networks, archery, specific types of ornamentation, and (presumably) shared | ||
942 | ideological, cultural and religious ideas, as well as social stratification | ||
943 | and the emergence of regional elites.[6][7] A wide range of regional | ||
944 | diversity persists within the widespread late Beaker culture, particularly | ||
945 | in local burial styles (including incidences of cremation rather than | ||
946 | burial), housing styles, economic profile, and local ceramic wares | ||
947 | (Begleitkeramik). Nonetheless, according to Lemercier (2018) the mature | ||
948 | phase of the Beaker culture represents "the appearance of a kind of Bell | ||
949 | Beaker civilization of continental scale."[8] | ||
950 | |||
951 | Bell Beaker people took advantage of transport by sea and rivers, creating a | ||
952 | cultural spread extending from Ireland to the Carpathian Basin and south | ||
953 | along the Atlantic coast and along the Rhône valley to Portugal, North | ||
954 | Africa, and Sicily, even penetrating northern and central Italy.[50] Its | ||
955 | remains have been found in what is now Portugal, Spain, France (excluding | ||
956 | the central massif), Ireland and Great Britain, the Low Countries and | ||
957 | Germany between the Elbe and Rhine, with an extension along the upper Danube | ||
958 | into the Vienna Basin (Austria), Hungary and the Czech Republic, with | ||
959 | Mediterranean outposts on Sardinia and Sicily; there is less certain | ||
960 | evidence for direct penetration in the east. | ||
961 | |] | ||
962 | "https://en.wikipedia.org/wiki/Bell_Beaker_culture", | ||
963 | |||
964 | CalendarEntry (11.7 & thousandYearsAgo) Nothing | ||
965 | "Ice Age ends" | ||
966 | "" | ||
967 | "" | ||
968 | "https://en.wikipedia.org/wiki/Last_Glacial_Period", | ||
969 | |||
970 | CalendarEntry (1600 & yearsBeforeCommonEra) Nothing | ||
971 | "Dynastic China" | ||
972 | "History begins" | ||
973 | [text| | ||
974 | The earliest known written records of the history of China date from as | ||
975 | early as 1250 BC, from the Shang dynasty (c. 1600–1046 BC), during the king | ||
976 | Wu Ding's reign | ||
977 | |||
978 | The state-sponsored Xia–Shang–Zhou Chronology Project dated them from c. | ||
979 | 1600 to 1046 BC based on the carbon 14 dates of the Erligang site. | ||
980 | |] | ||
981 | "", | ||
982 | |||
983 | CalendarEntry (480 & yearsBeforeCommonEra) Nothing | ||
984 | "Old Testament, Buddha" | ||
985 | "" | ||
986 | "" | ||
987 | "", | ||
988 | |||
989 | CalendarEntry (6 & yearsBeforeCommonEra) Nothing | ||
990 | "Christ born" | ||
991 | "" | ||
992 | "" | ||
993 | "", | ||
994 | |||
995 | -- CalendarEntry (300 & yearsBeforeCommonEra) Nothing | ||
996 | -- "Eratosthenes calculates the circumference of Earth" | ||
997 | -- "" | ||
998 | -- "" | ||
999 | -- "", | ||
1000 | |||
1001 | CalendarEntry (theYear 570) Nothing | ||
1002 | "Muhammad born" | ||
1003 | "" | ||
1004 | "" | ||
1005 | "", | ||
1006 | |||
1007 | CalendarEntry (theYear 1492) Nothing | ||
1008 | "Columbus arrives in America" | ||
1009 | "" | ||
1010 | "" | ||
1011 | "" | ||
1012 | ] | ||
diff --git a/src/countdown.hs b/src/countdown.hs new file mode 100755 index 0000000..1910bec --- /dev/null +++ b/src/countdown.hs | |||
@@ -0,0 +1,523 @@ | |||
1 | #!/usr/bin/env stack | ||
2 | {- stack script --resolver lts-19.23 --install-ghc -} | ||
3 | {-# OPTIONS_GHC | ||
4 | -Wall | ||
5 | -Wno-unused-imports | ||
6 | -Wno-unused-top-binds | ||
7 | -Wno-name-shadowing | ||
8 | #-} | ||
9 | {-# language NoImplicitPrelude #-} | ||
10 | {-# language RecordWildCards #-} | ||
11 | {-# language FlexibleContexts #-} | ||
12 | {-# language TemplateHaskell #-} | ||
13 | {-# language ViewPatterns #-} | ||
14 | {-# language OverloadedStrings #-} | ||
15 | import Rebase.Prelude hiding (toList, on, (<+>), Max) | ||
16 | import qualified Rebase.Prelude as Prelude | ||
17 | import Control.Lens hiding ((<|)) | ||
18 | import Data.Foldable (toList) | ||
19 | import Data.Ratio | ||
20 | import Text.Printf | ||
21 | import Graphics.Vty | ||
22 | import Data.Time.LocalTime | ||
23 | import Control.Monad.RWS | ||
24 | import Data.Time.Calendar.OrdinalDate | ||
25 | import qualified Data.Text as Text | ||
26 | import Data.Text.Format.Numbers | ||
27 | import Rebase.Data.Map.Strict (Map) | ||
28 | import qualified Rebase.Data.Map.Strict as Map | ||
29 | |||
30 | import Brick | ||
31 | import Brick.Types | ||
32 | import Data.Text (unpack) | ||
33 | import Control.Lens | ||
34 | import Control.Monad (void, forever) | ||
35 | import Control.Concurrent (threadDelay, forkIO) | ||
36 | import qualified Graphics.Vty as V | ||
37 | import Brick.Widgets.ProgressBar as P | ||
38 | import Brick.BChan | ||
39 | import Brick.Widgets.Center | ||
40 | import Brick.Widgets.Border | ||
41 | import Brick.Main | ||
42 | ( App(..) | ||
43 | , showFirstCursor | ||
44 | , customMain | ||
45 | , continue | ||
46 | , halt | ||
47 | ) | ||
48 | import Brick.AttrMap | ||
49 | ( attrMap | ||
50 | ) | ||
51 | import Brick.Types | ||
52 | ( Widget | ||
53 | , Next | ||
54 | , EventM | ||
55 | , BrickEvent(..) | ||
56 | ) | ||
57 | import Brick.Widgets.Core | ||
58 | ( (<=>) | ||
59 | , str | ||
60 | ) | ||
61 | import Brick.AttrMap as A | ||
62 | import Brick.Util (fg, bg, on, clamp) | ||
63 | import Brick.Widgets.Core | ||
64 | import Brick.Widgets.Table | ||
65 | |||
66 | import CosmicCalendar | ||
67 | import CosmicCalendarEvents | ||
68 | |||
69 | data CustomEvent = TimeChanged ZonedTime deriving Show | ||
70 | |||
71 | data St = | ||
72 | St { _stLastBrickEvent :: Maybe (BrickEvent () CustomEvent) | ||
73 | , _stClockTime :: LocalTime | ||
74 | , _stDisplayTime :: LocalTime | ||
75 | , _stNextEvent :: Maybe UTCTime | ||
76 | , _stPaused :: Bool | ||
77 | , _stShowConversion :: Bool | ||
78 | } | ||
79 | |||
80 | makeLenses ''St | ||
81 | |||
82 | yearNumber :: LocalTime -> Integer | ||
83 | yearNumber (LocalTime t _) = y | ||
84 | where | ||
85 | (y, _, _) = toGregorian t | ||
86 | |||
87 | yearEnd :: LocalTime -> LocalTime | ||
88 | yearEnd (LocalTime d _) = LocalTime d' t' | ||
89 | where | ||
90 | d' = fromGregorian (y + 1) 1 1 | ||
91 | t' = TimeOfDay 0 0 0 | ||
92 | (y, _, _) = toGregorian d | ||
93 | |||
94 | |||
95 | dayNumOfYear :: LocalTime -> Int | ||
96 | dayNumOfYear = snd . toOrdinalDate . localDay | ||
97 | |||
98 | pluralize :: (Num n, Eq n) => n -> String | ||
99 | pluralize 1 = "" | ||
100 | pluralize _ = "s" | ||
101 | |||
102 | pluralizeVerb :: (Num n, Eq n) => n -> String | ||
103 | pluralizeVerb 1 = "s" | ||
104 | pluralizeVerb _ = "" | ||
105 | |||
106 | drawUI :: St -> [Widget ()] | ||
107 | drawUI st = [a] | ||
108 | where | ||
109 | a = vBox [ | ||
110 | -- (str $ "Last event: " <> (show $ st ^. stLastBrickEvent)), | ||
111 | -- (str "\n"), | ||
112 | (str "\n"), | ||
113 | (countdownWidget (st ^. stShowConversion) (isSimulatedTime st) $ st ^. stDisplayTime) | ||
114 | ] | ||
115 | |||
116 | showTime' :: Bool -> NominalDiffTime -> String | ||
117 | showTime' True 1 = printf "%-3s second" ("1" :: Text) | ||
118 | showTime' True t | t < 60 = printf "%.1f seconds" (realToFrac t :: Float) | ||
119 | showTime' _ t = showTime t | ||
120 | |||
121 | showTime :: NominalDiffTime -> String | ||
122 | showTime t | t < 1 = printf "%.3f seconds" (realToFrac t :: Float) | ||
123 | showTime t | t == 1 = "1 second" | ||
124 | -- showTime t | t < 10 = formatTime defaultTimeLocale "%2Es seconds" t -- BUG! Doesn't respect <width> parameter at all! | ||
125 | showTime t | t < 60 = printf "%.1f seconds" (realToFrac t :: Float) | ||
126 | showTime t | t == 60 = formatTime defaultTimeLocale "%M minute" t | ||
127 | showTime t | t < 60*2 = formatTime defaultTimeLocale "%M minute %Ss" t | ||
128 | showTime t | t < 60*10 = formatTime defaultTimeLocale "%M minutes %Ss" t | ||
129 | showTime t | t < 60*60 = formatTime defaultTimeLocale "%M minutes" t | ||
130 | showTime t | t == 60*60 = "1 hour" | ||
131 | showTime t | t < 60*60*2 = formatTime defaultTimeLocale "%H hour %Mm" t | ||
132 | showTime t | t < 60*60*24 = formatTime defaultTimeLocale "%H hours %Mm" t | ||
133 | showTime t | t == 60*60*24 = formatTime defaultTimeLocale "%d day" t | ||
134 | showTime t | t < 60*60*24*2 = formatTime defaultTimeLocale "%d day %Hh" t | ||
135 | showTime t | t == 60*60*24*7 = formatTime defaultTimeLocale "%d days" t | ||
136 | showTime t | t < 60*60*24*10 = formatTime defaultTimeLocale "%d days %Hh" t | ||
137 | showTime t = formatTime defaultTimeLocale "%d days" t | ||
138 | -- showTime _ t = formatTime defaultTimeLocale "%w weeks %D days" t | ||
139 | |||
140 | yearsToCosmicTime :: Integral i => i -> NominalDiffTime | ||
141 | yearsToCosmicTime = (/ (realToFrac ageOfUniverseInYears)) . (* lengthOfYear) . realToFrac | ||
142 | |||
143 | showCosmicYears :: Integer -> Widget n | ||
144 | showCosmicYears = str . showTime . yearsToCosmicTime | ||
145 | |||
146 | toCosmicTime :: NominalDiffTime -> Rational | ||
147 | toCosmicTime t = realToFrac ageOfUniverseInYears * (realToFrac $ t // yearLength) :: Rational | ||
148 | where | ||
149 | yearLength = daysPerYear * nominalDay | ||
150 | x // y = fromRational $ toRational x / toRational y :: Double | ||
151 | |||
152 | showCosmicTime :: NominalDiffTime -> String | ||
153 | showCosmicTime n = showLarge (fromRational $ toCosmicTime n) ++ " years" | ||
154 | |||
155 | conversionTableRowFromCosmicSeconds :: NominalDiffTime -> [Widget n] | ||
156 | conversionTableRowFromCosmicSeconds n = [cosmicTime, realTime] | ||
157 | where | ||
158 | realTime = str $ showCosmicTime n | ||
159 | cosmicTime = str $ showTime n | ||
160 | |||
161 | cosmicConversion' :: Widget n | ||
162 | cosmicConversion' = renderTable $ | ||
163 | table | ||
164 | [ | ||
165 | conversionTableRowFromCosmicSeconds $ 30 * 24 * 60 * 60, | ||
166 | conversionTableRowFromCosmicSeconds $ 7 * 24 * 60 * 60, | ||
167 | conversionTableRowFromCosmicSeconds $ 24 * 60 * 60, | ||
168 | conversionTableRowFromCosmicSeconds $ 60 * 60, | ||
169 | conversionTableRowFromCosmicSeconds $ 60, | ||
170 | conversionTableRowFromCosmicSeconds $ 1 | ||
171 | ] | ||
172 | |||
173 | cosmicConversion :: Widget n | ||
174 | cosmicConversion = renderTable $ | ||
175 | table | ||
176 | [ | ||
177 | [str "1 billion years" , showCosmicYears $ 1000 * 1000 * 1000], | ||
178 | [str "100 million years" , showCosmicYears $ 100 * 1000 * 1000], | ||
179 | [str "10 million years" , showCosmicYears $ 10 * 1000 * 1000], | ||
180 | [str "1 million years" , showCosmicYears $ 1000 * 1000], | ||
181 | [str "100 thousand years" , showCosmicYears $ 100 * 1000], | ||
182 | [str "10 thousand years" , showCosmicYears $ 10 * 1000], | ||
183 | [str "1 thousand years" , showCosmicYears 1000], | ||
184 | [str "100 years" , showCosmicYears 100], | ||
185 | [str "10 years" , showCosmicYears 10], | ||
186 | [str "1 year" , showCosmicYears 1] | ||
187 | ] | ||
188 | |||
189 | showLarge :: Double -> String | ||
190 | showLarge n | n >= 10 * 1000 * 1000 * 1000 = printf "%.0f billion" (n / (1000 * 1000 * 1000)) | ||
191 | showLarge n | n >= 1000 * 1000 * 1000 = printf "%.1f billion" (n / (1000 * 1000 * 1000)) | ||
192 | showLarge n | n >= 10 * 1000 * 1000 = printf "%.0f million" (n / (1000 * 1000)) | ||
193 | showLarge n | n >= 1000 * 1000 = printf "%.1f million" (n / (1000 * 1000)) | ||
194 | showLarge n | n >= 10 * 1000 = printf "%.0f thousand" (n / 1000) | ||
195 | showLarge n | n >= 10 = unpack $ commasF 0 n | ||
196 | showLarge n = printf "%.3f" n | ||
197 | |||
198 | countdownWidget :: Bool -> Bool -> LocalTime -> Widget n | ||
199 | countdownWidget showConversion isSimulated t = | ||
200 | (border $ vBox [ | ||
201 | (hCenter $ hBox | ||
202 | [ countdownBox | ||
203 | , currentTimeBox | ||
204 | , cosmicTimeBox | ||
205 | ]) | ||
206 | , | ||
207 | str "\n" | ||
208 | , | ||
209 | (borderWithLabel (str progressLabel) $ | ||
210 | updateAttrMap | ||
211 | (A.mapAttrName yDoneAttr P.progressCompleteAttr . | ||
212 | A.mapAttrName yToDoAttr P.progressIncompleteAttr) $ | ||
213 | progressBar Nothing (realToFrac $ yearElapsed // yearLength)) | ||
214 | ]) | ||
215 | <=> | ||
216 | str "\n" | ||
217 | <=> | ||
218 | hCenter (hBox [ | ||
219 | -- TODO: accumulate all entries on today's date into one vBox | ||
220 | if currentEntryIsCurrent then | ||
221 | (borderWithLabel (txt "Now on the Cosmic Calendar") currentEntry) <=> | ||
222 | (fromMaybe (str "") $ fmap (borderWithLabel (txt "Next on the Cosmic Calendar")) nextEntryShort) | ||
223 | else | ||
224 | borderWithLabel (txt "Next on the Cosmic Calendar") nextEntry, | ||
225 | -- vBox [ cosmicCalendarCurrent, txt "\n", cosmicCalendarNext ], | ||
226 | if showConversion | ||
227 | then | ||
228 | str " " <=> borderWithLabel (str "Cosmic Conversion") (hBox [cosmicConversion, cosmicConversion']) | ||
229 | else | ||
230 | str "" | ||
231 | ]) | ||
232 | where | ||
233 | -- TODO: We want to display "today" or "now" on the cosmic calendar; | ||
234 | -- We want to display what happened previously on the cosmic calendar | ||
235 | -- We want to say how long ago the previous happening was relative to today's date and today's place on the cosmic calendar | ||
236 | -- (E.g., if it's 1AM Jan 1, then we say the big bang was 1 hour ago and 1.6 million years ago) | ||
237 | -- We want to say similar for how long until the next happening | ||
238 | -- We also _may_ want to say the same thing for the current happening, depending on if it's an instant or a stage | ||
239 | -- If it's a stage, we want to say how long it lasts; how long since it started, and how long until it ends | ||
240 | |||
241 | currentEntryIsCurrent = fromMaybe True $ do | ||
242 | (LocalTime entryDay _) <- (`addLocalTime` yearStart t) . calBeginTime <$> getCurrentCalendarEntry theCalendar t | ||
243 | let (LocalTime nowDay _) = t | ||
244 | return $ entryDay == nowDay | ||
245 | currentEntry = fromMaybe (str "none") $ calendarWidget False <$> getCurrentCalendarEntry theCalendar t | ||
246 | nextEntry = fromMaybe (str "none") $ calendarWidget False <$> getNextCalendarEntry theCalendar t | ||
247 | nextEntryShort = fmap (str "\n" <=>) (calendarWidget True <$> getNextCalendarEntry theCalendar t) | ||
248 | |||
249 | calendarWidget short CalendarEntry{..} = box -- vBox [eventCountdown, str "\n", box] | ||
250 | where | ||
251 | timeUntilActive = (calBeginTime `addLocalTime` yearStart t) `diffLocalTime` t | ||
252 | eventCountdown = if timeUntilActive >= 0 then | ||
253 | hBox [str $ "in " ++ showTime timeUntilActive, | ||
254 | padLeft Max $ str $ "in " ++ showCosmicTime timeUntilActive] | ||
255 | else | ||
256 | hBox [str $ showTime (-timeUntilActive) ++ " ago", | ||
257 | padLeft Max $ str $ showCosmicTime (-timeUntilActive) ++ " ago"] | ||
258 | years = fromRational $ toCosmicTime calBeginTime | ||
259 | box = vBox [ | ||
260 | if currentEntryIsCurrent && not short | ||
261 | then str "\n" | ||
262 | else eventCountdown <=> str "\n", | ||
263 | hCenter $ txt calTitle, | ||
264 | hCenter $ txt calSubtitle, | ||
265 | str "\n", | ||
266 | hBox [ | ||
267 | let cosmicSecondsAgo = nominalDiffTimeToSeconds (yearEnd cosmicCalendarT `diffLocalTime` cosmicCalendarT) | ||
268 | cosmicCalendarT = calBeginTime `addLocalTime` yearStart t | ||
269 | in vBox [ | ||
270 | str $ formatTime defaultTimeLocale "%A, %B %e%n%Y-%m-%d %r" $ cosmicCalendarT, | ||
271 | -- TODO: Choose correct cosmic unit | ||
272 | str $ printf "%s cosmic second%s ago" (commasF' 1 cosmicSecondsAgo) (pluralize cosmicSecondsAgo) | ||
273 | ], | ||
274 | padLeft Max $ vBox [ | ||
275 | str $ showLarge years ++ " years", | ||
276 | str $ printf "%s years ago" $ showLarge $ realToFrac (ageOfUniverseInYears - floor years) | ||
277 | ] | ||
278 | ], | ||
279 | -- str $ printf "%s years ago" (commas $ ageOfUniverseInYears - floor years), | ||
280 | if not short | ||
281 | then | ||
282 | str "\n" <=> | ||
283 | txtWrap calDescription | ||
284 | else | ||
285 | str "" | ||
286 | ] | ||
287 | |||
288 | strWhen b s = str $ if b then s else "" | ||
289 | countdownBox = | ||
290 | (borderWithLabel (str $ printf "Countdown %d" currentYear) $ | ||
291 | vBox $ | ||
292 | let secondsNow = 1 + toSeconds yearElapsed :: Int | ||
293 | secondsTotal = toSeconds yearLength | ||
294 | in | ||
295 | (str $ printf "Day %d of %d\nSecond %s of %s\n%s seconds remain" | ||
296 | dayNum | ||
297 | numDays | ||
298 | (commas secondsNow) | ||
299 | (commas secondsTotal) | ||
300 | (commas $ secondsTotal - secondsNow) | ||
301 | ) : remains | ||
302 | ) | ||
303 | remains = | ||
304 | [ | ||
305 | strWhen (hoursLeft >= 24) $ | ||
306 | printf "%d day%s remain%s" | ||
307 | daysLeft | ||
308 | (pluralize daysLeft) | ||
309 | (pluralizeVerb daysLeft), | ||
310 | |||
311 | strWhen (hoursLeft < 24 && hoursLeft > 1) $ | ||
312 | printf "%s hour%s remain%s" | ||
313 | (commasF 2 hoursLeft) | ||
314 | (pluralize $ (floor hoursLeft :: Integer)) | ||
315 | (pluralizeVerb $ (floor hoursLeft :: Integer)), | ||
316 | |||
317 | strWhen (hoursLeft <= 1 && minutesLeft > 1) $ | ||
318 | printf "%s minute%s remain%s" | ||
319 | (commasF 2 minutesLeft) | ||
320 | (pluralize $ (floor minutesLeft :: Integer)) | ||
321 | (pluralizeVerb $ (floor minutesLeft :: Integer)), | ||
322 | |||
323 | strWhen (minutesLeft <= 1) $ | ||
324 | printf "%s second%s remain%s" | ||
325 | (commasF' 1 secondsLeft) | ||
326 | (pluralize secondsLeft) | ||
327 | (pluralizeVerb secondsLeft) | ||
328 | ] | ||
329 | |||
330 | cosmicTimeBox = | ||
331 | (borderWithLabel (str "Cosmic Time") $ | ||
332 | vBox [(str $ printf "%s years" (commas $ (floor cosmicYears :: Integer))), | ||
333 | str "\n", | ||
334 | (str $ printf "%s years ago" (commas $ (floor cosmicYearsAgo :: Integer))) | ||
335 | -- , (str $ printf "%s years ago" (showLarge $ (realToFrac cosmicYearsAgo))) | ||
336 | -- , (str $ printf "%s billion years ago" (commasF 9 $ cosmicYearsAgo / (1000*1000*1000))) | ||
337 | -- , (str $ printf "%s million years ago" (commasF 6 $ cosmicYearsAgo / (1000*1000))) | ||
338 | -- , (str $ printf "%s thousand years ago" (commasF 3 $ cosmicYearsAgo / 1000)) | ||
339 | -- , (str $ printf "%s days ago" (commas $ (floor $ realToFrac cosmicYearsAgo * daysPerYear :: Integer))) | ||
340 | ]) | ||
341 | currentTimeBox = (hCenter (borderWithLabel (str $ printf "Current time%s" (if isSimulated then " (SIMULATED)" else "" :: String)) $ | ||
342 | padLeftRight 3 $ (str (formatTime defaultTimeLocale "%A, %B %e%n%Y-%m-%d %r" t)))) | ||
343 | cosmicYears = realToFrac ageOfUniverseInYears * (realToFrac $ (yearElapsed // yearLength)) :: Rational | ||
344 | cosmicYearsAgo = realToFrac ageOfUniverseInYears * (realToFrac $ 1 - (yearElapsed // yearLength)) :: Rational | ||
345 | -- cosmicYearsAgo = if yearElapsed == yearLength | ||
346 | -- then 0 | ||
347 | -- else realToFrac ageOfUniverseInYears * (realToFrac $ 1 - (yearElapsed // yearLength)) :: Rational | ||
348 | currentYear = yearNumber t | ||
349 | dayNum = dayNumOfYear t | ||
350 | numDays = daysInYear t | ||
351 | -- yearLength = fromIntegral numDays * nominalDay | ||
352 | yearLength = yearEnd t `diffLocalTime` yearStart t | ||
353 | yearElapsed = t `diffLocalTime` yearStart t | ||
354 | |||
355 | daysLeft = numDays - dayNum | ||
356 | hoursLeft = minutesLeft / 60 | ||
357 | minutesLeft = fromRational $ toRational secondsLeft / 60 :: Double | ||
358 | toSeconds = floor . nominalDiffTimeToSeconds | ||
359 | secondsLeft = nominalDiffTimeToSeconds (yearLength - yearElapsed) | ||
360 | x // y = fromRational $ toRational x / toRational y :: Double | ||
361 | progressLabel = printf "%.6F%%" (100 * (yearElapsed // yearLength)) | ||
362 | |||
363 | commasF' 1 n = if (floor (n * 10) `mod` 10 :: Int) == 0 then commasF 0 n `Text.append` " " else commasF 1 n | ||
364 | commasF' p n = commasF p n | ||
365 | |||
366 | commasF', commasF :: RealFrac x => Int -> x -> Text | ||
367 | commasF precision = prettyF cfg | ||
368 | where | ||
369 | cfg = PrettyCfg precision (Just ',') '.' | ||
370 | |||
371 | commas :: Integral i => i -> Text | ||
372 | commas = prettyI (Just ',') . fromIntegral | ||
373 | |||
374 | nextTenthOfSecond :: ZonedTime -> ZonedTime | ||
375 | nextTenthOfSecond (ZonedTime (LocalTime day (TimeOfDay h m s)) z) = (ZonedTime (LocalTime day (TimeOfDay h m s')) z) | ||
376 | where | ||
377 | s' = fromRational $ toRational (floor (s * 10) + 1 :: Integer) / 10 | ||
378 | |||
379 | nextWholeSecond :: ZonedTime -> ZonedTime | ||
380 | nextWholeSecond (ZonedTime (LocalTime day (TimeOfDay h m s)) z) = (ZonedTime (LocalTime day (TimeOfDay h m s')) z) | ||
381 | where | ||
382 | s' = fromIntegral $ (floor s + 1 :: Int) | ||
383 | |||
384 | diffZonedTime :: ZonedTime -> ZonedTime -> NominalDiffTime | ||
385 | diffZonedTime = diffLocalTime `Prelude.on` zonedTimeToLocalTime | ||
386 | |||
387 | isNewYearsEve :: LocalTime -> Bool | ||
388 | isNewYearsEve t = dayNumOfYear t == daysInYear t | ||
389 | |||
390 | queueNextEvent :: MonadIO m => Bool -> BChan CustomEvent -> m ZonedTime | ||
391 | queueNextEvent hyper chan = liftIO $ do | ||
392 | now <- getZonedTime | ||
393 | void . forkIO $ do | ||
394 | |||
395 | let getNext = if hyper then nextTenthOfSecond else nextWholeSecond | ||
396 | next = getNext now | ||
397 | delay = next `diffZonedTime` now | ||
398 | threadDelay $ floor $ delay * 1000 * 1000 | ||
399 | writeBChan chan $ TimeChanged next | ||
400 | return now | ||
401 | |||
402 | isSimulatedTime :: St -> Bool | ||
403 | isSimulatedTime st = st ^. stDisplayTime /= st ^. stClockTime | ||
404 | |||
405 | nextCalendarEntryTime :: LocalTime -> LocalTime | ||
406 | nextCalendarEntryTime t = fromMaybe t $ getNextCalendarEntry theCalendar t <&> (`addLocalTime` yearStart t) . calBeginTime | ||
407 | |||
408 | previousCalendarEntryTime :: LocalTime -> LocalTime | ||
409 | previousCalendarEntryTime t = fromMaybe t $ goBack t | ||
410 | where | ||
411 | goBack t = getPreviousCalendarEntry theCalendar t <&> (`addLocalTime` yearStart t) . calBeginTime | ||
412 | |||
413 | handleEvent :: BChan CustomEvent -> St -> BrickEvent () CustomEvent -> EventM () (Next St) | ||
414 | handleEvent chan st e = | ||
415 | case e of | ||
416 | VtyEvent (V.EvKey V.KEsc []) -> halt st | ||
417 | VtyEvent (V.EvKey (V.KChar 'p') []) -> cont $ st & stPaused %~ not | ||
418 | VtyEvent (V.EvKey (V.KFun 1) []) -> cont $ st & stPaused %~ not | ||
419 | |||
420 | VtyEvent (V.EvKey V.KRight [MShift]) -> cont $ st & stDisplayTime %~ (addLocalTime (1)) | ||
421 | VtyEvent (V.EvKey V.KLeft [MShift]) -> cont $ st & stDisplayTime %~ (addLocalTime (-1)) | ||
422 | |||
423 | VtyEvent (V.EvKey V.KRight [MCtrl]) -> cont $ st & stDisplayTime %~ (addLocalTime (60)) | ||
424 | VtyEvent (V.EvKey V.KLeft [MCtrl]) -> cont $ st & stDisplayTime %~ (addLocalTime (-60)) | ||
425 | |||
426 | VtyEvent (V.EvKey V.KPageDown [MCtrl]) -> cont $ st & stDisplayTime %~ (addLocalTime (60 * 60)) | ||
427 | VtyEvent (V.EvKey V.KPageUp [MCtrl]) -> cont $ st & stDisplayTime %~ (addLocalTime (-60 * 60)) | ||
428 | VtyEvent (V.EvKey V.KPageDown []) -> cont $ st & stDisplayTime %~ (addLocalTime lengthOfDay) | ||
429 | VtyEvent (V.EvKey V.KPageUp []) -> cont $ st & stDisplayTime %~ (addLocalTime (-lengthOfDay)) | ||
430 | |||
431 | VtyEvent (V.EvKey V.KHome []) -> cont $ st & stDisplayTime .~ (st ^. stClockTime) | ||
432 | VtyEvent (V.EvKey V.KHome [MShift]) -> cont $ st & stDisplayTime .~ (yearStart $ st ^. stClockTime) | ||
433 | VtyEvent (V.EvKey V.KEnd []) -> cont $ st & stDisplayTime .~ (newYearsEveLast10 $ st ^. stClockTime) | ||
434 | VtyEvent (V.EvKey V.KEnd [MShift]) -> cont $ st & stDisplayTime .~ (yearEnd $ st ^. stClockTime) | ||
435 | VtyEvent (V.EvKey V.KEnd [MCtrl]) -> cont $ st & stDisplayTime .~ (newYearsEveNoon $ st ^. stClockTime) | ||
436 | |||
437 | VtyEvent (V.EvKey V.KRight []) -> cont $ st & stDisplayTime %~ nextCalendarEntryTime | ||
438 | VtyEvent (V.EvKey V.KLeft []) -> cont $ st & stDisplayTime %~ previousCalendarEntryTime | ||
439 | VtyEvent (V.EvKey (V.KChar '.') []) -> cont $ st & stDisplayTime %~ nextCalendarEntryTime | ||
440 | VtyEvent (V.EvKey (V.KChar ',') []) -> cont $ st & stDisplayTime %~ previousCalendarEntryTime | ||
441 | |||
442 | VtyEvent (V.EvKey (V.KChar 'c') []) -> cont $ st & stShowConversion %~ not | ||
443 | VtyEvent (V.EvKey (V.KFun 2) []) -> cont $ st & stShowConversion %~ not | ||
444 | |||
445 | VtyEvent _ -> cont st | ||
446 | AppEvent (TimeChanged now) -> do | ||
447 | let hyper = isNewYearsEve $ st ^. stDisplayTime | ||
448 | void $ queueNextEvent hyper chan | ||
449 | let oldTime = st ^. stClockTime | ||
450 | cont $ st & stClockTime .~ (zonedTimeToLocalTime now) | ||
451 | & stDisplayTime %~ if st ^. stPaused then id else addLocalTime $ zonedTimeToLocalTime now `diffLocalTime` oldTime | ||
452 | _ -> cont st | ||
453 | where | ||
454 | cont s = do | ||
455 | continue $ s & stLastBrickEvent .~ (Just e) | ||
456 | |||
457 | newYearsEveLast10 :: LocalTime -> LocalTime | ||
458 | newYearsEveLast10 = addLocalTime (-11) . yearEnd | ||
459 | |||
460 | newYearsEveNoon :: LocalTime -> LocalTime | ||
461 | newYearsEveNoon (LocalTime d (TimeOfDay _ _ s)) = LocalTime d' t | ||
462 | where | ||
463 | (y, _) = toOrdinalDate d | ||
464 | d' = fromOrdinalDate y 366 | ||
465 | t = TimeOfDay 12 0 s' | ||
466 | s' = s `mod'` 1 -- keep the fractional part so we still tick the display on the same schedule | ||
467 | |||
468 | initialState :: LocalTime -> St | ||
469 | initialState t = | ||
470 | St { _stLastBrickEvent = Nothing | ||
471 | , _stClockTime = t | ||
472 | , _stDisplayTime = t | ||
473 | , _stNextEvent = Nothing | ||
474 | , _stPaused = False | ||
475 | , _stShowConversion = False | ||
476 | } | ||
477 | |||
478 | daysInYear :: LocalTime -> Int | ||
479 | daysInYear (toGregorian . localDay -> (y, _, _)) = if isLeapYear y then 366 else 365 | ||
480 | |||
481 | theBaseAttr :: A.AttrName | ||
482 | theBaseAttr = A.attrName "theBase" | ||
483 | |||
484 | xDoneAttr, xToDoAttr :: A.AttrName | ||
485 | xDoneAttr = theBaseAttr <> A.attrName "X:done" | ||
486 | xToDoAttr = theBaseAttr <> A.attrName "X:remaining" | ||
487 | |||
488 | yDoneAttr, yToDoAttr :: A.AttrName | ||
489 | yDoneAttr = theBaseAttr <> A.attrName "Y:done" | ||
490 | yToDoAttr = theBaseAttr <> A.attrName "Y:remaining" | ||
491 | |||
492 | zDoneAttr, zToDoAttr :: A.AttrName | ||
493 | zDoneAttr = theBaseAttr <> A.attrName "Z:done" | ||
494 | zToDoAttr = theBaseAttr <> A.attrName "Z:remaining" | ||
495 | |||
496 | theMap :: A.AttrMap | ||
497 | theMap = A.attrMap V.defAttr | ||
498 | [ (theBaseAttr, bg V.brightBlack) | ||
499 | , (xDoneAttr, V.black `on` V.white) | ||
500 | , (xToDoAttr, V.white `on` V.black) | ||
501 | , (yDoneAttr, V.magenta `on` V.yellow) | ||
502 | , (zDoneAttr, V.blue `on` V.green) | ||
503 | , (zToDoAttr, V.blue `on` V.red) | ||
504 | , (P.progressIncompleteAttr, fg V.yellow) | ||
505 | ] | ||
506 | |||
507 | theApp :: BChan CustomEvent -> App St CustomEvent () | ||
508 | theApp chan = | ||
509 | App { appDraw = drawUI | ||
510 | , appChooseCursor = showFirstCursor | ||
511 | , appHandleEvent = handleEvent chan | ||
512 | , appStartEvent = return | ||
513 | , appAttrMap = const theMap | ||
514 | } | ||
515 | |||
516 | main :: IO () | ||
517 | main = do | ||
518 | chan <- newBChan 10 | ||
519 | |||
520 | let buildVty = V.mkVty V.defaultConfig | ||
521 | initialVty <- buildVty | ||
522 | now <- queueNextEvent False chan | ||
523 | void $ customMain initialVty buildVty (Just chan) (theApp chan) (initialState $ zonedTimeToLocalTime now) | ||