` (and many other tags
+like `
`, ``, etc) will not find themselves in the tab order, so we'll
+have to put in some extra work. We'll start by specifying `tabindex="0"` on
+the tag.
+
+In the following example we've tabbed to the button and focused it (as shown
+by the black outline), and now we'll attempt to activate the button using the
+enter key (just as we would on a hyperlink or form).
+
+```html
+
Display
+```
+
+
+ Depicted below is the same demo as before, this time interacting with
+ the enter key. The button does not seem to do anything.
+
+
+
+Unfortunately, nothing happens :( Our "button" is listening for a click event,
+but we're attempting to activate it with a keyboard.
+
+Let's try and fix this by adding a `keypress` event handler.
+
+```html
+Display
+
+
+```
+
+
+ Depicted below is a demo of the code above interacting with the enter key.
+ The button now works similarly to the mouse pointer example before.
+
+
+
+I'll call that a success, sort of! The code's a bit longer now (even after
+a bit of refactoring), but it definitely works - our "button" can be
+activated with both a mouse and a keyboard, just like a real button.
+
+But hold on a second, why don't we just _use_ a real button?
+
+## Semantic buttons
+
+As I briefly mentioned earlier, there's nothing special about a ``. It
+doesn't have any magical behavior, it's just a container. We can shape it,
+paint it, and make it _look_ like a button, but it's not a button.
+
+We can write some extra JavaScript to make it _act_ like a button, but it's
+**not a button**.
+
+In fact, we're doing all this extra work (and often skipping it), when in
+reality we could just a real button, the semantic `
` tag. Let's try
+it.
+
+```html
+Display
+
+
+```
+
+
+ Depicted below is a demo of the code above interacting with both a mouse
+ pointer and the enter key. Both of these interactions work.
+
+
+
+
+
+Excellent! Now that we are using the semantic `` tag, **we get a click
+event for free**. No need to track both a `click` and `keypress` handler here,
+just a `click` will do.
+
+**It turns out that in order to make our button accessible, we don't have to
+do much.** In fact, the _only_ difference between our first example and this
+one is that we've replaced the `` with a `
` - seriously!
+
+## Sane markup goes a long way
+
+Beyond the obvious markup clarity and keyboard accessibility gains, we also
+unlock a few bonus features when we use a `` instead of a ``. For
+instance, a copy of VoiceOver on OSX will display the following:
+
+
+
+Letting users with screen readers know that "Display" corresponds to a button
+that can be activated with either their enter key or space bar.
+
+So go forth and prevent your contemporaries from skipping the semantic markup,
+make sure your buttons play nicely with the keyboard, and stop trying to copy
+browser behavior provided to you **for free**.
+
+It doesn't take much, but it makes a big difference.
diff --git a/hidden/2015-03-30-focus-and-hover-hand-in-hand.md b/hidden/2015-03-30-focus-and-hover-hand-in-hand.md
new file mode 100644
index 0000000..38006d0
--- /dev/null
+++ b/hidden/2015-03-30-focus-and-hover-hand-in-hand.md
@@ -0,0 +1,125 @@
+---
+title: Focus vs. Hover
+route: /a11y/focus-vs-hover
+date: 2015-04-03
+description: Visual interactions should never require a mouse, but a common CSS pattern leaves many keyboard-wielding visitors in the dark.
+tags: a11y
+---
+
+Visual interactions should never require a mouse.
+
+Consider the ever-popular `:hover` selector, which is used to declare styles
+on elements under a mouse cursor.
+
+```css
+.nav-link {
+ color: #ffffff;
+}
+
+.nav-link:hover {
+ opacity: 0.8;
+}
+```
+
+
+ The following example shows a mouse cursor hovering over various items
+ in a navigation bar which highlight as the mouse passes over them.
+
+
+
+
+
Home
+
About
+
Products
+
+
+
+If we attempt to access these buttons with a keyboard, however, we're met
+with an unfortunate short-coming.
+
+Nothing happens.
+
+
+ The following example is just a navigation bar with three links and no
+ animation, because we did not declare our styles correctly.
+
+
+
+
Home
+
About
+
Products
+
+
+
+Instead, we need to use the `:focus` selector, which is used to declare styles
+on focused elements - the items on the page that keyboards can highlight with
+subsequent presses of the tab key.
+
+**All we need to do is add the `:focus` selector**, so that it is applied in
+addition to the hover styles.
+
+```css
+.nav-link:hover,
+.nav-link:focus {
+ opacity: 0.8;
+}
+```
+
+Ta-da, now we get the same effect even when we're using a keyboard instead of
+a mouse! **This helps users keep track of their location in their page**, and
+also presents the same information that a mouse-wielding user would receive.
+
+
+ The example below shows three links on a nav bar highlighting in sequence
+ as a theoretical keyboard tabs to each of them.
+
+
+
+
Home
+
About
+
Products
+
+
+
+We can do still do better, though. Many of your visitors will be unable to
+detect subtle color changes (and, in some cases, very obvious ones!), so we'll
+add an underline to the link.
+
+It's okay if you don't want this on hover - since a mouse cursor is a good
+visual indicator in and of itself - but it's pretty essential to do this on
+focus for visitors using the keyboard.
+
+```css
+.nav-link:hover,
+.nav-link:focus {
+ opacity: 0.8;
+}
+
+.nav-link:focus {
+ text-decoration: underline;
+}
+```
+
+
+ The following example is the same as the previous example, but the links
+ also have an underline when focused.
+
+
+
+
Home
+
About
+
Products
+
+
+
+**Side note**: While browsers like Chrome _will_ declare a
+`focus-ring-color` outline for focused elements by default (a glowing blue
+outline), it's far too easy to accidentally remove these - and sadly many do!
+
+Adding a `:focus` rule is a trivial change with a potentially great impact, so
+there's no real reason not make use of it. Always keep keyboard accessibility
+in mind when writing style rules for interactions, and try not to leave any of
+your users in the dark.
diff --git a/hidden/2015-04-26-the-imperfect-development-setup.md b/hidden/2015-04-26-the-imperfect-development-setup.md
new file mode 100644
index 0000000..2da8f6f
--- /dev/null
+++ b/hidden/2015-04-26-the-imperfect-development-setup.md
@@ -0,0 +1,8 @@
+---
+title: The Imperfect Development Setup
+slug: the-imperfect-development-setup
+---
+
+I've put probably many days into my dev setup - the perfect font, the perfect
+color scheme, the perfect shortcut. And when I'm feeling unproductive, I think
+of the hours I've spent.
\ No newline at end of file
diff --git a/hidden/2015-07-28-building-jquery-elements-with-jsx.md b/hidden/2015-07-28-building-jquery-elements-with-jsx.md
new file mode 100644
index 0000000..de72e1b
--- /dev/null
+++ b/hidden/2015-07-28-building-jquery-elements-with-jsx.md
@@ -0,0 +1,38 @@
+---
+title: Building jQuery Elements with JSX
+date: 2015-07-28
+route: /jquery-and-jsx
+hidden: true
+---
+
+I've been spending a good amount of time with [tota11y](https://khan.github.io/tota11y), an accessibility visualization tool we shipped last month at Khan Academy. Specifically, spending time doing code cleanup to make it easier for contributors to wrap their head around how the tool works.
+
+tota11y is built with webpack, and written in ES6 using the wonderful Babel library. Its UI is mostly powered by jQuery. Now you're almost up to speed - that wasn't so bad, was it?
+
+Well, my jQuery chops are not very good, and tota11y rather quickly devolved into jQuery soup. tota11y is modular, meaning that each "plugin" lives in its own directory that encapsulates its logic, templates, and styling. It's clean and provides a lot of flexibility, but the boundaries between these modules is where things get a little suspicious.
+
+##
+
+```js
+let $toolbar = $(toolbarTemplate())
+$("body").append($toolbar)
+
+$toolbar.find(".tota11y-toolbar-toggle").click(e => {
+ e.preventDefault()
+ e.stopPropagation()
+ $toolbar.toggleClass("tota11y-expanded")
+})
+```
+
+Where `toolbarTemplate` corresponds to the following handlebars template.
+
+```html
+
+```
diff --git a/hidden/2015-08-10-reenergizing-my-love-for-web-development.md b/hidden/2015-08-10-reenergizing-my-love-for-web-development.md
new file mode 100644
index 0000000..1c43eb2
--- /dev/null
+++ b/hidden/2015-08-10-reenergizing-my-love-for-web-development.md
@@ -0,0 +1,92 @@
+---
+title: Falling in Love with Web Development Again
+route: /loving-web-development-again
+description: '"I''ve had a growing interest in accessibility lately. Screen readers, Braille keyboards, that sort of thing," I said, offhand.'
+date: 2015-08-10
+tags: a11y
+---
+
+During one of our weekly 1-on-1's, my manager [Marcia](https://twitter.com/marcia_lee) and I were speaking casually about some of the things I was interested in pursuing. I was a few months into my new job at [Khan Academy](https://khanacademy.org), building tools for teachers and parents.
+
+"I've had a growing interest in accessibility lately. Screen readers, Braille keyboards, that sort of thing," I said, offhand.
+
+My pal [Cassidy](https://twitter.com/cassidoo) had recently given a talk on accessibility, and I had been poking around Bootstrap's source code - seeing various mentions of this "aria" thing. It all seemed pretty nifty, but admittedly I knew _nothing_ about it, just that it helped people use the software I was writing.
+
+"Oh cool, I'll keep that in mind," replied Marcia (it was more enthusiastic than I can convey in a blog post). The rest of the walk was pretty normal - I think we saw some chickens that day.
+
+---
+
+Prior to starting my career, I spent a lot of my free time in college [building various things](/projects). I learned a lot this way - gaining some technical know-how, and even more non-technical skills like communication and time management.
+
+As I got into the groove of things at work, time passed, and my interests wandered. Issues built up, discussion died down, and I became less interested in the problems my open source projects were solving.
+
+**Because at the end of a long day of coding, writing more code isn't the most appealing thing in the world, and that's okay**. The unfortunate side-effect is that the way I used to learn technology - reckless experimentation - no longer held a significant presence in my day-to-day.
+
+Work was going well - really well in fact. I had the opportunity to
use cool technologies and solve interesting problems, but I wanted to make sure I still had opportunities to learn something _completely_ new. At work I had to follow style guidelines and deal with deadlines, while in college I'd spend three hours reading a rails tutorial and writing a blog engine I would never use.
+
+So, I was in a bit of a funk. I found myself reluctant to work on side projects, and was worried I wouldn't be leaving my comfort zone enough at work. I was hungry to attack something I had _zero_ experience with, just like I did in between classes in college.
+
+---
+
+An email found its way into my inbox about six weeks later.
+
+
+
+Word had spread that I was interested in accessibility (thanks Marcia), and an opportunity came up to do some related work as part of a new series of projects at Khan Academy. I happily accepted, and started doing some research.
+
+I found a [great talk on accessibility testing](https://www.youtube.com/watch?v=rxh6B3ChLIc) by Google's [Alice Boxhall](https://twitter.com/sundress). In it, she mentions [Accessibility Developer Tools](https://github.com/GoogleChrome/accessibility-developer-tools): a suite of tools for accessibility testing. "Neat! I know some of these words," I thought, and added the link to my in-progress "a11y-resources.txt".
+
+So I played around with [OSX's built-in screen reader](https://www.apple.com/voiceover/info/guide/), learned how folks with impaired vision or motor skills relied on the keyboard, and read up on some common accessibility mistakes.
+
+I started making blanket statements such as "These things can be completed in about a day" and "These things may take a week or more to fix." They were broad guesses, I had no idea what I was doing, and I was loving every minute of it. **Here I was, once again feeling my way around a new world of software development.** One day I'd think I knew something and the next I'd learn I was wrong.
+
+But I pushed forward and completed a write-up (my a11y puns have gotten way better since).
+
+
+
+Fun fact, not only was I terrible at accessibility, but I was also terrible at numeronyms - "Khan Academy" has _nine_ letters between the K and Y (or 10 if you count the space).
+
+---
+
+Thus began a few weeks of accessibility fixes: trying to fix things, not fixing them correctly, then learning and re-fixing. Each day my colleague [John](http://ejohn.org) and I would share links in our "Accessibility" HipChat room, and attempt to answer each other's questions.
+
+I realized that this sliver of software development was _far_ larger than I originally thought, and it was full of well-thought-out standards as well as many unknowns. Lots of work to be done, and I was excited to dive in head-first. I started
blogging again , and became overwhelmingly excited to learn and share.
+
+We built some testing infrastructure using [Accessibility Developer Tools](https://github.com/GoogleChrome/accessibility-developer-tools), caught some bugs, caught some things that _seemed_ like bugs, and started off on the monumental task of evangelizing web accessibility at Khan Academy.
+
+There were scary moments, of course. _What if I'm doing this wrong? What if I'm spreading misinformation? What if I'm making the experience even worse for people?_ But I kept an open mind, accepted the fact that mistakes would be made, and embraced my potential to figure it out.
+
+But there was one issue that stayed in the back of my head - I felt a _disconnect_ between my code and the issues it was causing. Other devs felt it too. I could preach all day about using the right tags with the right attributes, but how could I make these things more obvious? **How could I make accessibility development an interesting and informative experience?**
+
+---
+
+A few months later, during one of "Web Frontend" team meetings (don't worry, we don't quite know what the distinction is, either), I pitched this very idea - an interactive accessibility testing utility. I was still new to accessibility, everyone knew it, but folks agreed it seemed like an interesting idea. I didn't know what it would look like, I didn't know exactly what it would do, but I wanted to do it.
+
+So I did it.
+
+[](http://khan.github.io/tota11y)
+
+At the end of the month we released [tota11y](http://khan.github.io/tota11y) - an "accessibility visualization toolkit" - to the world, accompanied by [a post on our engineering blog](http://engineering.khanacademy.org/posts/tota11y.htm).
+
+The response was minimal, a few bites on social media at first, but people seemed to like it.
+
+
+
+
+Interestingly enough, tota11y was posted again (by someone else) to Hacker News a few weeks later, making its way to the top on a Monday morning and staying there until late in the evening.
+
+It was incredibly energizing to see so many folks talking about accessibility, many of whom were in the same boat as I was - web developers who knew it was a _thing_ but weren't sure how to approach the problem. But among those web developers were many who knew _a lot_ about accessibility. They spread the word, offered advice, and provided tons of motivating feedback.
+
+I learned a lot more from them as I went along, the most important lesson being that **everyone in this space is _so friggin' nice_. Like, seriously, _so nice_.** A bunch of approachable folks, eager to answer any question you throw at them. In my (admittedly short few) years in software, I've never come across a community as kind and welcoming.
+
+And it makes sense, given the work that they do, but it's just such a pleasant surprise.
+
+---
+
+**If you're looking for some cool things to learn, I highly encourage you to experience the wild world of accessibility and its amazing community.** There's a lot of room for improvement on the web, and chances are that your skills can impact many, many people. The barrier of entry is low, the impact is high, and you can [start learning wherever you'd like](http://a11yproject.com/).
+
+I get an incredible sense of satisfaction doing this work - whether it's running a screen reader on a new interface, adding a new feature to tota11y, or just interacting with folks in [the web-a11y slack channel](https://twitter.com/ryanflorence/status/578240236267773952). Each day brings a new challenge, and I feel empowered (and _excited_) to tackle it.
+
+Looking back on the past twelve months, I realize how quickly new interests can come forward and how, with time and care, you can learn a lot about new things. I'm still brand new to this field, and there's _so much_ more to learn, but I can't even begin to describe how excited I am for whatever's next.
+
+I've fallen in love with web development all over again.
diff --git a/hidden/2015-09-07-removing-collaborator-spam-from-your-github-feed.md b/hidden/2015-09-07-removing-collaborator-spam-from-your-github-feed.md
new file mode 100644
index 0000000..5ab5aef
--- /dev/null
+++ b/hidden/2015-09-07-removing-collaborator-spam-from-your-github-feed.md
@@ -0,0 +1,79 @@
+---
+title: Removing "Collaborator Spam" from Your GitHub Feed
+route: /github-collaborator-spam
+date: 2015-09-07
+description: Devious GitHub users are adding prominent members as collaborators to their repositories in an attempt to gain exposure. Here's how to stop it.
+hidden: true
+---
+
+I'm sick of seeing this garbage on GitHub.
+
+
+
+Project owners shamelessly adding dozens upon dozens of famous open source developers, in an attempt to get a link to their project on as many GitHub feeds as possible (while [chalking it up to "username errors"](https://github.com/joni2back/angular-filemanager/issues/59)). To be honest, I don't really care what repositories my friends get added to - even if legitimately. The feature has never proven useful to me.
+
+**Here's how to get rid of it.**
+
+## Using [AdBlock Plus](https://adblockplus.org/)
+
+We can remove the spammy elements from the page using a custom AdBlock filter. First, open up your extension settings (I'm using Chrome):
+
+
+
+Then, click the "Add your own filters" tab, enter the following filter string, and click "Add Filter":
+
+```
+github.com##.alert.member_add
+```
+
+
+
+This filter is made up of three parts:
+
+- `github.com` - the domain on which to filter
+- `##` - a separator
+- `.alert.member_add` - the CSS selector, matching the various `
` elements containing the spam
+
+Refresh your GitHub tab, and rejoice in your spam-free activity feed.
+
+## Using a custom userscript
+
+Alternatively, you can use the following userscript.
+
+```js
+// ==UserScript==
+// @name Remove collab spam
+// @description Removes "X added Y to Z" spam from the GitHub activity feed
+// @include https://github.com/*
+// ==/UserScript==
+//
+// by @jdan
+// MIT Licensed
+
+;[].slice
+ .call(document.querySelectorAll(".alert.member_add"))
+ .forEach(function(item) {
+ item.remove()
+ })
+```
+
+Copy and paste the above code into your favorite editor and save it as **remove-collab-spam.user.js**. In Chrome, you can simply drag this file into **chrome://extensions**.
+
+On Firefox, install [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/) and navigate to the Greasemonkey "User scripts" tab of **about:addons**.
+
+
+
+Drag the file here, then accept the following confirmation dialog.
+
+
+
+You can even customize the userscript to remove/keep elements containing particular usernames if you're into that sort of thing.
+
+```js
+// Always show tj-related activity items
+if (!/\/tj/.test(item.innerHTML)) {
+ item.remove()
+}
+```
+
+But I think we can safely remove 'em all :)
diff --git a/hidden/2015-10-15-ask-me-anything.md b/hidden/2015-10-15-ask-me-anything.md
new file mode 100644
index 0000000..786ca5e
--- /dev/null
+++ b/hidden/2015-10-15-ask-me-anything.md
@@ -0,0 +1,16 @@
+---
+title: Ask Me Anything!
+route: /ask-me-anything
+date: 2015-10-15
+hidden: true
+---
+
+Inspired by [Sindre Sorhus](https://github.com/sindresorhus/ama), I've decided
+to make an "AMA" repo on GitHub. I don't know if anyone will use it, but I'll
+leave it there anyway!
+
+So, [ask me anything](https://github.com/jdan/ama) about Khan Academy,
+accessibility, JavaScript, being a junior developer - anything that's on your
+mind.
+
+
diff --git a/hidden/2016-04-24-random-bowling.md b/hidden/2016-04-24-random-bowling.md
new file mode 100644
index 0000000..9186b17
--- /dev/null
+++ b/hidden/2016-04-24-random-bowling.md
@@ -0,0 +1,30 @@
+---
+title: Let's Go Bowling
+route: /toyshop/bowling
+date: 2016-04-24
+description: An experiment in scoring random bowling games.
+---
+
+
+
+
+
+
+
+
+ Generate throw
+ Generate game
+ Generate 100 games
+
+
+
+
+Here's a little experiment in scoring random bowling games. Each throw
+consists of a random number between 0 and the number of pins remaining. This
+is not even remotely close to modeling the actual physical aspect of knocking
+pins down, but nevertheless I was curious how a point distribution may look.
+
+A side goal of this experiment was to be more pragmatic in my coding. I've
+written bowling scoring logic dozens of times, each an attempt at making the
+code clearer and more readable. I decided to throw all of that out the window
+and just get it done(TM).
diff --git a/hidden/2016-05-27-color-blindness.md b/hidden/2016-05-27-color-blindness.md
new file mode 100644
index 0000000..8ef5aa7
--- /dev/null
+++ b/hidden/2016-05-27-color-blindness.md
@@ -0,0 +1,56 @@
+---
+title: Color Blindness Simulator
+route: /toyshop/color-blindness
+description: An experiment with color blindness simulation.
+date: 2016-05-27
+hidden: true
+---
+
+Here's an experiment with using SVG Filters to simulate color blindness. Props
+to [Kyo Nagashima](https://github.com/hail2u) for [the inspiration](https://github.com/hail2u/color-blindness-emulation).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hidden/2017-08-15-ocaml-microservices.md b/hidden/2017-08-15-ocaml-microservices.md
new file mode 100644
index 0000000..36ed4b2
--- /dev/null
+++ b/hidden/2017-08-15-ocaml-microservices.md
@@ -0,0 +1,293 @@
+---
+title: How to build disruptive OCaml microservices with BuckleScript
+route: /js-ocaml-microservices
+date: 2017-08-15
+description: For a few hours this past week, I decided to cram a bunch of different Very Fun™ things together to build a trivial web app.
+---
+
+Recently, I started tinkering with [OCaml](https://ocaml.org/). It’s Very Fun™,
+which makes it a great fit for a quick side project. So, for a few hours this
+past week, I decided to cram a bunch of different Very Fun™ things together to
+build a trivial web app. It went well — so here’s a tutorial on how I did it.
+
+---
+
+### The Plan
+
+We’ll be writing a few lines of [OCaml](https://ocaml.org/), compiling it to
+JavaScript using [BuckleScript](https://github.com/bucklescript/bucklescript),
+producing a .js file which runs a microservice using
+[Micro](https://github.com/zeit/micro).
+
+“Fatigue!” you may claim. Yeah, that’s kinda the point. We’ll get our hands
+dirty with a variety of cool things, each of which can be further explored or
+ignored as you see fit — that was my plan, anyway.
+
+### The Tools
+
+We’ll need a couple things from npm:
+
+ yarn add micro # or replace 'yarn' with 'npm install'
+ yarn add --dev bs-platform
+
+Allow me to briefly explain what these two things are.
+
+---
+
+[Micro](https://github.com/zeit/micro) is a super-tiny library for turning
+blocks of code like this…
+
+ module.exports = (req, res) => {
+ res.end('Welcome to Micro')
+ }
+
+…into web-servers. Just a few lines, no need for any boilerplate or
+configuration, making our lives much easier as we attempt to compile another
+language into it.
+
+[BuckleScript](https://github.com/bucklescript/bucklescript) is a toolchain
+developed at Bloomberg for compiling OCaml code into readable, performant
+JavaScript. It is incredibly powerful, and we’ll only be using a very, *very
+*small subset of its features, but it works quite well and is easy to get up and
+running.
+
+---
+
+Now a bit of config.
+
+First we’ll need to tell BuckleScript where our files are (let’s make a new
+`src/` directory and just put things in there). To do this we create a
+`bsconfig.json` with the following two fields.
+
+ {
+ "name": "bucklescript-micro-example",
+ "sources": [
+ "src/"
+ ]
+ }
+
+Sa-weet — now let’s add some scripts to `package.json` to make our lives easier.
+
+ {
+ "dependencies": {
+ "micro": "^8.0.1"
+ },
+ "devDependencies": {
+ "bs-platform": "^1.8.2"
+ },
+ "scripts": {
+ "build": "bsb",
+ "watch": "bsb -w",
+ "start": "node lib/js/src/index.js"
+ }
+ }
+
+Our `build` command will use the `bsb` executable (provided to us from
+`bs-platform`) to build our code. `watch` does the same thing, but will also
+watch for any file changes as we develop and re-build them automagically.
+
+Finally, `start` will run our web server. The path afterwards is where
+BuckleScript will put our compiled JavaScript.
+
+### The Code
+
+So far so good, right? Now, we can start writing code. Let’s kick things off
+with a simple function, just to get a feel for how BuckleScript works its magic.
+Start by creating a file `src/add.ml` and add the following:
+
+ let add a b = a + b
+
+If we run `npm run build` (or we can run `npm run watch` and leave it in a
+separate tab), we should see a brand new `lib/` folder in our profile. Diving
+in, we find lots of definitions, and the compiled output: `lib/src/add.js`:
+
+ // Generated by BUCKLESCRIPT VERSION 1.8.2, PLEASE EDIT WITH CARE
+ 'use strict';
+
+ function add(a, b) {
+ return a + b | 0;
+ }
+
+ exports.add = add;
+ /* No side effect */
+
+Magic! Not only did we compile the code, but we’re exporting our `add` function
+(with the right name and all). We can now use our `add` function, originally
+written in OCaml, in node:
+
+ $ node
+ > require("./lib/js/src/add.js").add(5, 6)
+ 11
+
+Now the fun part — let’s try to write some code that uses
+[micro](https://github.com/zeit/micro).
+
+### The Bindings
+
+We can write functions like `add` ourselves, but in order to interface our code
+with existing JS functions, we’ll need to dive into the world of
+[foreign function interface](https://en.wikipedia.org/wiki/Foreign_function_interface)_s
+_(also known as FFIs).
+
+Simply put, FFIs let BuckleScript know:
+
+- **The type definitions of our foreign objects**. This allows us to treat these
+ objects as first class citizens, passing them to and from other functions in
+ our codebase. (For example, `micro` will provide us with “request” and
+ “response” objects. We can type these so later on we can write functions such
+ as `renderIndexPage : res -> string -> unit`).
+- **What type of syntax our OCaml code should compile down to. **In other words,
+ should `fillStyle ctx "blue"` compile down to `ctx.fillStyle("blue")` or
+ `ctx.fillStyle = "blue"`?
+
+These bullet points will make more sense as we go along. For now, let me
+introduce what one of these bindings looks like.
+
+ type req
+ type res
+ type server
+ external micro : (req -> res -> string) -> server = "micro" [@@bs.module]
+ external listen : server -> int -> unit = "listen" [@@bs.send]
+
+Let’s break this down.
+
+- First we define a few types. Now we can create functions that consume/return a
+ “thing” of type `req`, `res`, and `server`.
+- `external` is a keyword used for defining FFIs in OCaml. You’ll see this a lot
+ when working with BuckleScript
+- `micro` and `listen` will correspond to functions we can now use in our OCaml
+ code. Thanks to the type definitions next to them (after the colon), they are
+ typesafe and will let your program compile (as well as make tooling such as
+ [merlin](https://github.com/ocaml/merlin) infinitely more useful).
+- The strings `"micro"` and `"listen"`, somewhat confusingly, correspond to the
+ JavaScript identifiers that BuckleScript will output. We can technically leave
+ these out (and instead specify `""`) since they are equal to the function
+ names we are binding to.
+- Finally, the items in the square brackets (namely `bs.module` and `bs.send`)
+ let BuckleScript know what sort of JavaScript expression we want our new
+ `micro` and `listen` functions to compile to.
+
+---
+
+I’d like to expand that last bullet point.
+
+#### `[@@bs.send]`
+
+This treats the first argument as a JS object and sends the remaining arguments
+as parameters.
+
+ external listen : server -> int -> unit = "listen" [@@bs.send]
+ (* ...other stuff... *)
+ listen thing_of_type_server 1337
+
+Will result in (roughly) the following code:
+
+ thing_of_type_server.listen(1337)
+
+#### [@@bs.module]
+
+This attribute lets BuckleScript know that you are interfacing with a JS module,
+adding a `require` when necessary.
+
+ external add : int -> int -> int = "add" [@@bs.module]
+ external sub : int -> int -> int = "sub" [@@bs.module "coolpackage"]
+ let f = add 1 2;;
+ let g = sub 7 6;;
+
+Results in:
+
+ var Add = require("add");
+ var Coolpackage = require("coolpackage");
+
+ var f = Add(1, 2);
+ var g = Coolpackage.sub(7, 6);
+
+**As an exercise to the reader: what do the attributes**`[@@bs.get]`**,
+**`[@@bs.set]`**, and **`[@@bs.val]`** do?**
+
+For more on FFI: refer to the
+[official BuckleScript docs](https://bucklescript.github.io/bucklescript/Manual.html#_ffi).
+
+---
+
+We now have access to two functions: `micro` and `listen` which are used in the
+following ways:
+
+`micro` accepts a function (which accepts two arguments of type `req` and `res`
+respectively and returns a `string`) and returns a `server`.
+
+ let server = micro (fun req -> fun res -> "Hello, world!");;
+
+`listen` accepts a `server` and an `int` and returns a noop (type `unit`).
+
+ listen server 1337;;
+
+All together now!
+
+ type req
+ type res
+ type server
+ external micro : (req -> res -> string) -> server = "micro" [@@bs.module]
+ external listen : server -> int -> unit = "listen" [@@bs.send]
+
+ let server = micro (fun req -> fun res -> "Hello, world!");;
+ listen server 1337;;
+
+If we place this code in `src/index.ml`, running `npm run build` will produce
+`lib/js/src/index.js` with the following contents:
+
+ // Generated by BUCKLESCRIPT VERSION 1.8.2, PLEASE EDIT WITH CARE
+ 'use strict';
+
+ var Micro = require("micro");
+
+ var server = Micro((function (_, _$1) {
+ return "Hello, world!";
+ }));
+
+ server.listen(1337);
+
+ exports.server = server;
+ /* server Not a pure module */
+
+Now let’s run `npm start` and visit `localhost:1337` .
+
+
+
+Better yet, we can install [now](https://github.com/zeit/now) (`npm install -g now`) and deploy our site instantly (simply by typing `now` in our terminal).
+
+
+
+And Voila! A “web-server” written in OCaml, compiled down to JavaScript. It’s
+not much, but it’s a straight spike through a variety of technologies. Hopefully
+you find one or two of ’em interesting, and I encourage you to continue playing
+and exploring.
+
+### Going Forward
+
+Here are some more questions to ponder on.
+
+- Using micro, the first argument represents an instance of
+ `http.IncomingMessage`. This instance has a `url` property — **how would we go
+ about extracting the URL and displaying a different message?**
+- If we surround `Hello, world!` with ` `, we see that our
+ browser renders an HTML document. **Experiment with creating various
+ “template” functions** to build a Real Website™. (i.e. `fun req -> fun res -> layout req`)
+- Instead of returning a string, **use various methods on the **`res`**
+ parameter**, which is an instance of `http.ServerResponse`.
+
+You may also be interested in [Reason](http://facebook.github.io/reason/): a new
+syntax for OCaml developed at Facebook. It’s gaining a lot of traction in the
+JavaScript community, and even has
+[React bindings](https://reasonml.github.io/reason-react/)! I’m personally a
+huge fan of my friend Jared’s recent (excellent)
+[blog post about ReasonReact](https://jaredforsyth.com/2017/07/05/a-reason-react-tutorial/).
+
+In part 2, We’ll explore `@@bs.send.pipe` and how to better interface with
+chainable JavaScript APIs:
+
+[Typesafe JavaScript Chaining with OCaml and BuckleScript](/js-ocaml-chaining)
+
+I hope this serves as a gentle introduction to one of my favorite things
+happening in JavaScript right now. Go forth and explore, and be sure to share
+what you create.
diff --git a/hidden/2017-08-19-typesafe-javascript-chaining-with-ocaml-and-bucklescript.md b/hidden/2017-08-19-typesafe-javascript-chaining-with-ocaml-and-bucklescript.md
new file mode 100644
index 0000000..9d9ab22
--- /dev/null
+++ b/hidden/2017-08-19-typesafe-javascript-chaining-with-ocaml-and-bucklescript.md
@@ -0,0 +1,318 @@
+---
+title: Typesafe JavaScript Chaining with OCaml and BuckleScript
+route: /js-ocaml-chaining
+date: 2017-08-19
+description: Let's write some concise OCaml code to interface with JavaScript libraries that have a chainable API.
+---
+
+
+
+In my [previous article](/js-ocaml-microservices), we explored how BuckleScript
+allows you to turn OCaml code into readable JavaScript, and how to interface
+with other modules in the JavaScript ecosystem.
+
+Today I’d like to continue on this path and show you the awesome
+`@@bs.send.pipe` binding attribute, which enables us to write concise OCaml code
+to interface with JavaScript libraries that have a chainable API.
+
+---
+
+### Exhibit A: Express
+
+To interface with the [express](https://expressjs.com/) Node.js web framework,
+we may write the following bindings in `src/FFI/Express.ml`. _(NOTE: Remember to
+include _`src/FFI`_ in the _`sources`_ field of _`bsconfig.json`_!)_
+
+ type app
+ external express : unit -> app = "" [@@bs.module]
+ external listen : app -> int -> unit = "" [@@bs.send]
+
+ type req
+ type res
+ external get : app -> string -> (req -> res -> res) -> unit = "" [@@bs.send]
+ external send : res -> string -> res = "" [@@bs.send]
+
+Then, in `src/index.ml` we could use this code as follows:
+
+ open Express
+
+ let app = express ();;
+
+ get app "/" (fun _ -> fun res ->
+ send res "Hello, world! Page 2 ");;
+
+ get app "/page" (fun _ -> fun res ->
+ send res "Hey Go back ");;
+
+ listen app 1337;;
+
+Running `bsb` results in the following `lib/js/src/index.js`:
+
+ // Generated by BUCKLESCRIPT VERSION 1.8.2, PLEASE EDIT WITH CARE
+ 'use strict';
+
+ var Express = require("express");
+
+ var app = Express();
+
+ app.get("/", (function (_, res) {
+ return res.send("Hello, world! Page 2 ");
+ }));
+
+ app.get("/page", (function (_, res) {
+ return res.send("Hey Go back ");
+ }));
+
+ app.listen(1337);
+
+ exports.app = app;
+ /* app Not a pure module */
+
+Nice! We can run `node lib/js/src/index.js` and get ourselves a running express
+server.
+
+### The Chaining Express API
+
+Consider the type we wrote for the `Express.get` function:
+
+ external get : app -> string -> (req -> res -> res) -> unit = "" [@@bs.send]
+
+`get` takes an `app` representing our express instance, a `string` for the path,
+a function (which takes a request and response), and returns a no-op (type
+`unit`).
+
+However — did you know we can _chain_ this API like so? In JavaScript:
+
+ app
+ .get("/", (req, res) => res.send("Hello, world!"))
+ .get("/about", (req, res) => res.send("About ..."))
+ .listen(1337)
+
+This pattern is very common in JS, and works in the following way: instead of
+`get` accepting an `app` and returning a `unit` (or no-op), we return another
+`app` which we can then use on a subsequent `get`!
+
+That’s a lot to unpack, so let’s demonstrate how to get from A to B in code.
+
+#### Step 1: Take an app, return an app
+
+ external get : app -> string -> (req -> res -> res) -> app = "" [@@bs.send]
+
+ let f: app = get (express ()) "/" index;;
+ let g: app = get f "/about" about;;
+ listen g 1337;;
+
+So what’s different here? First, we changed the return type of `get` from a
+`unit` to an `app`. Next we remove the definition for `app` and inline `express ()` in `f` directly.
+
+Then, instead of using `app` as the first argument for our second call to `get`,
+we pass in `f`. This is type-safe (remember: `f`, `g`, and `express ()` all have
+the same type) and sure enough if we compile this script and run it — we get a
+working Express app!
+
+In fact, if we wanted to, we could start combining some of these lines by
+inlining the definition for `f` entirely like so:
+
+ let g: app = get (get (express ()) "/" index) "/about" about;;
+ listen g 1337;;
+
+Or a step further, inlining `g` as well:
+
+ listen
+ (get
+ (get (express ()) "/" index)
+ "/about"
+ about)
+ 1337
+
+These two examples are _identical_ to the first, but notice that `app` is only
+referenced once in our code. Let’s peek at BuckleScript’s output
+`lib/js/src/index.js`:
+
+ Express().get("/", index).get("/about", about).listen(1337);
+
+🔗🔗🔗🔗🔗🔗🔗🔗!!!
+
+See, once we smush together our `get` and `listen` calls, there’s no need for
+temporary variables like `f` and `g`. BuckleScript knows this, and merely puts
+everything inline for us — in a “chained” manner.
+
+This may start to look a little LISP-y to you, and that’s fair — this syntax is
+not easier to read than our original example which specifies `app` multiple
+times. Let’s move on and see how we can clean up this code a little.
+
+#### Step 2: Some light plumbing, and a leak
+
+As we start composing functions (like we did by inlining `f` and `g` in the
+previous section), we’ll start to see quite a bit of parentheses. Consider the
+following bit of code:
+
+ apply_discount(
+ (get_age_group(get_age(user_from_id(id))))
+ price)
+
+Sure we can dress this up with further indentation, but developers reading this
+code will still construct a sort of “stack” in their head as they read the
+subsequent functions from left to right (_“Okay apply discount of the age group
+of the age of the…”_)
+
+To remedy this, OCaml provides the infix `|>` (or “pipe”) operator. We can
+inspect its type via `utop` :
+
+ utop # (|>);;
+ - : 'a -> ('a -> 'b) -> 'b =
+
+We see that we take an item of type `a`, a function from `a` to `b` and return
+an item of type `b`. \*_Exhale_ \*In code:
+
+ f(x) === x |> f
+
+And if we were to use this pipe multiple times:
+
+ f(g(x)) === x |> g |> f
+
+We can see here how the pipe operator (`|>`) allows us to unfold various layers
+of function composition. It’s quite neat, and leads to some very readable code.
+Let’s use it with our example above:
+
+ apply_discount(
+ (get_age_group(get_age(user_from_id(id))))
+ price)
+
+ (* turns into... *)
+
+ apply_discount(
+ (id |> user_from_id |> get_age |> get_age_group)
+ price)
+
+How about that last layer? What if we wanted to unfold `apply_discount` as well?
+
+ let f = id |> user_from_id |> get_age |> get_age_group |> apply_discount;;
+
+ f price;;
+
+Decent! However we hit a snag. `apply_discount` takes _two_ arguments, the
+user’s age group, and a price (`group -> price -> total`). If we were to write
+our code like so:
+
+ ... |> get_age_group |> apply_discount price
+
+We would receive a type error because `price` would be used as the _first_
+argument to `apply_discount`. This means we need some parentheses (technically
+you could use OCaml’s `@@`, but hold your horses), which we are trying to avoid!
+
+ (... |> get_age_group |> apply_discount) price
+
+One way to fix this? **Just make **`price`** the first argument!**
+
+#### Step 3: Save the app for last
+
+If we were to redefine `apply_discount` from `group -> price -> total` to `price -> group -> total`, we could then remove our parentheses entirely:
+
+ ... |> get_age_group |> apply_discount price
+
+Now price is used as the first argument, and second argument (the age group)
+makes its way to `apply_discount` from the pipeline.
+
+“Jordan this is great but I don’t really care about discounts and age groups,
+I’m trying to write a web server before my startup goes under.”
+
+Well fear no more, let’s return to our express example from earlier.
+
+ listen
+ (get
+ (get (express ()) "/" index)
+ "/about"
+ about)
+ 1337
+
+If we were to swap in some `|>` operators, we’ll quickly run into the same exact
+problem we had with `apply_discount`:
+
+ (((express () |> get) "/" index |> get) "/about" about |> listen) 1337
+
+Notice how `|>` doesn’t really buy us much. Since an `app` type must be the
+first argument to `get` and `listen`, we’re left with a confusing mix of
+parentheses and `|>` operators.
+
+As we learned in the previous section, our solution is to **move this argument
+to the end**. Let’s try it with some helper functions:
+
+ let get_ route handler app = get app route handler
+ let listen_ port app = listen app port
+
+And use ’em like so:
+
+ express () |>
+
+ get_ "/" index |>
+ get_ "/about" about |>
+
+ listen_ 1337
+
+And voila! An `app` type makes it way from `express ()`, through the pipe and
+onto the end of `get_ “/" index`. That method also returns an `app` type, which
+finds its way at the end of `get_ “/about" about`, and so on and so forth. We
+now have ourselves a beautiful, type-safe chain of functions that map to the
+chainable express API.
+
+ Express().get("/", index).get("/about", about).listen(1337);
+
+#### Step 4: BuckleScript can do this for us
+
+Defining a `function_` for every `function` you bind to JavaScript-land doesn’t
+sound all that exciting, though. Wouldn’t it be great if `get` and `listen`
+could work like that for us? Well they can!
+
+The current bindings for `get` and `listen` are defined using the `@@bs.send`
+attribute as follows:
+
+ external listen : app -> int -> unit = "" [@@bs.send]
+ external get : app -> string -> (req -> res -> res) -> app = "" [@@bs.send]
+
+However, BuckleScript also provides us with a `@@bs.send.pipe` which, you
+guessed it, allows us to define functions that work well with the `|>` operator.
+[From the docs](https://bucklescript.github.io/):
+
+> `bs.send.pipe` is similar to `bs.send` except that the first argument, i.e,
+> the object, is put in the position of last argument to help user write in a
+> _chaining style_:
+
+Here’s a modified binding for `get`:
+
+ external get : string -> (req -> res -> res) -> app = "" [@@bs.send.pipe: app]
+
+The difference here is that the first `app` in the type definition has been
+moved into the attribute, right after `@@bs.send.pipe:` . Here’s our new
+definition for `listen`:
+
+ external listen : int -> unit = "" [@@bs.send.pipe: app]
+
+Now, we can swap out `get_` and `listen_` in favor of their original
+counterparts.
+
+ express () |>
+
+ get "/" index |>
+ get "/about" about |>
+
+ listen 1337
+
+🎉🎉🎉🎉🎉🎉
+
+---
+
+### Closing Thoughts
+
+Okay so that was a lot of words to tell you how `@@bs.send.pipe` works, but I
+hope this post gave you a bit of intuition for why it exists and why you may
+want to use it. With that, here a few more questions to ponder on:
+
+- You may have noticed that the type of the callback for `get` is `req -> res -> res`. Why the second `res`? Well, express has
+ [operations](https://expressjs.com/en/4x/api.html#res.append) on `res` like
+ `send`, `status`, and `cookie` which are also chainable (they return a `res`
+ type). **Write chainable bindings for these methods.**
+- Imagine `@@bs.send.pipe` did not exist and we were stuck with our old
+ definitions of `get` and `listen`: could we create a function called
+ `make_chainable` where `make_chainable get === get_` and `make_chainable listen === listen_`? **Why or why not?** _(As a hint: what if _`get`_ and
+ _`listen`_ both had three arguments, could we do it then?)_
diff --git a/hidden/2018-01-07-j-fibonacci.md b/hidden/2018-01-07-j-fibonacci.md
new file mode 100644
index 0000000..07523dd
--- /dev/null
+++ b/hidden/2018-01-07-j-fibonacci.md
@@ -0,0 +1,258 @@
+---
+title: Hello, J! The Fibonacci Numbers
+route: /j-fibonacci
+date: 2018-01-07
+description: Today we're going to compute the Fibonacci numbers using a fun language called J.
+---
+
+Today we're going to compute the [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number) using a [fun language called J](https://en.wikipedia.org/wiki/J_(programming_language).
+
+You are welcome to [skip right to the action](#all-together-now-fibonacci) to see what this post is all about, but the following few paragraphs will introduce some J basics.
+
+## Hello, REPL!
+
+First thing's first, [go ahead and install J](http://code.jsoftware.com/wiki/System/Installation/All-in-One). I tend to run my code in `jconsole`, but `jqt` gives you a nice GUI with a package manager.
+
+In this post you'll find a number of code blocks. These represent lines from the J REPL. The top line, indented by two spaces, is our input. The line beneath is our output.
+
+```
+ 1 + 1
+2
+ 2 * 3 * 4 NB. this is a comment
+24
+ 'hello, world!'
+hello, world!
+```
+
+Easy enough, right?
+
+## Lists lists and more lists
+
+J really shines when it comes to lists - and we'll use 'em to build our sequence. You can build lists just by writing the elements separated with whitespace. Seriously.
+
+```
+ 1 2 3
+1 2 3
+```
+
+The `{.` verb (or function) is used to get the first element of a list. We can use it by just plopping it in the front.
+
+```
+ {. 1 2 3
+1
+ {. 10 17 100
+10
+```
+
+The `{:` verb is used to get the last element of the list.
+
+```
+ {: 1 2 3
+3
+ {: 10 17 100
+100
+ {: 1
+1
+```
+
+The `,` verb is used to join lists. You'll notice that this one is different in that it has stuff on both sides! Kinda like `+`.
+
+```
+ 1 , 2
+1 2
+ 1 2 3 , 4 5 6
+1 2 3 4 5 6
+```
+
+We can use the verb `+/` to sum the elements of a list.
+
+```
+ +/ 1 2 3
+6
+ +/ _1 5 NB. _ is for negative!
+4
+```
+
+## Stacking verbs
+
+We can use multiple verbs in an expression. Parentheses `()` help us control the order of things.
+
+```
+ {. 1 2 3
+1
+ {: 1 2 3
+3
+ ({. 1 2 3) , ({: 1 2 3)
+1 3
+ +/ ({. 1 2 3) , ({: 1 2 3)
+4
+```
+
+Let's kick things up by introducing "forks." J will automagically form a fork when we combine certain functions.
+
+```
+ ({. 1 2 3) , ({: 1 2 3)
+1 3
+ ({. , {:) 1 2 3
+1 3
+
+```
+
+See that? We were able to extract the `1 2 3` out as a single argument! J interprets the series of verbs `{.`, `,`, and `{:` as a "fork" - it sends our argument to the left and right sides, then takes the results and joins them with `,`. We can do this with all kinds of verbs.
+
+```
+ ({: , {.) 1 2 3
+3 1
+ ({: , {:) 1 2 3
+3 3
+ (+/ , {:) 1 2 3
+6 3
+ (+/ * {:) 1 2 3
+18
+```
+
+Cool, right? This helps us read out our expressions like sentences. For instance, "the sum times the last" can be written as `+/ * {:`, and our argument is automatically passed to both sides as it needs to be.
+
+## Defining verbs
+
+We can use the "is" verb `=:` to define our own verbs.
+
+```
+ (+/ , {:) 1 2 3
+6 3
+ sumlast =: +/ , {:
+ sumlast 1 2 3
+6 3
+ staticthing =: 55 NB. "nouns" too!
+ staticthing + 3
+58
+```
+
+We can also get a little more explicit with our verb definitions. The syntax of which is a little funky, but bear with me.
+
+```
+ sumlast =: +/ , {:
+ sumlast 1 2 3
+6 3
+ sumlast =: verb : '(+/ , {:) y'
+ NB. 'y' is our argument!
+ sumlast 1 2 3
+6 3
+```
+
+## All together now, Fibonacci
+
+Let's take what we've learned so far and start exploring.
+
+We can make a list.
+
+```
+ 1 2
+1 2
+```
+
+We can pick items from our list.
+
+```
+ {. 1 2
+1
+ {: 1 2
+2
+```
+
+The next [Fibonacci number](https://en.wikipedia.org/wiki/Fibonacci_number) is the sum of the previous two.
+
+```
+ +/ 1 2
+3
+ +/ 2 3
+5
+```
+
+We need the sum, but we also need to keep the second number around for next time.
+
+```
+ ({: 1 2) , (+/ 1 2)
+2 3
+ ({: 2 3) , (+/ 2 3)
+3 5
+```
+
+We can extract our argument using a fork to simplify our expression.
+
+```
+ ({: , +/) 1 2
+2 3
+ ({: , +/) 2 3
+3 5
+```
+
+We can stack our verbs multiple times.
+
+```
+ ({: , +/) 1 2
+2 3
+ ({: , +/) ({: , +/) 1 2
+3 5
+ ({: , +/) ({: , +/) ({: , +/) 1 2
+5 8
+```
+
+We can use the power verb `^:` to do this for us.
+
+```
+ (({: , +/)^:0) 1 2
+1 2
+ (({: , +/)^:1) 1 2
+2 3
+ (({: , +/)^:2) 1 2
+3 5
+ (({: , +/)^:5) 1 2
+13 21
+```
+
+We can start at `1 1`.
+
+```
+ (({: , +/)^:0) 1 1
+1 1
+ (({: , +/)^:1) 1 1
+1 2
+ (({: , +/)^:2) 1 1
+3 5
+ (({: , +/)^:5) 1 1
+8 13
+```
+
+We can take just the last number.
+
+```
+ {: (({: , +/)^:6) 1 1
+21
+ {: (({: , +/)^:20) 1 1
+17711
+```
+
+We can define a Fibonacci function.
+
+```
+ fib =: verb : '{: (({: , +/)^:y) 1 1'
+ fib 6
+21
+ fib 20
+17711
+ fib 50
+32951280099
+```
+
+## Closing notes
+
+I hope this gentle introduction alleviates some of the pain that comes with looking at an expression like `{: (({: , +/)^:20) 1 1` for the first time. Once you break it down, it's really not so special.
+
+J challenges what it means for code to be "readable." Terse by nature, it uses compact symbols and clever composition tools to let us write code that flows like a conversation.
+
+There's still so much to learn. J has a ton of great tools for representing matrices, polynomials, tables, and much more. If you find posts like these interesting, be sure to [let me know on twitter](https://twitter.com/jdan) so we can learn more together.
+
+Feel free to poke around the [complete J vocabulary](http://www.jsoftware.com/help/dictionary/vocabul.htm) to see what else this great language has to offer. The documentation is just as condensed as the language itself, so proceed with caution (and lots of patience).
+
+Thanks so much for reading!
diff --git a/hidden/2018-02-10-j-pascal.md b/hidden/2018-02-10-j-pascal.md
new file mode 100644
index 0000000..551a7b0
--- /dev/null
+++ b/hidden/2018-02-10-j-pascal.md
@@ -0,0 +1,279 @@
+---
+title: Hello, J! Pascal's Triangle
+route: /j-pascal
+date: 2018-02-10
+description:
+---
+
+Following [my previous post on the Fibonacci numbers](/j-fibonacci), here's a quick post on generating another famous mathematical sequence - [Pascal's Triangle](https://en.wikipedia.org/wiki/Pascal%27s_triangle).
+
+```
+ 1
+ 1 1
+ 1 2 1
+ 1 3 3 1
+1 4 6 4 1
+```
+
+## Quick Background
+
+Pascal's triangle contains numbers formed by binomial coefficients (often referred to as "N choose K"), but there's a simple and elegant way to generate it: **each item is the sum of the two numbers above it**.
+
+
+ 1 3 3 1
+1 4 6 4 1
+
+
+We see here that the underlined 6 is formed by adding the two threes above it.
+
+
+ 1 3 3 1
+1 4 6 4 1
+
+
+Similarly, we see the 4 is formed by adding the 1 and 3, and the 1 is formed by adding 1 to nothing (0).
+
+## Summing pairs
+
+Before we get started go ahead and [grab yourself a copy of the J runtime](http://code.jsoftware.com/wiki/System/Installation/All-in-One) if you haven't already.
+
+Let's start by grabbing the first 5 integers using the ["integers" verb `i.`](http://www.jsoftware.com/help/dictionary/didot.htm)
+
+```
+ i. 5
+0 1 2 3 4
+```
+
+We can use the ["same" verb `]`](http://www.jsoftware.com/help/dictionary/d500.htm) to echo whatever we pass into it.
+
+```
+ ] 10
+10
+ ] i.5
+0 1 2 3 4
+```
+
+Our primary tool will be J's [infix adverb `\`](http://www.jsoftware.com/help/dictionary/d430.htm). This single backslash allows us to scan through a list of numbers in groups and apply a function to them.
+
+Let's scan every 3 items and pass them to the "same" verb `]`.
+
+```
+ 3 ]\ i.5
+0 1 2
+1 2 3
+2 3 4
+```
+
+We can see here that J looks through `0 1 2 3 4` in overlapping groups of 3. So we'll have `0 1 2`, followed by `1 2 3`, etc.
+
+By changing the number in front, we can scan in groups of 2.
+
+```
+ 2 ]\ i.5
+0 1
+1 2
+2 3
+3 4
+```
+
+Let's swap out our boring `]` for something more interesting: `+/`, which sums a list of numbers.
+
+```
+ 3 +/\ i.5
+3 6 9
+ +/ 0 1 2
+3
+ +/ 1 2 3
+6
+ +/ 2 3 4
+9
+```
+
+Similarly, we can do this pairwise.
+
+```
+ 2 +/\ i.5
+1 3 5 7
+```
+
+Pretty nifty right?
+
+## Row after row
+
+So why is this useful? Well, if we take another look at our triangle:
+
+```
+ 1
+ 1 1
+ 1 2 1
+ 1 3 3 1
+1 4 6 4 1
+```
+
+We can see that the next row, `1 5 10 10 5 1` can be formed by this exact strategy: summing each pair of numbers to generate the number beneath it.
+
+```
+ 2 +/\ 1 3 3 1
+4 6 4
+ 2 +/\ 1 4 6 4 1
+5 10 10 5
+```
+
+Well, almost. Our issue is that we're missing out on the 1s on either side! This is because our infix operator `\` starts with `+/ 1 4` to get 5 - skipping over the 1.
+
+To fix this, let's surround our row with 0s.
+
+```
+ 2 ]\ 0 1 3 3 1 0
+0 1
+1 3
+3 3
+3 1
+1 0
+ 2 +/\ 0 1 3 3 1 0
+1 4 6 4 1
+ 2 +/\ 0 1 4 6 4 1 0
+1 5 10 10 5 1
+```
+
+Much better. So how do we surround with 0s automatically?
+
+The [append verb `,`](http://www.jsoftware.com/help/dictionary/d320.htm) is used to join items and lists.
+
+```
+ 0 , 1
+0 1
+ 1 2 3 , 7 8 9
+1 2 3 7 8 9
+```
+
+The ["bond" verb `&`](http://www.jsoftware.com/help/dictionary/d630n.htm) allows us to partially evaluate a verb that normally expects items on both sides.
+
+```
+ 1 + 2
+3
+ (1&+) 2
+3
+ 4 % 2 NB. "%" is division!
+2
+ (%&2) 4
+2
+```
+
+We can bind our append verb to add a 0 to either side.
+
+```
+ (0&,) 5 6 7
+0 5 6 7
+ (,&0) 5 6 7
+5 6 7 0
+```
+
+We can also do both.
+
+```
+ (0&,) (,&0) 5 6 7
+0 5 6 7 0
+ (,&0) (0&,) 5 6 7
+0 5 6 7 0
+```
+
+Putting it all together: we can append 0 on either side of our row:
+
+```
+ (0&,) (,&0) 1 4 6 4 1
+0 1 4 6 4 1 0
+```
+
+And sum each pair:
+
+```
+ 2 +/\ (0&,) (,&0) 1 4 6 4 1
+1 5 10 10 5 1
+```
+
+## All together now
+
+Let's wrap this in our own verb called `next`. "`y`" gives us access to the argument(s) passed in.
+
+```
+ next =: verb : '2 +/\ (0&,) (,&0) y'
+ next 1 3 3 1
+1 4 6 4 1
+ next 1 4 6 4 1
+1 5 10 10 5 1
+```
+
+Fortunately, `next` works just fine on the first row of our triangle: a single `1`.
+
+```
+ next 1
+1 1
+```
+
+We can apply `next` multiple times.
+
+```
+ next 1
+1 1
+ next 1 1
+1 2 1
+ next next 1
+1 2 1
+ next next next next 1
+1 4 6 4 1
+```
+
+We can use the ["power" verb `^:`](http://www.jsoftware.com/help/dictionary/d202n.htm) to do this for us.
+
+```
+ (next^:0) 1
+1
+ (next^:1) 1
+1 1
+ (next^:5) 1
+1 5 10 10 5 1
+```
+
+We can also pass a list to `^:` to generate multiple powers at the same time.
+
+```
+ (next^:(i.7)) 1
+1 0 0 0 0 0 0
+1 1 0 0 0 0 0
+1 2 1 0 0 0 0
+1 3 3 1 0 0 0
+1 4 6 4 1 0 0
+1 5 10 10 5 1 0
+1 6 15 20 15 6 1
+```
+
+We can store this as another verb to generate Pascal's Triangle. We’ll also simplify our definition of next using the ["atop" verb `@`](http://www.jsoftware.com/help/dictionary/d620.htm).
+
+```
+ next =: 2 +/\ (0&,) @ (,&0)
+ pascal =: verb : '(next^:(i.y)) 1'
+ NB. We can also inline `next` entirely
+ pascal =: verb : '((2 +/\ (0&,) @ (,&0))^:(i.y)) 1'
+ pascal 10
+1 0 0 0 0 0 0 0 0 0
+1 1 0 0 0 0 0 0 0 0
+1 2 1 0 0 0 0 0 0 0
+1 3 3 1 0 0 0 0 0 0
+1 4 6 4 1 0 0 0 0 0
+1 5 10 10 5 1 0 0 0 0
+1 6 15 20 15 6 1 0 0 0
+1 7 21 35 35 21 7 1 0 0
+1 8 28 56 70 56 28 8 1 0
+1 9 36 84 126 126 84 36 9 1
+```
+
+🎉 🎉
+
+Thanks to the powers of `\` and `^:`, we can intuitively generate Pascal's Triangle in a few dozen characters.
+
+J makes operations on lists and matrices a breeze, and contains a number of interesting ideas for function composition and application. I hope you found this post interesting and give a look at what J has to offer.
+
+I think you'll be pleasantly surprised at how fun it is.
+
+Thanks for reading!
diff --git a/hidden/2019-04-13-programming-languages.md b/hidden/2019-04-13-programming-languages.md
new file mode 100644
index 0000000..9a84ede
--- /dev/null
+++ b/hidden/2019-04-13-programming-languages.md
@@ -0,0 +1,511 @@
+---
+title: A Frontend Programmer's Guide to Languages
+route: /programming-languages
+date: 2019-04-13
+description: Today, we're going to make a programming language. No, it won't take a PhD, or years of your time (or even days for that matter). You and I, together, are going to learn what a programming language is and actually build one that can evaluate programs.
+---
+
+Today, we're going to make a programming language.
+
+No, it won't take a PhD, or years of your time (or even days for that matter). You and I, together, are going to learn what a programming language _is_ and actually build one that can evaluate programs.
+
+By the end of this post we'll have written a JavaScript function, `evaluate`, which interprets a small programming language with strings and variables. You won't be going off and rewriting your stack in it (though you're certainly welcome to try!), but I hope it's a fun exercise.
+
+I encourage you to copy the code examples in your editor of choice and actually run them. You should be able to make it through this post in a single listen of [Lights - Little Machines](https://open.spotify.com/album/1u8OmwItT46Y1gD2xKAK9D?si=CcY4GgT4TGyOa7eNcnLqTA).
+
+## Hello, world!
+
+To kick things off, we'll write an interpreter for a new HelloWorld language, and use it write a [Hello, world! program](https://en.wikipedia.org/wiki/%22Hello,_World!%22_program).
+
+Here's our goal:
+
+```js
+const program = { type: "HelloWorld" }
+console.log(evaluate(program))
+// => Hello, world!
+```
+
+I'm sure you have questions. _Real quick_, let's introduce some terms that we'll more clearly define as we go.
+
+- Our "**program**" is represented by the JavaScript object `{ type: "HelloWorld" }`. Throughout this post, we'll be adding more and more things to this object. For now, there's not much to it.
+- Our "**evaluator**" (or "interpreter" - it's your call) is a single JavaScript function that accepts a "**program**."
+- We receive a "**value**" from our "**evaluator**," which we send to the wonderful `console.log` function you're all familiar with.
+
+Now let's build our **evaluator**.
+
+```js
+function evaluate(node) {
+ switch (node.type) {
+ case "HelloWorld":
+ return "Hello, world!"
+ default:
+ throw `evaluate -- unknown node type ${node.type}`
+ }
+}
+```
+
+This function is not terribly interesting, but I'd like to call out a few details.
+
+- Our function accepts a parameter that we call `node` as in, a **node** of a tree. (_dramatic foreshadowing_)
+- The crux of this function is a single `switch` statement that operates on the `type` field of our node. Our language is very simple, so we only have a single "node type" (namely, "HelloWorld").
+- For the "HelloWorld" **expression** - we return the string "Hello, world!"
+- If we see something we don't recognize - we throw an error. The programmer messed up!
+
+At this point we have 8 lines of code that evaluate a simple HelloWorld language. I'll emphasize the _simple_ here, there are no variables, no loops, no modules, not even numbers - but it's a language. Our language has a very small **grammar**, but it's a language.
+
+Let's make things more interesting.
+
+## Strings
+
+In this section we'd like to make a new `HelloStrings` language (marketing wants us to be able to print more than just "Hello, world!") that can produce strings and run two operations on them.
+
+Here's our goal for this section:
+
+```js
+console.log(
+ evaluate({
+ type: "String",
+ content: "Apple",
+ })
+)
+// => Apple
+
+console.log(
+ evaluate({
+ type: "Excite",
+ expression: {
+ type: "String",
+ content: "Banana",
+ },
+ })
+)
+// => Banana!
+
+console.log(
+ evaluate({
+ type: "Append",
+ first: {
+ type: "String",
+ content: "Apple",
+ },
+ second: {
+ type: "Excite",
+ expression: {
+ type: "String",
+ content: "Banana",
+ },
+ },
+ })
+)
+// => AppleBanana!
+```
+
+Some initial observations:
+
+- We ditch our "HelloWorld" **expression** in favor of "String," which has a "content" field in addition to the "type" field we used in the previous section.
+- We introduce "Excite" which adds exclamation points to expressions.
+- We introduce "Append," which also contains expressions in its definition - two of 'em in fact!
+
+Let's start off by creating an **evaluator** to operate on "String" expressions.
+
+```js
+function evaluate(node) {
+ switch (node.type) {
+ case "String":
+ return node.content
+ default:
+ throw `evaluate -- unknown node type ${node.type}`
+ }
+}
+```
+
+Great, so we replace "HelloWorld" with "String" as the node's type - and return its "content" value instead of the string "Hello, world!"
+
+**_You just wrote a programming language with strings, let's celebrate!_**
+
+But if we continue with our desired goal above, we see the following:
+
+```
+Apple
+evaluate -- unknown node type Excite
+```
+
+We can evaluate `{ type: "String", content: "Apple" }` no problem, but we don't know what to do with this "Excite" thing just yet.
+
+So how might we evaluate "Excite" expressions? Based on how it produces "Banana!" in our desired output, we may be inclined to say that "Excite" _takes a string and adds an exclamation point to it_. Simple enough, right? But let's take a closer look.
+
+```js
+{
+ type: "Excite",
+ expression: {
+ type: "String",
+ content: "Banana"
+ }
+}
+```
+
+The "expression" field of our Excite expression node isn't a string per se, but an expression in the HelloStrings language! **Our expression contains an expression inside of it!** (Are you beginning to see why our evaluator accepts a `node` as in "nodes of a tree"?)
+
+To illustrate this further, allow me to propose the following, _valid_ program for the HelloStrings language.
+
+```js
+console.log(
+ evaluate({
+ type: "Excite",
+ expression: {
+ type: "Excite",
+ expression: {
+ type: "String",
+ content: "Banana",
+ },
+ },
+ })
+)
+```
+
+In the above example, we'll evaluate the string "Banana" - excite it to get "Banana!" - than excite _that_ to get "Banana!!" (how very exciting!)
+
+Let's begin adding Excite expressions to our language.
+
+```js
+function evaluate(node) {
+ switch (node.type) {
+ case "String":
+ return node.content;
+ case "Excite":
+ // We have this node.expression thing, but what do
+ // we do with it?
+ ???
+ default:
+ throw `evaluate -- unknown node type ${node.type}`;
+ }
+}
+```
+
+Rather than just returning a "value" like we did for String expressions (`return node.content`), we'll need to use `node.expression` somehow. As the name suggests, `node.expression` is an expression, and what do we do with expressions?
+
+We evaluate them!
+
+```js
+case "Excite":
+ return evaluate(node.expression) + "!";
+```
+
+`evaluate` is now a recursive function which operates on String and Excite expressions. Here's the function in all its glory and an invitation to implement `Append` yourself.
+
+```js
+function evaluate(node) {
+ switch (node.type) {
+ case "String":
+ return node.content
+ case "Excite":
+ return evaluate(node.expression) + "!"
+ case "Append":
+ // Now it's your turn, how might we evaluate
+ // Append expressions?
+ default:
+ throw `evaluate -- unknown node type ${node.type}`
+ }
+}
+```
+
+## Variables
+
+At this point we have a small language which can produce strings with "Excite" and "Append" statements. Nice job if you've made it this far!
+
+Let's use this momentum and expand our language to support a very popular language construct - **variables**.
+
+By the end of this section, we'll have a language which can declare and retrieve the value of variables in HelloStrings expressions.
+
+```js
+console.log(
+ evaluate(
+ {
+ type: "Let",
+ name: "x",
+ value: {
+ type: "String",
+ content: "Hello, world",
+ },
+ expression: {
+ type: "Excite",
+ expression: {
+ type: "Variable",
+ name: "x",
+ },
+ },
+ },
+ {}
+ )
+)
+// => Hello, world!
+```
+
+There's a lot there, so let's break it down.
+
+- `evaluate` now takes a second argument (_dramatic foreshadowing_)
+- We introduce a new "Variable" expression, which will **lookup** a variable by its name.
+- We introduce a "Let" expression, which makes a new variable with a "name" and a "value" (the value being an expression in our language!), and uses that when evaluating an inner **expression**.
+
+In our case, we're setting "x" to the evaluation of a "Hello, world" String, then retrieving the value of "x" to Excite it.
+
+Let's start by adding "Variable" expressions to `evaluate`.
+
+```js
+function evaluate(node) {
+ switch (node.type) {
+ case "Variable":
+ // We have `node.name`, but what to do with it?
+ ...
+ }
+}
+```
+
+Consider the following code:
+
+```js
+evaluate({ type: "Variable", name: "x" })
+```
+
+Here we want to evaluate the variable `x`, but there doesn't seem to be much to work with. In a typical programming language, what we might we do with a variable?
+
+We look it up!
+
+```js
+function evaluate(node) {
+ switch (node.type) {
+ case "Variable":
+ return lookup(node.name);
+ ...
+ }
+}
+
+```
+
+In order for `lookup` to do anything meaningful, we need to provide it with some sort of **environment** - a collection of variable names and values. We'll call this `env`.
+
+```js
+function evaluate(node) {
+ switch (node.type) {
+ case "Variable":
+ return lookup(env, node.name);
+ ...
+ }
+}
+
+```
+
+And where does `env` come from? Rather unfortunately we can't make it out of thin air (believe me, I tried for many hours), but we _can_ **pass it in to our evaluator.**
+
+```js
+function evaluate(node, env) {
+ switch (node.type) {
+ case "Variable":
+ return lookup(env, node.name)
+ case "String":
+ return node.content
+ case "Excite":
+ return evaluate(node.expression, env) + "!"
+ case "Append":
+ // Left as an exercise to the reader
+ default:
+ throw `evaluate -- unknown node type ${node.type}`
+ }
+}
+```
+
+_Remember to add `env` to our recursive calls in Excite and Append (you did implement Append, right?)_
+
+Let's define `lookup`. For simplicity's sake, we'll say an environment is a JavaScript object with `name` keys and `value` values.
+
+```js
+function lookup(env, name) {
+ return env[name]
+}
+```
+
+Simple, right?
+
+```js
+console.log(evaluate({ type: "Variable", name: "x" }, { x: "Hello, world!" }))
+// => Hello, world!
+```
+
+**Congratulations you just added variables to your language!**
+
+Last but not least, we'll want an easy way to create new variables. Without this, we'll be evaluating Excite's and Append's with nothing more than a bunch of global variables - and the marketing department _definitely_ doesn't want that.
+
+Let's start by listing what a "Let" expression actually contains:
+
+```js
+{
+ type: "Let",
+ name: "x",
+ value: {
+ type: "String",
+ content: "Hello, world"
+ },
+ expression: {
+ type: "Excite",
+ expression: {
+ type: "Variable",
+ name: "x"
+ }
+ }
+}
+```
+
+- A "Let" type
+- A "name" field for naming our new variable
+- A "value" field for giving our new variable a value
+- An "expression" field to use our new variable in!
+
+Excellent, now let's get started on implementing the thing.
+
+```js
+function evaluate(node, env) {
+ switch (node.type) {
+ case "Variable":
+ return lookup(env, node.name);
+ case "Let":
+ let newEnv = ???
+ return evaluate(node.expression, newEnv);
+ ...
+ }
+}
+```
+
+We'll be **adding a new variable to our environment**, and using that to evaluate our expression. For simplicity's sake, let's give ourselves an `extendEnv` function to do this.
+
+```js
+function evaluate(node, env) {
+ switch (node.type) {
+ case "Variable":
+ return lookup(env, node.name);
+ case "Let":
+ let name = ???
+ let value = ???
+ let newEnv = extendEnv(env, name, value)
+ return evaluate(node.expression, newEnv);
+ ...
+ }
+}
+```
+
+`name` is simple, that's just `node.name`. For `value`, however, we'll be given a _HelloStrings expression_ to evaluate.
+
+```js
+{
+ type: "Let",
+ name: "x",
+ value: {
+ type: "String",
+ content: "Hello, world"
+ },
+ ...
+}
+```
+
+Still, it's not much code :)
+
+```js
+function evaluate(node, env) {
+ switch (node.type) {
+ case "Variable":
+ return lookup(env, node.name);
+ case "Let":
+ let name = node.name;
+ let value = evaluate(node.value, env);
+ let newEnv = extendEnv(env, name, value);
+ return evaluate(node.expression, newEnv);
+ ...
+ }
+}
+```
+
+Finally, `extendEnv`.
+
+Our `env` is a simple JavaScript object that maps `names` to `values`. We'll need to extend an `env` with a _new_ name and value pair. We can do so with `Object.assign`:
+
+```js
+function extendEnv(env, name, value) {
+ let envAddition = {}
+ envAddition[name] = value
+
+ return Object.assign({}, env, envAddition)
+}
+```
+
+Or, using some of the latest and greatest JavaScript features:
+
+```js
+function extendEnv(env, name, value) {
+ return {
+ ...env,
+ [name]: value,
+ }
+}
+```
+
+Putting it all together, the combination of `lookup`, `extendEnv`, and `evaluate` completes the language.
+
+```js
+function lookup(env, name) {
+ return env[name]
+}
+
+function extendEnv(env, name, value) {
+ return {
+ ...env,
+ [name]: value,
+ }
+}
+
+function evaluate(node, env) {
+ switch (node.type) {
+ case "String":
+ return node.content
+ case "Excite":
+ return evaluate(node.expression, env) + "!"
+ case "Append":
+ // Left as an exercise to the reader
+ case "Variable":
+ return lookup(env, node.name)
+ case "Let":
+ let inner = node.expression
+ let value = evaluate(node.value, env)
+ let newEnv = extendEnv(env, node.name, value)
+ return evaluate(node.expression, newEnv)
+ default:
+ throw `evaluate -- unknown node type ${node.type}`
+ }
+}
+```
+
+## Closing notes and things to ponder
+
+If you made it to the end of this post, congratulations and thank you :)
+
+We developed a language and an evaluator that processes [Abstract Syntax Trees](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (or ASTs for short, but I just called 'em nodes for simplicity). Our language has [constants](https://en.wikipedia.org/wiki/Constant_(computer_programming), some small expressions to operate on strings, and [variables](https://en.wikipedia.org/wiki/Variable_(computer_science).
+
+But this is only the beginning! You are ending this article with an `evaluate` function that can grow to support all sorts of common language features (numbers, comments, functions), the only limit is your imagination.
+
+I'd like to leave you with a few concrete exercises, should you wish to revisit your new language on a rainy day:
+
+- How might we add Numbers to our language? How about operations to Add and Multiply them? What about _rational_ numbers (fractions with a numerator and a denominator)?
+- As we saw earlier, we can kickstart our `env` by populating it with global values. Could we add functions to this environment? How might we call them from our language?
+- Can we take our abstract syntax tree and use it to generate JavaScript code? How about Ruby code?
+- Writing our programs in as JavaScript objects doesn't seem to scale well. How might we go about creating a **syntax** for our language and converting that to an AST?
+
+I'll also go ahead and plug some of my favorite resources on Programming Languages.
+
+- Dan Grossman's [Programming Languages on Coursera](https://www.coursera.org/learn/programming-languages) is an entirely free, entirely amazing three-part course for learning the ins and outs of different types of programming languages. I can't recommend it enough.
+- This article is inspired in no short part by [@jamiebuilds's super tiny compiler](https://github.com/jamiebuilds/the-super-tiny-compiler). I encourage you to check out the code to see some of the concepts introduced in this article in more detail.
+- [Crafting Interpreters](https://craftinginterpreters.com/) is an effort to build "a handbook for making programming languages." An ambitious goal, but it's completely free and chock full of different interpreter concepts.
+
+That's all for now. If you liked this article feel free to share it and follow me on Twitter while you're at it: [@jdan](https://twitter.com/jdan).
+
+You should also come work with me at [Stripe](https://stripe.com/jobs). We're hiring all over the place.
+
+Thanks again for reading,
+Jordan
diff --git a/hidden/2019-05-10-infinite-lists.md b/hidden/2019-05-10-infinite-lists.md
new file mode 100644
index 0000000..5eee5c5
--- /dev/null
+++ b/hidden/2019-05-10-infinite-lists.md
@@ -0,0 +1,682 @@
+---
+title: Operating on Infinite Lists
+route: /infinite-lists
+date: 2019-05-10
+---
+
+Today we're going to step through one of my favorite exercises in composing functions - building and operating on infinite streams of data.
+
+The question we'll be answering is: How might you represent the following operations?
+
+```js
+nums
+// => 1, 2, 3, 4, ...
+double(nums)
+// => 2, 4, 6, 8, ...
+fib
+// => 0, 1, 1, 2, 3, 5, 8, ...
+```
+
+This post contains code written in JavaScript, but the ideas here apply to any language with functions and lists.
+
+## The Finite
+
+We can build a finite list in JavaScript like so:
+
+```js
+const ls = [1, 2, 3, 4, 5]
+// => [1, 2, 3, 4, 5]
+```
+
+We can access any element inside of it as well as its length:
+
+```js
+ls[0]
+// => 1
+ls[10]
+// => undefined
+ls.length
+// => 5
+```
+
+Alternatively, we can self-referentially represent lists as **an element, followed by a list**. This is commonly referred to as a "linked list." (You're welcome to scroll to the next section if this is familiar to you. You're welcome either way I guess, I'm not a cop.)
+
+In this data structure we'll use an object with a `first` field for the element and a `rest` field for the rest of the list. We'll use `null` for the empty list - where our list ends.
+
+```js
+const ll = {
+ first: 0,
+ rest: {
+ first: 1,
+ rest: {
+ first: 2,
+ rest: null,
+ },
+ },
+}
+```
+
+This is conceptually simpler, but pretty awkward (imagine if you had to use this instead of `[...]`!). Still, we can access elements inside of it:
+
+```js
+ll.first
+// => 0
+ll.rest.first
+// => 1
+ll.rest.rest.first
+// => 2
+```
+
+And we can compute its length using recursion (where our function is defined in terms of itself):
+
+```js
+function length(ll) {
+ if (ll === null) {
+ // empty list has length 0
+ return 0
+ } else {
+ // its length is 1 (the item)
+ // plus the length of the rest
+ return 1 + length(ll.rest)
+ }
+}
+length(ll)
+// => 3
+```
+
+## The Infinite
+
+Conceptually, an infinite list is a lot like a finite list. We'll want a way to get an item, and a way to get the rest. Let's kick things off by building a stream of ones:
+
+```js
+1, 1, 1, 1, ...
+```
+
+Our `first` will be a single piece of data in our stream - in this case, the number 1.
+
+```js
+const ones = {
+ first: 1,
+ rest: ???,
+}
+```
+
+In our linked list above, our `rest` was also a linked list. Similarly, the `rest` of our stream will be... a stream!
+
+```js
+const ones = {
+ first: 1,
+ rest: ones,
+}
+```
+
+You'll quickly find however, that we can't just define a variable in terms of itself. In JavaScript, we'll receive the following from our console:
+
+```
+ReferenceError: ones is not defined
+```
+
+What _can_ we define in terms of itself? Functions! Remember `length` from above?
+
+```js
+function length(ll) {
+ if (ll === null) {
+ return 0
+ } else {
+ return 1 + length(ll.rest)
+ }
+}
+```
+
+So...**let's switch `ones` to be a function**:
+
+```js
+function ones() {
+ return {
+ first: 1,
+ rest: ones(),
+ }
+}
+```
+
+But, we're not in the clear just yet:
+
+```js
+> ones()
+RangeError: Maximum call stack size exceeded
+ at ones (repl:1:14)
+ at ones (repl:4:11)
+ at ones (repl:4:11)
+```
+
+Uh oh. When creating our stream, `ones` is **eagerly** making subsequent calls to itself over and over again - never coming up for air before our JavaScript console lets us know we probably messed up.
+
+Instead, let's make our implementation **lazier** by returning the `ones` function and calling it when we need it.
+
+```js
+function ones() {
+ return {
+ first: 1,
+ rest: ones,
+ }
+}
+
+ones()
+// => { first: 1, rest: [Function: ones] }
+```
+
+No infinite loops! We can create a ones stream, and gather elements from it like so:
+
+```js
+ones().first
+// => 1
+ones().rest().first
+// => 1
+ones()
+ .rest()
+ .rest().first
+// => 1
+```
+
+## Defining and Building Streams
+
+Taking a step back, we can define a **stream** as a function which returns two things:
+
+(1) an item
+(2) a stream
+
+We can define a `twos` stream similarly to our `ones`:
+
+```js
+function twos() {
+ return {
+ first: 2,
+ rest: twos,
+ }
+}
+
+twos().first
+// => 2
+twos().rest().first
+// => 2
+twos()
+ .rest()
+ .rest().first
+// => 2
+```
+
+Still, these streams don't seem particularly _useful_. One potential smell is our streams are functions, but so far they haven't taken any arguments. What if they did?
+
+Let's kick things off with a stream of the natural numbers.
+
+```js
+function nums(n) {
+ return {
+ first: n,
+ // Remember, rest is a stream,
+ // and streams are functions.
+ rest: () => nums(n + 1),
+ }
+}
+
+nums(1).first
+// => 1
+nums(1).rest().first
+// => 2
+nums(1)
+ .rest()
+ .rest().first
+// => 3
+nums(999).first
+// => 999
+```
+
+An initial argument for `nums` doesn't seem particuarly useful, so let's use a default.
+
+```js
+function nums(n = 1) {
+ return {
+ first: n,
+ // Remember, rest is a stream,
+ // and streams are functions.
+ rest: () => nums(n + 1),
+ }
+}
+
+nums().first
+// => 1
+```
+
+All these `.rest()`/`.first` chains are becoming cumbersome, so let's take a second and define a function to grab the first `n` elements of a stream.
+
+```js
+function take(stream, n) {
+ if (n <= 0) {
+ return []
+ } else {
+ const { first, rest } = stream()
+ return [first].concat(take(rest, n - 1))
+ }
+}
+
+take(nums, 5)
+// => [1, 2, 3, 4, 5]
+```
+
+**Exercise: Write a function to grab the `nth` item of a stream**
+
+```js
+nth(nums, 100)
+// => 101
+```
+
+
+Solution
+
+function nth(stream, n) {
+ if (n < 0) return null
+
+ const {first, rest} = stream()
+ if (n === 0) {
+ return first
+ } else {
+ return nth(rest, n - 1)
+ }
+}
+
+
+
+At this point we have a stream with some interesting data in it.
+
+Now it's your turn. Try the following examples on your own machine. The solutions can be expanded if you get stuck (and it's okay if you do!)
+
+**Define a stream which returns the odd numbers.**
+
+```
+take(odds, 5)
+// => [1, 3, 5, 7, 9]
+```
+
+
+Solution
+function odds(n = 0) {
+ return {
+ first: 2 * n + 1,
+ rest: () => odds(n + 1),
+ }
+}
+
+
+
+**Define a stream which returns the square numbers.**
+
+```js
+take(squares, 5)
+// => [1, 4, 9, 16, 25]
+```
+
+
+Solution
+
+function squares(n = 1) {
+ return {
+ first: n * n,
+ rest: () => squares(n + 1),
+ }
+}
+
+
+
+**Define a stream which loops between 0 and 1.**
+
+```js
+take(flipFlop, 5)
+// => [0, 1, 0, 1, 0]
+```
+
+
+Solution
+
+function flipFlop(n = 0) {
+ return {
+ first: n % 2,
+ rest: () => flipFlop(n + 1),
+ }
+}
+
+
+
+Right on. Feel free to take a break, refill your water, and we'll continue onto the next section - writing functions to operate on our streams.
+
+## Streams Out / Streams In
+
+Now that we're comfortable creating streams, let's start writing functions that can create streams for us.
+
+To kick things off, let's write a function that takes in a number and **returns a stream** of that number.
+
+```js
+function fixed(n) {
+ // Streams are functions
+ return () => ({
+ // Which return an item...
+ first: n,
+
+ // ...and a stream
+ rest: fixed(n),
+ })
+}
+
+const sevens = fixed(7)
+take(sevens, 5)
+// => [7, 7, 7, 7, 7]
+```
+
+Our pattern here is a little different than the `ones` and `twos` from earlier - in particular we're **returning a function** instead of an object with `first` and `rest`.
+
+Additionally, our value for `rest` is a little simpler since `fixed(n)` returns a function (we don't need to make a new one inline like before).
+
+For our next example, let's recall our definitions for `odds`, `squares`, and `flipFlop`. Specifically, just the `first` and `rest` parts of each.
+
+```
+odds
+ first: 2 * n + 1,
+ rest: () => odds(n + 1),
+
+squares
+ first: n * n,
+ rest: () => squares(n + 1),
+
+flipFlop
+ first: n % 2,
+ rest: () => flipFlop(n + 1),
+```
+
+Interestingly, our three streams share the same `rest`! And the `first` is just a function of `n`.
+
+Let's materialize this some more, by building a function `funcStream` to generalize our three examples.
+
+```js
+function funcStream(f, n = 0) {
+ return () => ({
+ first: f(n),
+ rest: funcStream(f, n + 1),
+ })
+}
+
+take(funcStream(n => 2 * n + 1), 5)
+// => [1, 3, 5, 7, 9]
+take(funcStream(n => n * n), 5)
+// => [0, 1, 4, 9, 16]
+take(funcStream(n => n % 2), 5)
+// => [0, 1, 0, 1, 0]
+```
+
+Not bad - but we can do better. `funcStream` still needs to keep track of its own `n` and update it appropriately, but `nums` can do that for us. **What if our function operated on `nums`, or _any stream_ for that matter?**
+
+We can think of this as a "map" equivalent for streams. Here's how we might do it:
+
+```js
+function map(f, stream) {
+ return () => {
+ const { first, rest } = stream()
+
+ return {
+ first: f(first),
+ rest: map(f, rest),
+ }
+ }
+}
+
+take(map(n => 2 * n, nums), 5)
+// => [0, 2, 4, 6, 8]
+```
+
+Using this, we can define functions to operate on streams:
+
+```js
+const double = stream => map(n => 2 * n, stream)
+take(double(nums), 5)
+// => [0, 2, 4, 6, 8]
+```
+
+Better yet, these functions can **compose**.
+
+```js
+take(double(double(nums)), 5)
+// => [0, 4, 8, 12, 16]
+```
+
+Let's take stock. `nums` is an **infinite stream of numbers**, and we're able to apply a function to it. Under the hood, this function is **lazily** invoked when we need it - such as when we display the output with `take`.
+
+But mapping isn't the only thing we do with finite lists, so it shouldn't be the only thing we do with streams. **What if we wanted to filter a stream?**
+
+```js
+take(filter(n => n % 3 > 0, nums), 6)
+// => [1, 2, 4, 5, 7, 8]
+```
+
+When filtering a stream, we'll grab it's `first` and `rest`, then test `first`. If the test passes (and the function passed into `filter` returns true), we'll make sure to include that in the stream.
+
+If the test does not pass, we'll just filter the `tail` and ignore the `first`. Let's turn this into code:
+
+```js
+function filter(f, stream) {
+ const { first, rest } = stream()
+ if (f(first)) {
+ // Streams are functions
+ return () => ({
+ first: first,
+ rest: filter(f, rest),
+ })
+ } else {
+ // Ignore first, filter rest
+ return filter(f, rest)
+ }
+}
+```
+
+And just like that, we now have a `filter` that operates on an infinite stream of data.
+
+```js
+take(filter(n => n % 2 > 0, nums), 5)
+// => [1, 3, 5, 7, 9]
+take(filter(_ => true, nums), 5)
+// => [0, 1, 2, 3, 4]
+take(filter(_ => Math.random() < 0.05, nums), 5)
+// => [28, 31, 33, 37, 54]
+```
+
+## Closing Exercises
+
+Before you go, try your hand at the following exercises.
+
+**Using `map`, create a [FizzBuzz](https://en.wikipedia.org/wiki/Fizz_buzz) stream.**
+
+```js
+take(fizzbuzz, 5)
+// => [1, 2, 'Fizz', 4, 'Buzz']
+```
+
+
+Solution
+
+const fizzbuzz = map(n => {
+ if (n % 15 === 0) {
+ return 'FizzBuzz'
+ } else if (n % 3 === 0) {
+ return 'Fizz'
+ } else if (n % 5 === 0) {
+ return 'Buzz'
+ } else {
+ return n
+ }
+}, nums)
+
+
+
+**Using `map` and `nums`, write a function that takes two values and produces a stream that toggles between them.**
+
+```js
+take(toggle("hi", "ho"), 5)
+// => ['hi', 'ho', 'hi', 'ho', 'hi']
+```
+
+
+Solution
+
+function toggle(a, b) {
+ return map(
+ // nums starts at 1
+ n => (n - 1) % 2 === 0 ? a : b,
+ nums
+ )
+}
+
+
+
+**Using `map` and `nums`, write a function that takes an array of values and produces a stream that cycles between them.**
+
+```js
+take(cycle(["a", "b", "c"]), 5)
+// => ['a', 'b', 'c', 'a', 'b']
+```
+
+
+Solution
+
+function cycle(items) {
+ return map(
+ // nums starts at 1
+ n => items[(n - 1) % items.length],
+ nums
+ )
+}
+
+
+
+**Write a function that takes two streams and interleaves them.**
+
+```js
+take(interleave(fixed(0), fixed(9)), 5)
+// => [0, 9, 0, 9, 0]
+```
+
+
+Solution
+
+function interleave(a, b) {
+ const aPair = a()
+ const bPair = b()
+
+ return () => ({
+ first: aPair.first,
+ rest: () => ({
+ first: bPair.first,
+ rest: interleave(aPair.rest, bPair.rest),
+ })
+ })
+}
+
+
+
+**Write a function which accepts a stream and returns a new stream whose values are a running total of the original stream.**
+
+For `nums`: return 1, then 1 + 2, then 1 + 2 + 3, then 1 + 2 + 3 + 4, etc.
+
+```js
+take(total(nums), 6)
+// => [1, 3, 6, 10, 15, 21]
+```
+
+_Hint: give `total` a second argument that defaults to 0_
+
+
+Solution
+
+function total(stream, value = 0) {
+ return () => {
+ const pair = stream()
+ return {
+ first: value + pair.first,
+ rest: total(pair.rest, value + pair.first),
+ }
+ }
+}
+
+
+
+**Write `reduce` for streams.**
+
+`reduce` should take a 2-argument accumulator function, an initial value, and a stream.
+
+```js
+take(reduce((acc, value) => acc + value, 0, nums), 6)
+// => [1, 3, 6, 10, 15, 21]
+take(reduce((acc, value) => acc * value, 1, nums), 6)
+// => [1, 2, 6, 24, 120, 720]
+```
+
+_Hint: Generalize your solution for `total`._
+
+
+Solution
+
+function reduce(fn, init, stream) {
+ return () => {
+ const pair = stream()
+ const newValue = fn(init, pair.first)
+ return {
+ first: newValue,
+ rest: reduce(fn, newValue, pair.rest),
+ }
+ }
+}
+
+
+
+**Using `map` and `reduce`, create a stream of the [Fibonacci sequence](https://en.wikipedia.org/wiki/Fibonacci_number).**
+
+```js
+take(fib, 8)
+// => [0, 1, 1, 2, 3, 5, 8, 13]
+```
+
+_Hint #1: Your initial value should be the first **two** values of the sequence._
+
+_Hint #2: You do not need to use the input stream's values._
+
+
+Solution
+
+function fib() {
+ return {
+ // `reduce` will consume the first
+ // 0, so we'll manually put it
+ // at the front
+ first: 0,
+ rest: map(
+ pair => pair[0],
+ reduce(
+ ([a, b], _) => [b, a + b],
+ [0, 1],
+ fixed('foobar')
+ )
+ )
+ }
+}
+
+
+
+## 🎉🎉
+
+Using nothing but functions and some JavaScript objects, we were able to create and modify infinite sequences of data - and we did it all without making our computer cry!
+
+Thanks for reading this post, and an extra special thanks if you took the time to go through the exercises I put together after lots of editing. I really appreciate it. If not, you may want to try them out on a rainy day, I bet you'll learn something!
+
+It would be a mistake to leave you without some links for further reading.
+
+- [Structure and Interpretation of Computer Programs](https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-4.html#%_toc_start) is my favorite text on how to write and compose programs. Specifically, [Section 3.5](https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5) talk about streams that look eerily similar to the ones in this post. That's no accident!
+- My first introduction to this data structure was in Dan Grossman's [Programming Languages course on Coursera](https://www.coursera.org/learn/programming-languages). I had an absolute blast with this one, and learned a ton about FP, OOP, and type systems. I _highly_ recommend it.
+- Lastly, if you like the idea of infinite sequences but want to use more modern JS instead of first principles, [Reginald Braithwaite has written extensively on the topic](https://raganwald.com/2019/03/11/enumerations-denumerables-recursion-infinity.html).
+
+That's all I have for you now. Thanks again for reading, feel free to share on social media, and [come work with me at Stripe (we're hiring almost everywhere!)](https://stripe.com/jobs)
diff --git a/hidden/2019-05-18-katex-test.md b/hidden/2019-05-18-katex-test.md
new file mode 100644
index 0000000..feecee1
--- /dev/null
+++ b/hidden/2019-05-18-katex-test.md
@@ -0,0 +1,15 @@
+---
+title: KaTeX test
+date: 2019-05-18
+route: /katex-test
+hidden: true
+---
+
+Just testing server-side https://katex.org/.
+
+$$
+\begin{aligned}
+ z_0(n) &= n + 1 \\
+ z_0^n(n) &= z_1(n) = 2n
+\end{aligned}
+$$
diff --git a/hidden/2019-05-19-large-numbers.md b/hidden/2019-05-19-large-numbers.md
new file mode 100644
index 0000000..cb619e9
--- /dev/null
+++ b/hidden/2019-05-19-large-numbers.md
@@ -0,0 +1,469 @@
+---
+title: A Blueprint for Large Numbers
+route: /large-numbers
+date: 2019-05-19
+description: Let's generate numbers that can't fit in the observable universe.
+---
+
+Consider a modest function "A," which takes a number and adds one to it.
+
+$$
+\begin{aligned}
+ A(1) &= 2 \\
+ A(2) &= 3 \\
+ A(99) &= 100
+\end{aligned}
+$$
+
+It's not much of an operator, and is easily defeated by its counterpart: "evil A."
+
+$$
+\begin{aligned}
+ \check A(2) &= 1 \\
+ \check A(3) &= 2 \\
+ \check A(100) &= 99
+\end{aligned}
+$$
+
+We can apply "A" multiple times.
+
+$$
+\begin{aligned}
+ A(A(1)) = A(2) &= 3 \\
+ A(A(A(A(1)))) &= 5
+\end{aligned}
+$$
+
+Repeating "A" is a little tiring, so we can use a superscript to make things a little more concise.
+
+$$
+\begin{alignedat}{2}
+ A(A(1)) &= A^2(1) &&= 3 \\
+ A(A(A(A(10)))) &= A^4(10) &&= 14
+\end{alignedat}
+$$
+
+Since the superscript implies "add 1 this many times," the following properties unfold:
+
+$$
+\begin{aligned}
+A^n(1) &= 1 + n \\
+A^n(10) &= 10 + n \\
+A^n(99) &= 99 + n
+\end{aligned}
+$$
+
+Or, more generally:
+
+$$ A^n(m) = m + n $$
+
+Behold, **addition**!
+
+## Small steps
+
+Our goal is to make large numbers, so we may start throwing some of them at A in hopes of making them even bigger.
+
+$$
+\begin{aligned}
+A^{1000}(1000) &= 2000 \\
+A^{1000000}(1000000) &= 2000000
+\end{aligned}
+$$
+
+But we're not making much progress. For starters, we have to pass in _two_ big numbers - what a waste. Let's not repeat ourselves so much by creating a new function "B":
+
+$$ B(n) = A^n(n) $$
+
+Now we can pass large numbers into B just once - half the work (I checked!).
+
+$$
+\begin{aligned}
+B(1000) &= A^{1000}(1000) \\
+&= 1000 + 1000 \\
+&= 2000 \\
+B(1000000) &= 2000000 \\
+B(1000000000) &= 2000000000
+\end{aligned}
+$$
+
+We can see that the following property holds:
+
+$$ B(n) = A^n(n) = n + n = 2 \cdot n $$
+
+Behold, **multiplication!**
+
+Try as it might, "evil A" can't stop our new friend "B" from taking our numbers to great heights.
+
+$$
+\begin{aligned}
+\check A(n) &= n - 1 \\
+B(n) &= 2 \cdot n \\
+\check A(B(10)) &= 20 - 1 = 19 \\
+\check A(B(100)) &= 199 \\
+\check A(B(5000)) &= 9999 \\
+\end{aligned}
+$$
+
+But "evil B" can, stopping our numbers dead in their tracks.
+
+$$
+\begin{aligned}
+\check B(n) &= \frac{n}{2} \\
+B(n) &= 2 \cdot n \\
+\check B(B(10)) &= \frac{20}{2} = 10 \\
+\check B(B(100)) &= 100 \\
+\check B(B(5000)) &= 5000 \\
+\end{aligned}
+$$
+
+We'll need something stronger.
+
+## Slightly bigger steps
+
+We have a function "B" which _doubles_ a number.
+
+$$
+\begin{aligned}
+B(1) &= 2 \\
+B(99) &= 198 \\
+B(500) &= 1000
+\end{aligned}
+$$
+
+We can apply "B" multiple times.
+
+$$
+\begin{aligned}
+B(B(1)) = B(2) &= 4 \\
+B(B(B(10))) &= 80
+\end{aligned}
+$$
+
+To shorten things, we can use our trusty friend, the superscript.
+
+$$
+\begin{alignedat}{2}
+B(B(1)) &= B^2(1) &&= 4 \\
+B(B(B(10))) &= B^3(10) &&= 80
+\end{alignedat}
+$$
+
+This pattern may be a bit harder to spot, but we can handle it by expanding things a little.
+
+$$
+\begin{aligned}
+B^4(5) &= 2 \cdot B^3(5) \\
+&= 2 \cdot 2 \cdot B^2(5) \\
+&= 2 \cdot 2 \cdot 2 \cdot B(5) \\
+&= 2 \cdot 2 \cdot 2 \cdot 2 \cdot 5 \\
+&= 2^4 \cdot 5
+\end{aligned}
+$$
+
+The following pattern emerges:
+
+$$ B^n(5) = 2^n \cdot 5 $$
+
+Or, more generally:
+
+$$ B^n(m) = 2^n \cdot m $$
+
+Behold, **exponentiation!**
+
+Just as before, we'll consolidate m and n by introducing a new function "C."
+
+$$ C(n) = B^n(n) = 2^n \cdot n $$
+
+## Getting there
+
+Our numbers are starting to grow pretty quickly:
+
+$$
+\begin{alignedat}{2}
+C(3) &= 2^3 \cdot 3 &&= 24 \\
+C(10) &= 2^{10} \cdot 10 &&= 10240 \\
+C(100) &= 2^{100} \cdot 100 &&= 12676506\mathellipsis
+\end{alignedat}
+$$
+
+Passing 100 to our friend "C" produces `126765060022822940149670320537600`, which is a whopping 33 digits in length. Switch the 100 to 1000 and we get:
+
+107150860718626732094842504906000
+181056140481170553360744375038837
+035105112493612249319837881569585
+812759467291755314682518714528569
+231404359845775746985748039345677
+748242309854210746050623711418779
+541821530464749835819412673987675
+591655439460770629145711964776865
+421676604298316526243868372056680
+69376000
+
+
+Coming in at 305 digits. Pretty huge - larger than [the number of particles in the universe](https://en.wikipedia.org/wiki/Elementary_particle#Common_elementary_particles) - but still easily represented here in this article.
+
+Additionally, our "evil B" from earlier is no match for us now.
+
+$$
+\begin{aligned}
+\check B(n) &= \frac{n}{2} \\
+C(n) &= 2^n \cdot n \\
+\check B(C(10)) &= 5120 \\
+\check B(C(100)) &= 633825\mathellipsis \text{(32 digits)} \\
+\check B(C(1000)) &= 535754\mathellipsis \text{(304 digits)}\\
+\end{aligned}
+$$
+
+Try as it might, "evil B" can only occasionally knock a single digit off our numbers.
+
+A new challenger approaches, however, that can take them out using its secret weapon - [the logarithm](https://www.khanacademy.org/math/algebra2/exponential-and-logarithmic-functions/introduction-to-logarithms/a/intro-to-logarithms).
+
+$$
+\begin{aligned}
+\check C(n) &= \lg(n) \\
+C(n) &= 2^n \cdot n \\
+\check C(C(10)) &= 13.321\mathellipsis \\
+\check C(C(100)) &= 106.643\mathellipsis \\
+\check C(C(1000)) &= 1009.965\mathellipsis \\
+\end{aligned}
+$$
+
+Our numbers are _barely_ able to escape the mighty logarithm. We'll need something stronger.
+
+## To new heights
+
+We have a function "C" which raises 2 to the power "n" and multiplies it by "n"
+
+$$
+\begin{alignedat}{2}
+C(n) &= 2^n \cdot n \\
+C(3) &= 2^3 \cdot 3 &&= 24 \\
+C(10) &= 2^{10} \cdot 10 &&= 10240 \\
+\end{alignedat}
+$$
+
+This function has a little sibling which does the same thing, but does not multiply by "n". It won't produce numbers quite as big, but will be a little easier for us to work with.
+
+$$
+\begin{aligned}
+\dot C(n) &= 2^n \\
+\dot C(3) &= 8 \\
+\dot C(10) &= 1024
+\end{aligned}
+$$
+
+We can apply "little C" multiple times.
+
+$$
+\begin{alignedat}{2}
+\dot C(n) &= 2^n \\
+\dot C(\dot C(n)) &= 2^{\dot C(n)} &&= 2^{2^n} \\
+\dot C(\dot C(\dot C(n))) &= 2^{\dot C(\dot C(n))} \\
+&= 2^{2^{\dot C(n)}} &&= 2^{2^{2^{n}}}
+\end{alignedat}
+$$
+
+Just as before, we can use our trusty friend the superscript.
+
+$$\dot C^5(n) = 2^{2^{2^{2^{2^n}}}}$$
+
+Repeated applications of "little C" result in these fairly alien "towers" of 2s. In particular:
+
+$$\dot C^m(n) = \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2^n}}}}}}}_{\text{m copies of 2}}$$
+
+Once again we can consolidate m and n:
+
+$$D(n) = \dot C^n(n) = \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2^n}}}}}}}_{\text{n copies of 2}}$$
+
+Just as we removed the trailing end for "C", we'll remove the trailing n for "D" to simplify things.
+
+$$
+\begin{aligned}
+C(n) &= 2^n \cdot n \\
+\dot C(n) &= 2^n \\
+D(n) &= \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2^n}}}}}}}_{\text{n copies of 2}} \\
+\dot D(n) &= \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{\text{n copies of 2}}
+\end{aligned}
+$$
+
+These "towers of exponents" are referred to as "[tetrations](https://en.wikipedia.org/wiki/Tetration)" and are typically represented using [Knuth's up-arrow notation](https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation).
+
+$$
+\dot D(5) = 2^{2^{2^{2^2}}} = 2 \uparrow \uparrow 5
+$$
+
+They're bizarre-looking, and grow...**really quickly**. How quickly?
+
+$$
+\begin{alignedat}{2}
+\dot D(2) &= 2^2 &&= 4 \\
+\dot D(3) &= 2^{2^2} &&= 16 \\
+\dot D(4) &= 2^{2^{2^2}} &&= 65536 \\
+\dot D(5) &= 2^{2^{2^{2^2}}} &&= 2^{65536}
+\end{alignedat}
+$$
+
+At just 5 items in, we're produced a number that is 19,729 digits in length. Much larger than anything we've seen so far, but still _tangible_. In fact, I can print this number at size 11 font with 1" margins in just 7 sheets of paper (about 3,000 digits per page).
+
+
+
+Why stop there?
+
+$$\dot D(6) = 2^{2^{2^{2^{2^2}}}} = \text{???}$$
+
+What _is_ this number? Concretely, it's 2 raised to the giant number we just saw. How much larger does that make it?
+
+While we could print `D(5)` on 7 pages of paper, we'll need 7 pages of paper **just to print the number of digits in `D(6)`**. What if we wanted to print `D(6)` itself? We'll need about `D(5)` pages.
+
+More specifically, we'll need `D(5) / 3,000` pages, but `D(5)` is so massive the `/ 3,000` does absolutely nothing to it.
+
+How about `D(7)`? We'll need `D(5) / 3,000` pages to print its digits, and `D(6) / 3,000` pages to print the number itself. There's a pattern here, but not one that translates well into physical sheets of paper. Simply put, the number's big.
+
+In fact, our function generates numbers so big that "evil C" is quickly drowned by them.
+
+$$
+\begin{alignedat}{2}
+\check C(n) &= \lg(n) \\
+\check C(\dot D(2)) &= \lg{(2^2)} &&= 2 \\
+\check C(\dot D(3)) &= \lg{(2^{2^2})} &&= 2^2 \\
+\check C(\dot D(4)) &= \lg{(2^{2^{2^2}})} &&= 2^{2^2} \\
+\check C(\dot D(5)) &= \lg{(2^{2^{2^{2^2}}})} &&= 2^{2^{2^2}} \\
+\check C(\dot D(6)) &= \lg{(2^{2^{2^{2^{2^2}}}})} &&= 2^{2^{2^{2^2}}}
+\end{alignedat}
+$$
+
+Try as it might, "evil C" can only knock off a single item from our ever-growing tower of exponents.
+
+A tower of exponents is a real force to be reckoned with.
+
+## But not big enough
+
+We have a function "D" which generates a tower of 2s with a height of "n."
+
+$$
+\dot D(n) = \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{\text{n copies of 2}}
+$$
+
+We can apply this function to itself.
+
+$$
+\begin{aligned}
+\dot D(\dot D(n)) &= \dot D(\underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{\text{n copies of 2}}) \\
+&= \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{(\underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{\text{n copies of 2}})\text{ copies of 2}}
+\end{aligned}
+$$
+
+In the previous section, we saw how `D(n-1)` dictated the **number of digits** for `D(n)`. Well, `D(D(n))` grows not on the level of _exponents_, but on the level of the _number of exponents in the tower_.
+
+**While `D(6)` was practically impossible to imagine, `D(D(6))` is pure nightmare fuel. Let's continue.**
+
+Just as earlier, we can use a superscript to simplify things:
+
+$$
+\left.
+\dot D^m(n) = \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{(\underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{(\cdot^{\cdot^{\cdot}}) \text{ copies of 2}})\text{ copies of 2}}
+\right\} \text{m times}
+$$
+
+And we can consolidate m and n like so:
+
+$$
+\begin{aligned}
+E(n) &= \dot D^n(n) \\
+&= \left.
+ \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{(\underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{(\cdot^{\cdot^{\cdot}}) \text{ copies of 2}})\text{ copies of 2}}
+ \right\} \text{n times}
+\end{aligned}
+$$
+
+These towers-of-towers can be hard to read (and harder to write), so we can simplify things a bit using [our previous up-arrow notation](https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation).
+
+$$
+\begin{aligned}
+\dot D(n) &= 2 \uparrow \uparrow n \\
+\dot D(\dot D(n)) &= 2 \uparrow \uparrow (2 \uparrow \uparrow n) \\
+\dot D(\dot D(\dot D(n))) &= 2 \uparrow \uparrow (2 \uparrow \uparrow (2 \uparrow \uparrow n)) \\
+\dot D^m(n) &= \underbrace{\dot D(\dot D( \cdots \dot D(n)))}_{\text{m copies of } \dot D} \\
+&= \underbrace{2 \uparrow \uparrow (\cdots (2 \uparrow \uparrow n))}_{\text{m copies of 2}}
+\end{aligned}
+$$
+
+(and consolidate m and n):
+
+$$
+\begin{aligned}
+E(n) &= \dot D^n(n) \\
+&= \underbrace{2 \uparrow \uparrow (2 \uparrow \uparrow (\cdots (2 \uparrow \uparrow n))}_{\text{n copies of 2}}
+\end{aligned}
+$$
+
+Lastly, we'll want to get rid of that pesky "n" at the end and create a "little E" just as we did for "C" and "D".
+
+$$
+\begin{aligned}
+D(n) &= \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2^n}}}}}}}_{\text{n copies of 2}} \\
+\dot D(n) &= \underbrace{2^{2^{2^{\cdot^{\cdot^{\cdot^{2}}}}}}}_{\text{n copies of 2}} \\
+E(n) &= \underbrace{2 \uparrow \uparrow (2 \uparrow \uparrow (\cdots (2 \uparrow \uparrow n))}_{\text{n copies of 2}} \\
+\dot E(n) &= \underbrace{2 \uparrow \uparrow (2 \uparrow \uparrow (\cdots (2 \uparrow \uparrow 2))}_{\text{n copies of 2}}
+\end{aligned}
+$$
+
+Conveniently, mathematicians have an elegant way to represent "apply double-up-arrow n times," and all it takes is adding a third arrow.
+
+$$
+\begin{aligned}
+\dot E(n) &= \underbrace{2 \uparrow \uparrow (2 \uparrow \uparrow (\cdots (2 \uparrow \uparrow 2))}_{\text{n copies of 2}} \\
+\dot E(n) &= 2 \uparrow \uparrow \uparrow n
+\end{aligned}
+$$
+
+## Arrows, arrows, arrows
+
+In fact, if we repeat the process we used to generate "B" through "E":
+
+$$
+\begin{aligned}
+E^m(n) &= \underbrace{E(E(\cdots(E(n))}_{\text{m times}} \\
+E^n(n) &= \underbrace{E(E(\cdots(E(n))}_{\text{n times}} \\
+F(n) &= E^n(n) \\
+G(n) &= F^n(n) \\
+H(n) &= G^n(n) \\
+\dots
+\end{aligned}
+$$
+
+All we're really doing is **adding more arrows**.
+
+$$
+\begin{aligned}
+E(n) &= 2 \uparrow \uparrow \uparrow n \\
+F(n) &= 2 \uparrow \uparrow \uparrow \uparrow n \\
+G(n) &= 2 \uparrow \uparrow \uparrow \uparrow \uparrow n \\
+H(n) &= 2 \uparrow \uparrow \uparrow \uparrow \uparrow \uparrow n \\
+\dots
+\end{aligned}
+$$
+
+Eventually the arrows themselves will become unweildy:
+
+$$
+Z(n) = \underbrace{2 \uparrow \uparrow \cdots \uparrow n}_\text{25 arrows}
+$$
+
+Worry not, for we can provide a superscript _to the arrow_ itself. (Keep in mind that our numbers became _incomprehensibly_ large 23 arrows ago.)
+
+$$
+\begin{aligned}
+Z(n) &= \underbrace{2 \uparrow \uparrow \cdots \uparrow n}_\text{25 arrows} \\
+Z(n) &= 2 \uparrow^{25} n
+\end{aligned}
+$$
+
+So, what if we wanted to continue growing the number of arrows?
+
+[Existential Error] Shutting down...
+
+
+I'll leave that to you, dear reader, for I am exhausted.
+
+Thanks for reading :) If you enjoyed this article, you'll probably love [Graham's Number](https://www.youtube.com/watch?v=GuigptwlVHo) and [TREE(3)](https://www.youtube.com/watch?v=3P6DWAwwViU).
diff --git a/hidden/2020-04-01-j-sorting.md b/hidden/2020-04-01-j-sorting.md
new file mode 100644
index 0000000..2bc0bae
--- /dev/null
+++ b/hidden/2020-04-01-j-sorting.md
@@ -0,0 +1,173 @@
+---
+title: Hello, J! Sorting Some Strings
+route: /j-sorting
+date: 2020-04-01
+description: We'll learn a few fun features in the J programming language by sorting some strings.
+---
+
+
+
+
+Following my previous [(1)](/j-fibonacci) posts [(2)](/j-pascal) on a fun little language called J (http://jsoftware.com/), I thought I'd do a quick writeup for some source code I provided in the [Khan Academy Alumni](https://www.khanacademy.org/about/alumni) slack channel.
+
+([They're](https://www.khanacademy.org/careers) hiring! [Stripe](https://stripe.com/jobs) is too!)
+
+Over the next few paragraphs we're going to sort some strings by length, and end up with a function that is 5 characters in length: `\:#&>` (really!)
+
+```
+ (\:#&>) ;: 'sorting strings by length'
+┌───────┬───────┬──────┬──┐
+│sorting│strings│length│by│
+└───────┴───────┴──────┴──┘
+```
+
+## Boxes of strings
+
+We can use the [`;: Words`](https://www.jsoftware.com/docs/help804/dictionary/d332.htm) verb to get a list of words in a string.
+
+```
+ 'a'; 'tall'; 'cat'
+┌─┬────┬───┐
+│a│tall│cat│
+└─┴────┴───┘
+ ;: 'a tall cat'
+┌─┬────┬───┐
+│a│tall│cat│
+└─┴────┴───┘
+```
+
+The fancy characters around each word represent the fact that they are "boxed."
+
+We can [`> Open`](https://www.jsoftware.com/docs/help804/dictionary/d020.htm) boxes.
+
+```
+ > ;: 'a tall cat'
+a
+tall
+cat
+```
+
+We can get the number of items in a list (or a string - which is a list of characters) using the [`# Tally`](https://www.jsoftware.com/docs/help804/dictionary/d400.htm) verb.
+
+```
+ # 1 3 5
+3
+ # 'hello'
+5
+```
+
+We can compose these two operations with [`& Bond`](https://www.jsoftware.com/docs/help804/dictionary/d630n.htm) conjunction, which takes two verbs and returns a single verb.
+
+```
+ # & > ;: 'hello world'
+5 5
+ #&> ;: 'a tall cat'
+1 4 3
+```
+
+Now we are able to get the number of characters in each string.
+
+## Sorting and ranking
+
+[`\: Sort Down`](https://www.jsoftware.com/docs/help804/dictionary/d432.htm) is a powerful verb which sorts the left argument using the right argument for scoring (in descending order).
+
+For example, we can rearrange "hello" by giving `l` and `h` a score of 1 and 2 respectively, and giving `e` and `o` a score of 11 and 10 (respectively). `e` will then appear at the front of the result as it received the highest score.
+
+```
+ 'hello' \: 1 11 2 2 10
+eollh
+```
+
+We can use this to sort our list of words, using the length of each word as its score.
+
+```
+ #&> ;: 'a tall cat'
+1 4 3
+ (;: 'a tall cat') \: 1 4 3
+┌────┬───┬─┐
+│tall│cat│a│
+└────┴───┴─┘
+ (;: 'a tall cat') \: #&> ;: 'a tall cat'
+┌────┬───┬─┐
+│tall│cat│a│
+└────┴───┴─┘
+```
+
+## Making things shorter
+
+We've successfully used the `;:`, `\:`, `#`, `&`, and `>` operators to piece together a working sort mechanism, but there's one flaw - we have to repeat `;: 'a tall cat'` twice 😱
+
+To alleviate this, we can use one of J's strongest features, [hooks](https://www.jsoftware.com/docs/help804/primer/hook.htm).
+
+In the following example, we'll take a list of numbers and add 7% to each of them. We may be inclined to write it like so:
+
+```
+ 10 40 55 + 0.07&* 10 40 55
+10.7 42.8 58.85
+```
+
+Which reads, take the list `10 40 55` and apply `0.07&*` (remember [bond](https://www.jsoftware.com/docs/help804/dictionary/d630n.htm)?) to each item. Add the result to the list `10 40 55`.
+
+(Author's note: we also may be inclined to just multiply by 1.07 but that requires math).
+
+Hooks allow us to simplify this by simply leaving off one of the arguments.
+
+```
+ (+ 0.07&*) 10 40 55
+10.7 42.8 58.85
+```
+
+How does this work? J recognizes that we have two verbs within our parentheses (`+` and `0.07&*`) and combines them into a "[hook](https://www.jsoftware.com/docs/help804/primer/hook.htm)." When we place a single argument at the end, J **automatically applies it to both sides of the hook**.
+
+Put another way: `(f g) x <=> x f g x` for any two verbs `f` and `g` (don't forget your parentheses!)
+
+So, the following expressions are equivalent:
+
+```
+ 10 40 55 + 0.07&* 10 40 55
+10.7 42.8 58.85
+ (+ 0.07&*) 10 40 55
+10.7 42.8 58.85
+```
+
+Let's circle back to our sorting mechanism before and see where we can apply this.
+
+```
+ (;: 'a tall cat') \: #&> ;: 'a tall cat'
+┌────┬───┬─┐
+│tall│cat│a│
+└────┴───┴─┘
+```
+
+Spot it? Between our two instances of `;: 'a tall cat'` we have two verbs: `\:` and `#&>`. Let's hook 'em.
+
+```
+ (\: #&>) ;: 'a tall cat'
+┌────┬───┬─┐
+│tall│cat│a│
+└────┴───┴─┘
+```
+
+Lastly, we can eliminate some whitespace and build our custom verb.
+
+```
+ sort =. \:#&>
+ sort ;: 'a tall cat'
+┌────┬───┬─┐
+│tall│cat│a│
+└────┴───┴─┘
+```
+
+## We did it!
+
+I hope this was a decently short and pleasant introduction into some fun features of the [J programming language](https://www.jsoftware.com/#/README):
+
+- [`& Bond`](https://www.jsoftware.com/docs/help804/dictionary/d630n.htm)
+- [`\: Sort Down`](https://www.jsoftware.com/docs/help804/dictionary/d432.htm)
+- [Hooks](https://www.jsoftware.com/docs/help804/primer/hook.htm)
+
+I encourage you to download J and play around with it. Hooks and forks and [other trains](https://www.jsoftware.com/docs/help804/dictionary/dictf.htm) pop up in all sorts of places and may make you think differently about the code you write everyday.
+
+Also consider [following me on twitter](https://twitter.com/jdan).
+
+Thanks for reading ✨
diff --git a/hidden/2020-04-28-98-dot-css.md b/hidden/2020-04-28-98-dot-css.md
new file mode 100644
index 0000000..c5e501a
--- /dev/null
+++ b/hidden/2020-04-28-98-dot-css.md
@@ -0,0 +1,72 @@
+---
+title: 98.css
+date: 2020-04-28
+route: /98-dot-css
+description: A few days ago I launched 98.css, a design system for making interfaces that look like Windows 98. I'm pretty proud with how it turned out.
+---
+
+A few days ago [I launched 98.css](https://jdan.github.io/98.css/), a "design system" (it's a CSS file) for making
+interfaces that look like Windows 98 ([on GitHub](https://github.com/jdan/98.css)). I'm pretty proud with how it turned out.
+
+
+
+I actually started exploring this idea two years ago in [a small codepen](https://codepen.io/jdan/pen/QmXYPB) where I had a go at
+styling some buttons. This was born out of a remarkably pedantic observation I made where many people would draw Windows-98 buttons like this:
+
+
+
+Instead of with proper "pixelated" borders like so:
+
+
+
+Turns out this behavior is well-specified in the glorious [Microsoft Windows User Experience](https://amzn.to/2YdvLve) reference manual.
+I grabbed a copy and went to work. First buttons, then windows, navbars, scrollbars, inputs, and all sorts of things.
+
+
+
+My tools were a Windows 98 VM and MSPaint for measuring pixels. I used [Figma](https://www.figma.com/) to draw some icons (wonderful tool btw, great work team).
+I did all of my development on my Windows desktop using [Visual Studio Code](https://code.visualstudio.com/) and
+[Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10). Web development on Windows has come a long way and I really
+love my environment.
+
+The project itself had three main objectives:
+
+**Make it as pixel-perfect as I reasonably can** as a creative exercise. I'm going for nostalgia points and I have to really nail it.
+
+**Make it accessible**. Windows 98 is such a wonderfully accessible and intuitive UI style and I couldn't ruin that. I had to do right by it.
+
+**Make it a stylesheet that prettied up HTML and nothing more**. There are some obvious UI elements that I could build with JavaScript:
+nav menus, tab panels, that sort of thing, but I was incredibly hesitant to pick a JavaScript framework or roll my own. Instead I made
+the decision to style HTML and not care who sent it to me, be it React or Vue or whatever you want.
+
+So after about two weeks (with lots and lots of breaks, I'm just not good at sitting in front of a computer for hours anymore) of
+development and cutting scope, I shipped it. I was surprised by how many people "got" it, how many people felt the same nostalgia
+that I felt when I first set out to build this silly thing. The haunted orange website even had its
+[fair share of pleasant comments](https://news.ycombinator.com/item?id=22940564):
+
+> My heart beat a little faster when I saw the VB dialog box. I experienced building software for the first time when I was taken to my father's office where they used VB and Foxpro (and still do) to build ERP systems. Everything looked like this site.
+>
+> The waves of nostalgia are sure coming on hard. Thank you to the author of this. This whole site is a work of art!
+
+The community also sent [many PRs my way](https://github.com/jdan/98.css/pulls?q=is%3Apr+is%3Aclosed), from small bug-fixes to [giving 98.css properly-pixelated fonts](https://github.com/jdan/98.css/pull/27) to [semantically expandable tree views](https://github.com/jdan/98.css/pull/69). Y'all are the best ✨.
+
+I also found myself distracted for a few hours [building a service](https://github.com/jdan/98.css-badges) to generate these swanky npm version and bundle size badges, since the ones on the wonderful [shields.io](https://shields.io) didn't fit my aesthetic.
+
+
+
+The code for generating these on-demand [lives here and is quite terrible](https://github.com/jdan/98.css-badges/blob/main/api/size.js), but I'm
+proud of it for working at all.
+
+I was fortunate enough to lose myself in [a clicker game built with 98.css](https://twitter.com/pieskucom/status/1254396566863036418)
+called "Time is Money" for about an hour, and spent some time clicking around [the GitHub projects that brought in 98.css](https://github.com/jdan/98.css/network/dependents?package_id=UGFja2FnZS0xMTA3MTQ5NTgw).
+
+If you made anything cool, please send it my way, nothing would make me happier :)
+
+All in all I smiled while building this, and brought some smiles when I shipped it. That makes for a good project in my book, but only
+time will tell if this library is actually useful to anyone or just something people tweet about and move on.
+
+I'm peaceful with either outcome. ✌️
diff --git a/hidden/2020-05-05-mandel.md b/hidden/2020-05-05-mandel.md
new file mode 100644
index 0000000..23dc821
--- /dev/null
+++ b/hidden/2020-05-05-mandel.md
@@ -0,0 +1,107 @@
+---
+title: ASCII Mandelbrot Set
+route: /mandelbrot
+date: 2020-05-05
+description:
+---
+
+This is rendering of the [Mandelbrot set](https://en.wikipedia.org/wiki/Mandelbrot_set) in ASCII,
+using HTML anchor tags and the address bar.
+
+Click around to zoom in on different parts of the fractal, and use your browser history to zoom out.
+
+
+
+
+
+You'll hit a wall pretty quickly due to the precision of numbers in JavaScript. [Fraction.js](https://github.com/infusion/Fraction.js/) gets us pretty close, though.
+
+Feel free to poke around [on GitHub](https://github.com/jdan/thatjdanisso.cool/blob/main/articles/2020-05-05-mandel.md) if you have any ideas for improving this.
+
+
+
+
+
+
diff --git a/hidden/2020-05-22-functions-that-go-backwards.md b/hidden/2020-05-22-functions-that-go-backwards.md
new file mode 100644
index 0000000..cebd1f1
--- /dev/null
+++ b/hidden/2020-05-22-functions-that-go-backwards.md
@@ -0,0 +1,314 @@
+---
+title: Functions That Go Backwards
+route: /functions-that-go-backwards
+date: 2020-05-22
+description: A gentle introduction to logic programming with Prolog, exploring how to define programs in terms of relations instead of input and output.
+---
+
+In most programming languages, we may author a function that takes an **input** and produces some **output**.
+
+```js
+console.log(getTrafficLightColor("green", "wait"))
+// => "yellow"
+```
+
+We can say that our code answers the following question: **Given a light color and an action, what happens to the color of the light?**
+
+And it answers it well! We can test its behavior, give it some types, whatever we want - to get a solid answer. We can compose these questions to ask more interesting ones:
+
+**If I wait twice at a green light, what will the color of the light be?**
+
+```js
+console.log(
+ getTrafficLightColor(
+ getTrafficLightColor("green", "wait"),
+ "wait"
+ )
+) // => "red"
+```
+
+But if I asked another question: **What color should the light be such that if I wait, it will turn red?**
+
+We're no longer asking a question in terms of its **input** (which is easy!), but its **output** (which makes us scratch our heads).
+
+## Logically speaking
+
+We'll use a fun "logic programming" language called [Prolog](https://en.wikipedia.org/wiki/Prolog) (you can grab [SWI-Prolog](https://www.swi-prolog.org/) for free) to explore this concept.
+
+Instead of writing a function in terms of its inputs, we write _relationships_ between input and output. An example of such a relation is **a valid transition for our traffic light turns `green` with a `wait` action into `yellow`**.
+
+All we care about are the `green`, `wait`, and `yellow` (these are known as "atoms" in Prolog), and we can use them to build a "**fact**".
+
+```prolog
+transition(green, wait, yellow).
+```
+
+We can choose whatever order we want as long as we're consistent. We'll go with the one above since it matches the prose we translated into Prolog.
+
+Let's write a few more of these in a file called `fsm.prolog`.
+
+```prolog
+% fsm.prolog
+transition(green, wait, yellow).
+transition(yellow, wait, red).
+transition(red, wait, green).
+```
+
+We can then load up `swipl` in our terminal and test it out. After we load our facts with `[fsm].` we can begin "querying" them.
+
+```prolog
+?- [fsm]. % load fsm.prolog
+?- transition(green, wait, yellow).
+true.
+?- transition(red, wait, yellow).
+false.
+```
+
+Our first query `transition(green, wait, yellow).` is a fact, because we defined it as such on the first line of `fsm.prolog`. Prolog tells us "true" - the thing we asked is `true`.
+
+The second query, `transition(red, wait, yellow)` does not appear in our database, so it is `false`.
+
+Of course, Prolog can do much more than recall facts that we already entered! The magic happens when we query with variables.
+
+```prolog
+?- transition(green, wait, Color).
+Color = yellow.
+```
+
+By using a variable (we just need to begin a word with an uppercase letter), we're now asking Prolog to fill in the blank for us through a process called "**unification**." Which `Color` does `transition(green, wait, Color)` result in a fact? `yellow`!
+
+Better yet, we can put this variable **wherever we want**. Our original question: **What color should the light be such that if I wait, it will turn red?** can be queried like so.
+
+```prolog
+?- transition(X, wait, red).
+X = yellow.
+```
+
+Because transition does not work on input and output, we can swap 'em as we please.
+
+```prolog
+?- transition(X, wait, purple).
+false.
+```
+
+Rather unfortunately, the traffic light we invented can never turn purple.
+
+How about representing *multiple* transitions? We can join queries with a comma to ask that Prolog fills in the blanks to satisfy both. Let's start at `green` and `wait` twice.
+
+```prolog
+?- transition(green, wait, State1),
+| transition(State1, wait, Final).
+State1 = yellow,
+Final = red.
+```
+
+We left two blanks, `State1` and `Final`, and Prolog filled em both to find that **waiting twice at a green light results in a red light**. Of course this works backwards for free.
+
+```prolog
+?- transition(Start, wait, State1),
+| transition(State1, wait, yellow).
+Start = red,
+State1 = green.
+```
+
+Want to wait twice for a yellow? You'll start at red.
+
+## Improving relations
+
+Just as we can define functions and compose them in ordinary programming languages, we can build "**rules**" out of facts and variables. For example, if we wanted an easier way to query for "waiting twice":
+
+```prolog
+% fsm.prolog
+wait_twice(Start, End) :-
+ transition(Start, wait, Middle),
+ transition(Middle, wait, End).
+```
+
+We've defined `wait_twice` such that we'll `transition` once from `Start` to `Middle`, then `Middle` to `End`. We can use it like so:
+
+```prolog
+?- [fsm].
+?- wait_twice(green, red).
+true.
+?- wait_twice(green, yellow).
+false.
+```
+
+Waiting twice at a green does in fact give us a red light, while it is _not true_ that waiting twice at a green light gives us a yellow light. Similar to before, we can query with variables:
+
+```prolog
+?- wait_twice(green, X).
+X = red.
+?- wait_twice(X, yellow).
+X = red.
+?- wait_twice(X, purple).
+false.
+```
+
+Let's dive into something a little more complicated, but much more rewarding. How about a rule that relates a start and end light color with a **list** of actions?
+
+We'll call this rule `transition_multi` and define it recursively - starting with an empty list. If we have an initial `State` and an empty list of actions `[]`, what should our final state be? Right where we started.
+
+```prolog
+% fsm.prolog
+transition_multi(State, [], State).
+```
+
+For the recursive step it may help to see how Prolog's "unification" works with lists.
+
+```prolog
+?- A = [1, 2, 3, 4].
+A = [1, 2, 3, 4].
+?- [A, B, C] = [1, 2, 3].
+A = 1,
+B = 2,
+C = 3.
+?- [A, B] = [1, 2, 3].
+false.
+```
+
+We can set a list to a variable, or pattern-match on `[Var1, Var2, Etc...]` if the lengths are the same.
+
+If we want to match the "rest" of the list, we can use the `|` operator.
+
+```prolog
+?- [A | Rest] = [1, 2, 3, 4].
+A = 1,
+Rest = [2, 3, 4].
+?- [A, B | Rest] = [1, 2].
+A = 1,
+B = 2,
+Rest = [].
+```
+
+So, back to `transition_multi`. Our definition looks pretty similar to `wait_twice`.
+
+```prolog
+% fsm.prolog
+transition_multi(State, [], State).
+transition_multi(State, [Action | Rest], End) :-
+ transition(State, Action, Middle),
+ transition_multi(Middle, Rest, End).
+```
+
+We unify the list of actions into `Action` and `Rest`, then transition from `State` to `Middle` before recursively `transition_multi`'ing from `Middle` to `End`.
+
+Let's try it out.
+
+```prolog
+?- [fsm].
+?- transition_multi(green, [wait, wait], red).
+true
+```
+
+Groovy, so Prolog can confirm that `wait`ing twice at a green light gets us a red light. We can put a few variables in to flex a bit.
+
+```prolog
+?- transition_multi(yellow, [wait, wait, wait], X).
+X = yellow
+?- transition_multi(X, [wait, wait, wait, wait], yellow).
+X = green .
+```
+
+## Many answers
+
+How about the array in the middle? We can make that a variable too.
+
+```prolog
+?- transition_multi(green, Actions, red).
+Actions = [wait, wait]
+```
+
+Prolog tells us that `[wait, wait]` will work, then - interestingly - waits for input. We can hit `Enter` to get back to the original prompt, or hit semicolon `;` to **keep it going**.
+
+```prolog
+?- transition_multi(green, Actions, red).
+Actions = [wait, wait] ;
+Actions = [wait, wait, wait, wait, wait]
+```
+
+It appears that not only do two `wait`s bring us from green to red, but so do five. This is because waiting three times brings us back to green (then two more for red). We can keep going with another press of `;`.
+
+```
+?- transition_multi(green, Actions, red).
+Actions = [wait, wait] ;
+Actions = [wait, wait, wait, wait, wait] ;
+Actions = [wait, wait, wait, wait, wait, wait, wait, wait] ;
+Actions = [wait, wait, wait, wait, wait, wait, wait, wait, wait|...] .
+```
+
+We'll be here forever (and ever) so we can just hit `.` to stop.
+
+## What are you waiting for?
+
+Up until now we've been dealing with a single action `wait`, which moves the traffic light from one color to another. Let's introduce two more.
+
+```
+% fsm.prolog
+transition(green, wait, yellow).
+transition(yellow, wait, red).
+transition(red, wait, green).
+
+transition(green, power_outage, blinking).
+transition(yellow, power_outage, blinking).
+transition(red, power_outage, blinking).
+
+transition(blinking, power_on, red).
+```
+
+And query with them like so:
+
+```
+?- [fsm].
+?- transition_multi(green, [power_outage], X).
+X = blinking.
+?- transition_multi(green, [wait, power_outage], X).
+X = blinking.
+```
+
+Now we can answer more interesting questions such as **What two events can occur to take us from green to red?**.
+
+```
+?- transition_multi(green, [A, B], red).
+A = B, B = wait
+```
+
+We can wait twice, but Prolog asks if we want to keep going. We do, using `;`.
+
+```
+?- transition_multi(green, [A, B], red).
+A = B, B = wait ;
+A = power_outage,
+B = power_on.
+```
+
+So, we can go from `green` to `red` with two waits, or a `power_outage` and `power_on`. What if we give ourselves four actions?
+
+```
+?- transition_multi(green, [A, B, C, D], red).
+A = B, B = wait,
+C = power_outage,
+D = power_on ;
+A = C, C = power_outage,
+B = D, D = power_on.
+```
+
+We're left with two options:
+* [wait, wait, power_outage, power_on]
+* [power_outage, power_on, power_outage, power_on]
+
+## Closing notes
+
+Writing our program as a series of *relations* instead of instructions unlocks the ability to flip our code upside down. Not only can we feed it input and get output, but we can feed it "output" to determine what "input" we require to produce facts.
+
+When we combine this technique with more interesting data structures like lists, we can *generate* infinite sequences of inputs to get a desired output.
+
+I hope you found this post enlightening, and encourage to fire up [SWI-Prolog](https://www.swi-prolog.org/) to see what other sorts of problems logic programming can help solve.
+
+Until then, see you around [on twitter](https://twitter.com/jdan).
+
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..1265c75
--- /dev/null
+++ b/index.js
@@ -0,0 +1,42 @@
+const glob = require("glob");
+const generateTags = require("./generate-tags.js");
+const loadArticle = require("./load-article.js");
+const saveArticle = require("./save-article.js");
+const saveIndex = require("./save-index.js");
+const saveStaticFile = require("./save-static-file.js");
+const save32x32 = require("./save-32x32.js");
+
+glob("articles/*.md", (err, articles) => {
+ if (err) { throw err; }
+
+ Promise.all(articles.map(loadArticle))
+ .then(articles => {
+ const promises = articles.map(saveArticle);
+
+ promises.push(saveIndex(articles, "output/index.html"));
+ promises.push(generateTags(articles));
+
+ return Promise.all(promises);
+ })
+ .then(
+ () => console.log("Articles built."),
+ err => {
+ console.log("Error building articles.");
+ console.log(err);
+ }
+ );
+});
+
+glob("public/**/*.*", (err, staticFiles) => {
+ if (err) { throw err; }
+
+ Promise.all(staticFiles.map(saveStaticFile))
+ //.then(save32x32)
+ .then(
+ () => console.log("Static files built."),
+ err => {
+ console.log("Error saving static files.");
+ console.log(err);
+ }
+ );
+});
diff --git a/load-article.js b/load-article.js
new file mode 100644
index 0000000..c066a4a
--- /dev/null
+++ b/load-article.js
@@ -0,0 +1,75 @@
+const fm = require("front-matter");
+const fs = require("fs");
+const hljs = require("highlight.js");
+const katex = require("katex");
+const makeTweetUrl = require("./make-tweet-url.js");
+const marked = require("marked");
+const strftime = require("strftime");
+
+marked.setOptions({
+ gfm: true,
+ highlight: (code, lang) => {
+ return lang
+ ? hljs.highlight(lang, code).value
+ : hljs.highlightAuto(code).value;
+ },
+});
+
+function loadArticle(filename) {
+ return new Promise((resolve, reject) => {
+ fs.readFile(filename, (err, data) => {
+ if (err) { return reject(err); }
+
+ const article = fm(data.toString());
+ const body = marked(
+ article.body.replace(/\$\$([^$]*)\$\$/g, (_, tex) =>
+ katex.renderToString(tex, { displayMode: true })
+ )
+ );
+
+ let summary = article.attributes.description;
+ if (!summary) {
+ const paragraphBreak = article.body.match(/\r?\n\r?\n/);
+ if (paragraphBreak) {
+ summary = marked(article.body.slice(0, paragraphBreak.index));
+ } else {
+ summary = article.body;
+ }
+ }
+
+ const rawDate = article.attributes.date;
+ let date = null;
+
+ if (rawDate) {
+ ;["FullYear", "Month", "Date", "Hours"].forEach(field => {
+ rawDate["set" + field](rawDate["getUTC" + field]());
+ });
+
+ // date = strftime("%B %d, %Y", rawDate);
+ date = strftime("%Y. %B. %d.", rawDate);
+ }
+
+ const tweetUrl = makeTweetUrl(article);
+ const defaults = { hidden: false, timeless: false };
+
+ const tags = article.attributes.tags
+ ? article.attributes.tags.split(", ")
+ : [];
+
+ resolve(
+ Object.assign({}, defaults, article.attributes, {
+ filename,
+ summary,
+ date,
+ rawDate,
+ tweetUrl,
+ tags,
+ rawBody: article.body,
+ body,
+ })
+ );
+ });
+ });
+}
+
+module.exports = loadArticle;
diff --git a/make-tweet-url.js b/make-tweet-url.js
new file mode 100644
index 0000000..b440dcf
--- /dev/null
+++ b/make-tweet-url.js
@@ -0,0 +1,11 @@
+function makeTweetUrl(article) {
+ const title = article.attributes.title;
+ const route = article.attributes.route;
+
+ const baseUrl = "https://twitter.com/intent/tweet";
+ const text = "“" + title + "” by @xFuwn – http://blog.fuwn.me" + route;
+
+ return baseUrl + "?text=" + encodeURIComponent(text);
+}
+
+module.exports = makeTweetUrl;
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 0000000..a689fe2
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,7 @@
+# [[redirects]]
+# from = "https://blog.fuwn.me/*"
+# to = "https://jot-ten.vercel.app/:splat"
+# status = 200
+# force = true
+# [redirects.headers]
+# X-From = "Netlify"
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..c55453c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,46 @@
+{
+ "dependencies": {
+ "ejs": "^2.4.1",
+ "front-matter": "^3.0.2",
+ "glob": "^7.1.4",
+ "highlight.js": "^9.3.0",
+ "katex": "^0.10.2",
+ "marked": "^0.6.2",
+ "mkdirp": "^0.5.1",
+ "ncp": "^2.0.0",
+ "strftime": "^0.10.0"
+ },
+ "devDependencies": {
+ "express": "^4.16.2",
+ "multer": "^1.3.0",
+ "nodemon": "^1.19.0",
+ "serve": "^11.0.0"
+ },
+ "scripts": {
+ "build": "node index.js",
+ "build-prod": "node index.js",
+ "watch": "nodemon index.js",
+ "serve": "cd output && serve -l 8080",
+ "editor": "nodemon editor/editor.js"
+ },
+ "nodemonConfig": {
+ "ignore": [
+ "output/*"
+ ],
+ "ext": "js,md,css,ejs"
+ },
+ "name": "thatjdanisso.cool",
+ "description": "This is a collection of node scripts to build my blog - https://thatjdanisso.cool",
+ "version": "1.0.0",
+ "main": "index.js",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/jdan/thatjdanisso.cool.git"
+ },
+ "author": "Jordan Scales ",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/jdan/thatjdanisso.cool/issues"
+ },
+ "homepage": "https://github.com/jdan/thatjdanisso.cool#readme"
+}
diff --git a/plugins/tweet.js b/plugins/tweet.js
new file mode 100644
index 0000000..76b454b
--- /dev/null
+++ b/plugins/tweet.js
@@ -0,0 +1,6 @@
+module.exports = function (title, route) {
+ const baseUrl = "https://twitter.com/intent/tweet";
+ const text = "“" + title + "” by @jdan – http://thatjdanisso.cool" + route;
+
+ return baseUrl + "?text=" + encodeURIComponent(text);
+};
diff --git a/public/css/bowling.css b/public/css/bowling.css
new file mode 100644
index 0000000..332bc93
--- /dev/null
+++ b/public/css/bowling.css
@@ -0,0 +1,178 @@
+button {
+ color: #9d261d;
+ background: none;
+ font-family: inherit;
+ font-size: inherit;
+ border: 3px solid #9d261d;
+ padding: 15px;
+ margin-bottom: 10px;
+}
+
+button:hover {
+ color: #fff;
+ background-color: #9d261d;
+ cursor: pointer;
+}
+
+#demo {
+ margin: 40px auto;
+ position: relative;
+}
+
+#stats {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+
+.stats-label {
+ width: 80px;
+}
+
+#scoreboard {
+ height: 76px;
+ display: flex;
+ margin-bottom: 40px;
+}
+
+.scoreboard-half {
+ display: flex;
+ flex-grow: 15;
+}
+
+.scoreboard-half:first-of-type .frame:last-child {
+ border-right: none;
+}
+
+.scoreboard-half:nth-of-type(2) {
+ flex-grow: 16;
+}
+
+.frame {
+ position: relative;
+ box-sizing: border-box;
+ display: flex;
+ justify-content: flex-end;
+ flex-grow: 2;
+ height: 76px;
+ border: 3px solid #222;
+ border-right: none;
+}
+
+.frame:last-child {
+ flex-grow: 3;
+ border-right: 3px solid #222;
+}
+
+.square {
+ border-bottom: 3px solid #222;
+ border-left: 3px solid #222;
+ width: 23px;
+ height: 23px;
+ line-height: 23px;
+
+ text-align: center;
+}
+
+.square:first-of-type {
+ border: none;
+}
+
+.score {
+ position: absolute;
+ bottom: 5px;
+ left: 5px;
+}
+
+#graph {
+ display: flex;
+ height: 300px;
+ align-items: flex-end;
+}
+
+.bar {
+ background-color: #9d261d;
+ flex-grow: 1;
+ margin-right: 1px;
+}
+
+#controls {
+ display: flex;
+}
+
+#throw,
+#game {
+ flex-grow: 3;
+ margin-right: 10px;
+}
+
+#many-games {
+ flex-grow: 4;
+}
+
+.mobile-spacer {
+ display: none;
+}
+
+@media (max-width: 650px) {
+ #demo {
+ margin: 20px auto;
+ }
+
+ button:after {
+ clear: both;
+ }
+
+ #stats {
+ font-size: 16px;
+ }
+
+ .bar {
+ margin: 0;
+ }
+
+ #scoreboard {
+ flex-wrap: wrap;
+ height: auto;
+ }
+
+ #graph {
+ height: 200px;
+ }
+
+ .scoreboard-half:first-of-type .frame:nth-of-type(5) {
+ border-right: 3px solid #222;
+ }
+
+ .frame {
+ flex-basis: 0;
+ }
+
+ .scoreboard-half:first-of-type .frame {
+ border-bottom: none;
+ flex-grow: 2;
+ }
+
+ .mobile-spacer {
+ display: block;
+ flex-grow: 1;
+ }
+
+ #controls {
+ flex-wrap: wrap;
+ }
+
+ #controls button {
+ margin: 0 0 10px;
+ }
+
+ button#throw {
+ margin-right: 10px;
+ }
+}
+
+@media (max-width: 425px) {
+ button#throw {
+ margin-right: 0;
+ }
+}
diff --git a/public/css/color-blindness.css b/public/css/color-blindness.css
new file mode 100644
index 0000000..ebe492b
--- /dev/null
+++ b/public/css/color-blindness.css
@@ -0,0 +1,30 @@
+body {
+ filter: url("#color-filter");
+ -webkit-filter: url("#color-filter");
+}
+
+#controls {
+ margin-bottom: 60px;
+}
+
+img {
+ border: none;
+ width: 50%;
+ float: left;
+}
+
+svg {
+ width: 0;
+ height: 0;
+}
+
+.control .label-text {
+ display: inline-block;
+ width: 40px;
+}
+
+.control .label-value {
+ display: inline-block;
+ text-align: right;
+ width: 70px;
+}
diff --git a/public/css/demos/clicking.css b/public/css/demos/clicking.css
new file mode 100644
index 0000000..9a9016e
--- /dev/null
+++ b/public/css/demos/clicking.css
@@ -0,0 +1,46 @@
+.a11y-onclick .button {
+ text-align: center;
+ margin-right: 20px;
+ width: 100px;
+ color: white;
+ padding: 15px 25px;
+ background-color: #0074f6;
+}
+
+.a11y-onclick.active:not(.no-active) .button {
+ background-color: #004a93;
+}
+
+.a11y-onclick .output {
+ width: 200px;
+ padding: 15px;
+ background-color: #e9e9e9;
+}
+
+.a11y-onclick.active .mouse-pointer {
+ top: 29px;
+}
+
+.a11y-onclick .row {
+ width: 100%;
+}
+
+.a11y-onclick .enter-key {
+ margin: 0 auto 20px;
+ width: 129px;
+ padding: 15px 25px;
+ background-color: #222222;
+ color: #ffffff;
+ text-align: right;
+ border-radius: 7px;
+ border-bottom: 5px solid #666666;
+}
+
+.a11y-onclick.active .enter-key {
+ margin-top: 3px;
+ border-bottom-width: 2px;
+}
+
+.a11y-onclick .button.focused {
+ outline: 3px solid #000000;
+}
diff --git a/public/css/demos/hover.css b/public/css/demos/hover.css
new file mode 100644
index 0000000..23592da
--- /dev/null
+++ b/public/css/demos/hover.css
@@ -0,0 +1,120 @@
+.hover-a11y .row {
+ background-color: #004a93;
+}
+
+.hover-a11y .button {
+ color: #ffffff;
+ padding: 15px 25px;
+ text-align: center;
+}
+
+.hover-a11y .mouse-pointer {
+ animation: mousepos 6s ease-in-out 0s infinite;
+ -webkit-animation: mousepos 6s ease-in-out 0s infinite;
+ -moz-animation: mousepos 6s ease-in-out 0s infinite;
+ -o-animation: mousepos 6s ease-in-out 0s infinite;
+}
+
+.hover-a11y:not(.no-active) .button.active {
+ color: #aabbdd;
+}
+
+.hover-a11y.with-underline:not(.no-active) .button.active {
+ text-decoration: underline;
+}
+
+@-webkit-keyframes mousepos {
+ 0% {
+ -webkit-transform: translateX(30px) rotateZ(-20deg);
+ }
+ 15% {
+ -webkit-transform: translateX(100px) rotateZ(-20deg);
+ }
+ 20% {
+ -webkit-transform: translateX(100px) rotateZ(-20deg);
+ }
+ 40% {
+ -webkit-transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 45% {
+ -webkit-transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 80% {
+ -webkit-transform: translateX(30px) rotateZ(-20deg);
+ }
+ 100% {
+ -webkit-transform: translateX(30px) rotateZ(-20deg);
+ }
+}
+
+@-moz-keyframes mousepos {
+ 0% {
+ -moz-transform: translateX(30px) rotateZ(-20deg);
+ }
+ 15% {
+ -moz-transform: translateX(100px) rotateZ(-20deg);
+ }
+ 20% {
+ -moz-transform: translateX(100px) rotateZ(-20deg);
+ }
+ 40% {
+ -moz-transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 45% {
+ -moz-transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 80% {
+ -moz-transform: translateX(30px) rotateZ(-20deg);
+ }
+ 100% {
+ -moz-transform: translateX(30px) rotateZ(-20deg);
+ }
+}
+
+@-o-keyframes mousepos {
+ 0% {
+ -o-transform: translateX(30px) rotateZ(-20deg);
+ }
+ 15% {
+ -o-transform: translateX(100px) rotateZ(-20deg);
+ }
+ 20% {
+ -o-transform: translateX(100px) rotateZ(-20deg);
+ }
+ 40% {
+ -o-transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 45% {
+ -o-transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 80% {
+ -o-transform: translateX(30px) rotateZ(-20deg);
+ }
+ 100% {
+ -o-transform: translateX(30px) rotateZ(-20deg);
+ }
+}
+
+@keyframes mousepos {
+ 0% {
+ transform: translateX(30px) rotateZ(-20deg);
+ }
+ 15% {
+ transform: translateX(100px) rotateZ(-20deg);
+ }
+ 20% {
+ transform: translateX(100px) rotateZ(-20deg);
+ }
+ 40% {
+ transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 45% {
+ transform: translateX(300px) rotateZ(-20deg) translateY(10px);
+ }
+ 80% {
+ transform: translateX(30px) rotateZ(-20deg);
+ }
+ 100% {
+ transform: translateX(30px) rotateZ(-20deg);
+ }
+}
diff --git a/public/css/demos/shared.css b/public/css/demos/shared.css
new file mode 100644
index 0000000..7794d32
--- /dev/null
+++ b/public/css/demos/shared.css
@@ -0,0 +1,28 @@
+.mouse-pointer {
+ -webkit-transform: rotateZ(-20deg);
+ -moz-transform: rotateZ(-20deg);
+ -ms-transform: rotateZ(-20deg);
+ -o-transform: rotateZ(-20deg);
+ transform: rotateZ(-20deg);
+ position: relative;
+ width: 0;
+ top: 27px;
+ right: 45px;
+}
+
+.mouse-pointer .head {
+ border-left: 7px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 16px solid white;
+ width: 0;
+ height: 0;
+}
+
+.mouse-pointer .tail {
+ width: 3px;
+ height: 8px;
+ position: relative;
+ left: 5px;
+ top: -1px;
+ background-color: #ffffff;
+}
diff --git a/public/css/fonts/KaTeX_AMS-Regular.ttf b/public/css/fonts/KaTeX_AMS-Regular.ttf
new file mode 100644
index 0000000..afcd2eb
Binary files /dev/null and b/public/css/fonts/KaTeX_AMS-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_AMS-Regular.woff b/public/css/fonts/KaTeX_AMS-Regular.woff
new file mode 100644
index 0000000..4f57515
Binary files /dev/null and b/public/css/fonts/KaTeX_AMS-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_AMS-Regular.woff2 b/public/css/fonts/KaTeX_AMS-Regular.woff2
new file mode 100644
index 0000000..b982d6e
Binary files /dev/null and b/public/css/fonts/KaTeX_AMS-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Caligraphic-Bold.ttf b/public/css/fonts/KaTeX_Caligraphic-Bold.ttf
new file mode 100644
index 0000000..f84148d
Binary files /dev/null and b/public/css/fonts/KaTeX_Caligraphic-Bold.ttf differ
diff --git a/public/css/fonts/KaTeX_Caligraphic-Bold.woff b/public/css/fonts/KaTeX_Caligraphic-Bold.woff
new file mode 100644
index 0000000..ab56ab7
Binary files /dev/null and b/public/css/fonts/KaTeX_Caligraphic-Bold.woff differ
diff --git a/public/css/fonts/KaTeX_Caligraphic-Bold.woff2 b/public/css/fonts/KaTeX_Caligraphic-Bold.woff2
new file mode 100644
index 0000000..710c261
Binary files /dev/null and b/public/css/fonts/KaTeX_Caligraphic-Bold.woff2 differ
diff --git a/public/css/fonts/KaTeX_Caligraphic-Regular.ttf b/public/css/fonts/KaTeX_Caligraphic-Regular.ttf
new file mode 100644
index 0000000..97814db
Binary files /dev/null and b/public/css/fonts/KaTeX_Caligraphic-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Caligraphic-Regular.woff b/public/css/fonts/KaTeX_Caligraphic-Regular.woff
new file mode 100644
index 0000000..aec8a33
Binary files /dev/null and b/public/css/fonts/KaTeX_Caligraphic-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Caligraphic-Regular.woff2 b/public/css/fonts/KaTeX_Caligraphic-Regular.woff2
new file mode 100644
index 0000000..ee5193d
Binary files /dev/null and b/public/css/fonts/KaTeX_Caligraphic-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Fraktur-Bold.ttf b/public/css/fonts/KaTeX_Fraktur-Bold.ttf
new file mode 100644
index 0000000..483a7cd
Binary files /dev/null and b/public/css/fonts/KaTeX_Fraktur-Bold.ttf differ
diff --git a/public/css/fonts/KaTeX_Fraktur-Bold.woff b/public/css/fonts/KaTeX_Fraktur-Bold.woff
new file mode 100644
index 0000000..189fea5
Binary files /dev/null and b/public/css/fonts/KaTeX_Fraktur-Bold.woff differ
diff --git a/public/css/fonts/KaTeX_Fraktur-Bold.woff2 b/public/css/fonts/KaTeX_Fraktur-Bold.woff2
new file mode 100644
index 0000000..dc3bd4c
Binary files /dev/null and b/public/css/fonts/KaTeX_Fraktur-Bold.woff2 differ
diff --git a/public/css/fonts/KaTeX_Fraktur-Regular.ttf b/public/css/fonts/KaTeX_Fraktur-Regular.ttf
new file mode 100644
index 0000000..9aa5f67
Binary files /dev/null and b/public/css/fonts/KaTeX_Fraktur-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Fraktur-Regular.woff b/public/css/fonts/KaTeX_Fraktur-Regular.woff
new file mode 100644
index 0000000..d01450e
Binary files /dev/null and b/public/css/fonts/KaTeX_Fraktur-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Fraktur-Regular.woff2 b/public/css/fonts/KaTeX_Fraktur-Regular.woff2
new file mode 100644
index 0000000..7eeba37
Binary files /dev/null and b/public/css/fonts/KaTeX_Fraktur-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Main-Bold.ttf b/public/css/fonts/KaTeX_Main-Bold.ttf
new file mode 100644
index 0000000..dc0185a
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Bold.ttf differ
diff --git a/public/css/fonts/KaTeX_Main-Bold.woff b/public/css/fonts/KaTeX_Main-Bold.woff
new file mode 100644
index 0000000..acf48e6
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Bold.woff differ
diff --git a/public/css/fonts/KaTeX_Main-Bold.woff2 b/public/css/fonts/KaTeX_Main-Bold.woff2
new file mode 100644
index 0000000..cf5abab
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Bold.woff2 differ
diff --git a/public/css/fonts/KaTeX_Main-BoldItalic.ttf b/public/css/fonts/KaTeX_Main-BoldItalic.ttf
new file mode 100644
index 0000000..4346f17
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-BoldItalic.ttf differ
diff --git a/public/css/fonts/KaTeX_Main-BoldItalic.woff b/public/css/fonts/KaTeX_Main-BoldItalic.woff
new file mode 100644
index 0000000..d2cfe4e
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-BoldItalic.woff differ
diff --git a/public/css/fonts/KaTeX_Main-BoldItalic.woff2 b/public/css/fonts/KaTeX_Main-BoldItalic.woff2
new file mode 100644
index 0000000..d0178f4
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-BoldItalic.woff2 differ
diff --git a/public/css/fonts/KaTeX_Main-Italic.ttf b/public/css/fonts/KaTeX_Main-Italic.ttf
new file mode 100644
index 0000000..f2c3eba
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Italic.ttf differ
diff --git a/public/css/fonts/KaTeX_Main-Italic.woff b/public/css/fonts/KaTeX_Main-Italic.woff
new file mode 100644
index 0000000..1184295
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Italic.woff differ
diff --git a/public/css/fonts/KaTeX_Main-Italic.woff2 b/public/css/fonts/KaTeX_Main-Italic.woff2
new file mode 100644
index 0000000..aa05e14
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Italic.woff2 differ
diff --git a/public/css/fonts/KaTeX_Main-Regular.ttf b/public/css/fonts/KaTeX_Main-Regular.ttf
new file mode 100644
index 0000000..8acb365
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Main-Regular.woff b/public/css/fonts/KaTeX_Main-Regular.woff
new file mode 100644
index 0000000..9f8228f
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Main-Regular.woff2 b/public/css/fonts/KaTeX_Main-Regular.woff2
new file mode 100644
index 0000000..e3f71eb
Binary files /dev/null and b/public/css/fonts/KaTeX_Main-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Math-BoldItalic.ttf b/public/css/fonts/KaTeX_Math-BoldItalic.ttf
new file mode 100644
index 0000000..a645df6
Binary files /dev/null and b/public/css/fonts/KaTeX_Math-BoldItalic.ttf differ
diff --git a/public/css/fonts/KaTeX_Math-BoldItalic.woff b/public/css/fonts/KaTeX_Math-BoldItalic.woff
new file mode 100644
index 0000000..87d4f22
Binary files /dev/null and b/public/css/fonts/KaTeX_Math-BoldItalic.woff differ
diff --git a/public/css/fonts/KaTeX_Math-BoldItalic.woff2 b/public/css/fonts/KaTeX_Math-BoldItalic.woff2
new file mode 100644
index 0000000..83b4996
Binary files /dev/null and b/public/css/fonts/KaTeX_Math-BoldItalic.woff2 differ
diff --git a/public/css/fonts/KaTeX_Math-Italic.ttf b/public/css/fonts/KaTeX_Math-Italic.ttf
new file mode 100644
index 0000000..9c38359
Binary files /dev/null and b/public/css/fonts/KaTeX_Math-Italic.ttf differ
diff --git a/public/css/fonts/KaTeX_Math-Italic.woff b/public/css/fonts/KaTeX_Math-Italic.woff
new file mode 100644
index 0000000..959746e
Binary files /dev/null and b/public/css/fonts/KaTeX_Math-Italic.woff differ
diff --git a/public/css/fonts/KaTeX_Math-Italic.woff2 b/public/css/fonts/KaTeX_Math-Italic.woff2
new file mode 100644
index 0000000..e3ea522
Binary files /dev/null and b/public/css/fonts/KaTeX_Math-Italic.woff2 differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Bold.ttf b/public/css/fonts/KaTeX_SansSerif-Bold.ttf
new file mode 100644
index 0000000..ff10851
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Bold.ttf differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Bold.woff b/public/css/fonts/KaTeX_SansSerif-Bold.woff
new file mode 100644
index 0000000..f0d6ea7
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Bold.woff differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Bold.woff2 b/public/css/fonts/KaTeX_SansSerif-Bold.woff2
new file mode 100644
index 0000000..4cf8f14
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Bold.woff2 differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Italic.ttf b/public/css/fonts/KaTeX_SansSerif-Italic.ttf
new file mode 100644
index 0000000..3dd7671
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Italic.ttf differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Italic.woff b/public/css/fonts/KaTeX_SansSerif-Italic.woff
new file mode 100644
index 0000000..9da0dfe
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Italic.woff differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Italic.woff2 b/public/css/fonts/KaTeX_SansSerif-Italic.woff2
new file mode 100644
index 0000000..ce19ae0
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Italic.woff2 differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Regular.ttf b/public/css/fonts/KaTeX_SansSerif-Regular.ttf
new file mode 100644
index 0000000..f117cd6
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Regular.woff b/public/css/fonts/KaTeX_SansSerif-Regular.woff
new file mode 100644
index 0000000..6ed9878
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_SansSerif-Regular.woff2 b/public/css/fonts/KaTeX_SansSerif-Regular.woff2
new file mode 100644
index 0000000..2761149
Binary files /dev/null and b/public/css/fonts/KaTeX_SansSerif-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Script-Regular.ttf b/public/css/fonts/KaTeX_Script-Regular.ttf
new file mode 100644
index 0000000..e6f3454
Binary files /dev/null and b/public/css/fonts/KaTeX_Script-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Script-Regular.woff b/public/css/fonts/KaTeX_Script-Regular.woff
new file mode 100644
index 0000000..4a48e65
Binary files /dev/null and b/public/css/fonts/KaTeX_Script-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Script-Regular.woff2 b/public/css/fonts/KaTeX_Script-Regular.woff2
new file mode 100644
index 0000000..b0aed19
Binary files /dev/null and b/public/css/fonts/KaTeX_Script-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Size1-Regular.ttf b/public/css/fonts/KaTeX_Size1-Regular.ttf
new file mode 100644
index 0000000..37faa0f
Binary files /dev/null and b/public/css/fonts/KaTeX_Size1-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Size1-Regular.woff b/public/css/fonts/KaTeX_Size1-Regular.woff
new file mode 100644
index 0000000..0832f7a
Binary files /dev/null and b/public/css/fonts/KaTeX_Size1-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Size1-Regular.woff2 b/public/css/fonts/KaTeX_Size1-Regular.woff2
new file mode 100644
index 0000000..483e7b6
Binary files /dev/null and b/public/css/fonts/KaTeX_Size1-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Size2-Regular.ttf b/public/css/fonts/KaTeX_Size2-Regular.ttf
new file mode 100644
index 0000000..cf32623
Binary files /dev/null and b/public/css/fonts/KaTeX_Size2-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Size2-Regular.woff b/public/css/fonts/KaTeX_Size2-Regular.woff
new file mode 100644
index 0000000..14f6485
Binary files /dev/null and b/public/css/fonts/KaTeX_Size2-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Size2-Regular.woff2 b/public/css/fonts/KaTeX_Size2-Regular.woff2
new file mode 100644
index 0000000..5ff7060
Binary files /dev/null and b/public/css/fonts/KaTeX_Size2-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Size3-Regular.ttf b/public/css/fonts/KaTeX_Size3-Regular.ttf
new file mode 100644
index 0000000..ff7e2b9
Binary files /dev/null and b/public/css/fonts/KaTeX_Size3-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Size3-Regular.woff b/public/css/fonts/KaTeX_Size3-Regular.woff
new file mode 100644
index 0000000..d3626ce
Binary files /dev/null and b/public/css/fonts/KaTeX_Size3-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Size3-Regular.woff2 b/public/css/fonts/KaTeX_Size3-Regular.woff2
new file mode 100644
index 0000000..e45ca49
Binary files /dev/null and b/public/css/fonts/KaTeX_Size3-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Size4-Regular.ttf b/public/css/fonts/KaTeX_Size4-Regular.ttf
new file mode 100644
index 0000000..3034091
Binary files /dev/null and b/public/css/fonts/KaTeX_Size4-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Size4-Regular.woff b/public/css/fonts/KaTeX_Size4-Regular.woff
new file mode 100644
index 0000000..93c57a6
Binary files /dev/null and b/public/css/fonts/KaTeX_Size4-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Size4-Regular.woff2 b/public/css/fonts/KaTeX_Size4-Regular.woff2
new file mode 100644
index 0000000..53b65af
Binary files /dev/null and b/public/css/fonts/KaTeX_Size4-Regular.woff2 differ
diff --git a/public/css/fonts/KaTeX_Typewriter-Regular.ttf b/public/css/fonts/KaTeX_Typewriter-Regular.ttf
new file mode 100644
index 0000000..2fd8529
Binary files /dev/null and b/public/css/fonts/KaTeX_Typewriter-Regular.ttf differ
diff --git a/public/css/fonts/KaTeX_Typewriter-Regular.woff b/public/css/fonts/KaTeX_Typewriter-Regular.woff
new file mode 100644
index 0000000..e90fa2b
Binary files /dev/null and b/public/css/fonts/KaTeX_Typewriter-Regular.woff differ
diff --git a/public/css/fonts/KaTeX_Typewriter-Regular.woff2 b/public/css/fonts/KaTeX_Typewriter-Regular.woff2
new file mode 100644
index 0000000..e40ab15
Binary files /dev/null and b/public/css/fonts/KaTeX_Typewriter-Regular.woff2 differ
diff --git a/public/css/katex.min.css b/public/css/katex.min.css
new file mode 100644
index 0000000..7549d6e
--- /dev/null
+++ b/public/css/katex.min.css
@@ -0,0 +1,1052 @@
+@font-face {
+ font-family: KaTeX_AMS;
+ src: url(fonts/KaTeX_AMS-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_AMS-Regular.woff) format("woff"),
+ url(fonts/KaTeX_AMS-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Caligraphic;
+ src: url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),
+ url(fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),
+ url(fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype");
+ font-weight: 700;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Caligraphic;
+ src: url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Fraktur;
+ src: url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),
+ url(fonts/KaTeX_Fraktur-Bold.woff) format("woff"),
+ url(fonts/KaTeX_Fraktur-Bold.ttf) format("truetype");
+ font-weight: 700;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Fraktur;
+ src: url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Fraktur-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Fraktur-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Main;
+ src: url(fonts/KaTeX_Main-Bold.woff2) format("woff2"),
+ url(fonts/KaTeX_Main-Bold.woff) format("woff"),
+ url(fonts/KaTeX_Main-Bold.ttf) format("truetype");
+ font-weight: 700;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Main;
+ src: url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),
+ url(fonts/KaTeX_Main-BoldItalic.woff) format("woff"),
+ url(fonts/KaTeX_Main-BoldItalic.ttf) format("truetype");
+ font-weight: 700;
+ font-style: italic;
+}
+@font-face {
+ font-family: KaTeX_Main;
+ src: url(fonts/KaTeX_Main-Italic.woff2) format("woff2"),
+ url(fonts/KaTeX_Main-Italic.woff) format("woff"),
+ url(fonts/KaTeX_Main-Italic.ttf) format("truetype");
+ font-weight: 400;
+ font-style: italic;
+}
+@font-face {
+ font-family: KaTeX_Main;
+ src: url(fonts/KaTeX_Main-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Main-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Main-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Math;
+ src: url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),
+ url(fonts/KaTeX_Math-BoldItalic.woff) format("woff"),
+ url(fonts/KaTeX_Math-BoldItalic.ttf) format("truetype");
+ font-weight: 700;
+ font-style: italic;
+}
+@font-face {
+ font-family: KaTeX_Math;
+ src: url(fonts/KaTeX_Math-Italic.woff2) format("woff2"),
+ url(fonts/KaTeX_Math-Italic.woff) format("woff"),
+ url(fonts/KaTeX_Math-Italic.ttf) format("truetype");
+ font-weight: 400;
+ font-style: italic;
+}
+@font-face {
+ font-family: "KaTeX_SansSerif";
+ src: url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),
+ url(fonts/KaTeX_SansSerif-Bold.woff) format("woff"),
+ url(fonts/KaTeX_SansSerif-Bold.ttf) format("truetype");
+ font-weight: 700;
+ font-style: normal;
+}
+@font-face {
+ font-family: "KaTeX_SansSerif";
+ src: url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),
+ url(fonts/KaTeX_SansSerif-Italic.woff) format("woff"),
+ url(fonts/KaTeX_SansSerif-Italic.ttf) format("truetype");
+ font-weight: 400;
+ font-style: italic;
+}
+@font-face {
+ font-family: "KaTeX_SansSerif";
+ src: url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_SansSerif-Regular.woff) format("woff"),
+ url(fonts/KaTeX_SansSerif-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Script;
+ src: url(fonts/KaTeX_Script-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Script-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Script-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Size1;
+ src: url(fonts/KaTeX_Size1-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Size1-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Size1-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Size2;
+ src: url(fonts/KaTeX_Size2-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Size2-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Size2-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Size3;
+ src: url(fonts/KaTeX_Size3-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Size3-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Size3-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Size4;
+ src: url(fonts/KaTeX_Size4-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Size4-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Size4-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: KaTeX_Typewriter;
+ src: url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),
+ url(fonts/KaTeX_Typewriter-Regular.woff) format("woff"),
+ url(fonts/KaTeX_Typewriter-Regular.ttf) format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+.katex {
+ font: normal 1.21em KaTeX_Main, Times New Roman, serif;
+ line-height: 1.2;
+ text-indent: 0;
+ text-rendering: auto;
+}
+.katex * {
+ -ms-high-contrast-adjust: none !important;
+}
+.katex .katex-version:after {
+ content: "0.10.2";
+}
+.katex .katex-mathml {
+ position: absolute;
+ clip: rect(1px, 1px, 1px, 1px);
+ padding: 0;
+ border: 0;
+ height: 1px;
+ width: 1px;
+ overflow: hidden;
+}
+.katex .katex-html > .newline {
+ display: block;
+}
+.katex .base {
+ position: relative;
+ white-space: nowrap;
+ width: min-content;
+}
+.katex .base,
+.katex .strut {
+ display: inline-block;
+}
+.katex .textbf {
+ font-weight: 700;
+}
+.katex .textit {
+ font-style: italic;
+}
+.katex .textrm {
+ font-family: KaTeX_Main;
+}
+.katex .textsf {
+ font-family: KaTeX_SansSerif;
+}
+.katex .texttt {
+ font-family: KaTeX_Typewriter;
+}
+.katex .mathdefault {
+ font-family: KaTeX_Math;
+ font-style: italic;
+}
+.katex .mathit {
+ font-family: KaTeX_Main;
+ font-style: italic;
+}
+.katex .mathrm {
+ font-style: normal;
+}
+.katex .mathbf {
+ font-family: KaTeX_Main;
+ font-weight: 700;
+}
+.katex .boldsymbol {
+ font-family: KaTeX_Math;
+ font-weight: 700;
+ font-style: italic;
+}
+.katex .amsrm,
+.katex .mathbb,
+.katex .textbb {
+ font-family: KaTeX_AMS;
+}
+.katex .mathcal {
+ font-family: KaTeX_Caligraphic;
+}
+.katex .mathfrak,
+.katex .textfrak {
+ font-family: KaTeX_Fraktur;
+}
+.katex .mathtt {
+ font-family: KaTeX_Typewriter;
+}
+.katex .mathscr,
+.katex .textscr {
+ font-family: KaTeX_Script;
+}
+.katex .mathsf,
+.katex .textsf {
+ font-family: KaTeX_SansSerif;
+}
+.katex .mathboldsf,
+.katex .textboldsf {
+ font-family: KaTeX_SansSerif;
+ font-weight: 700;
+}
+.katex .mathitsf,
+.katex .textitsf {
+ font-family: KaTeX_SansSerif;
+ font-style: italic;
+}
+.katex .mainrm {
+ font-family: KaTeX_Main;
+ font-style: normal;
+}
+.katex .vlist-t {
+ display: inline-table;
+ table-layout: fixed;
+}
+.katex .vlist-r {
+ display: table-row;
+}
+.katex .vlist {
+ display: table-cell;
+ vertical-align: bottom;
+ position: relative;
+}
+.katex .vlist > span {
+ display: block;
+ height: 0;
+ position: relative;
+}
+.katex .vlist > span > span {
+ display: inline-block;
+}
+.katex .vlist > span > .pstrut {
+ overflow: hidden;
+ width: 0;
+}
+.katex .vlist-t2 {
+ margin-right: -2px;
+}
+.katex .vlist-s {
+ display: table-cell;
+ vertical-align: bottom;
+ font-size: 1px;
+ width: 2px;
+ min-width: 2px;
+}
+.katex .msupsub {
+ text-align: left;
+}
+.katex .mfrac > span > span {
+ text-align: center;
+}
+.katex .mfrac .frac-line {
+ display: inline-block;
+ width: 100%;
+ border-bottom-style: solid;
+}
+.katex .hdashline,
+.katex .hline,
+.katex .mfrac .frac-line,
+.katex .overline .overline-line,
+.katex .rule,
+.katex .underline .underline-line {
+ min-height: 1px;
+}
+.katex .mspace {
+ display: inline-block;
+}
+.katex .clap,
+.katex .llap,
+.katex .rlap {
+ width: 0;
+ position: relative;
+}
+.katex .clap > .inner,
+.katex .llap > .inner,
+.katex .rlap > .inner {
+ position: absolute;
+}
+.katex .clap > .fix,
+.katex .llap > .fix,
+.katex .rlap > .fix {
+ display: inline-block;
+}
+.katex .llap > .inner {
+ right: 0;
+}
+.katex .clap > .inner,
+.katex .rlap > .inner {
+ left: 0;
+}
+.katex .clap > .inner > span {
+ margin-left: -50%;
+ margin-right: 50%;
+}
+.katex .rule {
+ display: inline-block;
+ border: 0 solid;
+ position: relative;
+}
+.katex .hline,
+.katex .overline .overline-line,
+.katex .underline .underline-line {
+ display: inline-block;
+ width: 100%;
+ border-bottom-style: solid;
+}
+.katex .hdashline {
+ display: inline-block;
+ width: 100%;
+ border-bottom-style: dashed;
+}
+.katex .sqrt > .root {
+ margin-left: 0.27777778em;
+ margin-right: -0.55555556em;
+}
+.katex .fontsize-ensurer,
+.katex .sizing {
+ display: inline-block;
+}
+.katex .fontsize-ensurer.reset-size1.size1,
+.katex .sizing.reset-size1.size1 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size1.size2,
+.katex .sizing.reset-size1.size2 {
+ font-size: 1.2em;
+}
+.katex .fontsize-ensurer.reset-size1.size3,
+.katex .sizing.reset-size1.size3 {
+ font-size: 1.4em;
+}
+.katex .fontsize-ensurer.reset-size1.size4,
+.katex .sizing.reset-size1.size4 {
+ font-size: 1.6em;
+}
+.katex .fontsize-ensurer.reset-size1.size5,
+.katex .sizing.reset-size1.size5 {
+ font-size: 1.8em;
+}
+.katex .fontsize-ensurer.reset-size1.size6,
+.katex .sizing.reset-size1.size6 {
+ font-size: 2em;
+}
+.katex .fontsize-ensurer.reset-size1.size7,
+.katex .sizing.reset-size1.size7 {
+ font-size: 2.4em;
+}
+.katex .fontsize-ensurer.reset-size1.size8,
+.katex .sizing.reset-size1.size8 {
+ font-size: 2.88em;
+}
+.katex .fontsize-ensurer.reset-size1.size9,
+.katex .sizing.reset-size1.size9 {
+ font-size: 3.456em;
+}
+.katex .fontsize-ensurer.reset-size1.size10,
+.katex .sizing.reset-size1.size10 {
+ font-size: 4.148em;
+}
+.katex .fontsize-ensurer.reset-size1.size11,
+.katex .sizing.reset-size1.size11 {
+ font-size: 4.976em;
+}
+.katex .fontsize-ensurer.reset-size2.size1,
+.katex .sizing.reset-size2.size1 {
+ font-size: 0.83333333em;
+}
+.katex .fontsize-ensurer.reset-size2.size2,
+.katex .sizing.reset-size2.size2 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size2.size3,
+.katex .sizing.reset-size2.size3 {
+ font-size: 1.16666667em;
+}
+.katex .fontsize-ensurer.reset-size2.size4,
+.katex .sizing.reset-size2.size4 {
+ font-size: 1.33333333em;
+}
+.katex .fontsize-ensurer.reset-size2.size5,
+.katex .sizing.reset-size2.size5 {
+ font-size: 1.5em;
+}
+.katex .fontsize-ensurer.reset-size2.size6,
+.katex .sizing.reset-size2.size6 {
+ font-size: 1.66666667em;
+}
+.katex .fontsize-ensurer.reset-size2.size7,
+.katex .sizing.reset-size2.size7 {
+ font-size: 2em;
+}
+.katex .fontsize-ensurer.reset-size2.size8,
+.katex .sizing.reset-size2.size8 {
+ font-size: 2.4em;
+}
+.katex .fontsize-ensurer.reset-size2.size9,
+.katex .sizing.reset-size2.size9 {
+ font-size: 2.88em;
+}
+.katex .fontsize-ensurer.reset-size2.size10,
+.katex .sizing.reset-size2.size10 {
+ font-size: 3.45666667em;
+}
+.katex .fontsize-ensurer.reset-size2.size11,
+.katex .sizing.reset-size2.size11 {
+ font-size: 4.14666667em;
+}
+.katex .fontsize-ensurer.reset-size3.size1,
+.katex .sizing.reset-size3.size1 {
+ font-size: 0.71428571em;
+}
+.katex .fontsize-ensurer.reset-size3.size2,
+.katex .sizing.reset-size3.size2 {
+ font-size: 0.85714286em;
+}
+.katex .fontsize-ensurer.reset-size3.size3,
+.katex .sizing.reset-size3.size3 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size3.size4,
+.katex .sizing.reset-size3.size4 {
+ font-size: 1.14285714em;
+}
+.katex .fontsize-ensurer.reset-size3.size5,
+.katex .sizing.reset-size3.size5 {
+ font-size: 1.28571429em;
+}
+.katex .fontsize-ensurer.reset-size3.size6,
+.katex .sizing.reset-size3.size6 {
+ font-size: 1.42857143em;
+}
+.katex .fontsize-ensurer.reset-size3.size7,
+.katex .sizing.reset-size3.size7 {
+ font-size: 1.71428571em;
+}
+.katex .fontsize-ensurer.reset-size3.size8,
+.katex .sizing.reset-size3.size8 {
+ font-size: 2.05714286em;
+}
+.katex .fontsize-ensurer.reset-size3.size9,
+.katex .sizing.reset-size3.size9 {
+ font-size: 2.46857143em;
+}
+.katex .fontsize-ensurer.reset-size3.size10,
+.katex .sizing.reset-size3.size10 {
+ font-size: 2.96285714em;
+}
+.katex .fontsize-ensurer.reset-size3.size11,
+.katex .sizing.reset-size3.size11 {
+ font-size: 3.55428571em;
+}
+.katex .fontsize-ensurer.reset-size4.size1,
+.katex .sizing.reset-size4.size1 {
+ font-size: 0.625em;
+}
+.katex .fontsize-ensurer.reset-size4.size2,
+.katex .sizing.reset-size4.size2 {
+ font-size: 0.75em;
+}
+.katex .fontsize-ensurer.reset-size4.size3,
+.katex .sizing.reset-size4.size3 {
+ font-size: 0.875em;
+}
+.katex .fontsize-ensurer.reset-size4.size4,
+.katex .sizing.reset-size4.size4 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size4.size5,
+.katex .sizing.reset-size4.size5 {
+ font-size: 1.125em;
+}
+.katex .fontsize-ensurer.reset-size4.size6,
+.katex .sizing.reset-size4.size6 {
+ font-size: 1.25em;
+}
+.katex .fontsize-ensurer.reset-size4.size7,
+.katex .sizing.reset-size4.size7 {
+ font-size: 1.5em;
+}
+.katex .fontsize-ensurer.reset-size4.size8,
+.katex .sizing.reset-size4.size8 {
+ font-size: 1.8em;
+}
+.katex .fontsize-ensurer.reset-size4.size9,
+.katex .sizing.reset-size4.size9 {
+ font-size: 2.16em;
+}
+.katex .fontsize-ensurer.reset-size4.size10,
+.katex .sizing.reset-size4.size10 {
+ font-size: 2.5925em;
+}
+.katex .fontsize-ensurer.reset-size4.size11,
+.katex .sizing.reset-size4.size11 {
+ font-size: 3.11em;
+}
+.katex .fontsize-ensurer.reset-size5.size1,
+.katex .sizing.reset-size5.size1 {
+ font-size: 0.55555556em;
+}
+.katex .fontsize-ensurer.reset-size5.size2,
+.katex .sizing.reset-size5.size2 {
+ font-size: 0.66666667em;
+}
+.katex .fontsize-ensurer.reset-size5.size3,
+.katex .sizing.reset-size5.size3 {
+ font-size: 0.77777778em;
+}
+.katex .fontsize-ensurer.reset-size5.size4,
+.katex .sizing.reset-size5.size4 {
+ font-size: 0.88888889em;
+}
+.katex .fontsize-ensurer.reset-size5.size5,
+.katex .sizing.reset-size5.size5 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size5.size6,
+.katex .sizing.reset-size5.size6 {
+ font-size: 1.11111111em;
+}
+.katex .fontsize-ensurer.reset-size5.size7,
+.katex .sizing.reset-size5.size7 {
+ font-size: 1.33333333em;
+}
+.katex .fontsize-ensurer.reset-size5.size8,
+.katex .sizing.reset-size5.size8 {
+ font-size: 1.6em;
+}
+.katex .fontsize-ensurer.reset-size5.size9,
+.katex .sizing.reset-size5.size9 {
+ font-size: 1.92em;
+}
+.katex .fontsize-ensurer.reset-size5.size10,
+.katex .sizing.reset-size5.size10 {
+ font-size: 2.30444444em;
+}
+.katex .fontsize-ensurer.reset-size5.size11,
+.katex .sizing.reset-size5.size11 {
+ font-size: 2.76444444em;
+}
+.katex .fontsize-ensurer.reset-size6.size1,
+.katex .sizing.reset-size6.size1 {
+ font-size: 0.5em;
+}
+.katex .fontsize-ensurer.reset-size6.size2,
+.katex .sizing.reset-size6.size2 {
+ font-size: 0.6em;
+}
+.katex .fontsize-ensurer.reset-size6.size3,
+.katex .sizing.reset-size6.size3 {
+ font-size: 0.7em;
+}
+.katex .fontsize-ensurer.reset-size6.size4,
+.katex .sizing.reset-size6.size4 {
+ font-size: 0.8em;
+}
+.katex .fontsize-ensurer.reset-size6.size5,
+.katex .sizing.reset-size6.size5 {
+ font-size: 0.9em;
+}
+.katex .fontsize-ensurer.reset-size6.size6,
+.katex .sizing.reset-size6.size6 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size6.size7,
+.katex .sizing.reset-size6.size7 {
+ font-size: 1.2em;
+}
+.katex .fontsize-ensurer.reset-size6.size8,
+.katex .sizing.reset-size6.size8 {
+ font-size: 1.44em;
+}
+.katex .fontsize-ensurer.reset-size6.size9,
+.katex .sizing.reset-size6.size9 {
+ font-size: 1.728em;
+}
+.katex .fontsize-ensurer.reset-size6.size10,
+.katex .sizing.reset-size6.size10 {
+ font-size: 2.074em;
+}
+.katex .fontsize-ensurer.reset-size6.size11,
+.katex .sizing.reset-size6.size11 {
+ font-size: 2.488em;
+}
+.katex .fontsize-ensurer.reset-size7.size1,
+.katex .sizing.reset-size7.size1 {
+ font-size: 0.41666667em;
+}
+.katex .fontsize-ensurer.reset-size7.size2,
+.katex .sizing.reset-size7.size2 {
+ font-size: 0.5em;
+}
+.katex .fontsize-ensurer.reset-size7.size3,
+.katex .sizing.reset-size7.size3 {
+ font-size: 0.58333333em;
+}
+.katex .fontsize-ensurer.reset-size7.size4,
+.katex .sizing.reset-size7.size4 {
+ font-size: 0.66666667em;
+}
+.katex .fontsize-ensurer.reset-size7.size5,
+.katex .sizing.reset-size7.size5 {
+ font-size: 0.75em;
+}
+.katex .fontsize-ensurer.reset-size7.size6,
+.katex .sizing.reset-size7.size6 {
+ font-size: 0.83333333em;
+}
+.katex .fontsize-ensurer.reset-size7.size7,
+.katex .sizing.reset-size7.size7 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size7.size8,
+.katex .sizing.reset-size7.size8 {
+ font-size: 1.2em;
+}
+.katex .fontsize-ensurer.reset-size7.size9,
+.katex .sizing.reset-size7.size9 {
+ font-size: 1.44em;
+}
+.katex .fontsize-ensurer.reset-size7.size10,
+.katex .sizing.reset-size7.size10 {
+ font-size: 1.72833333em;
+}
+.katex .fontsize-ensurer.reset-size7.size11,
+.katex .sizing.reset-size7.size11 {
+ font-size: 2.07333333em;
+}
+.katex .fontsize-ensurer.reset-size8.size1,
+.katex .sizing.reset-size8.size1 {
+ font-size: 0.34722222em;
+}
+.katex .fontsize-ensurer.reset-size8.size2,
+.katex .sizing.reset-size8.size2 {
+ font-size: 0.41666667em;
+}
+.katex .fontsize-ensurer.reset-size8.size3,
+.katex .sizing.reset-size8.size3 {
+ font-size: 0.48611111em;
+}
+.katex .fontsize-ensurer.reset-size8.size4,
+.katex .sizing.reset-size8.size4 {
+ font-size: 0.55555556em;
+}
+.katex .fontsize-ensurer.reset-size8.size5,
+.katex .sizing.reset-size8.size5 {
+ font-size: 0.625em;
+}
+.katex .fontsize-ensurer.reset-size8.size6,
+.katex .sizing.reset-size8.size6 {
+ font-size: 0.69444444em;
+}
+.katex .fontsize-ensurer.reset-size8.size7,
+.katex .sizing.reset-size8.size7 {
+ font-size: 0.83333333em;
+}
+.katex .fontsize-ensurer.reset-size8.size8,
+.katex .sizing.reset-size8.size8 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size8.size9,
+.katex .sizing.reset-size8.size9 {
+ font-size: 1.2em;
+}
+.katex .fontsize-ensurer.reset-size8.size10,
+.katex .sizing.reset-size8.size10 {
+ font-size: 1.44027778em;
+}
+.katex .fontsize-ensurer.reset-size8.size11,
+.katex .sizing.reset-size8.size11 {
+ font-size: 1.72777778em;
+}
+.katex .fontsize-ensurer.reset-size9.size1,
+.katex .sizing.reset-size9.size1 {
+ font-size: 0.28935185em;
+}
+.katex .fontsize-ensurer.reset-size9.size2,
+.katex .sizing.reset-size9.size2 {
+ font-size: 0.34722222em;
+}
+.katex .fontsize-ensurer.reset-size9.size3,
+.katex .sizing.reset-size9.size3 {
+ font-size: 0.40509259em;
+}
+.katex .fontsize-ensurer.reset-size9.size4,
+.katex .sizing.reset-size9.size4 {
+ font-size: 0.46296296em;
+}
+.katex .fontsize-ensurer.reset-size9.size5,
+.katex .sizing.reset-size9.size5 {
+ font-size: 0.52083333em;
+}
+.katex .fontsize-ensurer.reset-size9.size6,
+.katex .sizing.reset-size9.size6 {
+ font-size: 0.5787037em;
+}
+.katex .fontsize-ensurer.reset-size9.size7,
+.katex .sizing.reset-size9.size7 {
+ font-size: 0.69444444em;
+}
+.katex .fontsize-ensurer.reset-size9.size8,
+.katex .sizing.reset-size9.size8 {
+ font-size: 0.83333333em;
+}
+.katex .fontsize-ensurer.reset-size9.size9,
+.katex .sizing.reset-size9.size9 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size9.size10,
+.katex .sizing.reset-size9.size10 {
+ font-size: 1.20023148em;
+}
+.katex .fontsize-ensurer.reset-size9.size11,
+.katex .sizing.reset-size9.size11 {
+ font-size: 1.43981481em;
+}
+.katex .fontsize-ensurer.reset-size10.size1,
+.katex .sizing.reset-size10.size1 {
+ font-size: 0.24108004em;
+}
+.katex .fontsize-ensurer.reset-size10.size2,
+.katex .sizing.reset-size10.size2 {
+ font-size: 0.28929605em;
+}
+.katex .fontsize-ensurer.reset-size10.size3,
+.katex .sizing.reset-size10.size3 {
+ font-size: 0.33751205em;
+}
+.katex .fontsize-ensurer.reset-size10.size4,
+.katex .sizing.reset-size10.size4 {
+ font-size: 0.38572806em;
+}
+.katex .fontsize-ensurer.reset-size10.size5,
+.katex .sizing.reset-size10.size5 {
+ font-size: 0.43394407em;
+}
+.katex .fontsize-ensurer.reset-size10.size6,
+.katex .sizing.reset-size10.size6 {
+ font-size: 0.48216008em;
+}
+.katex .fontsize-ensurer.reset-size10.size7,
+.katex .sizing.reset-size10.size7 {
+ font-size: 0.57859209em;
+}
+.katex .fontsize-ensurer.reset-size10.size8,
+.katex .sizing.reset-size10.size8 {
+ font-size: 0.69431051em;
+}
+.katex .fontsize-ensurer.reset-size10.size9,
+.katex .sizing.reset-size10.size9 {
+ font-size: 0.83317261em;
+}
+.katex .fontsize-ensurer.reset-size10.size10,
+.katex .sizing.reset-size10.size10 {
+ font-size: 1em;
+}
+.katex .fontsize-ensurer.reset-size10.size11,
+.katex .sizing.reset-size10.size11 {
+ font-size: 1.19961427em;
+}
+.katex .fontsize-ensurer.reset-size11.size1,
+.katex .sizing.reset-size11.size1 {
+ font-size: 0.20096463em;
+}
+.katex .fontsize-ensurer.reset-size11.size2,
+.katex .sizing.reset-size11.size2 {
+ font-size: 0.24115756em;
+}
+.katex .fontsize-ensurer.reset-size11.size3,
+.katex .sizing.reset-size11.size3 {
+ font-size: 0.28135048em;
+}
+.katex .fontsize-ensurer.reset-size11.size4,
+.katex .sizing.reset-size11.size4 {
+ font-size: 0.32154341em;
+}
+.katex .fontsize-ensurer.reset-size11.size5,
+.katex .sizing.reset-size11.size5 {
+ font-size: 0.36173633em;
+}
+.katex .fontsize-ensurer.reset-size11.size6,
+.katex .sizing.reset-size11.size6 {
+ font-size: 0.40192926em;
+}
+.katex .fontsize-ensurer.reset-size11.size7,
+.katex .sizing.reset-size11.size7 {
+ font-size: 0.48231511em;
+}
+.katex .fontsize-ensurer.reset-size11.size8,
+.katex .sizing.reset-size11.size8 {
+ font-size: 0.57877814em;
+}
+.katex .fontsize-ensurer.reset-size11.size9,
+.katex .sizing.reset-size11.size9 {
+ font-size: 0.69453376em;
+}
+.katex .fontsize-ensurer.reset-size11.size10,
+.katex .sizing.reset-size11.size10 {
+ font-size: 0.83360129em;
+}
+.katex .fontsize-ensurer.reset-size11.size11,
+.katex .sizing.reset-size11.size11 {
+ font-size: 1em;
+}
+.katex .delimsizing.size1 {
+ font-family: KaTeX_Size1;
+}
+.katex .delimsizing.size2 {
+ font-family: KaTeX_Size2;
+}
+.katex .delimsizing.size3 {
+ font-family: KaTeX_Size3;
+}
+.katex .delimsizing.size4 {
+ font-family: KaTeX_Size4;
+}
+.katex .delimsizing.mult .delim-size1 > span {
+ font-family: KaTeX_Size1;
+}
+.katex .delimsizing.mult .delim-size4 > span {
+ font-family: KaTeX_Size4;
+}
+.katex .nulldelimiter {
+ display: inline-block;
+ width: 0.12em;
+}
+.katex .delimcenter,
+.katex .op-symbol {
+ position: relative;
+}
+.katex .op-symbol.small-op {
+ font-family: KaTeX_Size1;
+}
+.katex .op-symbol.large-op {
+ font-family: KaTeX_Size2;
+}
+.katex .op-limits > .vlist-t {
+ text-align: center;
+}
+.katex .accent > .vlist-t {
+ text-align: center;
+}
+.katex .accent .accent-body {
+ position: relative;
+}
+.katex .accent .accent-body:not(.accent-full) {
+ width: 0;
+}
+.katex .overlay {
+ display: block;
+}
+.katex .mtable .vertical-separator {
+ display: inline-block;
+ margin: 0 -0.025em;
+ border-right: 0.05em solid;
+ min-width: 1px;
+}
+.katex .mtable .vs-dashed {
+ border-right: 0.05em dashed;
+}
+.katex .mtable .arraycolsep {
+ display: inline-block;
+}
+.katex .mtable .col-align-c > .vlist-t {
+ text-align: center;
+}
+.katex .mtable .col-align-l > .vlist-t {
+ text-align: left;
+}
+.katex .mtable .col-align-r > .vlist-t {
+ text-align: right;
+}
+.katex .svg-align {
+ text-align: left;
+}
+.katex svg {
+ display: block;
+ position: absolute;
+ width: 100%;
+ height: inherit;
+ fill: currentColor;
+ stroke: currentColor;
+ fill-rule: nonzero;
+ fill-opacity: 1;
+ stroke-width: 1;
+ stroke-linecap: butt;
+ stroke-linejoin: miter;
+ stroke-miterlimit: 4;
+ stroke-dasharray: none;
+ stroke-dashoffset: 0;
+ stroke-opacity: 1;
+}
+.katex svg path {
+ stroke: none;
+}
+.katex img {
+ border-style: none;
+ min-width: 0;
+ min-height: 0;
+ max-width: none;
+ max-height: none;
+}
+.katex .stretchy {
+ width: 100%;
+ display: block;
+ position: relative;
+ overflow: hidden;
+}
+.katex .stretchy:after,
+.katex .stretchy:before {
+ content: "";
+}
+.katex .hide-tail {
+ width: 100%;
+ position: relative;
+ overflow: hidden;
+}
+.katex .halfarrow-left {
+ position: absolute;
+ left: 0;
+ width: 50.2%;
+ overflow: hidden;
+}
+.katex .halfarrow-right {
+ position: absolute;
+ right: 0;
+ width: 50.2%;
+ overflow: hidden;
+}
+.katex .brace-left {
+ position: absolute;
+ left: 0;
+ width: 25.1%;
+ overflow: hidden;
+}
+.katex .brace-center {
+ position: absolute;
+ left: 25%;
+ width: 50%;
+ overflow: hidden;
+}
+.katex .brace-right {
+ position: absolute;
+ right: 0;
+ width: 25.1%;
+ overflow: hidden;
+}
+.katex .x-arrow-pad {
+ padding: 0 0.5em;
+}
+.katex .mover,
+.katex .munder,
+.katex .x-arrow {
+ text-align: center;
+}
+.katex .boxpad {
+ padding: 0 0.3em;
+}
+.katex .fbox,
+.katex .fcolorbox {
+ box-sizing: border-box;
+ border: 0.04em solid;
+}
+.katex .cancel-pad {
+ padding: 0 0.2em;
+}
+.katex .cancel-lap {
+ margin-left: -0.2em;
+ margin-right: -0.2em;
+}
+.katex .sout {
+ border-bottom-style: solid;
+ border-bottom-width: 0.08em;
+}
+.katex-display {
+ display: block;
+ margin: 1em 0;
+ text-align: center;
+}
+.katex-display > .katex {
+ display: block;
+ text-align: center;
+ white-space: nowrap;
+}
+.katex-display > .katex > .katex-html {
+ display: block;
+ position: relative;
+}
+.katex-display > .katex > .katex-html > .tag {
+ position: absolute;
+ right: 0;
+}
+.katex-display.leqno > .katex > .katex-html > .tag {
+ left: 0;
+ right: auto;
+}
+.katex-display.fleqn > .katex {
+ text-align: left;
+}
diff --git a/public/css/style.css b/public/css/style.css
new file mode 100644
index 0000000..d1f1837
--- /dev/null
+++ b/public/css/style.css
@@ -0,0 +1,229 @@
+body {
+ color: #222;
+ background-color: #ffffff;
+ font-size: 20px;
+}
+
+body,
+code {
+ font-family: "Inconsolata", monospace;
+}
+
+h1,
+h2,
+h3 {
+ font-size: inherit;
+ display: inline;
+ font-weight: bold;
+}
+
+h2::before {
+ content: "## ";
+}
+
+h3::before {
+ content: "### ";
+}
+
+p {
+ margin: 30px 0;
+}
+
+h1 + p,
+h2 + p,
+h3 + p {
+ margin-top: 0;
+}
+
+p.listing {
+ margin-top: 0;
+}
+
+hr {
+ margin: 0;
+ border: none;
+}
+
+hr::after {
+ content: "---";
+ display: block;
+ text-align: center;
+}
+
+.main {
+ box-sizing: border-box;
+ width: 650px;
+ padding: 30px;
+ margin: 40px auto;
+}
+
+.blog-title {
+ border-bottom: 1px solid #ccc;
+ margin-bottom: 40px;
+}
+
+.article {
+ margin: 34px 0;
+ line-height: 1.6;
+}
+
+a,
+a:visited {
+ color: #9d261d;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a:focus {
+ background-color: #9d261d;
+ color: #fff;
+ outline: none;
+ text-decoration: none;
+}
+
+.date {
+ float: right;
+ color: #767676;
+ font-style: italic;
+}
+
+.tweet {
+ float: right;
+}
+
+code {
+ background-color: #eeeeee;
+}
+
+pre {
+ border-left: 1px solid #d9d9d9;
+ position: relative;
+ left: -20px;
+ padding-left: 20px;
+ overflow-x: scroll;
+}
+
+pre code {
+ background-color: #ffffff;
+ display: block;
+}
+
+img {
+ border: 2px solid black;
+ width: 100%;
+}
+
+.flex {
+ display: -webkit-flex;
+ display: -moz-box;
+ display: -ms-flexbox;
+ display: flex;
+ width: 100%;
+
+ flex-flow: row wrap;
+ -webkit-justify-content: center;
+ justify-content: center;
+}
+
+.demo {
+ border: 2px solid #000;
+ box-sizing: border-box;
+ margin: 20px 0;
+ padding: 40px 0;
+}
+
+.flash-item {
+ animation: flash 8s linear 0s infinite;
+ -webkit-animation: flash 8s linear 0s infinite;
+ -moz-animation: flash 8s linear 0s infinite;
+ -o-animation: flash 8s linear 0s infinite;
+}
+
+.sr-only {
+ border: 0;
+ clip: rect(0, 0, 0, 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+@keyframes flash {
+ 0% {
+ opacity: 1;
+ }
+ 10% {
+ opacity: 0.1;
+ }
+ 20% {
+ opacity: 1;
+ }
+}
+@-webkit-keyframes flash {
+ 0% {
+ opacity: 1;
+ }
+ 10% {
+ opacity: 0.1;
+ }
+ 20% {
+ opacity: 1;
+ }
+}
+@-moz-keyframes flash {
+ 0% {
+ opacity: 1;
+ }
+ 10% {
+ opacity: 0.1;
+ }
+ 20% {
+ opacity: 1;
+ }
+}
+@-o-keyframes flash {
+ 0% {
+ opacity: 1;
+ }
+ 10% {
+ opacity: 0.1;
+ }
+ 20% {
+ opacity: 1;
+ }
+}
+
+@media (max-width: 480px) {
+ body {
+ font-size: 20px;
+ line-height: 1.4;
+ }
+
+ .main {
+ width: 100%;
+ padding: 10px;
+ margin-top: 0;
+ }
+
+ .article {
+ margin-top: 30px;
+ }
+
+ .date {
+ float: none;
+ display: block;
+ }
+
+ .sep {
+ display: none;
+ }
+
+ header a {
+ display: block;
+ }
+}
diff --git a/public/css/tomorrow.min.css b/public/css/tomorrow.min.css
new file mode 100644
index 0000000..b025a41
--- /dev/null
+++ b/public/css/tomorrow.min.css
@@ -0,0 +1,75 @@
+.hljs-comment {
+ color: #8e908c;
+}
+.hljs-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-regexp,
+.ruby .hljs-constant,
+.xml .hljs-tag .hljs-title,
+.xml .hljs-pi,
+.xml .hljs-doctype,
+.html .hljs-doctype,
+.css .hljs-id,
+.css .hljs-class,
+.css .hljs-pseudo {
+ color: #c82829;
+}
+.hljs-number,
+.hljs-preprocessor,
+.hljs-pragma,
+.hljs-built_in,
+.hljs-literal,
+.hljs-params,
+.language-prolog .hljs-symbol,
+.hljs-constant {
+ color: #f5871f;
+}
+.ruby .hljs-class .hljs-title,
+.css .hljs-rule .hljs-attribute {
+ color: #eab700;
+}
+.hljs-string,
+.hljs-value,
+.hljs-inheritance,
+.hljs-header,
+.hljs-name,
+.ruby .hljs-symbol,
+.xml .hljs-cdata {
+ color: #718c00;
+}
+.hljs-title,
+.css .hljs-hexcolor {
+ color: #3e999f;
+}
+.hljs-function,
+.python .hljs-decorator,
+.python .hljs-title,
+.ruby .hljs-function .hljs-title,
+.ruby .hljs-title .hljs-keyword,
+.perl .hljs-sub,
+.javascript .hljs-title,
+.coffeescript .hljs-title {
+ color: #4271ae;
+}
+.hljs-keyword,
+.javascript .hljs-function {
+ color: #8959a8;
+}
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: white;
+ color: #4d4d4c;
+ padding: 0.5em;
+ -webkit-text-size-adjust: none;
+}
+.coffeescript .javascript,
+.javascript .xml,
+.tex .hljs-formula,
+.xml .javascript,
+.xml .vbscript,
+.xml .css,
+.xml .hljs-cdata {
+ opacity: 0.5;
+}
diff --git a/public/img/a11y-invite.png b/public/img/a11y-invite.png
new file mode 100644
index 0000000..f52ad6f
Binary files /dev/null and b/public/img/a11y-invite.png differ
diff --git a/public/img/accessicademy.png b/public/img/accessicademy.png
new file mode 100644
index 0000000..c347e27
Binary files /dev/null and b/public/img/accessicademy.png differ
diff --git a/public/img/ama.png b/public/img/ama.png
new file mode 100644
index 0000000..4526b20
Binary files /dev/null and b/public/img/ama.png differ
diff --git a/public/img/custom-filters.png b/public/img/custom-filters.png
new file mode 100644
index 0000000..b3e7dfe
Binary files /dev/null and b/public/img/custom-filters.png differ
diff --git a/public/img/digits.PNG b/public/img/digits.PNG
new file mode 100644
index 0000000..655ea07
Binary files /dev/null and b/public/img/digits.PNG differ
diff --git a/public/img/extension-settings.png b/public/img/extension-settings.png
new file mode 100644
index 0000000..f2a1a9f
Binary files /dev/null and b/public/img/extension-settings.png differ
diff --git a/public/img/github-spam.png b/public/img/github-spam.png
new file mode 100644
index 0000000..89a3d49
Binary files /dev/null and b/public/img/github-spam.png differ
diff --git a/public/img/greasemonkey-confirm.png b/public/img/greasemonkey-confirm.png
new file mode 100644
index 0000000..b05b5b3
Binary files /dev/null and b/public/img/greasemonkey-confirm.png differ
diff --git a/public/img/greasemonkey.png b/public/img/greasemonkey.png
new file mode 100644
index 0000000..b62db8d
Binary files /dev/null and b/public/img/greasemonkey.png differ
diff --git a/public/img/spam.png b/public/img/spam.png
new file mode 100644
index 0000000..d3992c7
Binary files /dev/null and b/public/img/spam.png differ
diff --git a/public/img/tota11y.png b/public/img/tota11y.png
new file mode 100644
index 0000000..d787d89
Binary files /dev/null and b/public/img/tota11y.png differ
diff --git a/public/img/voiceover.png b/public/img/voiceover.png
new file mode 100644
index 0000000..afa7ff3
Binary files /dev/null and b/public/img/voiceover.png differ
diff --git a/public/img/window.png b/public/img/window.png
new file mode 100644
index 0000000..da10689
Binary files /dev/null and b/public/img/window.png differ
diff --git a/public/js/bowling.js b/public/js/bowling.js
new file mode 100644
index 0000000..e65bf13
--- /dev/null
+++ b/public/js/bowling.js
@@ -0,0 +1,402 @@
+document.addEventListener("DOMContentLoaded", function() {
+ var graph = document.getElementById("graph")
+ var stats = document.getElementById("stats")
+ var scoreboard = document.getElementById("scoreboard")
+
+ function generateEmptyGame() {
+ var frames = []
+ for (var i = 0; i < 9; i++) {
+ frames.push({
+ throws: [null, null],
+ score: null,
+ })
+ }
+
+ frames.push({
+ throws: [null, null, null],
+ score: null,
+ })
+
+ return {
+ frames: frames,
+ currentFrame: 0,
+ isComplete: false,
+ }
+ }
+
+ function scoreGame(game) {
+ var thisFrameScore
+ for (var i = 0; i < 10; i++) {
+ if (game.frames[i].throws[0] === null) {
+ break
+ }
+
+ if (i === 9) {
+ var firstThrow = game.frames[i].throws[0] || 0
+ var secondThrow = game.frames[i].throws[1] || 0
+ var thirdThrow = game.frames[i].throws[2] || 0
+
+ thisFrameScore = firstThrow + secondThrow + thirdThrow
+ } else {
+ // Fetch the next two throws in case we get a mark
+ var firstBonusThrow = game.frames[i + 1].throws[0] || 0
+ var secondBonusThrow
+ if (firstBonusThrow === 10) {
+ // If we're in the 9th frame, pick the second throw of
+ // the next frame as the 10th frame can have multiple
+ // strikes
+ if (i === 8) {
+ secondBonusThrow = game.frames[i + 1].throws[1] || 0
+ } else {
+ secondBonusThrow = game.frames[i + 2].throws[0] || 0
+ }
+ } else {
+ secondBonusThrow = game.frames[i + 1].throws[1] || 0
+ }
+
+ var firstThrow = game.frames[i].throws[0] || 0
+ var secondThrow = game.frames[i].throws[1] || 0
+
+ if (firstThrow === 10) {
+ thisFrameScore = 10 + firstBonusThrow + secondBonusThrow
+ } else if (firstThrow + secondThrow === 10) {
+ thisFrameScore = 10 + firstBonusThrow
+ } else {
+ thisFrameScore = firstThrow + secondThrow
+ }
+ }
+
+ if (i === 0) {
+ game.frames[i].score = thisFrameScore
+ } else {
+ game.frames[i].score = game.frames[i - 1].score + thisFrameScore
+ }
+ }
+ }
+
+ function generateThrow(game) {
+ var isNewFrame = game.frames[game.currentFrame].throws[0] === null
+
+ if (isNewFrame) {
+ var firstThrow = Math.floor(Math.random() * 11)
+ game.frames[game.currentFrame].throws[0] = firstThrow
+
+ if (firstThrow === 10 && game.currentFrame !== 9) {
+ game.currentFrame++
+ }
+ } else {
+ if (game.currentFrame !== 9) {
+ var lastThrow = game.frames[game.currentFrame].throws[0]
+ var nextThrow = Math.floor(Math.random() * (10 - lastThrow + 1))
+
+ game.frames[game.currentFrame].throws[1] = nextThrow
+
+ if (game.currentFrame !== 9) {
+ game.currentFrame++
+ }
+ } else {
+ var firstThrow = game.frames[game.currentFrame].throws[0]
+ var secondThrow = game.frames[game.currentFrame].throws[1]
+
+ if (firstThrow === 10 && secondThrow === null) {
+ var secondThrow = Math.floor(Math.random() * 11)
+ game.frames[game.currentFrame].throws[1] = secondThrow
+ } else if (secondThrow === null) {
+ var secondThrow = Math.floor(Math.random() * (10 - firstThrow + 1))
+
+ game.frames[game.currentFrame].throws[1] = secondThrow
+
+ if (firstThrow + secondThrow !== 10) {
+ game.isComplete = true
+ }
+ } else if (firstThrow === 10 && secondThrow === 10) {
+ var thirdThrow = Math.floor(Math.random() * 11)
+ game.frames[game.currentFrame].throws[2] = thirdThrow
+ game.isComplete = true
+ } else if (firstThrow === 10) {
+ var thirdThrow = Math.floor(Math.random() * (10 - secondThrow + 1))
+
+ game.frames[game.currentFrame].throws[2] = thirdThrow
+ game.isComplete = true
+ } else if (firstThrow + secondThrow === 10) {
+ var thirdThrow = Math.floor(Math.random() * 11)
+ game.frames[game.currentFrame].throws[2] = thirdThrow
+ game.isComplete = true
+ }
+ }
+ }
+ }
+
+ function renderScoreBoard(game) {
+ var frame
+ scoreboard.innerHTML = ""
+
+ var firstHalf = document.createElement("div")
+ firstHalf.classList.add("scoreboard-half")
+
+ var secondHalf = document.createElement("div")
+ secondHalf.classList.add("scoreboard-half")
+
+ for (var i = 0; i < 5; i++) {
+ frame = game.frames[i]
+
+ firstHalf.appendChild(renderFrame(frame.score, frame.throws, i === 9))
+ }
+
+ var mobileSpacer = document.createElement("div")
+ mobileSpacer.classList.add("mobile-spacer")
+ firstHalf.appendChild(mobileSpacer)
+
+ for (var i = 5; i < 10; i++) {
+ frame = game.frames[i]
+
+ secondHalf.appendChild(renderFrame(frame.score, frame.throws, i === 9))
+ }
+
+ scoreboard.appendChild(firstHalf)
+ scoreboard.appendChild(secondHalf)
+ }
+
+ function throwToString(points) {
+ if (points === null) {
+ return " "
+ } else if (points === 10) {
+ return "X"
+ } else if (points === 0) {
+ return "-"
+ } else {
+ return points + ""
+ }
+ }
+
+ // Not the 10th though!
+ function frameToString(throws) {
+ if (throws[0] === 10) {
+ return ["X", ""]
+ } else if (throws[0] + throws[1] === 10) {
+ return [throwToString(throws[0]), "/"]
+ } else {
+ return throws.map(throwToString)
+ }
+ }
+
+ function renderFrame(score, throws, isTenth) {
+ var contents
+ if (isTenth) {
+ // 10th frame has weird logic
+ if (throws === undefined) {
+ contents = ["", "", ""]
+
+ // Two strikes = XX[third throw]
+ } else if (throws[0] === 10 && throws[1] === 10) {
+ contents = [
+ throwToString(10),
+ throwToString(10),
+ throwToString(throws[2]),
+ ]
+
+ // X[normal frame]
+ } else if (throws[0] === 10) {
+ contents = [throwToString(10)].concat(frameToString(throws.slice(1)))
+
+ // [normal frame][bonus throw]
+ } else if (throws[0] + throws[1] === 10) {
+ contents = frameToString(throws.slice(0, 2)).concat([
+ throwToString(throws[2]),
+ ])
+ } else {
+ contents = frameToString(throws)
+ }
+
+ // Make contents 3 items long... lol
+ if (contents.length < 3) {
+ contents.push("")
+ }
+
+ if (contents.length < 3) {
+ contents.push("")
+ }
+ } else {
+ contents = frameToString(throws)
+
+ if (contents.length < 2) {
+ contents.push("")
+ }
+ }
+
+ var frame = document.createElement("div")
+ frame.classList.add("frame")
+
+ contents.forEach(function(formattedThrow) {
+ var square = document.createElement("div")
+ square.classList.add("square")
+ square.innerHTML = formattedThrow
+
+ frame.appendChild(square)
+ })
+
+ var scoreDiv = document.createElement("div")
+ scoreDiv.classList.add("score")
+ scoreDiv.innerHTML = score
+
+ frame.appendChild(scoreDiv)
+
+ return frame
+ }
+
+ function renderGraph(graphDiv) {
+ graphDiv.innerHTML = ""
+
+ var distribution = []
+ for (var i = 0; i <= 300; i++) {
+ distribution[i] = scores[i] || 0
+ }
+ var highestPopulation = Math.max.apply(null, distribution)
+
+ var bar
+ for (var i = 0; i <= 300; i++) {
+ bar = document.createElement("div")
+ bar.classList.add("bar")
+ bar.style.height = ((scores[i] || 0) / highestPopulation) * 100 + "%"
+ graphDiv.appendChild(bar)
+ }
+ }
+
+ function renderStats(statsDiv) {
+ var distribution = []
+ for (var i = 0; i <= 300; i++) {
+ distribution[i] = scores[i] || 0
+ }
+
+ var numGames = distribution.reduce(function(a, b) {
+ return a + b
+ })
+
+ var allGames = []
+ var totalPins = 0
+ var minScore, maxScore
+
+ var mode = 0,
+ modeIndex
+
+ for (var i = 0; i <= 300; i++) {
+ for (var j = 0; j < distribution[i]; j++) {
+ allGames.push(i)
+ totalPins += i
+ }
+
+ if (distribution[i] > 0) {
+ maxScore = i
+
+ if (minScore === undefined) {
+ minScore = i
+ }
+ }
+
+ if (distribution[i] > mode) {
+ mode = distribution[i]
+ modeIndex = i
+ }
+ }
+
+ var mean = Math.floor((totalPins / numGames) * 100) / 100
+
+ // TODO: Odd/even
+ var median
+ if (allGames.length % 2 === 1) {
+ median = allGames[Math.floor(allGames.length / 2)]
+ } else {
+ median =
+ (allGames[Math.floor(allGames.length / 2)] +
+ allGames[Math.floor(allGames.length / 2) - 1]) /
+ 2
+ }
+
+ statsDiv.innerHTML =
+ "" +
+ [
+ 'Games: ' + numGames + " ",
+ 'Min: ' + minScore + " ",
+ 'Max: ' + maxScore + " ",
+ 'Mean: ' + mean + " ",
+ 'Median: ' + median + " ",
+ 'Mode: ' +
+ modeIndex +
+ " (" +
+ mode +
+ " games) ",
+ ].join("
") +
+ "
"
+ }
+
+ var scores = []
+ var game = generateEmptyGame()
+ renderScoreBoard(game)
+
+ var throwButton = document.getElementById("throw")
+ var gameButton = document.getElementById("game")
+ var manyGamesButton = document.getElementById("many-games")
+
+ function handleThrowClick(e) {
+ e.preventDefault()
+
+ if (game.isComplete) {
+ game = generateEmptyGame()
+ }
+
+ generateThrow(game)
+ scoreGame(game)
+ renderScoreBoard(game)
+
+ if (game.isComplete) {
+ var score = game.frames[9].score
+ scores[score] = (scores[score] || 0) + 1
+ renderGraph(graph)
+ renderStats(stats)
+ }
+ }
+
+ function simulateGame() {
+ game = generateEmptyGame()
+ while (!game.isComplete) {
+ generateThrow(game)
+ }
+
+ scoreGame(game)
+ renderScoreBoard(game)
+
+ var score = game.frames[9].score
+ scores[score] = (scores[score] || 0) + 1
+ renderGraph(graph)
+ }
+
+ function handleGameClick(e) {
+ e.preventDefault()
+ simulateGame()
+ renderStats(stats)
+ }
+
+ function handleManyClick(e) {
+ e.preventDefault()
+ var simulations = 0
+
+ ;(function run() {
+ simulations++
+ simulateGame()
+ renderStats(stats)
+
+ if (simulations < 100) {
+ setTimeout(run, 5)
+ }
+ })()
+ }
+
+ throwButton.addEventListener("click", handleThrowClick)
+ throwButton.addEventListener("touchend", handleThrowClick)
+
+ gameButton.addEventListener("click", handleGameClick)
+ gameButton.addEventListener("touchend", handleGameClick)
+
+ manyGamesButton.addEventListener("click", handleManyClick)
+ manyGamesButton.addEventListener("touchend", handleManyClick)
+})
diff --git a/public/js/color-blindness.js b/public/js/color-blindness.js
new file mode 100644
index 0000000..306c98f
--- /dev/null
+++ b/public/js/color-blindness.js
@@ -0,0 +1,30 @@
+var values = {
+ red: 100,
+ green: 100,
+ blue: 100,
+}
+
+function renderLabel(control) {
+ document.getElementById(control + "-value").innerText =
+ "(" + values[control] + ")"
+}
+
+function renderFilter() {
+ var matrix = [
+ [values.red / 100, 0, 0, 0, 0].join(","),
+ [0, values.green / 100, 0, 0, 0].join(","),
+ [0, 0, values.blue / 100, 0, 0].join(","),
+ [0, 0, 0, 1, 0].join(","),
+ ].join("\n")
+
+ document.getElementById("color-matrix").setAttribute("values", matrix)
+}
+
+;["red", "green", "blue"].forEach(function(control) {
+ document.getElementById(control).addEventListener("input", function(e) {
+ values[control] = e.target.value
+
+ renderLabel(control)
+ renderFilter()
+ })
+})
diff --git a/public/js/demos/clicking.js b/public/js/demos/clicking.js
new file mode 100644
index 0000000..4e2e191
--- /dev/null
+++ b/public/js/demos/clicking.js
@@ -0,0 +1,24 @@
+setInterval(function() {
+ var examples = [].slice.call(document.querySelectorAll(".a11y-onclick"))
+ var outputs = [].slice.call(
+ document.querySelectorAll(".a11y-onclick:not(.no-output) .output")
+ )
+
+ examples.forEach(function(el) {
+ el.classList.add("active")
+ })
+
+ outputs.forEach(function(o) {
+ o.innerHTML = "Clicked!"
+ })
+
+ setTimeout(function() {
+ examples.forEach(function(el) {
+ el.classList.remove("active")
+ })
+
+ outputs.forEach(function(o) {
+ o.innerHTML = " "
+ })
+ }, 1000)
+}, 2500)
diff --git a/public/js/demos/hover.js b/public/js/demos/hover.js
new file mode 100644
index 0000000..57d9f3c
--- /dev/null
+++ b/public/js/demos/hover.js
@@ -0,0 +1,42 @@
+var highlightIntervals = [
+ {
+ on: [550, 3900],
+ off: [1400, 4150],
+ },
+ {
+ on: [1700, 3500],
+ off: [1900, 3800],
+ },
+ {
+ on: [2000],
+ off: [3400],
+ },
+]
+
+function highlightSequence() {
+ var examples = [].slice.call(
+ document.querySelectorAll(".hover-a11y:not(.no-active)")
+ )
+
+ examples.forEach(function(example) {
+ console.log(example)
+ var links = [].slice.call(example.querySelectorAll(".button"))
+
+ highlightIntervals.forEach(function(timers, i) {
+ timers.on.forEach(function(ms) {
+ setTimeout(function() {
+ links[i].classList.add("active")
+ }, ms)
+ })
+
+ timers.off.forEach(function(ms) {
+ setTimeout(function() {
+ links[i].classList.remove("active")
+ }, ms)
+ })
+ })
+ })
+}
+
+setInterval(highlightSequence, 6000)
+highlightSequence() // call once to start
diff --git a/public/js/flasher.js b/public/js/flasher.js
new file mode 100644
index 0000000..3c82f28
--- /dev/null
+++ b/public/js/flasher.js
@@ -0,0 +1,16 @@
+var flashEl = document.querySelector(".flash")
+var flashText = flashEl.innerHTML
+var flashItems, i
+
+flashEl.innerHTML = ""
+for (var i = 0; i < flashText.length; i++) {
+ item = document.createElement("span")
+ item.innerHTML = flashText[i]
+ item.className = "flash-item"
+
+ // animation delay
+ item.style.animationDelay = item.style.webkitAnimationDelay = item.style.mozAnimationDelay = item.style.oAnimationDelay =
+ 1 + 0.1 * i + "s"
+
+ flashEl.appendChild(item)
+}
diff --git a/public/js/fraction.min.js b/public/js/fraction.min.js
new file mode 100644
index 0000000..2b6a66b
--- /dev/null
+++ b/public/js/fraction.min.js
@@ -0,0 +1,18 @@
+/*
+Fraction.js v4.0.12 09/09/2015
+http://www.xarg.org/2014/03/rational-numbers-in-javascript/
+
+Copyright (c) 2015, Robert Eisele (robert@xarg.org)
+Dual licensed under the MIT or GPL Version 2 licenses.
+*/
+(function(x){function l(a,b){var c=0,k=1,h=1,e=0,u=0,l=0,p=1,r=1,f=0,g=1,t=1,q=1;if(void 0!==a&&null!==a)if(void 0!==b)c=a,k=b,h=c*k;else switch(typeof a){case "object":"d"in a&&"n"in a?(c=a.n,k=a.d,"s"in a&&(c*=a.s)):0 in a?(c=a[0],1 in a&&(k=a[1])):v();h=c*k;break;case "number":0>a&&(h=a,a=-a);if(0===a%1)c=a;else if(0=g&&1E7>=q;)if(c=(f+t)/(g+q),a===c){1E7>=g+q?(c=f+t,k=g+q):q>g?(c=t,k=q):(c=f,k=g);break}else a>c?(f+=t,
+ g+=q):(t+=f,q+=g),1E7h?-1:1;d.n=Math.abs(c);d.d=Math.abs(k)}function w(a){function b(){var b=Error.apply(this,arguments);b.name=this.name=a;this.stack=b.stack;this.message=b.message}function c(){}c.prototype=Error.prototype;b.prototype=new c;return b}function n(a,b){isNaN(a=parseInt(a,10))&&v();return a*b}function v(){throw new z;
+ }function p(a,b){if(!a)return b;if(!b)return a;for(;;){a%=b;if(!a)return b;b%=a;if(!b)return a}}function e(a,b){if(!(this instanceof e))return new e(a,b);l(a,b);a=e.REDUCE?p(d.d,d.n):1;this.s=d.s;this.n=d.n/a;this.d=d.d/a}var d={s:1,n:0,d:1},y=e.DivisionByZero=w("DivisionByZero"),z=e.InvalidParameter=w("InvalidParameter");e.REDUCE=1;e.prototype={s:1,n:0,d:1,abs:function(){return new e(this.n,this.d)},neg:function(){return new e(-this.s*this.n,this.d)},add:function(a,b){l(a,b);return new e(this.s*
+ this.n*d.d+d.s*this.d*d.n,this.d*d.d)},sub:function(a,b){l(a,b);return new e(this.s*this.n*d.d-d.s*this.d*d.n,this.d*d.d)},mul:function(a,b){l(a,b);return new e(this.s*d.s*this.n*d.n,this.d*d.d)},div:function(a,b){l(a,b);return new e(this.s*d.s*this.n*d.d,this.d*d.n)},clone:function(){return new e(this)},mod:function(a,b){if(isNaN(this.n)||isNaN(this.d))return new e(NaN);if(void 0===a)return new e(this.s*this.n%this.d,1);l(a,b);0===d.n&&0===this.d&&e(0,0);return new e(this.s*d.d*this.n%(d.n*this.d),
+ d.d*this.d)},gcd:function(a,b){l(a,b);return new e(p(d.n,this.n)*p(d.d,this.d),d.d*this.d)},lcm:function(a,b){l(a,b);return 0===d.n&&0===this.n?new e:new e(d.n*this.n,p(d.n,this.n)*p(d.d,this.d))},ceil:function(a){a=Math.pow(10,a||0);return isNaN(this.n)||isNaN(this.d)?new e(NaN):new e(Math.ceil(a*this.s*this.n/this.d),a)},floor:function(a){a=Math.pow(10,a||0);return isNaN(this.n)||isNaN(this.d)?new e(NaN):new e(Math.floor(a*this.s*this.n/this.d),a)},round:function(a){a=Math.pow(10,a||0);return isNaN(this.n)||
+ isNaN(this.d)?new e(NaN):new e(Math.round(a*this.s*this.n/this.d),a)},inverse:function(){return new e(this.s*this.d,this.n)},pow:function(a){return 0>a?new e(Math.pow(this.s*this.d,-a),Math.pow(this.n,-a)):new e(Math.pow(this.s*this.n,a),Math.pow(this.d,a))},equals:function(a,b){l(a,b);return this.s*this.n*d.d===d.s*d.n*this.d},compare:function(a,b){l(a,b);var c=this.s*this.n*d.d-d.s*d.n*this.d;return(0c)},simplify:function(a){function b(a){return 1===a.length?new e(a[0]):b(a.slice(1)).inverse().add(a[0])}
+ if(isNaN(this.n)||isNaN(this.d))return this;var c=this.abs().toContinued();a=a||.001;for(var k=0;kthis.s&&(c+="-");1===e?c+=k:(a&&0<(b=Math.floor(k/e))&&(c=c+b+" ",k%=e),c=c+k+"/",c+=e);return c},toLatex:function(a){var b,
+ c="",e=this.n,d=this.d;0>this.s&&(c+="-");1===d?c+=e:(a&&0<(b=Math.floor(e/d))&&(c+=b,e%=d),c=c+"\\frac{"+e+"}{"+d,c+="}");return c},toContinued:function(){var a=this.n,b=this.d,c=[];if(isNaN(this.n)||isNaN(this.d))return c;do{c.push(Math.floor(a/b));var e=a%b;a=b;b=e}while(1!==a);return c},toString:function(a){var b=this.n,c=this.d;if(isNaN(b)||isNaN(c))return"NaN";if(!e.REDUCE){var d=p(b,c);b/=d;c/=d}a:{for(d=c;0===d%2;d/=2);for(;0===d%5;d/=5);if(1===d)d=0;else{for(var h=10%d,m=1;1!==h;m++)if(h=
+ 10*h%d,2E3>=1)l&1&&(n=n*m%c);m=n;for(l=0;300>l;l++){if(h===m){m=l;break a}h=10*h%c;m=10*m%c}m=0}h=-1===this.s?"-":"";h+=b/c|0;(b=b%c*10)&&(h+=".");if(d){for(a=m;a--;)h+=b/c|0,b%=c,b*=10;h+="(";for(a=d;a--;)h+=b/c|0,b%=c,b*=10;h+=")"}else for(a=a||15;b&&a--;)h+=b/c|0,b%=c,b*=10;return h}};"function"===typeof define&&define.amd?define([],function(){return e}):"object"===typeof exports?(Object.defineProperty(exports,"__esModule",{value:!0}),
+ e["default"]=e,e.Fraction=e,module.exports=e):x.Fraction=e})(this);
diff --git a/save-32x32.js b/save-32x32.js
new file mode 100644
index 0000000..5cef273
--- /dev/null
+++ b/save-32x32.js
@@ -0,0 +1,24 @@
+const exec = require("child_process").exec;
+
+const command = [
+ "cd 32x32",
+ "npm install",
+ "npm run build",
+ "mv build/static ../output/", // HACK - move static first
+ "mv build ../output/32x32",
+].join(" && ");
+
+function save32x32() {
+ return new Promise((resolve, reject) => {
+ console.log(command);
+ exec(command, (err, stdout, stderr) => {
+ if (err || stderr) {
+ return reject(err || stderr);
+ }
+
+ resolve(stdout);
+ });
+ });
+}
+
+module.exports = save32x32;
diff --git a/save-article.js b/save-article.js
new file mode 100644
index 0000000..63145a2
--- /dev/null
+++ b/save-article.js
@@ -0,0 +1,40 @@
+const ejs = require("ejs");
+const fs = require("fs");
+const mkdirp = require("mkdirp");
+const path = require("path");
+
+function saveArticle(article) {
+ return new Promise((resolve, reject) => {
+ fs.readFile("templates/article.ejs", (err, articleTemplate) => {
+ if (err) { return reject(err); }
+
+ fs.readFile("templates/layout.ejs", (err, layoutTemplate) => {
+ if (err) { return reject(err); }
+
+ const articleBodyHTML = ejs.render(articleTemplate.toString(), article);
+ const articleHTML = ejs.render(layoutTemplate.toString(), {
+ title: article.title + " | Fuwn",
+ body: articleBodyHTML,
+ description: article.description || article.summary,
+ });
+
+ const articlePath = path.join("output", article.route);
+
+ mkdirp(articlePath, err => {
+ if (err) { return reject(err); }
+
+ fs.writeFile(
+ path.join(articlePath, "index.html"),
+ articleHTML,
+ err => {
+ if (err) { return reject(err); }
+ resolve("ok");
+ }
+ );
+ });
+ });
+ });
+ });
+}
+
+module.exports = saveArticle;
diff --git a/save-index.js b/save-index.js
new file mode 100644
index 0000000..b914eb6
--- /dev/null
+++ b/save-index.js
@@ -0,0 +1,37 @@
+const ejs = require("ejs");
+const fs = require("fs");
+
+function saveIndex(articles, outputFile, title, banner) {
+ articles.sort((a, b) => {
+ return (b.rawDate || 0) - (a.rawDate || 0);
+ });
+
+ return new Promise((resolve, reject) => {
+ fs.readFile("templates/index.ejs", (err, data) => {
+ if (err) { return reject(err); }
+
+ const indexBodyHTML = ejs.render(data.toString(), {
+ articles: articles.filter(article => {
+ return !article.hidden;
+ }),
+ banner,
+ });
+
+ fs.readFile("templates/layout.ejs", (err, data) => {
+ const indexHTML = ejs.render(data.toString(), {
+ title: title || "blog | fuwn",
+ description: "fuwn, a naritive through my struggles",
+ body: indexBodyHTML,
+ });
+
+ fs.writeFile(outputFile, indexHTML, err => {
+ if (err) { return reject(err); }
+
+ resolve("ok!");
+ });
+ });
+ });
+ });
+}
+
+module.exports = saveIndex;
diff --git a/save-static-file.js b/save-static-file.js
new file mode 100644
index 0000000..51791b4
--- /dev/null
+++ b/save-static-file.js
@@ -0,0 +1,22 @@
+const ncp = require("ncp");
+const path = require("path");
+const mkdirp = require("mkdirp");
+
+function saveStaticFile(filePath) {
+ return new Promise((resolve, reject) => {
+ const relativePath = path.relative("public", filePath);
+ const destination = path.join("output", relativePath);
+
+ mkdirp(path.dirname(destination), err => {
+ if (err) { return reject(err); }
+
+ ncp(filePath, destination, err => {
+ if (err) { return reject(err); }
+
+ resolve("ok");
+ });
+ });
+ });
+}
+
+module.exports = saveStaticFile;
diff --git a/templates/article.ejs b/templates/article.ejs
new file mode 100644
index 0000000..df12d51
--- /dev/null
+++ b/templates/article.ejs
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
diff --git a/templates/index.ejs b/templates/index.ejs
new file mode 100644
index 0000000..0bbbfdf
--- /dev/null
+++ b/templates/index.ejs
@@ -0,0 +1,21 @@
+<% if (typeof banner !== "undefined") { %>
+ <%= banner %>
+<% } %>
+
+<% articles.forEach(function (article) { %>
+
+
+
+
+
+ <%- (article.description || article.summary).replace(/<.?p>/g, "") %>
+
+ read on »
+ continue reading this article
+
+
+
+
+<% }) %>
diff --git a/templates/layout.ejs b/templates/layout.ejs
new file mode 100644
index 0000000..484c56e
--- /dev/null
+++ b/templates/layout.ejs
@@ -0,0 +1,122 @@
+
+
+
+
+
+ <%= title %>
+
+
+
+
+
+
+
+
+
+ <% if (typeof isEditor !== "undefined" && isEditor) { %>
+
+ <% } %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ //
+ fuwn, a naritive through my struggles
+ .
+ home
+ .
+ more
+
+
+ <%- body %>
+
+ <% if (typeof isEditor !== "undefined" && isEditor) { %>
+
+
+
+
+
+ <% } %>
+
+
+
+
+
+
+ <% if (typeof isEditor !== "undefined" && isEditor) { %>
+
+
+
+
+ <% } %>
+
+
+
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000..666a545
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,2140 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@zeit/schemas@2.6.0":
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3"
+ integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+accepts@~1.3.5, accepts@~1.3.7:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+ integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+ dependencies:
+ mime-types "~2.1.24"
+ negotiator "0.6.2"
+
+ajv@6.5.3:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
+ integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ansi-align@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
+ integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
+ dependencies:
+ string-width "^2.0.0"
+
+ansi-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+ integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+anymatch@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+ integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
+ dependencies:
+ micromatch "^3.1.4"
+ normalize-path "^2.1.1"
+
+append-field@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
+ integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
+
+arch@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
+ integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
+
+arg@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-2.0.0.tgz#c06e7ff69ab05b3a4a03ebe0407fac4cba657545"
+ integrity sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+ integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+
+arr-flatten@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+ integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+ integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+
+array-unique@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+ integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+ integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+
+async-each@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
+ integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
+
+atob@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+ integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+ integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+base@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+ dependencies:
+ cache-base "^1.0.1"
+ class-utils "^0.3.5"
+ component-emitter "^1.2.1"
+ define-property "^1.0.0"
+ isobject "^3.0.1"
+ mixin-deep "^1.2.0"
+ pascalcase "^0.1.1"
+
+binary-extensions@^1.0.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
+ integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
+
+bindings@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
+ integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
+ dependencies:
+ file-uri-to-path "1.0.0"
+
+body-parser@1.19.0:
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
+ integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+ dependencies:
+ bytes "3.1.0"
+ content-type "~1.0.4"
+ debug "2.6.9"
+ depd "~1.1.2"
+ http-errors "1.7.2"
+ iconv-lite "0.4.24"
+ on-finished "~2.3.0"
+ qs "6.7.0"
+ raw-body "2.4.0"
+ type-is "~1.6.17"
+
+boxen@1.3.0, boxen@^1.2.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
+ integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
+ dependencies:
+ ansi-align "^2.0.0"
+ camelcase "^4.0.0"
+ chalk "^2.0.1"
+ cli-boxes "^1.0.0"
+ string-width "^2.0.0"
+ term-size "^1.2.0"
+ widest-line "^2.0.0"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^2.3.1, braces@^2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+ integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
+ dependencies:
+ arr-flatten "^1.1.0"
+ array-unique "^0.3.2"
+ extend-shallow "^2.0.1"
+ fill-range "^4.0.0"
+ isobject "^3.0.1"
+ repeat-element "^1.1.2"
+ snapdragon "^0.8.1"
+ snapdragon-node "^2.0.1"
+ split-string "^3.0.2"
+ to-regex "^3.0.1"
+
+buffer-from@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+ integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+
+busboy@^0.2.11:
+ version "0.2.14"
+ resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
+ integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
+ dependencies:
+ dicer "0.2.5"
+ readable-stream "1.1.x"
+
+bytes@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
+ integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+
+bytes@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
+ integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+
+cache-base@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+ dependencies:
+ collection-visit "^1.0.0"
+ component-emitter "^1.2.1"
+ get-value "^2.0.6"
+ has-value "^1.0.0"
+ isobject "^3.0.1"
+ set-value "^2.0.0"
+ to-object-path "^0.3.0"
+ union-value "^1.0.0"
+ unset-value "^1.0.0"
+
+camelcase@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+ integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+
+capture-stack-trace@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
+ integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
+
+chalk@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
+ integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chalk@^2.0.1:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chokidar@^2.1.8:
+ version "2.1.8"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
+ integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
+ dependencies:
+ anymatch "^2.0.0"
+ async-each "^1.0.1"
+ braces "^2.3.2"
+ glob-parent "^3.1.0"
+ inherits "^2.0.3"
+ is-binary-path "^1.0.0"
+ is-glob "^4.0.0"
+ normalize-path "^3.0.0"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.2.1"
+ upath "^1.1.1"
+ optionalDependencies:
+ fsevents "^1.2.7"
+
+ci-info@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
+ integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
+
+class-utils@^0.3.5:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
+
+cli-boxes@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
+ integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
+
+clipboardy@1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef"
+ integrity sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==
+ dependencies:
+ arch "^2.1.0"
+ execa "^0.8.0"
+
+collection-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+ integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
+ dependencies:
+ map-visit "^1.0.0"
+ object-visit "^1.0.0"
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+commander@^2.19.0:
+ version "2.20.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+component-emitter@^1.2.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+ integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
+compressible@~2.0.14:
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+ integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
+ dependencies:
+ mime-db ">= 1.43.0 < 2"
+
+compression@1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db"
+ integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==
+ dependencies:
+ accepts "~1.3.5"
+ bytes "3.0.0"
+ compressible "~2.0.14"
+ debug "2.6.9"
+ on-headers "~1.0.1"
+ safe-buffer "5.1.2"
+ vary "~1.1.2"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-stream@^1.5.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+ dependencies:
+ buffer-from "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^2.2.2"
+ typedarray "^0.0.6"
+
+configstore@^3.0.0:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.5.tgz#e9af331fadc14dabd544d3e7e76dc446a09a530f"
+ integrity sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==
+ dependencies:
+ dot-prop "^4.2.1"
+ graceful-fs "^4.1.2"
+ make-dir "^1.0.0"
+ unique-string "^1.0.0"
+ write-file-atomic "^2.0.0"
+ xdg-basedir "^3.0.0"
+
+content-disposition@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
+ integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
+
+content-disposition@0.5.3:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
+ integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+ dependencies:
+ safe-buffer "5.1.2"
+
+content-type@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+ integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+
+cookie@0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
+ integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+
+copy-descriptor@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+ integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+
+core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+ integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+create-error-class@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
+ integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
+ dependencies:
+ capture-stack-trace "^1.0.0"
+
+cross-spawn@^5.0.1:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+ integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+ dependencies:
+ lru-cache "^4.0.1"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
+crypto-random-string@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
+ integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+
+debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@^3.2.6:
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+ integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+ dependencies:
+ ms "^2.1.1"
+
+decode-uri-component@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+ integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+define-property@^0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+ integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
+ dependencies:
+ is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+ integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
+ dependencies:
+ is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+ dependencies:
+ is-descriptor "^1.0.2"
+ isobject "^3.0.1"
+
+depd@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+ integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
+destroy@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+ integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
+dicer@0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
+ integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
+ dependencies:
+ readable-stream "1.1.x"
+ streamsearch "0.1.2"
+
+dot-prop@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4"
+ integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==
+ dependencies:
+ is-obj "^1.0.0"
+
+duplexer3@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
+ integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
+ejs@^2.4.1:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
+ integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+
+execa@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+ integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+execa@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
+ integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+expand-brackets@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+ integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
+ dependencies:
+ debug "^2.3.3"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ posix-character-classes "^0.1.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+express@^4.16.2:
+ version "4.17.1"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
+ integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+ dependencies:
+ accepts "~1.3.7"
+ array-flatten "1.1.1"
+ body-parser "1.19.0"
+ content-disposition "0.5.3"
+ content-type "~1.0.4"
+ cookie "0.4.0"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "~1.1.2"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "~1.1.2"
+ fresh "0.5.2"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "~2.3.0"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.7"
+ proxy-addr "~2.0.5"
+ qs "6.7.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.1.2"
+ send "0.17.1"
+ serve-static "1.14.1"
+ setprototypeof "1.1.1"
+ statuses "~1.5.0"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extglob@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+ dependencies:
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ expand-brackets "^2.1.4"
+ extend-shallow "^2.0.1"
+ fragment-cache "^0.2.1"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+fast-deep-equal@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+ integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-url-parser@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
+ integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=
+ dependencies:
+ punycode "^1.3.2"
+
+file-uri-to-path@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
+ integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
+
+fill-range@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+ integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+ to-regex-range "^2.1.0"
+
+finalhandler@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+ integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.3"
+ statuses "~1.5.0"
+ unpipe "~1.0.0"
+
+for-in@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+ integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+forwarded@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+ integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+
+fragment-cache@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+ integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
+ dependencies:
+ map-cache "^0.2.2"
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
+front-matter@^3.0.2:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-3.2.1.tgz#88be839638f397bbbcb0d61ac03bd08abb4f0a40"
+ integrity sha512-YUhgEhbL6tG+Ok3vTGIoSDKqcr47aSDvyhEqIv8B+YuBJFsPnOiArNXTPp2yO07NL+a0L4+2jXlKlKqyVcsRRA==
+ dependencies:
+ js-yaml "^3.13.1"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+fsevents@^1.2.7:
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
+ integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==
+ dependencies:
+ bindings "^1.5.0"
+ nan "^2.12.1"
+
+get-stream@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+ integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+
+get-value@^2.0.3, get-value@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+ integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+
+glob-parent@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+ integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
+ dependencies:
+ is-glob "^3.1.0"
+ path-dirname "^1.0.0"
+
+glob@^7.1.4:
+ version "7.1.6"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+ integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+global-dirs@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
+ integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
+ dependencies:
+ ini "^1.3.4"
+
+got@^6.7.1:
+ version "6.7.1"
+ resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
+ integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
+ dependencies:
+ create-error-class "^3.0.0"
+ duplexer3 "^0.1.4"
+ get-stream "^3.0.0"
+ is-redirect "^1.0.0"
+ is-retry-allowed "^1.0.0"
+ is-stream "^1.0.0"
+ lowercase-keys "^1.0.0"
+ safe-buffer "^5.0.1"
+ timed-out "^4.0.0"
+ unzip-response "^2.0.1"
+ url-parse-lax "^1.0.0"
+
+graceful-fs@^4.1.11, graceful-fs@^4.1.2:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
+ integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-value@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+ integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
+ dependencies:
+ get-value "^2.0.3"
+ has-values "^0.1.4"
+ isobject "^2.0.0"
+
+has-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+ integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+ dependencies:
+ get-value "^2.0.6"
+ has-values "^1.0.0"
+ isobject "^3.0.0"
+
+has-values@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+ integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
+
+has-values@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+ integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+highlight.js@^9.3.0:
+ version "9.18.3"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.3.tgz#a1a0a2028d5e3149e2380f8a865ee8516703d634"
+ integrity sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ==
+
+http-errors@1.7.2:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
+ integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.1"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.0"
+
+http-errors@~1.7.2:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
+ integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.4"
+ setprototypeof "1.1.1"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.0"
+
+iconv-lite@0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+ignore-by-default@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
+ integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
+
+import-lazy@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
+ integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+ini@^1.3.4, ini@~1.3.0:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+ integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
+is-accessor-descriptor@^0.1.6:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+ integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+ integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
+ dependencies:
+ kind-of "^6.0.0"
+
+is-binary-path@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+ integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
+ dependencies:
+ binary-extensions "^1.0.0"
+
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-ci@^1.0.10:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
+ integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
+ dependencies:
+ ci-info "^1.5.0"
+
+is-data-descriptor@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+ integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+ integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
+ dependencies:
+ kind-of "^6.0.0"
+
+is-descriptor@^0.1.0:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+ integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
+ dependencies:
+ is-accessor-descriptor "^0.1.6"
+ is-data-descriptor "^0.1.4"
+ kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+ integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
+ dependencies:
+ is-accessor-descriptor "^1.0.0"
+ is-data-descriptor "^1.0.0"
+ kind-of "^6.0.2"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+ integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+ integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+ integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-installed-globally@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
+ integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=
+ dependencies:
+ global-dirs "^0.1.0"
+ is-path-inside "^1.0.0"
+
+is-npm@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
+ integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-obj@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+ integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
+
+is-path-inside@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
+ integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
+ dependencies:
+ path-is-inside "^1.0.1"
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+ dependencies:
+ isobject "^3.0.1"
+
+is-redirect@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
+ integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
+
+is-retry-allowed@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
+ integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
+
+is-stream@^1.0.0, is-stream@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+ integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-windows@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+ integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+ integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
+isarray@1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+ integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+js-yaml@^3.13.1:
+ version "3.14.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
+ integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+katex@^0.10.2:
+ version "0.10.2"
+ resolved "https://registry.yarnpkg.com/katex/-/katex-0.10.2.tgz#39973edbb65eda5b6f9e7f41648781e557dd4932"
+ integrity sha512-cQOmyIRoMloCoSIOZ1+gEwsksdJZ1EW4SWm3QzxSza/QsnZr6D4U1V9S4q+B/OLm2OQ8TCBecQ8MaIfnScI7cw==
+ dependencies:
+ commander "^2.19.0"
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+ integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+latest-version@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
+ integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
+ dependencies:
+ package-json "^4.0.0"
+
+lowercase-keys@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
+ integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
+
+lru-cache@^4.0.1:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+ integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+ dependencies:
+ pseudomap "^1.0.2"
+ yallist "^2.1.2"
+
+make-dir@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
+ integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
+ dependencies:
+ pify "^3.0.0"
+
+map-cache@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+ integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
+map-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+ integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
+ dependencies:
+ object-visit "^1.0.0"
+
+marked@^0.6.2:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-0.6.3.tgz#79babad78af638ba4d522a9e715cdfdd2429e946"
+ integrity sha512-Fqa7eq+UaxfMriqzYLayfqAE40WN03jf+zHjT18/uXNuzjq3TY0XTbrAoPeqSJrAmPz11VuUA+kBPYOhHt9oOQ==
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+ integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+
+micromatch@^3.1.10, micromatch@^3.1.4:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+ integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ braces "^2.3.1"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ extglob "^2.0.4"
+ fragment-cache "^0.2.1"
+ kind-of "^6.0.2"
+ nanomatch "^1.2.9"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.2"
+
+mime-db@1.44.0:
+ version "1.44.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
+ integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
+
+"mime-db@>= 1.43.0 < 2":
+ version "1.45.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea"
+ integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==
+
+mime-db@~1.33.0:
+ version "1.33.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
+ integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==
+
+mime-types@2.1.18:
+ version "2.1.18"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
+ integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==
+ dependencies:
+ mime-db "~1.33.0"
+
+mime-types@~2.1.24:
+ version "2.1.27"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
+ integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
+ dependencies:
+ mime-db "1.44.0"
+
+mime@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+minimatch@3.0.4, minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist@^1.2.0, minimist@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+
+mixin-deep@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+ integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+ dependencies:
+ for-in "^1.0.2"
+ is-extendable "^1.0.1"
+
+mkdirp@^0.5.1:
+ version "0.5.5"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
+ integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
+ dependencies:
+ minimist "^1.2.5"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+ integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+ms@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+multer@^1.3.0:
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
+ integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==
+ dependencies:
+ append-field "^1.0.0"
+ busboy "^0.2.11"
+ concat-stream "^1.5.2"
+ mkdirp "^0.5.1"
+ object-assign "^4.1.1"
+ on-finished "^2.3.0"
+ type-is "^1.6.4"
+ xtend "^4.0.0"
+
+nan@^2.12.1:
+ version "2.14.2"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
+ integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
+
+nanomatch@^1.2.9:
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+ integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ fragment-cache "^0.2.1"
+ is-windows "^1.0.2"
+ kind-of "^6.0.2"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+ncp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
+ integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
+
+negotiator@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+ integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
+nodemon@^1.19.0:
+ version "1.19.4"
+ resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.4.tgz#56db5c607408e0fdf8920d2b444819af1aae0971"
+ integrity sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==
+ dependencies:
+ chokidar "^2.1.8"
+ debug "^3.2.6"
+ ignore-by-default "^1.0.1"
+ minimatch "^3.0.4"
+ pstree.remy "^1.1.7"
+ semver "^5.7.1"
+ supports-color "^5.5.0"
+ touch "^3.1.0"
+ undefsafe "^2.0.2"
+ update-notifier "^2.5.0"
+
+nopt@~1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
+ integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
+ dependencies:
+ abbrev "1"
+
+normalize-path@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+ integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+ dependencies:
+ remove-trailing-separator "^1.0.1"
+
+normalize-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+npm-run-path@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+ integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+ dependencies:
+ path-key "^2.0.0"
+
+object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-copy@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+ integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
+ dependencies:
+ copy-descriptor "^0.1.0"
+ define-property "^0.2.5"
+ kind-of "^3.0.3"
+
+object-visit@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+ integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
+ dependencies:
+ isobject "^3.0.0"
+
+object.pick@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+ dependencies:
+ isobject "^3.0.1"
+
+on-finished@^2.3.0, on-finished@~2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+ integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+ dependencies:
+ ee-first "1.1.1"
+
+on-headers@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+ integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ dependencies:
+ wrappy "1"
+
+p-finally@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+ integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+
+package-json@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
+ integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
+ dependencies:
+ got "^6.7.1"
+ registry-auth-token "^3.0.1"
+ registry-url "^3.0.3"
+ semver "^5.1.0"
+
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascalcase@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+ integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
+
+path-dirname@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+ integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@1.0.2, path-is-inside@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+ integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-key@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+ integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+
+path-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+ integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+
+path-to-regexp@2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45"
+ integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==
+
+pify@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+ integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+
+posix-character-classes@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+ integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+
+prepend-http@^1.0.1:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+ integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
+
+process-nextick-args@~2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+proxy-addr@~2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
+ integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
+ dependencies:
+ forwarded "~0.1.2"
+ ipaddr.js "1.9.1"
+
+pseudomap@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+ integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
+
+pstree.remy@^1.1.7:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
+ integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
+
+punycode@^1.3.2:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+ integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+ integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+qs@6.7.0:
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
+ integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+
+range-parser@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
+ integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
+
+range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
+ integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+ dependencies:
+ bytes "3.1.0"
+ http-errors "1.7.2"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+rc@^1.0.1, rc@^1.1.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+readable-stream@1.1.x:
+ version "1.1.14"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+ integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+readable-stream@^2.0.2, readable-stream@^2.2.2:
+ version "2.3.7"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
+ integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readdirp@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
+ integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
+ dependencies:
+ graceful-fs "^4.1.11"
+ micromatch "^3.1.10"
+ readable-stream "^2.0.2"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+ dependencies:
+ extend-shallow "^3.0.2"
+ safe-regex "^1.1.0"
+
+registry-auth-token@3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20"
+ integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==
+ dependencies:
+ rc "^1.1.6"
+ safe-buffer "^5.0.1"
+
+registry-auth-token@^3.0.1:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
+ integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
+ dependencies:
+ rc "^1.1.6"
+ safe-buffer "^5.0.1"
+
+registry-url@3.1.0, registry-url@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
+ integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
+ dependencies:
+ rc "^1.0.1"
+
+remove-trailing-separator@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+ integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+
+repeat-element@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+ integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+
+repeat-string@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+ integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+ integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+ integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@^5.0.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+safe-regex@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+ integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
+ dependencies:
+ ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+semver-diff@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
+ integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=
+ dependencies:
+ semver "^5.0.3"
+
+semver@^5.0.3, semver@^5.1.0, semver@^5.7.1:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
+send@0.17.1:
+ version "0.17.1"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
+ integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+ dependencies:
+ debug "2.6.9"
+ depd "~1.1.2"
+ destroy "~1.0.4"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "~1.7.2"
+ mime "1.6.0"
+ ms "2.1.1"
+ on-finished "~2.3.0"
+ range-parser "~1.2.1"
+ statuses "~1.5.0"
+
+serve-handler@6.1.3:
+ version "6.1.3"
+ resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8"
+ integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==
+ dependencies:
+ bytes "3.0.0"
+ content-disposition "0.5.2"
+ fast-url-parser "1.1.3"
+ mime-types "2.1.18"
+ minimatch "3.0.4"
+ path-is-inside "1.0.2"
+ path-to-regexp "2.2.1"
+ range-parser "1.2.0"
+
+serve-static@1.14.1:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
+ integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+ dependencies:
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.17.1"
+
+serve@^11.0.0:
+ version "11.3.2"
+ resolved "https://registry.yarnpkg.com/serve/-/serve-11.3.2.tgz#b905e980616feecd170e51c8f979a7b2374098f5"
+ integrity sha512-yKWQfI3xbj/f7X1lTBg91fXBP0FqjJ4TEi+ilES5yzH0iKJpN5LjNb1YzIfQg9Rqn4ECUS2SOf2+Kmepogoa5w==
+ dependencies:
+ "@zeit/schemas" "2.6.0"
+ ajv "6.5.3"
+ arg "2.0.0"
+ boxen "1.3.0"
+ chalk "2.4.1"
+ clipboardy "1.2.3"
+ compression "1.7.3"
+ serve-handler "6.1.3"
+ update-check "1.5.2"
+
+set-value@^2.0.0, set-value@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+ integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.3"
+ split-string "^3.0.1"
+
+setprototypeof@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
+ integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
+
+shebang-command@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+ integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+ dependencies:
+ shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+ integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
+ integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
+
+snapdragon-node@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+ integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
+ dependencies:
+ define-property "^1.0.0"
+ isobject "^3.0.0"
+ snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+ integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
+ dependencies:
+ kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+ dependencies:
+ base "^0.11.1"
+ debug "^2.2.0"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ map-cache "^0.2.2"
+ source-map "^0.5.6"
+ source-map-resolve "^0.5.0"
+ use "^3.1.0"
+
+source-map-resolve@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+ integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+ dependencies:
+ atob "^2.1.2"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-url@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+ integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+
+source-map@^0.5.6:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+split-string@^3.0.1, split-string@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+ dependencies:
+ extend-shallow "^3.0.0"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+static-extend@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+ integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
+ dependencies:
+ define-property "^0.2.5"
+ object-copy "^0.1.0"
+
+"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+streamsearch@0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
+ integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
+
+strftime@^0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/strftime/-/strftime-0.10.0.tgz#b3f0fa419295202a5a289f6d6be9f4909a617193"
+ integrity sha1-s/D6QZKVICpaKJ9ta+n0kJphcZM=
+
+string-width@^2.0.0, string-width@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+ integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^4.0.0"
+
+string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+ integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+strip-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+ integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+ dependencies:
+ ansi-regex "^3.0.0"
+
+strip-eof@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+ integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+supports-color@^5.3.0, supports-color@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+term-size@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
+ integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
+ dependencies:
+ execa "^0.7.0"
+
+timed-out@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
+ integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
+
+to-object-path@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+ integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+ dependencies:
+ kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+ integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
+ dependencies:
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+ dependencies:
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ regex-not "^1.0.2"
+ safe-regex "^1.1.0"
+
+toidentifier@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
+ integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+
+touch@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
+ integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
+ dependencies:
+ nopt "~1.0.10"
+
+type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+ integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+undefsafe@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae"
+ integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==
+ dependencies:
+ debug "^2.2.0"
+
+union-value@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+ integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
+ dependencies:
+ arr-union "^3.1.0"
+ get-value "^2.0.6"
+ is-extendable "^0.1.1"
+ set-value "^2.0.1"
+
+unique-string@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
+ integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
+ dependencies:
+ crypto-random-string "^1.0.0"
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+
+unset-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+ integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
+ dependencies:
+ has-value "^0.3.1"
+ isobject "^3.0.0"
+
+unzip-response@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
+ integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
+
+upath@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
+ integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
+
+update-check@1.5.2:
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.2.tgz#2fe09f725c543440b3d7dabe8971f2d5caaedc28"
+ integrity sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==
+ dependencies:
+ registry-auth-token "3.3.2"
+ registry-url "3.1.0"
+
+update-notifier@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
+ integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
+ dependencies:
+ boxen "^1.2.1"
+ chalk "^2.0.1"
+ configstore "^3.0.0"
+ import-lazy "^2.1.0"
+ is-ci "^1.0.10"
+ is-installed-globally "^0.1.0"
+ is-npm "^1.0.0"
+ latest-version "^3.0.0"
+ semver-diff "^2.0.0"
+ xdg-basedir "^3.0.0"
+
+uri-js@^4.2.2:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"
+ integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==
+ dependencies:
+ punycode "^2.1.0"
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+ integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+
+url-parse-lax@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
+ integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
+ dependencies:
+ prepend-http "^1.0.1"
+
+use@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+ integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+which@^1.2.9:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+widest-line@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
+ integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
+ dependencies:
+ string-width "^2.1.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+write-file-atomic@^2.0.0:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
+ integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
+ dependencies:
+ graceful-fs "^4.1.11"
+ imurmurhash "^0.1.4"
+ signal-exit "^3.0.2"
+
+xdg-basedir@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
+ integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
+
+xtend@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+yallist@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+ integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
--
cgit v1.2.3