Commit graph

133 commits

Author SHA1 Message Date
William Carroll
05d52e403c Tweak styles
- Change header to blue
- Change habit to gray when completed
- Prefer app font for footer instead of monospaced font
2020-10-11 10:24:11 +01:00
William Carroll
0a15ea7366 Create UI module for common components
Create UI.elm to house components like `button`, which is a simple HTML button
with `focus:outline-none` applied as a `class`, which is an accessibility
feature that I don't need for this touch-screen application.

I like this pattern more than my more opinionated patterns for UI modules in Elm
where I'd define all of the arguments as a record type (i.e. kwargs).
2020-10-11 10:15:03 +01:00
William Carroll
106457de4b Prefer handwritten font
Use the Google Fonts API to fetch a handwritten font, which gives the app a
modicum of personality. There are more "best practices" ways to do this, such
as:

- Download the font once, and include it in the bundle
- Extend the Tailwind configure to recognize the font
- Ditch the inline <style> block

But I don't need the performance benefits that the first bullet provides. And
the second two bullets are more relevant for a larger application with more than
one font. So I think in this case, the easiest solution is best.

Also:
- Use `container` and `mx-auto` to constrain content for wide screens
2020-10-11 10:09:15 +01:00
William Carroll
19fbdad1c0 Support viewing different days
Allow users to browse the habits of the other days of the week.
2020-10-10 18:20:24 +01:00
William Carroll
487232d1aa Ensure weekday is updated
This ensures us that our view is consistent within ~1 minute of reality.
2020-10-10 17:34:14 +01:00
William Carroll
7d425de48d Tweak styles
- Increase font size for header
- Prefer a bulleted list
- Reduce horizontal padding
2020-10-10 17:31:34 +01:00
William Carroll
bfbe7dc988 Add a footer
With personal information and information about the project's stack.
2020-10-10 17:31:00 +01:00
William Carroll
df8e45681d Remove Nap from Saturday; prefer Yin Yoga
Since Warm Yin Yoga is at 15:00, it's difficult to attend that *and* nap.
2020-10-10 17:30:22 +01:00
William Carroll
9d331f3077 Begin working on Habit Screens project
Created a small MVP for digitizing my weekly habits. Much more to come.

Lots of things happening:

- Copied the boilerplate to get started
- Added a brief project-level README
- Outlined my ambitions in design.md

See README and design.md for more context on this project.
2020-10-10 17:04:24 +01:00
William Carroll
0f160a8029 Ignore comments in output for grocery export
TL;DR:
- Ignore lines starting with "#"
- Tidy up the code
2020-10-03 11:00:11 +01:00
William Carroll
a7aef84408 Update my grocery list for Bermondsey London
I haven't updated this list since I was living in Dargow, Germany over the
summer. Now that I've settled down, and I'm situated in the London Bridge area,
I'm updating the list.
2020-10-03 11:00:05 +01:00
William Carroll
33890d8a8b Move scratch/brilliant into //assessments
Where it belongs...
2020-08-20 11:26:32 +01:00
William Carroll
0c71fc9d1d Drop support for dir-locals.nix, <nixpkgs>, etc.
In the spirit of Marie Kondo, I'm tidying up!

TL;DR:
- Prefer .envrc `use_nix` and delete all dir-locals.nix files
- Remove ~all references to <nixpkgs>, <unstable>, <depot> and prefer
  referencing each with briefcase.third_party.{pkgs,unstable,depot}
- Delete nixBufferFromShell function since I was only using that in
  dir-locals.nix files
2020-08-20 11:26:32 +01:00
William Carroll
59f7481411 Revise previous opinions about absolute paths GT <bracket-notation>
Unforeseen problem: `buildkite-agent` runs its builds in a separate directory,
so if I want the `nix-build` command to build the newly checked out code, I need
to set <briefcase> to the CWD.
2020-08-20 11:26:31 +01:00
William Carroll
2da4b12266 Consume buildHaskell functions
Use the newly defined `buildHaskell` function for a few of my existing Haskell
projects. So far, it works as intended!
2020-08-12 16:28:39 +01:00
William Carroll
bba3f16c43 Prefer snake-shift instead of a row-by-row shift
Per the assignment's instructions, the `Shift n` operation should treat
the *entire keyboard* like a cycle and shift that. I was erroneously
treating *each row* like a cycle and shifting those one-by-one.

This change fixes that. In addition, it also:
- Updates README.md with expected inputs and outputs
- Updates test suite
- Adds `split` dependency to {default,shell}.nix
2020-08-12 12:03:35 +01:00
William Carroll
f11b91c985 Adds property tests to generically test keyboard transformations
Tests:
- HorizontalFlip
- VerticalFlip
- Shift n
2020-08-12 11:27:06 +01:00
William Carroll
f3ddd89302 Prefer literal, not computed, examples in the unit tests
TL:DR:
- Remove unused imports: Test.QuickCheck and Control.Exception
- Remove calls to `reverse` and `Utils.rotate` with their results
2020-08-12 11:07:37 +01:00
William Carroll
3d6130c7cf Provide more useful instructions for building this project
TL;DR:
- include a default.nix to allow users to build an named executable
- emphasize in the README that the user needs Nix to build this project
- pin nixpkgs to a specific commit and fetch it from GitHub
2020-08-12 10:28:04 +01:00
William Carroll
17e1764ef8 Generate coords function from existing qwerty keyboard
Per my take-home assignment's reviewer's comments, with which for the record I
agree, I should generate the character->coordinate table from my existing qwerty
keyboard definition.

The best part is: by doing this I found a bug: Notice how the original '0'
character was mapped to the Coordinate (0,0)... thus every subsequent digit
key (i.e. the first row) is off-by-one.
2020-08-12 09:46:36 +01:00
William Carroll
5f52077492 Re-type type using the altered keyboard
Remember: always read the instructions; that's the most important part.
2020-08-06 00:18:44 +01:00
William Carroll
e14fff7d4b Support Transforms.optimize
Partially optimize inputs and document rules for further optimizations we can
make.
2020-08-06 00:15:31 +01:00
William Carroll
d45685e245 Apply a series of transformation to a QWERTY keyboard
TL;DR:
- Accept input from the CLI
- Add a project README.md
2020-08-05 23:36:04 +01:00
William Carroll
244503bba9 Support App.transform
Apply the transform to a Keyboard. Onwards to the final demonstration!
2020-08-05 23:21:08 +01:00
William Carroll
61a2fb108d Support parsing the list of transforms
Using Haskell's Text.ParserCombinators.ReadP library for the first time, and I
enjoyed it thoroughly! It's nice avoiding a third-party library like MegaParsec.
2020-08-05 22:54:50 +01:00
William Carroll
d948ed9ebf Define an instance for Show for a Keyboard
This will help me debug.
2020-08-05 21:52:10 +01:00
William Carroll
1af0007a7d Create a Utils module
To stylize things...
2020-08-05 21:51:55 +01:00
William Carroll
40753e9f3b Add some the scaffolding for testing
As I attempt to habituate TDD, I should have some examples of tests to minimize
all friction preventing me from testing.
2020-08-05 21:37:08 +01:00
William Carroll
b1c403f6b9 Create small command line program that parses arguments
Before starting my take-home assignment, the instructions advised me to create a
"Hello, world" program in the language of my choice. Since I'm choosing Haskell,
I created this example as my starter boilerplate.
2020-08-04 16:36:31 +01:00
William Carroll
32480f1913 Move AOC into //scratch
Also rename it advent-of-code-2019 since I expect to participate this year as
well.

TODO: Should directories and files be name like-this or like_this?
2020-07-20 10:06:40 +01:00
William Carroll
a2475d2337 Partially complete IO chapter exercises
Inconveniently, I do not have the cipher code that I wrote from a previous
chapter, and I'm not eager to reimplement it.

TODO
- Implement encrypt
- Implement decrypt
- Read all characters from STDIN
2020-07-17 23:41:03 +01:00
William Carroll
3a2704eba2 Update grocery list
- Add new entries
- Change quantities of existing entries
2020-07-17 12:46:25 +01:00
William Carroll
0f1146cc4c Partially complete the "Basic Libraries" chapter exercises
I was instructed to benchmark these functions, but I couldn't get the
benchmarking library to run using Nix -- although I'm *sure* it's
possible. Unfortunately the book recommends using `stack`, which I couldn't
reproduce.
2020-07-17 11:39:44 +01:00
William Carroll
feb74b3091 Complete exercises for "Non-Strictness" chapter
I completed most of the exercises for this enlightening chapter in ghci.
2020-07-14 22:28:24 +01:00
William Carroll
e5abc3d675 Finish exercises for Monad Transformer chapter
I expect to look back on this code and cringe, but... it compiles!
2020-07-12 22:43:29 +01:00
William Carroll
5116cc3463 Partially complete Monad Transformer exercises
Write Functor, Applicative, Monad instances for:
- MaybeT
- EitherT
- ReaderT
2020-07-12 17:40:54 +01:00
William Carroll
3665ea457b Partially complete some of the exercises for Composing Types
I believe there are two exercises sets in the "Composing Types" chapter. Here
are *some* of my answers so far...

I'm having trouble implementing Foldable for Compose. I was able to implement a
version of it by adding the (Functor f) constraint to the instance signature,
but I think I cheated.

I will revisit these problems as well as the earlier exercises later.
2020-07-11 11:25:07 +01:00
William Carroll
155dff562a Impl part 3/3 for Memo
Refactor the caching policy for the Memo by evicting the elements that have been
the least-recently-accessed.

Python's heapq module default to a min-heap. By storing our heap elements
as (UnixTime, a), we can guarantee that when we call heappop, we will get the
element with the lowest UnixTime value in heap (i.e. the oldest). When we call
heappush, we use (time.time(), key) and these values -- by having the largest
UnixTime, will propogate to the bottom of the min-heap.
2020-07-01 15:13:56 +01:00
William Carroll
a8b3a2d3c0 Support part 2/3 for the Memo problem
Bound the size of the memo by creating a BoundedQueue. Whenever we add elements
to the BoundedQueue, we remove the oldest elements. We use the BoundedQueue to
control the size of our dictionary that we're using to store our key-value pairs.
2020-07-01 14:59:49 +01:00
William Carroll
ec7c8516f7 Implement part 1/3 for "Memo"
After hearing from a Jane Street recruiter, I decided to dust off some of the
DS&As knowledge. I found this article online, which outlines an example problem
called "Memo":

https://blog.janestreet.com/what-a-jane-street-dev-interview-is-like/

Here's part 1 of the solution in Python.
2020-07-01 14:40:40 +01:00
William Carroll
011f7aeaec Convert grocery list to an .org file
Ensure that the export.hs script refers to the .org file.
2020-07-01 10:45:28 +01:00
William Carroll
ee1aeee5f8 Complete exercises for Reader and State chapters
It's beautiful how State is just Reader that returns a tuple of (a, r) instead
of just a, allowing you to modify the environment (i.e. state).

```haskell
newtype Reader r a = Reader { runReader :: r -> a }
newtype State s a = State { runState :: s -> (a, s) }
```
2020-07-01 10:42:57 +01:00
William Carroll
c4fe3c92c7 Create a .ghci for this directory
I would've created on at $HOME/.ghci, but I don't need that yet, and I didn't
want to bother with home-manager.
2020-07-01 10:38:56 +01:00
William Carroll
d820898de5 Complete exercises from Traversable chapter
I feel much more comfortable using `traverse` and `sequenceA`. I even used both
of them in the Haskell program that I wrote at work to export a trix.
2020-07-01 10:37:54 +01:00
William Carroll
da24a38995 Group groceries/list
- Change list.txt -> list.org
- Group groceries by category
- Sort categories by store layout
2020-06-27 14:24:02 +01:00
William Carroll
25a45fb222 Add export script for groceries
At this point, I may be taking this idea too far, but what the heck?
2020-06-27 14:06:59 +01:00
William Carroll
362a31166d Create Nix shell for Haskell scratchpad
Helps me run my chapter exercises.
2020-06-18 11:08:55 +01:00
William Carroll
a981bb0d4a Complete the Monad chapter
From "Haskell Programming from First Principles"...

I have completed all of the exercises in the book thus far, but I only recently
dedicated a Haskell module for each chapter. Previously I created ad hoc modules
per exercise, per chapter... it was chaotic.
2020-06-18 11:07:55 +01:00
William Carroll
71e79f5f5d Complete exercises from Applicative chapter
From "Haskell Programming from First Principles"...
2020-06-18 11:07:03 +01:00
William Carroll
406764f552 Complete exercises from Foldable chapter
I'm creating Haskell modules to host my attempts and solutions for the exercises
defined in each chapter of "Haskell Programming From First Principles".
2020-06-18 11:05:49 +01:00
William Carroll
766a2a6b78 Add grocery list for Shaalsee
Mimi and I will go to the grocery store every Monday here. If we track what we
buy, we can easily generate grocery lists that get better over time.
2020-06-16 21:01:02 +01:00
William Carroll
b2849682d3 Progress with InterviewCake's coin problem
I'm writing a function that returns the total number of ways a cashier can make
change given the `amount` of change that the customer needs and an array of
`coins` from which to create the change.

My solution conceptually works but it actually does not return the results I am
expecting because I cannot create a Set of Map<A, B> in JavaScript. I'm also
somewhat sure that InterviewCake is expecting a less computationally expensive
answer.
2020-03-31 14:43:03 +01:00
William Carroll
8d36c6d00f Solve InterviewCake's compute nth Fibonacci
While the "Dynamic programming and recursion" section hosts this problem, the
optimal solution does not use recursion. Many cite the Fibonacci problem as a
quintessential dynamic programming question. I assume these people expect an
answer like:

```python
def fib(n):
  cache = {0: 0, 1: 1}
  def do_fib(n):
    if n in cache:
      return cache[n]
    else:
      cache[n - 1] = do_fib(n - 1)
      cache[n - 2] = do_fib(n - 2)
      return cache[n - 1] + cache[n - 2]
  return do_fib(n)
```

The cache turns the runtime of the classic Fibonacci solution...

```python
def fib(n):
  if n in {0, 1}:
    return n
  return fib(n - 1) + fib(n - 2)
```

... from O(2^n) to a O(n). But both the cache itself and the additional stacks
that the runtime allocates for each recursive call create an O(n) space
complexity.

InterviewCake wants the answer to be solved in O(n) time with O(1)
space. To achieve this, instead of solving fib(n) from the top-down, we solve it
from the bottom-up.

I found this problem to be satisfying to solve.
2020-03-30 14:14:02 +01:00
William Carroll
514136c99a Run Prettier across projects
Problem:
Prettier was not running when I saved Emacs buffers.

Why?
- prettier-js-mode needs needs node; lorri exposes node to direnv; direnv
  exposes node to Emacs; lorri was not working as expected.

Solution:
Now that I'm using nix-buffer, I can properly expose node (and other
dependencies) to my Emacs buffers. Now Prettier is working.

Commentary:
Since prettier hadn't worked for so long, I stopped thinking about it. As such,
I did not include it as a dependency in boilerplate/typescript. I added it
now. I retroactively ran prettier across a few of my frontend projects to unify
the code styling.

I may need to run...
```shell
$ cd ~/briefcase
$ nix-shell
$ npx prettier --list-different "**/*.{js,ts,jsx,tsx,html,css,json}"
```
...to see which files I should have formatted.
2020-03-27 10:59:50 +00:00
William Carroll
6b224a9e31 Drop support for lorri
Lorri does not cleanly integrate with my corporate device, which cannot run
NixOS. To expose dependencies to Emacs buffers, I will use nix-buffer.el, which
reads its values from dir-locals.nix. To easily expose dependencies from my
existing shell.nix files into dir-locals.nix, I wrote a Nix utility function.
2020-03-27 10:59:50 +00:00
William Carroll
2f817e4dd7 Solve InterviewCake's recursive string permutations problem
Write a function that returns the set of all of the possible permutations of an
input string. This function should be solved recursively.
2020-03-26 19:43:40 +00:00
William Carroll
062af32e4e Solve InterviewCake's find duplicate beast mode
Write a function to find a duplicate item in a list of numbers. The values are
in the range [1, n]; the length of the list is n + 1. The solution should run in
linear time and consume constant space.

The solution is to construct a graph from the list. Each graph will have a cycle
where the last element in the cycle is a duplicate value.

See the solution for specific techniques on how to compute the length the cycle
without infinitely looping.
2020-03-26 11:55:06 +00:00
William Carroll
ae9e83f5d7 Solve InterviewCake.com's mesh-message problem
Write a function that returns the shortest path between nodes A and B in an
unweighted graph.

I know two algorithms for finding the shortest path in a *weighted* graph:
- Use a heap as a priority queue instead of the regular queue that you would use
  when doing a BFT. This is called Dijkstra's algorithm. You can also use
  Dijkstra's algorithm in an unweight graph by imaginging that all of the
  weights on the edges are the same value (e.g. 1).
- Map the weighted graph into an unweighted graph by inserting N nodes between
  each node, X and Y, where N is equal to the weight of the edge between X and
  Y. After you map the weighted graph into an unweighted graph, perform a BFT
  from A to B. A BFT will always find the shortest path between nodes A and B in
  an unweighted graph.

I had forgotten that a BFT in an unweighted graph will always return the
shortest path between two nodes. I learned two things from InterviewCake.com's
solution:
1. I remembered that a BFT in an unweighted graph will return the shortest
   path (if one exists).
2. I learned to use a dictionary to store the edge information and then
   back-tracking to reconstruct the shortest path.
2020-03-20 16:49:49 +00:00
William Carroll
380a6a352c Solve InterviewCake's graph-coloring problem
Write a function that colors the nodes of a graph such that no two neighbors
share a color.
2020-03-19 12:31:24 +00:00
William Carroll
319652fe08 Solve InterviewCake's second-largest-item-in-bst
Return a function that returns the second largest item in a binary search
tree (i.e. BST).

A BST is a tree where each node has no more than two children (i.e. one left
child and one right child). All of the values in a BST's left subtree must be
less than the value of the root node; all of the values in a BST's right subtree
must be greater than the value of the root node; both left and right subtrees
must also be BSTs themselves.

I solved this problem thrice -- improving the performance profile each time. The
final solution has a runtime complexity of O(n) and a spacetime complexity of
O(1).
2020-03-16 11:45:34 +00:00
William Carroll
56d8d1d7b2 Solve InterviewCake's bst-checker problem
Write a function that returns true if a given binary tree is a valid binary
search tree (i.e. if all of root's left nodes are less than root.value, all of
root's right nodes are greater than root.value, and both left and right subtrees
are also valid binary search trees).
2020-03-15 23:09:29 +00:00
William Carroll
47a11b76a2 Solve InterviewCake's balanced-binary-tree problem
Write a predicate for determining if a binary tree is "super balanced", which
means that the depths of all of the tree's leaves are equal or differ by at most
one.
2020-03-14 12:48:37 +00:00
William Carroll
0f82a527de Mark duplicate InterviewCake questions as DONE
I wrongfully assumed that the relationship between a question and a question
category was one-to-one; it is actually one-to-many. This explains why I
completed the "Cafe Order Checker" and "Top Scores" questions twice.

I'm marking the questions that I've completed as DONE because I would prefer to
do every question once and then prioritize repeating the questions with which I
experienced difficulty.
2020-03-14 12:20:43 +00:00
William Carroll
bd67b07f52 Add default value for pkgs parameter in shell.nix
Commands like `nix-shell shell.nix` couldn't resolve `pkgs` without a default
value. I'm unsure how I expected this to work previously...
2020-03-13 16:52:40 +00:00
William Carroll
a2a5a62836 Solve InterviewCake's top-scores problem
Write a function to sort a list of scores for a game in linear time. While I had
previously solved this in python, I hadn't marked the todo.org file, so I ended
up doing this again.

"Perfect practice makes perfect."
2020-03-13 16:51:38 +00:00
William Carroll
452a8fd4c7 WIP: Partially solve InterviewCake's find duplicate number
Write a function that finds one duplicate number from a list of numbers 1..n.

The function should satisfy the following performance objectives:
Runtime complexity: O(n*log(n))
Space complexity:   O(1)
2020-03-10 15:01:30 +00:00
William Carroll
58ed992059 Solve InterviewCake's "find rotation point" problem
Write a function that accepts a rotated cycle of alphabetically sorted strings
and returns the index what should be the first element if the elements were not
rotated.
2020-03-10 13:27:11 +00:00
William Carroll
b04b1dafd2 Implement an in-place shuffling algorithm
I believe this may be the Fisher-Yates shuffle, but I'm not sure.
2020-03-06 18:45:55 +00:00
William Carroll
549e56186b Solve InterviewCake's product-of-other-numbers
This problem challenged me: without using division, write a function that maps a
list of integers into a list of the product of every integer in the list except
for the integer at that index.

This was another greedy algorithm. The take-away is to first solve the problem
using brute force; this yields an algorithm with O(n*(n-1)) time
complexity. Instead of a quadratic time complexity, a linear time complexity can
be achieved my iterating over the list of integers twice:
1. Compute the products of every number to the left of the current number.
2. Compute the products of every number to the right of the current number.

Finally, iterate over each of these and compute lhs * rhs. Even though I've
solved this problem before, I used InterviewCake's hints because I was stuck
without them.

I should revisit this problem in a few weeks.
2020-03-02 16:45:15 +00:00
William Carroll
b4689761d9 Solve InterviewCake's highest-product-of-3
Write a function that returns the highest product of three integers within a
list of integers. This solution uses a greedy algorithm that solves for the
answer in linear time. The space complexity is constant.
2020-03-01 22:32:25 +00:00
William Carroll
dff621922c Remove HTML-encoded quote
Prefer ' to &#39;
2020-03-01 22:32:25 +00:00
William Carroll
4d2d19f136 Solve InterviewCake's stock-price problem
Write a function that returns the maximum profit that a trader could have made
in a day. I solved this using a greedy algorithm which constantly sets the
maximum profit by tracking the lowest price we've encountered.
2020-03-01 22:32:25 +00:00
William Carroll
d2aa66a5b1 Solve InterviewCake's top-scores
Using a counting sort to sort a list of values in linear time.
2020-03-01 22:32:24 +00:00
William Carroll
e4cdb5daed Solve InterviewCake's word-cloud problem
Write a function to count the frequency of words in a sentence. Ignore casing
for words; ignore punctuation.
2020-03-01 22:32:24 +00:00
William Carroll
93d654df77 Solve InterviewCake permutation-palindrome problem
Write a predicate to test whether any permutation of an input string is a
palindrome.
2020-03-01 22:32:24 +00:00
William Carroll
9e0fdd3973 Remove default values for Nix expression parameters
I'm not sure if this commit breaks everything in my monorepo. I think it
will.

Why am I doing this? Perhaps it's a bad idea. I don't fully understand how
readTree works. My ignorance is costing me hours of time spent debugging. In an
effort to better understand readTree, I'm removing the default values for my Nix
expression parameters, which I believe have preventing errors from surfacing.
2020-03-01 22:32:24 +00:00
William Carroll
0dd3987821 Solve InterviewCake's inflight-entertainment problem
Write a predicate that tests whether two films in a list of films can exactly
fill the duration of a flight.
2020-02-21 11:30:01 +00:00
William Carroll
66c38f8656 Solve InterviewCake's cafe-order-checker problem
Write a predicate that tests if a given list of integers, zs, is a possible
interleaving of two other lists, xs and ys.
2020-02-20 15:20:58 +00:00
William Carroll
737bdd0a23 Solve InterviewCake's merge sorted arrays question
Write a function merging two sorted arrays into one sorted array.
2020-02-19 16:02:38 +00:00
William Carroll
ca6bd29ed8 Solve bonus part of reverse-words
InterviewCake asks "How would you handle punctuation?". Without precise specs
about what that entails, I'm supporting sentences ending with punctuation.
2020-02-19 15:01:42 +00:00
William Carroll
acf1b8c4f0 Solve InterviewCake's reverse-words
Wrote a function to reverse the words in a list of characters. A word is a
space-delimited strings of characters.

The trick here is to first reverse the entire string and then reverse each word
individually.
2020-02-19 15:01:42 +00:00
William Carroll
9fa97eab67 Solve merging-ranges
Write a function to merge meeting times. Added an in-place solution, which the
"Bonus" section suggested attempting to solve.

- Added some simple benchmarks to test the performance differences between the
  in-place and not-in-place variants. To my surprise, the in-place solution was
  consistently slower than the not-in-place solution.
2020-02-13 14:52:20 +00:00
William Carroll
fabf1c9334 Tidy up structure of briefcase
I had a spare fifteen minutes and decided that I should tidy up my
monorepo. The work of tidying up is not finished; this is a small step in the
right direction.

TL;DR
- Created a tools directory
- Created a scratch directory (see README.md for more information)
- Added README.md to third_party
- Renamed delete_dotfile_symlinks -> symlinkManager
- Packaged symlinkManager as an executable symlink-mgr using buildGo
2020-02-12 16:58:29 +00:00