aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCadey Dodrill <me@christine.website>2016-12-14 06:20:25 -0800
committerCadey Dodrill <me@christine.website>2016-12-14 06:20:25 -0800
commit90f176019a1723aa0d4b7cbb97009944e60e963d (patch)
treea816f40b0c8c823aef2c8efe60ba4ef8891d876b
parent060a7c913a6eb1f30052504678e04fccc404b930 (diff)
downloadxesite-90f176019a1723aa0d4b7cbb97009944e60e963d.tar.xz
xesite-90f176019a1723aa0d4b7cbb97009944e60e963d.zip
add API backend
-rw-r--r--backend/christine.website/main.go97
-rw-r--r--blog/cinemaquestria-orchestration-2015-03-13.markdown122
-rw-r--r--blog/coming-out-2015-12-01.markdown72
-rw-r--r--blog/ffi-ing-golang-from-nim-for-fun-and-profit-2015-12-20.markdown281
-rw-r--r--blog/getting-started-with-go-2015-01-28.markdown148
-rw-r--r--blog/metaprogramming-partial-application-2015-08-26.markdown430
-rw-r--r--blog/nim-and-tup-2015-06-10.markdown100
-rw-r--r--blog/plt-1-the-beginning-2015-02-14.markdown150
-rw-r--r--blog/plt-2-entering-the-cave-2015-02-14.markdown205
-rw-r--r--blog/pursuit-of-dsl-2014-08-16.markdown116
-rw-r--r--blog/the-origin-of-h-2015-12-14.markdown94
-rw-r--r--blog/the-universal-design-2015-10-17.markdown150
-rw-r--r--blog/this-site-text-stack-2015-02-14.markdown85
-rw-r--r--blog/thoughts-on-community-2014-07-31.markdown98
-rw-r--r--blog/trying-vagga-2015-03-21.markdown56
-rw-r--r--frontend/.psc-ide-port1
-rw-r--r--frontend/src/BlogIndex.purs12
-rw-r--r--frontend/src/Layout.purs2
-rw-r--r--frontend/support/index.html27
19 files changed, 2239 insertions, 7 deletions
diff --git a/backend/christine.website/main.go b/backend/christine.website/main.go
new file mode 100644
index 0000000..aafdfa3
--- /dev/null
+++ b/backend/christine.website/main.go
@@ -0,0 +1,97 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "github.com/gernest/front"
+)
+
+type Post struct {
+ Title string `json:"title"`
+ Link string `json:"link"`
+ Summary string `json:"summary"`
+ Date string `json:"date"`
+}
+
+var posts []*Post
+
+func init() {
+ err := filepath.Walk("./blog/", func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ if info.IsDir() {
+ return nil
+ }
+
+ fin, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer fin.Close()
+
+ m := front.NewMatter()
+ m.Handle("---", front.YAMLHandler)
+ front, _, err := m.Parse(fin)
+ if err != nil {
+ return err
+ }
+
+ p := &Post{
+ Title: front["title"].(string),
+ Date: front["date"].(string),
+ Link: strings.Split(path, ".")[0],
+ }
+
+ posts = append(posts, p)
+
+ return nil
+ })
+
+ if err != nil {
+ panic(err)
+ }
+}
+
+func main() {
+ http.HandleFunc("/api/blog/posts", writeBlogPosts)
+ http.HandleFunc("/api/blog/post", func(w http.ResponseWriter, r *http.Request) {
+ q := r.URL.Query()
+ name := q.Get("name")
+
+ fin, err := os.Open(path.Join("./blog", name))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ defer fin.Close()
+
+ m := front.NewMatter()
+ m.Handle("---", front.YAMLHandler)
+ _, body, err := m.Parse(fin)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ fmt.Fprintln(w, body)
+ })
+ http.Handle("/dist/", http.FileServer(http.Dir("./frontend/static/")))
+ http.HandleFunc("/", writeIndexHTML)
+
+ log.Fatal(http.ListenAndServe(":9090", nil))
+}
+
+func writeBlogPosts(w http.ResponseWriter, r *http.Request) {
+ json.NewEncoder(w).Encode(posts)
+}
+
+func writeIndexHTML(w http.ResponseWriter, r *http.Request) {
+ http.ServeFile(w, r, "./frontend/static/dist/index.html")
+}
diff --git a/blog/cinemaquestria-orchestration-2015-03-13.markdown b/blog/cinemaquestria-orchestration-2015-03-13.markdown
new file mode 100644
index 0000000..9a16bfb
--- /dev/null
+++ b/blog/cinemaquestria-orchestration-2015-03-13.markdown
@@ -0,0 +1,122 @@
+---
+title: CinemaQuestria Orchestration
+date: 2015-03-13
+---
+
+CinemaQuestria Orchestration
+============================
+
+### Or: Continuous Defenstration in a Container-based Ecosystem
+
+I've been a core member of the staff for [CinemaQuestria](http://cinemaquestria.com)
+for many months. In that time we have gone from shared hosting (updated by hand
+with FTP) to a git-based deployment system that has won over the other
+staffers.
+
+In this blogpost I'm going to take a look at what it was, what it is, and what
+it will be as well as some challenges that have been faced or will be faced as
+things advance into the future.
+
+The Past
+--------
+
+The site for CinemaQuestria is mostly static HTML. This was chosen mainly
+because it made the most sense for the previous shared hosting environment as
+it was the least surprising to set up and test.
+
+The live site content is about 50 MB of data including PDF transcripts of
+previous podcast episodes and for a long time was a Good Enough solution that
+we saw no need to replace it.
+
+However, being on shared hosting it meant that there was only one set of
+authentication credentials and they had to be shared amongst ourselves. This
+made sense as we were small but as we started to grow it didn't make much
+sense. Combined with the fact that the copy of the site on the live server *was
+pretty much the only copy of the site* we also lost disaster recovery points.
+
+Needless to say, I started researching into better solutions for this.
+
+The first solution I took a look at was AWS S3. It would let us host the CQ
+site for about 0 dollars per month. On paper this looked amazing, until we
+tried it and everyone was getting huge permissions issues. The only way to have
+fixed this would have been to have everyone use the same username/password or
+to have only one person do the deploys. In terms of reducing the [Bus
+factor](https://en.wikipedia.org/wiki/Bus_factor) of the site's staff, this was
+also unacceptable.
+
+I had done a lot of work with [Dokku-alt](https://github.com/dokku-alt/dokku-alt)
+for hosting my personal things (this site is one of many hosted on this
+server), so I decided to give it a try with us.
+
+The Present
+-----------
+
+Presently the CQ website is hosted on a Dokku-alt server inside a container.
+For a while while I was working on getting the warts out only I had access to
+deploy code to the server, but quickly on I set up a private repo on my git
+server for us to be able to track changes.
+
+Once the other staffers realized the enormous amount of flexibility being on
+git gave us they loved it. From the comments I received the things they liked
+the most were:
+
+ - Accountability for who made what change
+ - The ability to rollback changes if need be
+ - Everyone being able to have an entire copy of the site and its history
+
+After the warts were worked out I gave the relevant people access to the dokku
+server in the right way and the productivity has skyrocketed. Not only have
+people loved how simple it is to push out new changes but they love how
+consistent it is and the brutal simplicity of it.
+
+Mind you these are not all super-technically gifted people, but the command
+line git client was good enough that not only were they able to commit and make
+changes to the site, but they also took initiative and *corrected things they
+messed up* and made sure things were consistent and correct.
+
+When I saw those commits in the news feed, I almost started crying tears of
+happy.
+
+Nowadays our site is hosted inside a simple [nginx
+container](https://registry.hub.docker.com/_/nginx/). In fact, I'll even paste
+the entire Dockerfile for the site below:
+
+```Dockerfile
+FROM nginx
+
+COPY . /usr/share/nginx/html
+```
+
+That's it. When someone pushes a new change to the server it figures out
+everything from just those two lines of code.
+
+Of course, this isn't to say this system is completely free of warts. I'd love
+to someday be able to notify the backrooms on skype every time a push to the
+live server is made, but that might be for another day.
+
+The Future
+----------
+
+In terms of future expansion I am split mentally. On one hand the existing
+static HTML is *hysterically fast* and efficient on the server, meaning that
+anything such as a Go binary, Lua/Lapis environment or other web application
+framework would have a very tough reputation to beat.
+
+I have looked into using Lapis for [this beta test site](http://cqsite-beta.apps.xeserv.us/),
+but the fact that HTML is so dead easy to modify made that idea lose out.
+
+Maybe this is in the realm of something like [jekyll](http://jekyllrb.com/),
+[Hugo](http://gohugo.io/) or [sw](https://github.com/jroimartin/sw) to take
+care of. I'd need to do more research into this when I have the time.
+
+If you look at the website code currently a lot of it is heavily duplicated
+code because the shared hosting version used to use Apache server-side
+includes. I think a good place to apply these would be in the build in the
+future. Maybe with a nice husking operation on build.
+
+---
+
+Anyways, I hope this was interesting and a look into a side of CinemaQuestria
+that most of you haven't seen before. The Season 5 premiere is coming up soon
+and this poor server is going to get hammered like nothing else, so that will
+be a nice functional test of Dokku-alt in a production setting.
diff --git a/blog/coming-out-2015-12-01.markdown b/blog/coming-out-2015-12-01.markdown
new file mode 100644
index 0000000..115ca6b
--- /dev/null
+++ b/blog/coming-out-2015-12-01.markdown
@@ -0,0 +1,72 @@
+---
+title: Coming Out
+date: 2015-12-01
+---
+
+Coming Out
+==========
+
+I'd like to bring up something that has been hanging over my head for a
+long time. This is something I did try (and fail) to properly express way
+back in middle school, but now I'd like to get it all of my chest and let
+you know the truth of the matter.
+
+I don't feel comfortable with myself as I am right now. I haven't really
+felt comfortable with myself for at least 10 years, maybe more; I'm not
+entirely sure.
+
+At this point in my life I am really faced with a clear fork in the road.
+I can either choose to continue living how I currently do, lying to myself
+and others and saying everything is normal, or I can cooperate with the
+reality that my brain is telling me that I don't feel comfortable with
+myself as I have been for the last almost 22 years. I feel like I don't fit
+inside my own skin. I think it is overall better for me to face the facts
+and cooperate with reality. I have been repressing this off and on out of
+fear of being shot down or not accepted the way I want to be seen to you
+all. This has been a really hard thing for me to think through and even
+harder for me to work up the courage to start taking action towards. This
+is not a choice for me. I need to pursue this.
+
+In fact, I have been pursing this. My current business cards reflect who
+I really am. My co-workers accept my abnormal status (when compared to the
+majority of society), and even will help stand up for me if something goes
+south with regards to it.
+
+I fully understand how much information this is to take in at once. I know
+it will be difficult for you to hear that your firstborn son is actually a
+daughter in a son's body, but I am still the same person. Most of the
+changes that I want to pursue are purely cosmetic, but they are a bit more
+noticeable than changing hair color. I feel that transitioning to living
+as a woman like this will help me feel like I fit in with the world better
+and help to make me more comfortable with who I am and how I want other
+people to see me. Below I have collected some resources for you to look
+through. They will help for you to understand my views better explained
+in language you would be familiar with.
+
+I have been trialing a lot of possible first names to use, Zoe (the name
+you were going to give me if I was born a girl) did come to mind, but after
+meditating on it for a while I have decided that it doesn't fit me at all.
+The name I am going with for now and eventually will change my official
+documents to use is Christine Cadence Dodrill.
+
+Additionally I have been in a long-distance relationship with someone
+since mid-June 2014. His name is Victor and he lives in Ottawa, Ontario.
+He has been helping me a lot as I sort through all this; it has been a
+godsend. He is a student in college for Computer Science. He knows and is
+aware about my transition and has been a huge part of my emotional line
+of support as I have been accepting these facts about who I am.
+
+---
+
+Above is (a snipped version of) the letter I sent to my parents in the
+last 48 hours. With this I have officially come out to all of my friends
+and family as transgender. I am currently on hormone replacement therapy
+and have been living full time as a woman. My workplace is very accepting
+of this and has been a huge help over the last 7-8 months as I have
+battled some of my inner demons and decided to make things official.
+
+I am now deprecating my old [facebook account](https://facebook.com/shadowh511)
+and will be encouraging people to send friend requests and the like to my
+[new account under the correct name](https://www.facebook.com/chrissycade1337).
+
+Thank you all for understanding and be well.
diff --git a/blog/ffi-ing-golang-from-nim-for-fun-and-profit-2015-12-20.markdown b/blog/ffi-ing-golang-from-nim-for-fun-and-profit-2015-12-20.markdown
new file mode 100644
index 0000000..7c26449
--- /dev/null
+++ b/blog/ffi-ing-golang-from-nim-for-fun-and-profit-2015-12-20.markdown
@@ -0,0 +1,281 @@
+---
+title: FFI-ing Golang from Nim for Fun and Profit
+date: 2015-12-20
+---
+
+FFI-ing Golang from Nim for Fun and Profit
+==========================================
+
+As a side effect of Go 1.5, the compiler and runtime recently gained the
+ability to compile code and run it as FFI code running in a C namespace. This
+means that you can take any Go function that expresses its types and the like
+as something compatible with C and use it from C, Haskell, Nim, Luajit, Python,
+anywhere. There are some unique benefits and disadvantages to this however.
+
+A Simple Example
+----------------
+
+Consider the following Go file `add.go`:
+
+```go
+package main
+
+import "C"
+
+//export add
+func add(a, b int) int {
+ return a + b
+}
+
+func main() {}
+```
+
+This just exposes a function `add` that takes some pair of C integers and then
+returns their sum.
+
+We can build it with:
+
+```
+$ go build -buildmode=c-shared -o libsum.so add.go
+```
+
+And then test it like this:
+
+```
+$ python
+>>> from ctypes import cdll
+>>> a = cdll.LoadLibrary("./libsum.so")
+>>> print a.add(4,5)
+9
+```
+
+And there we go, a Go function exposed and usable in Python. However now we
+need to consider the overhead when switching contexts from your app to your Go
+code. To minimize context switches, I am going to write the rest of the code in
+this post in [Nim](http://nim-lang.org) because it natively compiles down to
+C and has some of the best C FFI I have used.
+
+We can now define `libsum.nim` as:
+
+```
+proc add*(a, b: cint): cint {.importc, dynlib: "./libsum.so", noSideEffect.}
+
+when isMainModule:
+ echo add(4,5)
+```
+
+Which when ran:
+
+```
+$ nim c -r libsum
+Hint: system [Processing]
+Hint: libsum [Processing]
+CC: libsum
+CC: system
+Hint: [Link]
+Hint: operation successful (9859 lines compiled; 1.650 sec total; 14.148MB; Debug Build) [SuccessX]
+9
+```
+
+Good, we can consistently add `4` and `5` and get `9` back.
+
+Now we can benchmark this by using the `times.cpuTime()` proc:
+
+```
+# test.nim
+
+import
+ times,
+ libsum
+
+let beginning = cpuTime()
+
+echo "Starting Go FFI at " & $beginning
+
+for i in countup(1, 100_000):
+ let myi = i.cint
+ discard libsum.add(myi, myi)
+
+let endTime = cpuTime()
+
+echo "Ended at " & $endTime
+echo "Total: " & $(endTime - beginning)
+```
+
+```
+$ nim c -r test
+Hint: system [Processing]
+Hint: test [Processing]
+Hint: times [Processing]
+Hint: strutils [Processing]
+Hint: parseutils [Processing]
+Hint: libsum [Processing]
+CC: test
+CC: system
+CC: times
+CC: strutils
+CC: parseutils
+CC: libsum
+Hint: [Link]
+Hint: operation successful (13455 lines compiled; 1.384 sec total; 21.220MB; Debug Build) [SuccessX]
+Starting Go FFI at 0.000845
+Ended at 0.131602
+Total: 0.130757
+```
+
+Yikes. This takes 0.13 seconds to do the actual computation of every number
+i in the range of `0` through `100,000`. I ran this for a few hundred times and
+found out that it was actually consistently scoring between `0.12` and `0.2`
+seconds. Obviously this cannot be a universal hammer and the FFI is very
+expensive.
+
+For comparison, consider the following C library code:
+
+```
+// libcsum.c
+#include "libcsum.h"
+
+int add(int a, int b) {
+ return a+b;
+}
+```
+
+```
+// libcsum.h
+extern int add(int a, int b);
+```
+
+```
+# libcsum.nim
+proc add*(a, b: cint): cint {.importc, dynlib: "./libcsum.so", noSideEffect.}
+
+when isMainModule:
+ echo add(4, 5)
+```
+
+and then have `test.nim` use the C library for comparison:
+
+```
+# test.nim
+
+import
+ times,
+ libcsum,
+ libsum
+
+let beginning = cpuTime()
+
+echo "Starting Go FFI at " & $beginning
+
+for i in countup(1, 100_000):
+ let myi = i.cint
+ discard libsum.add(myi, myi)
+
+let endTime = cpuTime()
+
+echo "Ended at " & $endTime
+echo "Total: " & $(endTime - beginning)
+
+let cpre = cpuTime()
+echo "starting C FFI at " & $cpre
+
+for i in countup(1, 100_000):
+ let myi = i.cint
+ discard libcsum.add(myi, myi)
+
+let cpost = cpuTime()
+
+echo "Ended at " & $cpost
+echo "Total: " & $(cpost - cpre)
+```
+
+Then run it:
+
+```
+➜ nim c -r test
+Hint: system [Processing]
+Hint: test [Processing]
+Hint: times [Processing]
+Hint: strutils [Processing]
+Hint: parseutils [Processing]
+Hint: libcsum [Processing]
+Hint: libsum [Processing]
+CC: test
+CC: system
+CC: times
+CC: strutils
+CC: parseutils
+CC: libcsum
+CC: libsum
+Hint: [Link]
+Hint: operation successful (13455 lines compiled; 0.972 sec total; 21.220MB; Debug Build) [SuccessX]
+Starting Go FFI at 0.00094
+Ended at 0.119729
+Total: 0.118789
+
+starting C FFI at 0.119866
+Ended at 0.12206
+Total: 0.002194000000000002
+```
+
+Interesting. The Go library must be doing more per instance than just adding
+the two numbers and continuing about. Since we have two near identical test
+programs for each version of the library, let's `strace` it and see if there is
+anything that can be optimized. [The Go one](https://gist.github.com/Xe/e0cd06d1d93e3299102e)
+and [the C one](https://gist.github.com/Xe/7641cdba5657a4e8435a) are both very simple
+and it looks like the Go runtime is adding the overhead.
+
+Let's see what happens if we do that big loop in Go:
+
+```
+// add.go
+
+//export addmanytimes
+func addmanytimes() {
+ for i := 0; i < 100000; i++ {
+ add(i, i)
+ }
+}
+```
+
+Then amend `libsum.nim` for this function:
+
+```
+proc addmanytimes*() {.importc, dynlib: "./libsum.so".}
+```
+
+And finally test it:
+
+```
+# test.nim
+
+echo "Doing the entire loop in Go. Starting at " & $beforeGo
+
+libsum.addmanytimes()
+
+let afterGo = cpuTime()
+
+echo "Ended at " & $afterGo
+echo "Total: " & $(afterGo - beforeGo) & " seconds"
+```
+
+Which yields:
+
+```
+Doing the entire loop in Go. Starting at 0.119757
+Ended at 0.119846
+Total: 8.899999999999186e-05 seconds
+```
+
+Porting the C library to have a similar function would likely yield similar
+results, as would putting the entire loop inside Nim. Even though this trick
+was only demonstrated with Nim and Python, it will work with nearly any
+language that can convert to/from C types for FFI. Given the large number of
+languages that do have such an interface though, it seems unlikely that there
+will be any language in common use that you *cannot* write to bind to Go code.
+Just be careful and offload as much of it as you can to Go. The FFI barrier
+**really hurts**.
+
+---
+
+This post's code is available [here](https://github.com/Xe/code/tree/master/experiments/go-nim).
diff --git a/blog/getting-started-with-go-2015-01-28.markdown b/blog/getting-started-with-go-2015-01-28.markdown
new file mode 100644
index 0000000..fa22f79
--- /dev/null
+++ b/blog/getting-started-with-go-2015-01-28.markdown
@@ -0,0 +1,148 @@
+---
+title: Getting Started with Go
+date: 2015-01-28
+---
+
+Getting Started with Go
+=======================
+
+Go is an exciting language made by Google for systems programming. This article
+will help you get up and running with the Go compiler tools.
+
+System Setup
+------------
+
+First you need to install the compilers.
+
+```console
+$ sudo apt-get install golang golang-go.tools
+```
+
+`golang-go.tools` contains some useful tools that aren't part of the standard
+Go distribution.
+
+Shell Setup
+-----------
+
+Create a folder in your home directory for your Go code to live in. I use
+`~/go`.
+
+```console
+$ mkdir -p ~/go/{bin,pkg,src}
+```
+
+`bin` contains go binaries that are created from `go get` or `go install`.
+`pkg` contains static (`.a`) compiled versions of go packages that are not go
+programs. `src` contains go source code.
+
+After you create this, add
+[this](https://github.com/Xe/dotfiles/blob/master/.zsh/go-completion.zsh) and
+the following to your zsh config:
+
+```sh
+export GOPATH=$HOME/go
+export PATH=$PATH:/usr/lib/go/bin:$GOPATH/bin
+```
+
+This will add the go compilers to your `$PATH` as well as programs you install.
+
+Rehash your shell config (I use
+a [`resource`](https://github.com/Xe/dotfiles/blob/master/.zsh/resource.zsh#L3)
+command for this) and then run:
+
+```console
+$ go env
+GOARCH="amd64"
+GOBIN=""
+GOCHAR="6"
+GOEXE=""
+GOHOSTARCH="amd64"
+GOHOSTOS="linux"
+GOOS="linux"
+GOPATH="/home/xena/go"
+GORACE=""
+GOROOT="/usr/lib/go"
+GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
+TERM="dumb"
+CC="gcc"
+GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread"
+CXX="g++"
+CGO_ENABLED="1"
+```
+
+This will verify that the go toolchain knows where the go compilers are as well
+as where your `$GOPATH` is.
+
+Testing
+-------
+
+To test the go compilers with a simple
+[todo command](http://github.com/mattn/todo), run this:
+
+```console
+$ go get github.com/mattn/todo
+$ todo add foo
+$ todo list
+☐ 001: foo
+```
+
+Vim Setup
+---------
+
+For Vim integration, I suggest using the
+[vim-go](https://github.com/fatih/vim-go) plugin. This plugin used to be part
+of the standard Go distribution.
+
+To install:
+
+1. Add `Plugin 'fatih/vim-go'` to the plugins part of your vimrc.
+2. Run these commands:
+
+```console
+$ vim +PluginInstall +qall
+$ vim +GoInstallBinaries +qall
+```
+
+This will install the go oracle and the go autocompletion daemon gocode as well
+as some other useful tools that will integrate seamlessly into vim. This will
+also run `gofmt` on save to style your code to the standard way to write Go
+code.
+
+Resources
+---------
+
+[Effective Go](https://golang.org/doc/effective_go.html) and the
+[language spec](https://golang.org/ref/spec) provide a nice overview of the
+syntax.
+
+The Go [blog](http://blog.golang.org) contains a lot of detailed articles
+covering advanced and simple Go topics.
+[This page](https://golang.org/doc/#articles) has a list of past articles that
+you may find useful.
+
+The Go standard library is a fantastic collection of Go code for solving many
+problems. In some cases you can even write entire programs using only the
+standard library. This includes things like web application support, tarfile
+support, sql drivers, support for most kinds of commonly used crypto, command
+line flag parsing, html templating, and regular expressions. A full list of
+the standard library packages can be found [here](http://godoc.org/-/go).
+
+Variable type declarations will look backwards. It takes a bit to get used to
+but makes a lot of sense once you realize it reads better left to right.
+
+For a nice primer on building web apps with Go, codegangsta is writing a book
+on the common first steps, starting from the standard library and working up.
+You can find his work in progress book
+[here](http://codegangsta.gitbooks.io/building-web-apps-with-go/).
+
+Go has support for unit testing baked into the core language tools. You can
+find information about writing unit tests [here](http://golang.org/pkg/testing/).
+
+When creating a new go project, please resist the urge to make the folder in your
+normal code folder. Drink the `$GOPATH` koolaid. Yes it's annoying, yes it's the
+language forcing you to use its standard. Just try it. It's an amazingly useful
+thing once you get used to it.
+
+Learn to love godoc. Godoc lets you document code like
+[this](https://gist.github.com/Xe/b973e30d81280899955d). This also includes an
+example of the builtin unit testing support.
diff --git a/blog/metaprogramming-partial-application-2015-08-26.markdown b/blog/metaprogramming-partial-application-2015-08-26.markdown
new file mode 100644
index 0000000..61fc9a9
--- /dev/null
+++ b/blog/metaprogramming-partial-application-2015-08-26.markdown
@@ -0,0 +1,430 @@
+---
+title: "Metaprogramming: Partial Application..."
+date: 2015-08-26
+---
+
+Metaprogramming: Partial Application and Currying 101
+=====================================================
+
+The title of this post looks intimidating. There's a lot of words there that
+look like they are very complicated and will take a long time to master. In
+reality, they are really very simple things. Let's start with a mundane example
+and work our way up to a real-world bit of code. Let's begin with a small
+story:
+
+---
+
+ACMECorp has a world-renowned Python application named Itera that is known for
+its superb handling of basic mathematic functions. It's so well known and
+industry proven that it is used in every school and on every home computer. You
+have just accepted a job there as an intermediate programmer set to do
+maintenance on it. Naturally, you are very excited to peek under the hood of
+this mysterious and powerful program and offer your input to make it even
+better for the next release and its users.
+
+Upon getting there, you settle in and look at your ticket queue for the day.
+A user is complaining that whenever they add `3` and `5`, they get `7` instead
+of `8`, which is what they expected. Your first step is to go look into the
+`add3` function and see what it does:
+
+```Python
+def add1(x):
+ return x + 1
+
+def add2(x):
+ return x + 2
+
+def add3(x):
+ return x + 2
+
+def add4(x):
+ return x + 4
+```
+
+You are aghast. Your company's multi-billion dollar calculator is brought to
+its knees by a simple copy-paste error. You wonder, "how in Sam Hill are these
+people making any money???" (The answer, of course, is that they are a big
+enterprise corporation)
+
+You let your boss know about the bad news, you are immediately given any
+resource in the company that you need to get this mission-critical problem
+solved for *any input*. Yesterday. Without breaking the API that the rest of
+the program has hard-coded in.
+
+---
+
+Let's look at what is common about all these functions. The `add*` family of
+functions seems to all be doing one thing consistently: adding one number to
+another.
+
+Let's define a function called `add` that adds any two numbers:
+
+```Python
+def add(x, y):
+ return x + y
+```
+
+This is nice, but it won't work for the task we were given, which is to not
+break the API.
+
+Let's go over what a function is in Python. We can define a function as
+something that takes some set of Python values and produces some set of Python
+values:
+
+```haskell
+PythonFunction :: [PythonValue] -> [PythonValue]
+```
+
+We can read this as "a Python function takes a set of Python values and
+produces a set of Python values". Now we need to define what a Python value
+actually is. To keep things simple, we're only going to define the following
+types of values:
+
+- `None` -> no value
+- `Int` -> any whole number (Python calls this `int`)
+- `Text` -> any string value (Python calls this `str`)
+- `Function` -> something that takes and produces values
+
+Python [itself has a lot more types that any value can be](https://docs.Python.org/3.4/library/stdtypes.html),
+but for the scope of this blog post, this will do just fine.
+
+Now, since a function can return a value and a function is a value, let's see
+what happens if you return a function:
+
+```python
+def outer():
+ def inner():
+ return "Hello!"
+ return inner
+```
+
+And in the repl:
+
+```
+>>> type(outer)
+<type 'function'>
+```
+
+So `outer` is a function as we expect. It takes `None` (in Python, a function
+without arguments has `None` for the type of them) and returns a function that
+takes `None` and that function returns `Text` containing `"Hello!"`.
+Let's make sure of this:
+
+```
+>>> outer()()
+'Hello!'
+>>> type(outer()())
+<type 'str'>
+```
+
+Yay! When nothing is applied to the result of applying nothing to `outer`, it
+returns the `Text` value `"Hello!"`. We can define the type of `outer` as the
+following:
+
+```haskell
+outer :: None -> None -> Text
+```
+
+Now, let's use this for addition:
+
+```python
+# add :: Int -> Int -> Int
+def add(x):
+ def inner(y):
+ return x + y
+
+ return inner
+```
+
+And in the repl:
+
+```
+>>> add(4)(5)
+9
+```
+
+A cool feature about this is that now we can dip into something called Partial
+Application. Partial application lets you apply part of the arguments of
+a function and you get another function out of it. Let's trace the type of the
+`inner` function inside the `add` function, as well as the final computation
+for clarity:
+
+```python
+# add :: Int -> Int -> Int
+def add(x):
+ # inner :: Int -> Int
+ def inner(y):
+ return x + y # :: Int
+
+ return inner
+```
+
+Starting from the inside, we can see how the core computation here is `x + y`,
+which returns an `Int`. Then we can see that `y` is passed in and in the scope
+also as an `Int`. Then we can also see that `x` is passed in the outermost
+layer as an int, giving it the type `Int -> Int -> Int`. Since `inner` is
+a value, and a Python variable can contain any Python value, let's make
+a function called `increment` using the `add` function:
+
+```python
+# increment :: Int -> Int
+increment = add(1)
+```
+
+And in the repl:
+
+```
+>>> increment(50)
+1
+```
+
+`increment` takes the integer given and increases it by 1, it is the same thing
+as de