view my resume

This commit is contained in:
Cadey Ratio 2016-12-18 08:51:32 -08:00
parent 0315c0b721
commit dba3ae46f8
6 changed files with 235 additions and 9 deletions

View File

@ -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)

View File

@ -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 ] ]

View File

@ -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

66
frontend/src/Resume.purs Normal file
View File

@ -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 "." ]
]

View File

@ -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

132
static/resume/resume.md Normal file
View File

@ -0,0 +1,132 @@
# Christine Dodrill
---
> #### Rockstar Hacker, Cloud Architect, Gopher, Haskeller, Container Expert
> ##### Mountain View, CA &emsp; [christine.website][homepage] &emsp; [@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 &emsp; <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 &emsp; <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) &emsp; <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) &emsp; <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 &emsp; <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