view my resume
This commit is contained in:
parent
0315c0b721
commit
dba3ae46f8
|
@ -36,7 +36,10 @@ func (p Posts) Less(i, j int) bool {
|
||||||
}
|
}
|
||||||
func (p Posts) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
func (p Posts) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
|
||||||
var posts Posts
|
var (
|
||||||
|
posts Posts
|
||||||
|
rbody string
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
err := filepath.Walk("./blog/", func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk("./blog/", func(path string, info os.FileInfo, err error) error {
|
||||||
|
@ -87,6 +90,13 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(sort.Reverse(posts))
|
sort.Sort(sort.Reverse(posts))
|
||||||
|
|
||||||
|
resume, err := ioutil.ReadFile("./static/resume/resume.md")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rbody = string(resume)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -109,6 +119,13 @@ func main() {
|
||||||
fail:
|
fail:
|
||||||
http.Error(w, "Not Found", http.StatusNotFound)
|
http.Error(w, "Not Found", http.StatusNotFound)
|
||||||
})
|
})
|
||||||
|
http.HandleFunc("/api/resume", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
json.NewEncoder(w).Encode(struct {
|
||||||
|
Body string `json:"body"`
|
||||||
|
}{
|
||||||
|
Body: rbody,
|
||||||
|
})
|
||||||
|
})
|
||||||
http.Handle("/dist/", http.FileServer(http.Dir("./frontend/static/")))
|
http.Handle("/dist/", http.FileServer(http.Dir("./frontend/static/")))
|
||||||
http.Handle("/static/", http.FileServer(http.Dir(".")))
|
http.Handle("/static/", http.FileServer(http.Dir(".")))
|
||||||
http.HandleFunc("/", writeIndexHTML)
|
http.HandleFunc("/", writeIndexHTML)
|
||||||
|
|
|
@ -82,5 +82,5 @@ view state =
|
||||||
[]
|
[]
|
||||||
[ h1 [] [ text "Posts" ]
|
[ h1 [] [ text "Posts" ]
|
||||||
, documentTitle [ title "Posts - Christine Dodrill" ] []
|
, documentTitle [ title "Posts - Christine Dodrill" ] []
|
||||||
, p [] [ text state.status ]
|
, div [ className "row" ] $ map post state.posts
|
||||||
, div [ className "row" ] $ map post state.posts ]
|
, p [] [ text state.status ] ]
|
||||||
|
|
|
@ -3,6 +3,7 @@ module App.Layout where
|
||||||
import App.BlogEntry as BlogEntry
|
import App.BlogEntry as BlogEntry
|
||||||
import App.BlogIndex as BlogIndex
|
import App.BlogIndex as BlogIndex
|
||||||
import App.Counter as Counter
|
import App.Counter as Counter
|
||||||
|
import App.Resume as Resume
|
||||||
import App.Routes (Route(..))
|
import App.Routes (Route(..))
|
||||||
import Control.Monad.RWS (state)
|
import Control.Monad.RWS (state)
|
||||||
import DOM (DOM)
|
import DOM (DOM)
|
||||||
|
@ -20,20 +21,23 @@ data Action
|
||||||
= Child (Counter.Action)
|
= Child (Counter.Action)
|
||||||
| BIChild (BlogIndex.Action)
|
| BIChild (BlogIndex.Action)
|
||||||
| BEChild (BlogEntry.Action)
|
| BEChild (BlogEntry.Action)
|
||||||
|
| REChild (Resume.Action)
|
||||||
| PageView Route
|
| PageView Route
|
||||||
|
|
||||||
type State =
|
type State =
|
||||||
{ route :: Route
|
{ route :: Route
|
||||||
, count :: Counter.State
|
, count :: Counter.State
|
||||||
, bistate :: BlogIndex.State
|
, bistate :: BlogIndex.State
|
||||||
, bestate :: BlogEntry.State }
|
, bestate :: BlogEntry.State
|
||||||
|
, restate :: Resume.State }
|
||||||
|
|
||||||
init :: State
|
init :: State
|
||||||
init =
|
init =
|
||||||
{ route: NotFound
|
{ route: NotFound
|
||||||
, count: Counter.init
|
, count: Counter.init
|
||||||
, bistate: BlogIndex.init
|
, bistate: BlogIndex.init
|
||||||
, bestate: BlogEntry.init }
|
, bestate: BlogEntry.init
|
||||||
|
, restate: Resume.init }
|
||||||
|
|
||||||
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
||||||
update (PageView route) state = routeEffects route $ state { route = route }
|
update (PageView route) state = routeEffects route $ state { route = route }
|
||||||
|
@ -43,14 +47,19 @@ update (BIChild action) state = BlogIndex.update action state.bistate
|
||||||
update (BEChild action) state = BlogEntry.update action state.bestate
|
update (BEChild action) state = BlogEntry.update action state.bestate
|
||||||
# mapState (state { bestate = _ })
|
# mapState (state { bestate = _ })
|
||||||
# mapEffects BEChild
|
# mapEffects BEChild
|
||||||
|
update (REChild action) state = Resume.update action state.restate
|
||||||
|
# mapState ( state { restate = _ })
|
||||||
|
# mapEffects REChild
|
||||||
update (Child action) state = noEffects $ state { count = Counter.update action state.count }
|
update (Child action) state = noEffects $ state { count = Counter.update action state.count }
|
||||||
update _ state = noEffects $ state
|
update _ state = noEffects $ state
|
||||||
|
|
||||||
routeEffects :: Route -> State -> EffModel State Action (dom :: DOM, ajax :: AJAX)
|
routeEffects :: Route -> State -> EffModel State Action (dom :: DOM, ajax :: AJAX)
|
||||||
routeEffects BlogIndex state = { state: state
|
routeEffects (BlogIndex) state = { state: state
|
||||||
, effects: [ pure BlogIndex.RequestPosts ] } # mapEffects BIChild
|
, effects: [ pure BlogIndex.RequestPosts ] } # mapEffects BIChild
|
||||||
routeEffects (BlogPost page) state = { state: state { bestate = BlogEntry.init { name = page } }
|
routeEffects (Resume) state = { state: state
|
||||||
, effects: [ pure BlogEntry.RequestPost ] } # mapEffects BEChild
|
, effects: [ pure Resume.RequestResume ] } # mapEffects REChild
|
||||||
|
routeEffects (BlogPost page') state = { state: state { bestate = BlogEntry.init { name = page' } }
|
||||||
|
, effects: [ pure BlogEntry.RequestPost ] } # mapEffects BEChild
|
||||||
routeEffects _ state = noEffects $ state
|
routeEffects _ state = noEffects $ state
|
||||||
|
|
||||||
view :: State -> Html Action
|
view :: State -> Html Action
|
||||||
|
@ -162,7 +171,7 @@ index =
|
||||||
page :: Route -> State -> Html Action
|
page :: Route -> State -> Html Action
|
||||||
page NotFound _ = h1 [] [ text "not found" ]
|
page NotFound _ = h1 [] [ text "not found" ]
|
||||||
page Home _ = index
|
page Home _ = index
|
||||||
page Resume state = h1 [] [ text "Christine Dodrill" ]
|
page Resume state = map REChild $ Resume.view state.restate
|
||||||
page BlogIndex state = map BIChild $ BlogIndex.view state.bistate
|
page BlogIndex state = map BIChild $ BlogIndex.view state.bistate
|
||||||
page (BlogPost _) state = map BEChild $ BlogEntry.view state.bestate
|
page (BlogPost _) state = map BEChild $ BlogEntry.view state.bestate
|
||||||
page ContactPage _ = contact
|
page ContactPage _ = contact
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
module App.Resume where
|
||||||
|
|
||||||
|
import App.Utils (mdify)
|
||||||
|
import Control.Monad.Aff (attempt)
|
||||||
|
import DOM (DOM)
|
||||||
|
import Data.Argonaut (class DecodeJson, decodeJson, (.?))
|
||||||
|
import Data.Either (Either(..), either)
|
||||||
|
import Data.Maybe (Maybe(..))
|
||||||
|
import Network.HTTP.Affjax (AJAX, get)
|
||||||
|
import Prelude (Unit, bind, pure, show, unit, ($), (<>), (<<<))
|
||||||
|
import Pux (noEffects, EffModel)
|
||||||
|
import Pux.DocumentTitle (documentTitle)
|
||||||
|
import Pux.Html (Html, a, div, h1, p, text)
|
||||||
|
import Pux.Html.Attributes (href, dangerouslySetInnerHTML, className, id_, title)
|
||||||
|
|
||||||
|
data Action = RequestResume
|
||||||
|
| ReceiveResume (Either String Resume)
|
||||||
|
|
||||||
|
type State =
|
||||||
|
{ status :: String
|
||||||
|
, err :: String
|
||||||
|
, resume :: Maybe Resume }
|
||||||
|
|
||||||
|
data Resume = Resume
|
||||||
|
{ body :: String }
|
||||||
|
|
||||||
|
instance decodeJsonResume :: DecodeJson Resume where
|
||||||
|
decodeJson json = do
|
||||||
|
obj <- decodeJson json
|
||||||
|
body <- obj .? "body"
|
||||||
|
pure $ Resume { body: body }
|
||||||
|
|
||||||
|
init :: State
|
||||||
|
init =
|
||||||
|
{ status: "Loading..."
|
||||||
|
, err: ""
|
||||||
|
, resume: Nothing }
|
||||||
|
|
||||||
|
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
||||||
|
update (ReceiveResume (Left err)) state =
|
||||||
|
noEffects $ state { resume = Nothing, status = "Error in fetching resume, please use the plain text link below.", err = err }
|
||||||
|
update (ReceiveResume (Right body)) state =
|
||||||
|
noEffects $ state { status = "", err = "", resume = Just body }
|
||||||
|
where
|
||||||
|
got' = Just unit
|
||||||
|
update RequestResume state =
|
||||||
|
{ state: state
|
||||||
|
, effects: [ do
|
||||||
|
res <- attempt $ get "/api/resume"
|
||||||
|
let decode r = decodeJson r.response :: Either String Resume
|
||||||
|
let resume = either (Left <<< show) decode res
|
||||||
|
pure $ ReceiveResume resume
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
view :: State -> Html Action
|
||||||
|
view { status: status, err: err, resume: resume } =
|
||||||
|
case resume of
|
||||||
|
Nothing -> div [] [ text status, p [] [ text err ] ]
|
||||||
|
(Just (Resume resume')) ->
|
||||||
|
div [ className "row" ]
|
||||||
|
[ documentTitle [ title "Resume - Christine Dodrill" ] []
|
||||||
|
, div [ className "col s8 offset-s2" ]
|
||||||
|
[ p [ className "browser-default", dangerouslySetInnerHTML $ mdify resume'.body ] []
|
||||||
|
, a [ href "/static/resume/resume.md" ] [ text "Plain-text version of this resume here" ], text "." ]
|
||||||
|
]
|
|
@ -27,3 +27,5 @@ match url = fromMaybe NotFound $ router url $
|
||||||
BlogPost <$> (lit "blog" *> str) <* end
|
BlogPost <$> (lit "blog" *> str) <* end
|
||||||
<|>
|
<|>
|
||||||
ContactPage <$ lit "contact" <* end
|
ContactPage <$ lit "contact" <* end
|
||||||
|
<|>
|
||||||
|
Resume <$ lit "resume" <* end
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
# Christine Dodrill
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> #### Rockstar Hacker, Cloud Architect, Gopher, Haskeller, Container Expert
|
||||||
|
> ##### Mountain View, CA   [christine.website][homepage]   [@theprincessxena][twitter] ![twit][]
|
||||||
|
> `Docker`, `Git`, `Haskell`, `Nim`, `Go`, `C`, `CentOS`, `CoreOS`, `IRC`, `Matrix`
|
||||||
|
|
||||||
|
---
|
||||||
|
> **"** A github power user, constantly learns new things to keep up on what's new in tech.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## Experience
|
||||||
|
#### Backplane.io - Software Engineer   <small>*2016 - 2016*</small>
|
||||||
|
`Go`, `Docker`, `docker-compose`, `devops`, `PostgreSQL`
|
||||||
|
> [Backplane](https://backplane.io) is an innovative reverse reverse proxy that
|
||||||
|
> helps administrators and startups simplify their web application routing.
|
||||||
|
>
|
||||||
|
> #### Highlights
|
||||||
|
>
|
||||||
|
> - Performance monitoring of production servers
|
||||||
|
> - Continuous deployment and development in Go
|
||||||
|
> - Learning a lot about HTTP/2 and load balancing
|
||||||
|
|
||||||
|
---
|
||||||
|
#### IMVU - Site Reliability Engineer   <small>*2015 - 2016*</small>
|
||||||
|
`Ubuntu Server`, `CFEngine`, `Haskell`, `Go`, `Perl`, `Nginx`, `JunOS`, `Ceph`, `MySQL`, `Redis`, `Memcached`, `PHP`, `Erlang`
|
||||||
|
> IMVU, inc is a company whose mission is to help people find and communicate
|
||||||
|
> with eachother. Their main product is a 3D avatar-based chat client and its
|
||||||
|
> surrounding infrastructure allowing creators to make content for the avatars
|
||||||
|
> to wear.
|
||||||
|
>
|
||||||
|
> #### Highlights
|
||||||
|
>
|
||||||
|
> - Wrote up technical designs
|
||||||
|
> - Implemented technical designs on an over 800 machine cluster
|
||||||
|
> - Continuous learning of a lot of very powerful systems and improving upon them
|
||||||
|
> when it is needed
|
||||||
|
|
||||||
|
---
|
||||||
|
#### VTCSecure - Deis Consultant (contract)   <small>*2014 - 2015*</small>
|
||||||
|
`Deis`, `Docker`, `CoreOS`, `Go`, `Freeswitch`
|
||||||
|
> VTCSecure is a company dedicated to helping with custom and standard
|
||||||
|
> audio/video conferencing solutions. They specialize in helping the deaf and
|
||||||
|
> blind communicate over today's infrastructure without any trouble on their end.
|
||||||
|
>
|
||||||
|
> #### Highlights
|
||||||
|
>
|
||||||
|
> - Started groundwork for a dynamically scalable infrastructure on a project for helping the blind see things
|
||||||
|
> - Developed a prototype of a new website for VTCSecure
|
||||||
|
> - Education on best practices using Docker and CoreOS
|
||||||
|
> - Learning Freeswitch
|
||||||
|
|
||||||
|
---
|
||||||
|
#### Crowdflower - Deis Consultant (Contract)   <small>*2014 - 2014*</small>
|
||||||
|
`Ruby`, `Rails`, `Chef`, `CoreOS`, `Docker`, `Deis`
|
||||||
|
> Crowdflower is a company that uses crowdsourcing to have its customers submit
|
||||||
|
> tasks to be done, similar to Amazon's Mechanical Turk. CrowdFlower has over 50
|
||||||
|
> labor channel partners, and its network has more than 5 million contributors
|
||||||
|
> worldwide.
|
||||||
|
>
|
||||||
|
> #### Highlights
|
||||||
|
>
|
||||||
|
> - Research and development on scalable Linux deployments on AWS via CoreOS and
|
||||||
|
> Docker
|
||||||
|
> - Development of in-house tools to speed instance creation
|
||||||
|
> - Laid groundwork on the creation and use of better tools for managing large
|
||||||
|
> clusters of CoreOS and Fleet machines
|
||||||
|
|
||||||
|
---
|
||||||
|
#### OpDemand - Software Engineering Intern   <small>*2014 - 2014*</small>
|
||||||
|
`Deis`, `CoreOS`, `Go`, `Docker`
|
||||||
|
> OpDemand is the company behind the open source project Deis, a distributed
|
||||||
|
> platform-as-a-service (PaaS) designed from the ground up to emulate Heroku but
|
||||||
|
> on privately owned servers.
|
||||||
|
>
|
||||||
|
> #### Highlights
|
||||||
|
>
|
||||||
|
> - Built new base image for Deis components
|
||||||
|
> - Research and development on a new builder component
|
||||||
|
|
||||||
|
---
|
||||||
|
## Open Source
|
||||||
|
#### [Elemental-IRCd](http://elemental-ircd.com)
|
||||||
|
A scalable RFC compliant IRCv3 enabled IRC server for personal and professional use.
|
||||||
|
|
||||||
|
#### Accomplishments
|
||||||
|
|
||||||
|
* Automated testing via [Travis](https://travis-ci.org/Elemental-IRCd/elemental-ircd)
|
||||||
|
* Community management via [Github](https://github.com/elemental-ircd/elemental-ircd)
|
||||||
|
|
||||||
|
Elemental is currently in use in production on several networks, totaling 800-1000
|
||||||
|
users per day with spikes of up to 50,000 on special events.
|
||||||
|
|
||||||
|
---
|
||||||
|
#### [Tetra](https://github.com/Xe/Tetra)
|
||||||
|
A modern IRC services platform for TS6 IRC daemons.
|
||||||
|
|
||||||
|
#### Accomplishments
|
||||||
|
|
||||||
|
* Parallel, safe execution of handlers and scripts
|
||||||
|
* Moonscript -> Lua transpiling support
|
||||||
|
* A clean, declarative domain-specific language for declaring features or bot commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
Command "PING", ->
|
||||||
|
"PONG"
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a command named "PING" that will return "PONG" to the user when it is used.
|
||||||
|
|
||||||
|
---
|
||||||
|
#### [PonyAPI](https://github.com/Xe/ponyapi)
|
||||||
|
A simple API for information on episodes of My Little Pony: Friendship is Magic written in Nim to be run inside a container.
|
||||||
|
|
||||||
|
All data is loaded into ram and there are no usage limits as long as you agree to not take down the server it is running on.
|
||||||
|
|
||||||
|
---
|
||||||
|
#### [Professional Projects](https://github.com/Xe)
|
||||||
|
Projects here will be of a more professional nature (save a few here and there).
|
||||||
|
|
||||||
|
---
|
||||||
|
## Writing
|
||||||
|
|
||||||
|
> Articles listed below will be either personal or professional and do not reflect the views of any company or group I am affiliated with. The writing is my own.
|
||||||
|
#### [My Blog](https://christine.website/blog) *<small>@christine.website/blog</small>*
|
||||||
|
|
||||||
|
---
|
||||||
|
[homepage]: https://christine.website
|
||||||
|
[twitter]: https://twitter.com/theprincessxena
|
||||||
|
[twit]: http://cdn-careers.sstatic.net/careers/Img/icon-twitter.png?v=b1bd58ad2034
|
Loading…
Reference in New Issue