diff --git a/week1/week1.hoon b/101/week1/week1.hoon similarity index 100% rename from week1/week1.hoon rename to 101/week1/week1.hoon diff --git a/week2/week2.hoon b/101/week2/week2.hoon similarity index 100% rename from week2/week2.hoon rename to 101/week2/week2.hoon diff --git a/101/week3/assignment_3a.hoon b/101/week3/assignment_3a.hoon new file mode 100644 index 0000000..5d60635 --- /dev/null +++ b/101/week3/assignment_3a.hoon @@ -0,0 +1,24 @@ +:: Hoon 101: Assignment 3a. Comment each line of code to tell the reader what the code is doing. +:: Comments should be written as "breathing comments" as suggested in the Hoon Style Guide: https://urbit.org/docs/learn/hoon/style/ + +:: create a gate, with the sample @ud, given the face n +:: +|= n=@ud +:: attach a 't' faced @ud to the subject, with the value 1 +:: +=/ t=@ud 1 +:: create and execute a gate, such that we can recurse back to this point +:: +|- +:: if n is 1, return the next child, otherwise the one after +:: +?: =(n 1) +:: at the end, return our total +:: + t +:: otherwise recurse with n minus one, +:: and t multiplied by n. note t is +:: not reset with the recurse, as it +:: is attached before our recurse point +:: +$(n (dec n), t (mul t n)) diff --git a/101/week3/week3.hoon b/101/week3/week3.hoon new file mode 100644 index 0000000..2ae12a5 --- /dev/null +++ b/101/week3/week3.hoon @@ -0,0 +1,8 @@ +|= a=(list *) +=/ n=@ud 1 +|- +?~ a + %napoleonesque-list +?: =(3 n) + i.a +$(n +(n), a t.a) diff --git a/101/week3/week3.txt b/101/week3/week3.txt new file mode 100644 index 0000000..f6792ed --- /dev/null +++ b/101/week3/week3.txt @@ -0,0 +1,36 @@ +:: Hoon 101: Assignment 3a. Comment each line of code to tell the reader what the code is doing. +:: Comments should be written as "breathing comments" as suggested in the Hoon Style Guide: https://urbit.org/docs/learn/hoon/style/ + +:: create a gate, with the sample @ud, given the face n +:: +|= n=@ud +:: attach a 't' faced @ud to the subject, with the value 1 +:: +=/ t=@ud 1 +:: create and execute a gate, such that we can recurse back to this point +:: +|- +:: if n is 1, return the next child, otherwise the one after +:: +?: =(n 1) +:: at the end, return our total +:: + t +:: otherwise recurse with n minus one, +:: and t multiplied by n. note t is +:: not reset with the recurse, as it +:: is attached before our recurse point +:: +$(n (dec n), t (mul t n)) + +:: Hoon 101 - Week 3 Assignment +:: ~bannum-magtus | s@p7.co.nz +:: +|= a=(list *) +=/ n=@ud 1 +|- +?~ a + %napoleonesque-list +?: =(3 n) + i.a +$(n +(n), a t.a) diff --git a/101/week4/week4.hoon b/101/week4/week4.hoon new file mode 100644 index 0000000..df55391 --- /dev/null +++ b/101/week4/week4.hoon @@ -0,0 +1,40 @@ +:: Hoon 101 - Week 4 +:: ~bannum-magtus || s@p7.co.nz +:: +|= n=@ +^- @ +=< (wrrrm n) +|% +:: +:: the atom made a 'clink' as it fell into the hole +++ clink + |= [a=@ b=@] + ^- ? + =(0 (mod a b)) +:: +:: there was a 'clunk' as the atom fell multiple times +++ clunk + |= a=@ + ^- ? + ?| + (clink a 3) + (clink a 5) + == +:: +:: a 'bzzrp' was heard as certain atoms were vapourised +++ bzzrp + |= a=@ + ?: (clunk a) + a + 0 +:: +:: 'wrrrm' was all you could hear as the machine started up +++ wrrrm + |= x=@ + ^- @ + %- roll + :_ add + %- turn + :_ bzzrp + (gulf 1 x) +-- diff --git a/101/week5/goldman.hoon b/101/week5/goldman.hoon new file mode 100644 index 0000000..b652b5b --- /dev/null +++ b/101/week5/goldman.hoon @@ -0,0 +1,89 @@ +:: create a gate taking an atom as input, giving it the face 'n' +:: +|= n=@ +:: compose the calling of `goldbach` with the core containing goldbach +:: this has the effect of `running` the core when the outer gate is run +:: +=< (goldbach n) +:: form a core +:: +|% +:: create an arm named 'prime' +:: +++ prime + :: create a gate with an atom input given the face 'n' + :: + |= n=@ + :: typecast the output to a flag + :: + ^- ? + :: if n is less than two, return false, otherwise return the other branch + :: + ?: (lth n 2) | + :: if n is less than 4, return true, otherwise return the other branch + :: + ?: (lth n 4) & + :: add the atom named i to the subject, set to 2 + :: + =/ i=@ 2 + :: add the atom named j to the subject, set to 2 + :: + =/ j=@ 2 + :: create a gate and typecast the output to a flag + :: + |- ^- ? + :: if i * j equals n, return false, otherwise return the other branch + :: + ?: =((mul i j) n) | + :: if j is equal to n/2, return true, otherwise return the other branch + :: + ?: =(j (div n 2)) & + :: if i*j is greater than n, return the first branch, else the second + :: + ?: (gth (mul i j) n) + :: call the current battery (defined at the gate) with a modified payload + :: of i set to 2, and j incremented by one + :: + $(i 2, j +(j)) + :: call the current battery with the modified payload of i incremented by one + :: + $(i +(i)) +:: start a new arm called goldbach (this arm gets called with the tisgal) +:: +++ goldbach + :: create a gate with an input atom faced 'n' + :: + |= n=@ + :: typecast the output as a union of a flag (?) + :: and a cell of a cell of atoms, and a flag ([[@ @] ?]) + :: + ^- ?(? [[@ @] ?]) + :: if one of; n is less than 4, or n is odd, is true, return false + :: otherwise return the other branch + :: + ?: |((lth n 4) =((mod n 2) 1)) | + :: attach an atom name i to the subject, set to 2 + :: + =/ i=@ 2 + :: attach an atom name i to the subject, set to n minus 2 + :: + =/ j=@ (sub n 2) + :: create a trap, and typecast the output to the aformentioned union of + :: flag and cell of cell of atoms, and flag + :: + |- ^- ?(? [[@ @] ?]) + :: if both i and j are prime numbers, return a cell of: + :: a cell of i and j, and a false flag + :: otherwise return the other branch + :: + ?: &((prime i) (prime j)) [[i j] |] + :: if n is equal to i plus 2, return a true flag, otherwise the next branch + :: + ?: =((add 2 i) n) & + :: run the current battery, with an updated payload of + :: i incremented, and j decremented + :: + $(i +(i), j (dec j)) +:: close off the core +:: +-- :: this is for my pal ~rapfyr-diglyt diff --git a/101/week5/morse.hoon b/101/week5/morse.hoon new file mode 100644 index 0000000..e474fe6 --- /dev/null +++ b/101/week5/morse.hoon @@ -0,0 +1,64 @@ +:: the comment ":: code belongs here" indicates that one or more lines of code are needed to make this section of the program work. +|= raw=tape +=< +=. raw (cuss raw) +(convert raw) +|% +:: the latest and greatest rapper +++ mcelem + |= l=@t + ?| + &((gte l 'A') (lte l 'Z')) + &((gte l '0') (lte l '9')) + == +++ convert + |= m=tape + ^- tape + %- zing + %+ turn m + |= l=@t + ?: =(l ' ') + "[_]" + ?: (mcelem l) + ~[' ' (~(got by table) l) ' '] + ~['[' l ']'] +++ table + %- my + :~ :- 'A' '.-' + :- 'B' '-...' + :- 'C' '-.-.' + :- 'D' '-..' + :- 'E' '.' + :- 'F' '..-.' + :- 'G' '--.' + :- 'H' '....' + :- 'I' '..' + :- 'J' '.---' + :- 'K' '-.-' + :- 'L' '.-..' + :- 'M' '--' + :- 'N' '-.' + :- 'O' '---' + :- 'P' '.--.' + :- 'Q' '--.-' + :- 'R' '.-.' + :- 'S' '...' + :- 'T' '-' + :- 'U' '..-' + :- 'V' '...-' + :- 'W' '.--' + :- 'X' '-..-' + :- 'Y' '-.--' + :- 'Z' '--..' + :- '0' '-----' + :- '1' '.----' + :- '2' '..---' + :- '3' '...--' + :- '4' '....-' + :- '5' '.....' + :- '6' '-....' + :- '7' '--...' + :- '8' '---..' + :- '9' '----.' + == +-- diff --git a/101/week6/cards.hoon b/101/week6/cards.hoon new file mode 100644 index 0000000..4e278b7 --- /dev/null +++ b/101/week6/cards.hoon @@ -0,0 +1,61 @@ +:: Hoon 101 - Week 6 +:: ~bannum-magtus || s@p7.co.nz +:: +:- %say +|= [[* eny=@uvJ *] [x=@ y=@ ~] ~] +:- %noun +?: (gth (mul x y) 52) + !! +=< +:: Im so sorry +(take-hands x y new-deck) +|% +++ take-hands + |= [x=@ y=@ d=(list tape)] + ^- (list (list tape)) + =/ hands=(list (list tape)) ~ + |- + ?: =(x 0) + hands + %= $ + hands :-((scag y d) hands) + d (slag y d) + x (dec x) + == +++ suit-store + ^- (list tape) + ["H" "D" "C" "S" ~] +++ suit-donnees + ^- (list tape) + ["A" "2" "3" "4" "5" "6" "7" "8" "9" "10" "J" "Q" "K" ~] +++ new-deck + =/ nd=(list tape) ~ + =/ s 0 + |- + ?: (gte s 4) + (shuffle-deck nd eny) + =/ v 0 + |- + ?. (lth v 13) + ^$(s +(s)) + %= $ + v +(v) + nd :-((weld (snag v suit-donnees) (snag s suit-store)) nd) + == +++ shuffle-deck + |= [unshuffled=(list tape) entropy=@] + ^- (list tape) + =| shuffled=(list tape) + =/ random ~(. og entropy) + =/ remaining (lent unshuffled) + |- + ?: =(remaining 1) + :_ shuffled + (snag 0 unshuffled) + =^ index random (rads:random remaining) + %= $ + shuffled (snag index unshuffled)^shuffled + remaining (dec remaining) + unshuffled (oust [index 1] unshuffled) + == +-- diff --git a/201/week1/poker.hoon b/201/week1/poker.hoon new file mode 100644 index 0000000..4c01e5b --- /dev/null +++ b/201/week1/poker.hoon @@ -0,0 +1,258 @@ +:: Hoon 201 - Week 1 +:: ~bannum-magtus || s@p7.co.nz +:: +:: im very sorry i messed up all my faces and i also dont know +:: how to make gates that make gates so this is messy code :( +:: dont leave your assignments until the last minute kids. +:: +/+ playing-cards +:- %say +|= [[* eny=@uv *] *] +:- %noun +=< +%- rank-hands +%- score-hands +%- sort-hands +%- draw-hands +[%pregame 4] +!: +|% ++$ title + $% %royal-flush + %straight-flush + %four-of-a-kind + %full-house + %flush + %straight + %three-of-a-kind + %two-pair + %pair + %high-card + == ++$ card darc:playing-cards ++$ suit suit:playing-cards ++$ deck deck:playing-cards ++$ grouped (list (list card)) ++$ unsorted (list card) ++$ sorted (list card) ++$ hands [g=grouped s=sorted u=unsorted] ++$ tiebreaker (list [v=@ s=@]) ++$ draw-phase-state [h=(list unsorted) d=deck] ++$ sort-phase-state [h=(list hands) d=deck] ++$ score-phase-state [s=(list [r=@ t=title h=hands b=tiebreaker]) d=deck] ++$ rank-phase-state (list [r=@ t=title h=unsorted]) +++ rank-hands + |= [%score st=score-phase-state] + ^- [%ranking rank-phase-state] + =. s.st (sort s.st rank-sort) + [%ranking (flop (rank-display s.st))] +++ rank-display + |= i=(list [* t=title h=hands *]) + ^- (list [r=@ t=title h=unsorted]) + =/ c=@ 1 + =| l=(list [r=@ t=title h=unsorted]) + |- + ?~ i l + =/ s [c t.i.i u.h.i.i] + %= $ + c .+(c) + l :-(s l) + i t.i + == +++ rank-sort + |= [a=[r=@ * * b=tiebreaker] b=[r=@ * * b=tiebreaker]] + ^- ? + ?. =(r.a r.b) + (gth r.a r.b) + (tb-comp b.a b.b) +++ tb-comp + |= [a=tiebreaker b=tiebreaker] + ^- ? + ?. =((lent a) (lent b)) + !! + |- + ?~ a %.y + ?~ b %.n + ?. =(v.i.a v.i.b) + (gth v.i.a v.i.b) + $(a t.a, b t.b) +++ draw-hands + |= [%pregame n=@] + =/ d=deck init-deck + =| h=(list unsorted) + ^- [%draw draw-phase-state] + |- + ?~ n [%draw [h d]] + =/ i (draw:playing-cards 5 d) + $(h :-(hand.i h), d rest.i, n (dec n)) +++ sort-hands + |= [%draw st=draw-phase-state] + ^- [%sort sort-phase-state] + [%sort [(turn h.st zip-sorted) d.st]] +++ card-sort + |= [a=card b=card] + ^- ? + (gth val.a val.b) +++ sort-hand + |= u=unsorted + ^- sorted + (sort u card-sort) +++ tuples + |= h=sorted + ^- grouped + =| c=(list card) + =| l=(list (list card)) + |- + ?~ h :-(c l) + ?~ c + %= $ + c [i.h ~] + h t.h + == + ?: =(val.i.c val.i.h) + %= $ + c :-(i.h c) + h t.h + == + %= $ + c ~ + l :-(c l) + == +++ zip-sorted + |= u=unsorted + ^- hands + =/ sh (sort-hand u) + =/ gh (tuples sh) + [gh sh u] +++ score-hands + |= [%sort st=sort-phase-state] + ^- [%score score-phase-state] + [%score (turn h.st con-tb) d.st] +++ init-deck + (shuffle-deck:playing-cards make-deck:playing-cards eny) +++ suit-to-num + |= c=darc:playing-cards + ^- @ + ?- sut.c + %spades 4 + %hearts 3 + %diamonds 2 + %clubs 1 + == +++ get-title + |= h=hands + ^- [t=title r=@] + ?: (is-royal-flush h) [%royal-flush 9] + ?: (is-straight-flush h) [%straight-flush 8] + ?: (is-four-of-a-kind h) [%four-of-a-kind 7] + ?: (is-full-house h) [%full-house 6] + ?: (is-flush h) [%flush 5] + ?: (is-straight h) [%straight 4] + ?: (is-three-of-a-kind h) [%three-of-a-kind 3] + ?: (is-two-pair h) [%two-pair 2] + ?: (is-pair h) [%pair 1] + [%high-card 0] +++ is-flush + |= [* h=sorted *] + ^- ? + =| s=?(~ suit) + |- + ?~ h %.y + ?~ s + $(h t.h, s sut.i.h) + ?. =(s sut.i.h) + %.n + $(h t.h) +++ is-straight + |= [* h=sorted *] + ^- ? + =| l=?(~ @) + |- + ?~ h %.y + ?~ l + $(h t.h, l val.i.h) + ?. =(.+(l) val.i.h) + %.n + $(l val.i.h, h t.h) +++ high-card + |= [* h=sorted *] + ^- card + ?~ h !! + i.h +++ is-royal-flush + |= i=[* h=sorted *] + ^- ? + ?& (is-straight-flush i) + =(13 val:(high-card i)) + == +++ is-straight-flush + |= i=[* h=sorted *] + ^- ? + ?& (is-straight i) + (is-flush i) + == +++ one-of + |= [n=@ [g=grouped * *]] + ^- @ + =| t=@ + |- + ?~ g t + ?: =(n (lent i.g)) + $(g t.g, t .+(t)) + $(g t.g) +++ is-four-of-a-kind + |= i=[g=grouped * *] + ^- ? + =(1 (one-of 4 i)) +++ is-full-house + |= i=[g=grouped * *] + ^- ? + ?& =(1 (one-of 3 i)) + =(1 (one-of 2 i)) + == +++ is-three-of-a-kind + |= i=[g=grouped * *] + ^- ? + =(1 (one-of 3 i)) +++ is-two-pair + |= i=[g=grouped * *] + ^- ? + =(2 (one-of 2 i)) +++ is-pair + |= i=[g=grouped * *] + ^- ? + =(1 (one-of 2 i)) +++ con-tb + |= fh=hands + =/ o=[t=title r=@] (get-title fh) + [r.o t.o fh (get-tiebreaker fh)] +++ get-tiebreaker + |= [g=grouped * *] + ^- tiebreaker + =. g (sort g tuple-sort) + (turn g tuple-tb) +++ tuple-tb + |= l=(list card) + ^- [v=@ s=@] + =| sv=@ + =| vv=@ + |- + ?~ l [vv sv] + =. vv val.i.l + ?. (gth (suit-to-num i.l) sv) + $(l t.l) + $(l t.l, sv (suit-to-num i.l)) +++ tuple-sort + |= [a=(list card) b=(list card)] + ^- ? + =/ la (lent a) + =/ lb (lent b) + ?. =(la lb) + (gth la lb) + ?~ a !! + ?~ b !! + ?: =(val.i.a val.i.b) + (gth (suit-to-num i.a) (suit-to-num i.b)) + (gth val.i.a val.i.b) +-- + diff --git a/201/week2/dfs.hoon b/201/week2/dfs.hoon new file mode 100644 index 0000000..31a7971 --- /dev/null +++ b/201/week2/dfs.hoon @@ -0,0 +1,42 @@ +:: Hoon 201 - Week 2 +:: ~bannum-magtus || s@p7.co.nz +:: +:: i could not figure out how to +:: cast the output of a wet gate +:: to a list of the same type :( +:: +:- %say +|= [* [t=(tree @) x=@ ~] *] +:- %noun +^- [? (list @)] +=< +:- (dfs-search t x) (dfs t) +|% +++ dfs + |= t=(tree @) + ^- (list @) + ?~ t + ~ + %+ weld + (dfs l.t) + %+ weld + (dfs r.t) + [n.t ~] +++ dfs-search + |= [t=(tree @) x=@] + ^- ? + ?~ t + %.n + ?| (dfs-search l.t x) + (dfs-search r.t x) + =(n.t x) + == + :: i assume ?| will stop as + :: soon as it sees a true, + :: otherwise below is better + :: + ::?: (dfs-search l.t x) %.y + ::?: (dfs-search r.t x) %.y + ::=(x n.t) +-- + diff --git a/201/week3/tarn.hoon b/201/week3/tarn.hoon new file mode 100644 index 0000000..e91d6a6 --- /dev/null +++ b/201/week3/tarn.hoon @@ -0,0 +1,12 @@ +:: Hoon 201 - Week 3 +:: ~bannum-magtus | s@p7.co.nz +:: +:: not sure how deep into the different variants +:: we needed to go, hope the kiss method works fine +:: +|* [l=(list) f=gate] +|- +?~ l + ~ +:- i=(f i.l) +f=$(l t.l) diff --git a/201/week4/egg.hoon b/201/week4/egg.hoon new file mode 100644 index 0000000..e010be6 --- /dev/null +++ b/201/week4/egg.hoon @@ -0,0 +1,18 @@ +|% ++$ effect (pair bone syscall) ++$ syscall [%wait path @da] +-- +|_ [bowl:gall ~] +++ poke-noun + |= t=@da + ?: (lth t now) + !! + ^+ [*(list effect) +>.$] + :_ +>.$ :_ ~ + [ost %wait /egg-timer t] +++ wake + |= [=wire error=(unit tang)] + ^+ [*(list effect) +>.$] + ~& "Timer went off!" + [~ +>.$] +-- diff --git a/201/week5/poke.hoon b/201/week5/poke.hoon new file mode 100644 index 0000000..b3e91dd --- /dev/null +++ b/201/week5/poke.hoon @@ -0,0 +1,53 @@ +/+ tapp, stdio +:: +=> + |% + +$ state + $: pokedex=(map cord json) + == + +$ peek-data _!! + +$ in-poke-data [%noun =cord] + +$ out-poke-data ~ + +$ in-peer-data ~ + +$ out-peer-data + $% [%pokemon json] + == + ++ tapp (^tapp state peek-data in-poke-data out-poke-data in-peer-data out-peer-data) + ++ stdio (^stdio out-poke-data out-peer-data) + -- +=> + |% + ++ comment-to-tang + |= =tape + ^- tang + %+ welp + %+ turn (rip 10 (crip tape)) + |= line=cord + leaf+(trip line) + [leaf+""]~ + ++ urls + =/ base "https://pokeapi.co/api/v2/" + :* pokemon=(weld base "pokemon/") + == + -- +=, async=async:tapp +=, tapp-async=tapp-async:tapp +=, stdio +:: +%- create-tapp-poke-peer-take:tapp +^- tapp-core-poke-peer-take:tapp +|_ [=bowl:gall state] +:: +++ handle-poke + |= =in-poke-data + =/ m tapp-async + =/ pokename cord.in-poke-data + ^- form:m + :: + ?: (~(has by state) pokename) + ~& 'pokemon already caught' + (pure:m (~(got by state) pokename)) + =/ pokeurl (weld pokemon:urls (trip pokename)) + %+ (set-timeout _json) (add now.bowl ~s15) + ;< =json bind:m (fetch-json pokeurl) + diff --git a/201/week6/lib/dfs.hoon b/201/week6/lib/dfs.hoon new file mode 100644 index 0000000..6888a13 --- /dev/null +++ b/201/week6/lib/dfs.hoon @@ -0,0 +1,24 @@ +:: depth first library +:: +|% +++ traverse + |= t=(tree @) + ^- (list @) + ?~ t + ~ + %+ weld + (traverse l.t) + %+ weld + (traverse r.t) + [n.t ~] +++ search + |= [t=(tree @) x=@] + ^- ? + ?~ t + %.n + ?| (search l.t x) + (search r.t x) + =(n.t x) + == +-- + diff --git a/201/week6/tests/lib/dfs.hoon b/201/week6/tests/lib/dfs.hoon new file mode 100644 index 0000000..6577e61 --- /dev/null +++ b/201/week6/tests/lib/dfs.hoon @@ -0,0 +1,44 @@ +:: Hoon 201 - Week 6 +:: ~bannum-magtus | s@p7.co.nz +:: +/+ *test, dfs +:: +|% +++ test-dfs-search ^- tang + =/ null-tree=(tree @) *(tree @) + =/ fill-tree=(tree @) [12 [8 [4 ~ ~] ~] [14 ~ [16 ~ ~]]] + ;: weld + :: cant find something in an empty tree + %+ expect-eq + !> %.n + !> (search:dfs null-tree 42) + :: cant find something thats not in a tree + %+ expect-eq + !> %.n + !> (search:dfs fill-tree 42) + :: can find something that is in a tree + %+ expect-eq + !> %.y + !> (search:dfs fill-tree 12) + == +++ test-dfs-traverse ^- tang + =/ null-tree=(tree @) *(tree @) + =/ a-tree=(tree @) [12 [8 [4 ~ ~] ~] [14 ~ [16 ~ ~]]] + =/ b-tree=(tree @) [8 [4 [12 ~ ~] ~] [16 ~ [14 ~ ~]]] + =/ a-list=(list @) [4 8 16 14 12 ~] + =/ b-list=(list @) [12 4 14 16 8 ~] + ;: weld + :: null tree has empty traversal + %+ expect-eq + !> ~ + !> (traverse:dfs null-tree) + :: tree a has traversal a + %+ expect-eq + !> a-list + !> (traverse:dfs a-tree) + :: tree b has traversal b + %+ expect-eq + !> b-list + !> (traverse:dfs b-tree) + == +-- diff --git a/README.md b/README.md index cc83841..f9e20dc 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,53 @@ My assignments for each week of Hoon 101. ## Week 2 > Build a naked generator that takes a noun and checks if that noun is a cell or an atom. If that input noun is an atom, check if it’s even or odd. The output should be of the tape type. + +## Week 3 + +> Build a naked generator that returns the third item of a list, without using standard library functions (in the core logic, could use (list) as the input) + +## Week 4 + +> Find the sum of all numbers that are a multiple of 3 or 5, [1..n] + +## Week 5 + +> morse code converter + +## Week 6 + +> Produce x hands of y cards from a deck of 52 distinct cards + +# Hoon 201 + +## Week 1 + +deal two poker hands and rank them + +## Week 2 + +Depth first search a tree + +## Week 3 + +Write +turn without stdlib + +## Week 4 + +Rewrite Egg-Timer (Gall App) to take an absolute date + +## Week 5 + +Write a Gall App that queries an api + +## Week 6 + +Write a test suite for a library + +## Week 7 + +Write a Modulo Tile for a simple Todo List + +## Week 8 + +Create something hopefully impressive