├── .gitignore ├── README.md ├── _config.yml ├── _includes ├── footer.html └── head.html ├── _layouts └── workshop.html ├── _sass ├── _columns.scss ├── _content.scss ├── _forms.scss ├── _graph.scss ├── _header.scss ├── _next-nav.scss ├── _syntax-highlighting.scss ├── _window.scss ├── font │ ├── _animation.scss │ └── _fontello.scss ├── globals │ ├── _colors.scss │ ├── _mixins.scss │ ├── _reset.scss │ └── _size.scss └── main.scss ├── _workshop ├── 00-introduction.js ├── 01-1-context.js ├── 01-2-arguments.js ├── 01-3-prototype.js ├── 02-1-applicative.js ├── 02-2-map.js ├── 02-3-filter.js ├── 02-4-reduce.js ├── 02-5-lodash.js ├── 02-6-point-free.js ├── 02-7-context.js ├── 03-1-factories.js ├── 03-2-higher-order.js ├── 03-3-functions-with-functions.js ├── 03-4-fluent.js ├── 03-5-arity.js ├── 04-1-partial-application.js ├── 04-2-functions-from-functions.js ├── 05-1-currying.js ├── 05-2-compose.js ├── 05-3-pipelines.js ├── 05-4-parse-url.js ├── 06-shared-state.js ├── 07-collections.js └── 08-done.js ├── assets ├── component-tree.svg ├── font │ ├── LICENSE.txt │ ├── fontello.eot │ ├── fontello.svg │ ├── fontello.ttf │ └── fontello.woff ├── github.png ├── logo.svg └── omniscient.svg ├── css ├── main.css └── vendor │ └── base16-mocha-dark.css ├── gulpfile.js ├── index.html ├── notes.md ├── package.json ├── previous_presentations ├── .gitignore ├── dag1 │ ├── 1_intro.js │ ├── 2_applicative.js │ ├── 3_functions.js │ ├── 4_partially.js │ ├── 5_curry_compose.js │ ├── 6_immutability.js │ ├── 7_collections.js │ ├── README.md │ ├── agenda.md │ ├── books.json │ ├── package.json │ ├── slides │ │ ├── font │ │ │ ├── 0AKsP294HTD-nvJgucYTaIbN6UDyHWBl620a-IRfuBk.woff │ │ │ └── YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff │ │ ├── img │ │ │ ├── functional-map.png │ │ │ ├── iterative-map.png │ │ │ ├── plot-languages.png │ │ │ └── plot.svg │ │ ├── index.html │ │ ├── remark-styling.css │ │ └── remark.min.js │ └── solutions │ │ ├── 1_intro.js │ │ ├── 2_applicative.js │ │ ├── 3_functions.js │ │ ├── 4_partially.js │ │ ├── 5_curry_compose.js │ │ ├── 6_immutability.js │ │ └── 7_collections.js └── dag2 │ ├── agenda.md │ ├── big-case │ ├── .gitignore │ ├── README.md │ ├── baconchat.png │ ├── browser │ │ ├── _solution.js │ │ ├── config.js │ │ ├── lib │ │ │ ├── chat.js │ │ │ ├── helpers.js │ │ │ └── webrtc.js │ │ └── main.js │ ├── gulpfile.js │ ├── lib │ │ └── users.js │ ├── package.json │ ├── server.js │ ├── static-server.js │ ├── static │ │ ├── assets │ │ │ └── bacon.png │ │ └── index.html │ └── style │ │ ├── chat.less │ │ ├── colors.less │ │ ├── main.less │ │ ├── mixins.less │ │ └── reset.less │ ├── slides │ ├── css │ │ ├── presentation.css │ │ ├── print │ │ │ ├── paper.css │ │ │ └── pdf.css │ │ ├── reveal.css │ │ ├── reveal.min.css │ │ └── theme │ │ │ ├── README.md │ │ │ ├── beige.css │ │ │ ├── default.css │ │ │ ├── moon.css │ │ │ ├── night.css │ │ │ ├── serif.css │ │ │ ├── simple.css │ │ │ ├── sky.css │ │ │ ├── solarized.css │ │ │ ├── source │ │ │ ├── beige.scss │ │ │ ├── default.scss │ │ │ ├── moon.scss │ │ │ ├── night.scss │ │ │ ├── serif.scss │ │ │ ├── simple.scss │ │ │ ├── sky.scss │ │ │ └── solarized.scss │ │ │ └── template │ │ │ ├── mixins.scss │ │ │ ├── settings.scss │ │ │ └── theme.scss │ ├── img │ │ ├── avengers2.gif │ │ ├── batman.gif │ │ ├── data_flow.svg │ │ └── kevin_bacon.gif │ ├── index.html │ ├── js │ │ ├── reveal.js │ │ └── reveal.min.js │ ├── lib │ │ ├── css │ │ │ └── zenburn.css │ │ ├── font │ │ │ ├── league_gothic-webfont.eot │ │ │ ├── league_gothic-webfont.svg │ │ │ ├── league_gothic-webfont.ttf │ │ │ ├── league_gothic-webfont.woff │ │ │ └── league_gothic_license │ │ └── js │ │ │ ├── bacon.js │ │ │ ├── classList.js │ │ │ ├── head.min.js │ │ │ ├── html5shiv.js │ │ │ └── jquery.js │ └── plugin │ │ ├── highlight │ │ └── highlight.js │ │ ├── markdown │ │ ├── example.html │ │ ├── example.md │ │ ├── markdown.js │ │ └── marked.js │ │ ├── math │ │ └── math.js │ │ ├── notes-server │ │ ├── client.js │ │ ├── index.js │ │ └── notes.html │ │ ├── notes │ │ ├── notes.html │ │ └── notes.js │ │ ├── postmessage │ │ ├── example.html │ │ └── postmessage.js │ │ ├── print-pdf │ │ └── print-pdf.js │ │ ├── remotes │ │ └── remotes.js │ │ ├── search │ │ └── search.js │ │ └── zoom-js │ │ └── zoom.js │ └── small-case │ ├── _app.js │ ├── api.js │ ├── app.js │ ├── index.html │ ├── package.json │ ├── readme.md │ ├── recordapp.png │ └── style.css ├── scripts ├── components │ ├── books.js │ ├── codemirror-editor.js │ ├── component.js │ ├── editor.js │ ├── run-code.js │ └── run-result.js ├── entry.build.js ├── entry.js ├── playground-reporter.js └── vendor │ ├── browser.js │ ├── codemirror-base16-mocha-dark.css │ ├── codemirror-kimbie-dark.css │ └── codemirror.css └── webpack.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | _site 6 | .sass-cache 7 | 8 | 9 | .DS_Store 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 23 | .grunt 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | # Commenting this out is preferred by some people, see 30 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 31 | node_modules 32 | 33 | # Users Environment Variables 34 | .lock-wscript 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Workshop](http://bekk.github.io/functional-js/workshop/) 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Site settings 2 | title: Functional JavaScript Workshop 3 | description: Workshop for teaching Functional Programming with JavaScript 4 | baseurl: "/functional-js" # the subpath of your site, e.g. /blog/ 5 | url: "http://bekkopen.github.io/" # the base hostname & protocol for your site 6 | 7 | version: 3.1.0 8 | 9 | # Build settings 10 | markdown: kramdown 11 | 12 | exclude: 13 | - node_modules 14 | 15 | collections: 16 | workshop: 17 | output: true 18 | output_ext: html 19 | collection: workshop 20 | permalink: /workshop/:path/ 21 | 22 | permalink: pretty 23 | 24 | kramdown: 25 | input: GFM 26 | hard_wrap: false 27 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /_layouts/workshop.html: -------------------------------------------------------------------------------- 1 | 2 | {% include head.html %} 3 | 4 | 5 |
6 |

Task: {{page.title}}

7 | 8 | {% if page.slides %} 9 |

See related slides for this part: {{page.slides}}

10 | {% endif %} 11 | 12 |
13 | {% if page.prev %} 14 | ← Previous task 15 | {% endif %} 16 | {% if page.next %} 17 | Next task → 18 | {% endif %} 19 |
20 | 21 | {% if page.info %} 22 |

Information

23 |
{{page.info | markdownify}}
24 | {% endif %} 25 | 26 |
27 | 28 |

Tasks

29 |
    30 | {% for item in site.workshop %} 31 | {% if item.hide != true %} 32 | {% assign pageID = page.name %} 33 | {% assign itemID = item.name %} 34 | {% assign className = pageID == itemID ? ' class="active"' : '' %} 35 |
  1. 36 | {% if item.start == true %} 37 | 38 | {% else %} 39 | 40 | {% endif %} 41 | {% if item["section"] %}Part {{item["section"]}}: {% endif %} 42 | {{item["title"]}} 43 | 44 | {% if pageID == itemID %}[Active]{% endif %} 45 |
  2. 46 | {% endif %} 47 | {% endfor %} 48 |
49 | 50 |
51 | {% if page.prev %} 52 | ← Previous task 53 | {% endif %} 54 | {% if page.next %} 55 | Next task → 56 | {% endif %} 57 |
58 | 59 |

Help

60 | 61 |

Available globals

62 | 66 | 67 |

Testing

68 | 77 | 78 |
79 | {% include footer.html %} 80 | 81 | 82 | -------------------------------------------------------------------------------- /_sass/_columns.scss: -------------------------------------------------------------------------------- 1 | @import "globals/size"; 2 | 3 | .column { 4 | margin-left: calc(#{$column-sidebar-width} + #{$column-sidebar-margin + 1}); 5 | } 6 | 7 | .nav-left { 8 | float: left; 9 | width: $column-sidebar-width; 10 | margin-right: $column-sidebar-margin; 11 | 12 | font-size: 0.9rem; 13 | } 14 | .nav-left ul, 15 | .nav-left ol { 16 | padding: 0; 17 | padding-left: 10px; 18 | list-style-type: none; 19 | } 20 | .nav-left h3 { 21 | margin: 0; 22 | } 23 | .nav-left > :not(:first-child) { 24 | margin-top: 30px; 25 | } 26 | .nav-left h3 a { 27 | font-size: 1.2rem; 28 | font-weight: 100; 29 | color: $color-leftNav-header; 30 | 31 | text-transform: uppercase; 32 | display: block; 33 | } 34 | 35 | .nav-left { 36 | ul, ol { 37 | a { 38 | display: block; 39 | padding: 5px 0; 40 | 41 | color: $color-leftNav; 42 | 43 | transition: all 300ms; 44 | 45 | &:hover { 46 | color: lighten($color-leftNav, 40%); 47 | } 48 | } 49 | } 50 | } 51 | 52 | @media (max-width: $first-breakpoint-width) { 53 | .nav-left { 54 | display: none; 55 | } 56 | .column { 57 | margin-left: 0; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /_sass/_content.scss: -------------------------------------------------------------------------------- 1 | @import "./globals/mixins"; 2 | @import "./globals/colors"; 3 | 4 | .mainContent { 5 | @include width-constraint; 6 | margin-top: 30px; 7 | display: block; 8 | 9 | &.playground { 10 | @include width-constraint-large; 11 | } 12 | } 13 | 14 | .mainContent h1, 15 | .mainContent h2, 16 | .mainContent h3 { 17 | font-size: 2rem; 18 | margin-bottom: 10px; 19 | font-weight: 100; 20 | position: relative; 21 | word-wrap: break-word; 22 | 23 | color: $color-organge-normal; 24 | } 25 | .mainContent h1 { 26 | margin-top: 50px; 27 | margin-top: 0; 28 | } 29 | .mainContent h2 { 30 | font-size: 1.5rem; 31 | } 32 | .mainContent h3 { 33 | font-size: 1.4rem; 34 | } 35 | 36 | .mainContent p { 37 | line-height: 1.7rem; 38 | } 39 | 40 | .mainContent table { 41 | width: 100%; 42 | margin: 10px 0; 43 | background: $color-table-white; 44 | 45 | td, th { 46 | padding: 5px; 47 | } 48 | 49 | tr:nth-child(odd) td { 50 | background: $color-table-zebra; 51 | } 52 | } 53 | 54 | 55 | .playground h1, 56 | .playground h2, 57 | .playground h3 { 58 | margin-top: 1rem; 59 | } 60 | 61 | .mainContent p { 62 | margin-bottom: 20px; 63 | } 64 | 65 | .mainContent img { 66 | max-width: 100%; 67 | } 68 | 69 | .edit-page-link { 70 | position: absolute; 71 | top: -0.8rem; 72 | right: 0; 73 | font-size: 0.7rem; 74 | } 75 | 76 | .fromMarkdown pre code { 77 | margin-bottom: 30px; 78 | } 79 | 80 | p img { 81 | background: #fff; 82 | } 83 | 84 | .column ul, 85 | .column ol { 86 | margin: 20px 0; 87 | } 88 | -------------------------------------------------------------------------------- /_sass/_forms.scss: -------------------------------------------------------------------------------- 1 | form { margin: 0; } 2 | // prevent ios zoom on focus 3 | input[type=text], textarea { font-size: 1rem; } 4 | -------------------------------------------------------------------------------- /_sass/_graph.scss: -------------------------------------------------------------------------------- 1 | @import "./globals/colors"; 2 | 3 | .graphNode--blue { 4 | fill: $color-topNode; 5 | 6 | -webkit-animation-name: 'pulse_animation'; 7 | -webkit-animation-duration: 2500ms; 8 | -webkit-animation-iteration-count: infinite; 9 | -webkit-animation-timing-function: linear; 10 | -webkit-transform-origin:70% 70%; 11 | } 12 | 13 | 14 | .graphEdge--fade, 15 | .graphNode--fade { 16 | -webkit-animation-name: 'fade_animation'; 17 | -webkit-animation-duration: 5000ms; 18 | -webkit-animation-iteration-count: infinite; 19 | -webkit-animation-timing-function: linear; 20 | } 21 | 22 | @-webkit-keyframes pulse_animation { 23 | 0% { -webkit-transform: scale(1); } 24 | 50% { -webkit-transform: scale(.95); } 25 | 100% { -webkit-transform: scale(1); } 26 | } 27 | 28 | @-webkit-keyframes fade_animation { 29 | 0% { opacity: 1; } 30 | 20% { opacity: .9; } 31 | 30% { opacity: .2; } 32 | 50% { opacity: .2; } 33 | 60% { opacity: .2; } 34 | 70% { opacity: .2; } 35 | 100% { opacity: 1; } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /_sass/_header.scss: -------------------------------------------------------------------------------- 1 | @import "./globals/colors"; 2 | @import "./globals/mixins"; 3 | @import "./globals/size"; 4 | 5 | .mainHeader { 6 | background: linear-gradient(to bottom, $color-header-background 0%, $color-header-background--bottom 100%); 7 | } 8 | 9 | .mainHeader-illustration { 10 | @include width-constraint; 11 | 12 | display: flex; 13 | align-items: center; 14 | flex-wrap: wrap; 15 | 16 | svg { 17 | min-width: 400px; 18 | margin: auto; 19 | flex: 3 0 30%; 20 | } 21 | } 22 | 23 | .mainHeader-illustration .illustrationText { 24 | flex: 1 1 30%; 25 | color: $color-infoBoxes; 26 | text-shadow: 1px 1px 1px rgba(0,0,0,.4); 27 | 28 | .github-badges { 29 | margin-top: 15px; 30 | text-align: center; 31 | } 32 | 33 | h1 { 34 | font-size: 2.5rem; 35 | } 36 | } 37 | 38 | @media (max-width: $remove-graphics-width) { 39 | .mainHeader-illustration svg { 40 | display: none; 41 | } 42 | } 43 | 44 | .mainNavigation { 45 | z-index: 3; // .CodeMirror pre is 2 46 | 47 | height: $header-height; 48 | position: fixed; 49 | min-height: initial; 50 | top: 0; 51 | left: 0; 52 | width: 100%; 53 | background: $color-header-background--small; 54 | } 55 | 56 | .mainNavigation-inner { 57 | @include width-constraint; 58 | 59 | display: flex; 60 | align-items: center; 61 | padding: 15px 0; 62 | 63 | justify-content: space-between; 64 | 65 | ul { 66 | // display: flex; 67 | list-style-type: none; 68 | margin-top: 5px; 69 | font-size: 1.2rem; 70 | 71 | li { 72 | float: left; 73 | 74 | &:last-child a { 75 | margin-right: 0; 76 | } 77 | } 78 | 79 | li a { 80 | display: block; 81 | margin-left: 20px; 82 | 83 | color: $color-header-linkColor; 84 | transition: all 300ms; 85 | 86 | text-transform: uppercase; 87 | text-decoration: none; 88 | font-weight: 300; 89 | 90 | 91 | &:hover { 92 | text-shadow: 1px 1px 3px rgba(0,0,0, .7); 93 | } 94 | } 95 | 96 | li:first-child a { 97 | margin-left: 0; 98 | } 99 | } 100 | } 101 | 102 | @media (max-width: $minify-header-width) { 103 | .mainNavigation-inner ul { 104 | li:nth-last-child(1), 105 | li:nth-last-child(2) { 106 | display: none; 107 | } 108 | } 109 | } 110 | 111 | .mainNavigation-inner h1 a { 112 | display: block; 113 | 114 | img { 115 | height: 33px; 116 | } 117 | } 118 | 119 | .chevronDown { 120 | height: 25px; 121 | display: block; 122 | text-align: center; 123 | transition: all 400ms; 124 | 125 | i { 126 | transition: all 400ms; 127 | @include chevron($color-blue-light, 5px, 50px); 128 | top: 10px; 129 | opacity: 0.5; 130 | } 131 | 132 | &:hover i { 133 | opacity: 1; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /_sass/_next-nav.scss: -------------------------------------------------------------------------------- 1 | @import "globals/mixins"; 2 | 3 | .docs-prevnext { 4 | margin: 20px 0; 5 | @include clearfix; 6 | } 7 | .docs-prev { 8 | float: left; 9 | } 10 | .docs-next { 11 | float: right; 12 | } -------------------------------------------------------------------------------- /_sass/_syntax-highlighting.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Syntax highlighting styles 3 | */ 4 | .highlight { 5 | background: #fff; 6 | @extend %vertical-rhythm; 7 | 8 | .c { color: #998; font-style: italic } // Comment 9 | .err { color: #a61717; background-color: #e3d2d2 } // Error 10 | .k { font-weight: bold } // Keyword 11 | .o { font-weight: bold } // Operator 12 | .cm { color: #998; font-style: italic } // Comment.Multiline 13 | .cp { color: #999; font-weight: bold } // Comment.Preproc 14 | .c1 { color: #998; font-style: italic } // Comment.Single 15 | .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special 16 | .gd { color: #000; background-color: #fdd } // Generic.Deleted 17 | .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific 18 | .ge { font-style: italic } // Generic.Emph 19 | .gr { color: #a00 } // Generic.Error 20 | .gh { color: #999 } // Generic.Heading 21 | .gi { color: #000; background-color: #dfd } // Generic.Inserted 22 | .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific 23 | .go { color: #888 } // Generic.Output 24 | .gp { color: #555 } // Generic.Prompt 25 | .gs { font-weight: bold } // Generic.Strong 26 | .gu { color: #aaa } // Generic.Subheading 27 | .gt { color: #a00 } // Generic.Traceback 28 | .kc { font-weight: bold } // Keyword.Constant 29 | .kd { font-weight: bold } // Keyword.Declaration 30 | .kp { font-weight: bold } // Keyword.Pseudo 31 | .kr { font-weight: bold } // Keyword.Reserved 32 | .kt { color: #458; font-weight: bold } // Keyword.Type 33 | .m { color: #099 } // Literal.Number 34 | .s { color: #d14 } // Literal.String 35 | .na { color: #008080 } // Name.Attribute 36 | .nb { color: #0086B3 } // Name.Builtin 37 | .nc { color: #458; font-weight: bold } // Name.Class 38 | .no { color: #008080 } // Name.Constant 39 | .ni { color: #800080 } // Name.Entity 40 | .ne { color: #900; font-weight: bold } // Name.Exception 41 | .nf { color: #900; font-weight: bold } // Name.Function 42 | .nn { color: #555 } // Name.Namespace 43 | .nt { color: #000080 } // Name.Tag 44 | .nv { color: #008080 } // Name.Variable 45 | .ow { font-weight: bold } // Operator.Word 46 | .w { color: #bbb } // Text.Whitespace 47 | .mf { color: #099 } // Literal.Number.Float 48 | .mh { color: #099 } // Literal.Number.Hex 49 | .mi { color: #099 } // Literal.Number.Integer 50 | .mo { color: #099 } // Literal.Number.Oct 51 | .sb { color: #d14 } // Literal.String.Backtick 52 | .sc { color: #d14 } // Literal.String.Char 53 | .sd { color: #d14 } // Literal.String.Doc 54 | .s2 { color: #d14 } // Literal.String.Double 55 | .se { color: #d14 } // Literal.String.Escape 56 | .sh { color: #d14 } // Literal.String.Heredoc 57 | .si { color: #d14 } // Literal.String.Interpol 58 | .sx { color: #d14 } // Literal.String.Other 59 | .sr { color: #009926 } // Literal.String.Regex 60 | .s1 { color: #d14 } // Literal.String.Single 61 | .ss { color: #990073 } // Literal.String.Symbol 62 | .bp { color: #999 } // Name.Builtin.Pseudo 63 | .vc { color: #008080 } // Name.Variable.Class 64 | .vg { color: #008080 } // Name.Variable.Global 65 | .vi { color: #008080 } // Name.Variable.Instance 66 | .il { color: #099 } // Literal.Number.Integer.Long 67 | } 68 | -------------------------------------------------------------------------------- /_sass/_window.scss: -------------------------------------------------------------------------------- 1 | .CodeMirror { 2 | z-index: 0; 3 | padding-bottom: 0.5rem; 4 | border-top-left-radius: 3px; 5 | border-top-right-radius: 3px; 6 | } 7 | .CodeMirror, 8 | .inner--result { 9 | font-size: 1rem; 10 | } 11 | .window .CodeMirror-lines { 12 | padding: 0; 13 | padding-left: 0.4rem; 14 | } 15 | 16 | .playground { 17 | 18 | .window .CodeMirror-lines { 19 | padding: 0; 20 | } 21 | 22 | .CodeMirror { 23 | border-top-left-radius: 3px; 24 | border-top-right-radius: 0; 25 | border-bottom-left-radius: 3px; 26 | } 27 | 28 | .CodeMirror-line-numbers { 29 | font-size: 0.2rem; 30 | } 31 | 32 | .CodeMirror, 33 | .inner--result { 34 | font-size: 1.15rem; 35 | } 36 | 37 | .window { 38 | display: flex; 39 | flex-flow: row wrap; 40 | } 41 | 42 | .control { 43 | flex: 1 100%; 44 | } 45 | .inner--code { 46 | flex: 1 65%; 47 | } 48 | .inner--result { 49 | flex: 1 35%; 50 | } 51 | } 52 | 53 | $color-error: #f25156; 54 | $color-success: #4ca73c; 55 | $color-pending: #f7ac3c; 56 | 57 | .test-summary { 58 | font-size: 0.9rem; 59 | text-align: center; 60 | } 61 | 62 | .editor-pending { 63 | color: $color-pending; 64 | } 65 | .editor-success { 66 | color: $color-success; 67 | } 68 | 69 | .editor > .inner > textarea { 70 | display: none; 71 | } 72 | .editor-error { 73 | color: $color-error; 74 | pre { 75 | font-size: 12px; 76 | white-space: pre-wrap; /* CSS 3 */ 77 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 78 | white-space: -pre-wrap; /* Opera 4-6 */ 79 | white-space: -o-pre-wrap; /* Opera 7 */ 80 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 81 | } 82 | } 83 | 84 | .window { 85 | background: #fafafa; 86 | width: 100%; 87 | border-radius: 3px; 88 | margin: 20px auto; 89 | box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.2); 90 | } 91 | 92 | .window .inner { 93 | padding: 0.5rem 0.75rem 0.1rem 0.75rem; 94 | } 95 | .window .inner--result { 96 | border-bottom-left-radius: 3px; 97 | border-bottom-right-radius: 3px; 98 | } 99 | .window .inner--code--withoutResult { 100 | border-bottom-left-radius: 3px; 101 | border-bottom-right-radius: 3px; 102 | } 103 | 104 | .window.window--code { 105 | background: none; 106 | } 107 | .window .inner--code { 108 | padding: 0; 109 | } 110 | 111 | .inner--result { 112 | color: #474747; 113 | font-weight: 300; 114 | } 115 | 116 | pre code { 117 | padding: 0 10px; 118 | background: #141414; 119 | display: block; 120 | padding: 10px; 121 | border-radius: 3px; 122 | overflow: auto; 123 | } 124 | 125 | p code, ul code, li code { 126 | background: darken($color-table-zebra, 1%); 127 | border: 1px solid darken($color-table-zebra, 10%); 128 | line-height: 1.4rem; 129 | padding: 0 5px; 130 | display: inline-block; 131 | border-radius: 2px; 132 | } 133 | -------------------------------------------------------------------------------- /_sass/font/_animation.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Animation example, for spinners 3 | */ 4 | .animate-spin { 5 | -moz-animation: spin 2s infinite linear; 6 | -o-animation: spin 2s infinite linear; 7 | -webkit-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | display: inline-block; 10 | } 11 | @-moz-keyframes spin { 12 | 0% { 13 | -moz-transform: rotate(0deg); 14 | -o-transform: rotate(0deg); 15 | -webkit-transform: rotate(0deg); 16 | transform: rotate(0deg); 17 | } 18 | 19 | 100% { 20 | -moz-transform: rotate(359deg); 21 | -o-transform: rotate(359deg); 22 | -webkit-transform: rotate(359deg); 23 | transform: rotate(359deg); 24 | } 25 | } 26 | @-webkit-keyframes spin { 27 | 0% { 28 | -moz-transform: rotate(0deg); 29 | -o-transform: rotate(0deg); 30 | -webkit-transform: rotate(0deg); 31 | transform: rotate(0deg); 32 | } 33 | 34 | 100% { 35 | -moz-transform: rotate(359deg); 36 | -o-transform: rotate(359deg); 37 | -webkit-transform: rotate(359deg); 38 | transform: rotate(359deg); 39 | } 40 | } 41 | @-o-keyframes spin { 42 | 0% { 43 | -moz-transform: rotate(0deg); 44 | -o-transform: rotate(0deg); 45 | -webkit-transform: rotate(0deg); 46 | transform: rotate(0deg); 47 | } 48 | 49 | 100% { 50 | -moz-transform: rotate(359deg); 51 | -o-transform: rotate(359deg); 52 | -webkit-transform: rotate(359deg); 53 | transform: rotate(359deg); 54 | } 55 | } 56 | @-ms-keyframes spin { 57 | 0% { 58 | -moz-transform: rotate(0deg); 59 | -o-transform: rotate(0deg); 60 | -webkit-transform: rotate(0deg); 61 | transform: rotate(0deg); 62 | } 63 | 64 | 100% { 65 | -moz-transform: rotate(359deg); 66 | -o-transform: rotate(359deg); 67 | -webkit-transform: rotate(359deg); 68 | transform: rotate(359deg); 69 | } 70 | } 71 | @keyframes spin { 72 | 0% { 73 | -moz-transform: rotate(0deg); 74 | -o-transform: rotate(0deg); 75 | -webkit-transform: rotate(0deg); 76 | transform: rotate(0deg); 77 | } 78 | 79 | 100% { 80 | -moz-transform: rotate(359deg); 81 | -o-transform: rotate(359deg); 82 | -webkit-transform: rotate(359deg); 83 | transform: rotate(359deg); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_sass/font/_fontello.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'fontello'; 3 | src: url('../assets/font/fontello.eot?22358951'); 4 | src: url('../assets/font/fontello.eot?22358951#iefix') format('embedded-opentype'), 5 | url('../assets/font/fontello.woff?22358951') format('woff'), 6 | url('../assets/font/fontello.ttf?22358951') format('truetype'), 7 | url('../assets/font/fontello.svg?22358951#fontello') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ 12 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ 13 | /* 14 | @media screen and (-webkit-min-device-pixel-ratio:0) { 15 | @font-face { 16 | font-family: 'fontello'; 17 | src: url('../font/fontello.svg?22358951#fontello') format('svg'); 18 | } 19 | } 20 | */ 21 | 22 | [class^="icon-"]:before, [class*=" icon-"]:before { 23 | font-family: "fontello"; 24 | font-style: normal; 25 | font-weight: normal; 26 | speak: none; 27 | 28 | display: inline-block; 29 | text-decoration: inherit; 30 | width: 1em; 31 | margin-right: .2em; 32 | text-align: center; 33 | /* opacity: .8; */ 34 | 35 | /* For safety - reset parent styles, that can break glyph codes*/ 36 | font-variant: normal; 37 | text-transform: none; 38 | 39 | /* fix buttons height, for twitter bootstrap */ 40 | line-height: 1em; 41 | 42 | /* Animation center compensation - margins should be symmetric */ 43 | /* remove if not needed */ 44 | margin-left: .2em; 45 | 46 | /* you can be more comfortable with increased icons size */ 47 | /* font-size: 120%; */ 48 | 49 | /* Uncomment for 3D effect */ 50 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 51 | } 52 | 53 | .icon-twitter:before { content: '\e800'; } /* '' */ 54 | .icon-fork:before { content: '\e801'; } /* '' */ 55 | .icon-spin2:before { content: '\e802'; } /* '' */ 56 | .icon-github-circled:before { content: '\e803'; } /* '' */ -------------------------------------------------------------------------------- /_sass/globals/_colors.scss: -------------------------------------------------------------------------------- 1 | // Color palette 2 | $color-blue-darkest: #2C3E50; 3 | $color-blue-dark: #2980B9; 4 | $color-blue-normal: #3498DB; 5 | $color-blue-light: #0EC2DB; 6 | $color-organge-normal: #E74C3C; 7 | 8 | $color-omniscient-blue: #0098C6; 9 | 10 | $color-white-bg: #fafafa; 11 | $color-darkGray-background: $color-white-bg; 12 | $color-white-fontColor: #2d2d2d; 13 | 14 | $color-header-border: $color-blue-light; 15 | $color-header-background: $color-omniscient-blue; 16 | $color-header-background--bottom: lighten($color-blue-darkest, 10%); 17 | $color-header-background--small: $color-omniscient-blue; 18 | 19 | $color-header-linkColor: $color-white-bg; 20 | 21 | 22 | // Graph colors: 23 | 24 | $color-topNode: $color-blue-darkest; 25 | 26 | $color-infoBoxes: $color-white-bg; 27 | 28 | $color-leftNav: $color-blue-darkest; 29 | $color-leftNav-header: $color-blue-darkest; 30 | 31 | $color-table-white: #fff; 32 | $color-table-zebra: lighten($color-organge-normal, 40%); 33 | 34 | // Links 35 | 36 | $color-links: $color-blue-normal; 37 | $color-links--hover: darken($color-links, 15%); 38 | $color-links--active: darken($color-links, 25%); 39 | -------------------------------------------------------------------------------- /_sass/globals/_mixins.scss: -------------------------------------------------------------------------------- 1 | 2 | @mixin width-constraint () { 3 | width: 93%; 4 | max-width: 1100px; 5 | margin: 0 auto; 6 | } 7 | 8 | @mixin width-constraint-large() { 9 | width: auto; 10 | max-width: none; 11 | margin: 3rem $header-height; 12 | } 13 | 14 | @mixin chevron ($color, $height: 30px, $width: 200px) { 15 | position: relative; 16 | display: inline-block; 17 | text-align: center; 18 | margin-bottom: 6px; 19 | height: $height; 20 | width: $width; 21 | 22 | &:before { 23 | content: ''; 24 | position: absolute; 25 | top: 0; 26 | left: 0; 27 | height: 100%; 28 | width: 51%; 29 | background: $color; 30 | -webkit-transform: skew(0deg, 6deg); 31 | -moz-transform: skew(0deg, 6deg); 32 | -ms-transform: skew(0deg, 6deg); 33 | -o-transform: skew(0deg, 6deg); 34 | transform: skew(0deg, 6deg); 35 | } 36 | 37 | &:after { 38 | content: ''; 39 | position: absolute; 40 | top: 0; 41 | right: 0; 42 | height: 100%; 43 | width: 50%; 44 | background: $color; 45 | -webkit-transform: skew(0deg, -6deg); 46 | -moz-transform: skew(0deg, -6deg); 47 | -ms-transform: skew(0deg, -6deg); 48 | -o-transform: skew(0deg, -6deg); 49 | transform: skew(0deg, -6deg); 50 | } 51 | } 52 | 53 | @mixin triangle ($color, $width: 100px, $height: 30px) { 54 | width: 0; 55 | height: 0; 56 | border-left: $width / 2 solid transparent; 57 | border-right: $width / 2 solid transparent; 58 | border-top: $height solid $color; 59 | } 60 | 61 | @mixin clearfix { 62 | &:after { 63 | content: ""; 64 | display: table; 65 | clear: both; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /_sass/globals/_reset.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Global Reset of all HTML Elements 3 | * 4 | * Resetting all of our HTML Elements ensures a smoother 5 | * visual transition between browsers. If you don't believe me, 6 | * try temporarily commenting out this block of code, then go 7 | * and look at Mozilla versus Safari, both good browsers with 8 | * a good implementation of CSS. The thing is, all browser CSS 9 | * defaults are different and at the end of the day if visual 10 | * consistency is what we're shooting for, then we need to 11 | * make sure we're resetting all spacing elements. 12 | * 13 | */ 14 | html, body { 15 | border: 0; 16 | font-family: "Helvetica-Neue", "Helvetica", Arial, sans-serif; 17 | line-height: 1.5; 18 | margin: 0; 19 | padding: 0; 20 | } 21 | 22 | div, span, object, iframe, img, table, caption, thead, tbody, 23 | tfoot, tr, tr, td, article, aside, canvas, details, figure, hgroup, menu, 24 | nav, footer, header, section, summary, mark, audio, video { 25 | border: 0; 26 | margin: 0; 27 | padding: 0; 28 | } 29 | 30 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, address, cit, code, 31 | del, dfn, em, ins, q, samp, small, strong, sub, sup, b, i, hr, dl, dt, dd, 32 | ol, ul, li, fieldset, legend, label { 33 | border: 0; 34 | font-size: 100%; 35 | vertical-align: baseline; 36 | margin: 0; 37 | padding: 0; 38 | } 39 | 40 | article, aside, canvas, figure, figure img, figcaption, hgroup, 41 | footer, header, nav, section, audio, video { 42 | display: block; 43 | } 44 | 45 | table { 46 | border-collapse: separate; 47 | border-spacing: 0; 48 | caption, th, td { 49 | text-align: left; 50 | vertical-align: middle; 51 | } 52 | } 53 | 54 | a img { 55 | border: 0; 56 | } 57 | 58 | :focus { 59 | outline: 0; 60 | } 61 | -------------------------------------------------------------------------------- /_sass/globals/_size.scss: -------------------------------------------------------------------------------- 1 | $column-sidebar-width: 31%; 2 | $column-sidebar-margin: 1rem; 3 | 4 | $first-breakpoint-width: 650px; 5 | $remove-graphics-width: 870px; 6 | $minify-header-width: 630px; 7 | $min-width: 350px; 8 | 9 | $header-height: 0px; 10 | -------------------------------------------------------------------------------- /_sass/main.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | @import "globals/reset"; 4 | @import "globals/colors"; 5 | @import "globals/size"; 6 | 7 | @import url(http://fonts.googleapis.com/css?family=Khula:400,700,600,300); 8 | 9 | body { 10 | font-family: 'Khula', sans-serif; 11 | background: $color-darkGray-background; 12 | color: $color-white-fontColor; 13 | padding: 0 5%; 14 | } 15 | 16 | * { 17 | box-sizing: border-box; 18 | } 19 | 20 | @media (max-width: $first-breakpoint-width) { 21 | .link--github { 22 | display: none; 23 | } 24 | } 25 | 26 | .anchor-link { 27 | display: block; 28 | position: relative; 29 | top: -$header-height; 30 | visibility: hidden; 31 | } 32 | 33 | a:link, a:visited { 34 | color: $color-links; 35 | text-decoration: none; 36 | } 37 | 38 | a:hover { 39 | color: $color-links--hover; 40 | } 41 | 42 | a:active { 43 | color: $color-links--active; 44 | } 45 | 46 | 47 | ul, ol { 48 | list-style-position: inside; 49 | padding-left: 20px; 50 | } 51 | 52 | .info { 53 | max-width: 65%; 54 | } 55 | 56 | @import "header"; 57 | @import "graph"; 58 | @import "window"; 59 | @import "content"; 60 | @import "columns"; 61 | @import "next-nav"; 62 | @import "forms"; 63 | 64 | // Fonts 65 | @import "font/animation"; 66 | @import "font/fontello"; 67 | -------------------------------------------------------------------------------- /_workshop/00-introduction.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Introduction to the workshop 5 | permalink: /workshop/ 6 | section: 0 7 | start: true 8 | name: 00-introduction 9 | next: 01-1-context 10 | slides: 11 | info: | 12 | Welcome to a workshop for learning functional programming in JavaScript. 13 | 14 | This workshop runs in your browser. Assignments are written as tests that 15 | you need to make pass. When you have all passing test you can move on to the 16 | next task. There will be additional information in the comments. 17 | 18 | If you at any time need to freshen up your JS-fu, start any Google 19 | search with "mdn" and you will always end up at the amazing Mozilla 20 | Developer Network, which has the best JS explanations around. 21 | --- 22 | 23 | // You can create functions like this: 24 | function hello(arg) { 25 | return 'result of function called with ' + arg; 26 | } 27 | 28 | // You can call the function and save the result: 29 | var result = hello('some argument'); 30 | 31 | // A handy way of printing has been added to the environment 32 | log(result); 33 | // And will display in the sidebar to the right of the editor 34 | 35 | // Assignments will be written as tests that you need to make pass 36 | // You will either need to modify the tests themselves or the code that the 37 | // tests execute. 38 | describe('mocha inside the workshop', function () { 39 | 40 | it('shows tests', function () { 41 | 42 | expect(2).to.equal(2); 43 | 44 | }); 45 | 46 | it('shows failing tests', function () { 47 | 48 | expect(hello('some argument')).to.equal( 49 | 'Hello, some argument', 50 | 'hello should greet argument' 51 | ); 52 | 53 | }); 54 | 55 | }); 56 | -------------------------------------------------------------------------------- /_workshop/01-1-context.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: A functions context 5 | section: 1 6 | prev: '' 7 | name: 01-1-context 8 | next: 01-2-arguments 9 | slides: 10 | info: | 11 | It is time to get started. This workshop will start with some of the basics of 12 | JavaScript, with scope and context, to ensure that you fully understand how 13 | functions work in JavaScript. 14 | 15 | We start with how context works when using functions in JavaScript. 16 | --- 17 | //A couple of functions that we will work with during this exercise 18 | 19 | function hello() { 20 | return this + ' says hello'; 21 | } 22 | 23 | describe('a functions context', function() { 24 | // In JavaScript we can dynamically choose the value of `this` 25 | // using several techniques. Today we will focus on some of these, 26 | // starting with `call` and `apply`. 27 | 28 | it('is undefined by default', function() { 29 | //call function to observe default behavior 30 | var result = null; 31 | expect(result).to.equal('undefined says hello'); 32 | }); 33 | 34 | // `call` calls a function with a given `this` value as the first 35 | // parameter, then arguments provided individually: 36 | // 37 | // func.call(this, arg1, arg2, ...) 38 | it('can change when using call', function() { 39 | //change context of `hello` by using `call` 40 | var result = hello(); 41 | expect(result).to.equal('kim says hello'); 42 | }); 43 | 44 | // `apply` calls a function with a given `this` value as the first 45 | // parameter, then arguments provided as an array 46 | // 47 | // func.apply(this, [arg1, arg2, ...]) 48 | it('can change when using apply', function() { 49 | //change context of `hello` by using `apply` 50 | var result = hello(); 51 | expect(result).to.equal('kim says hello'); 52 | }); 53 | 54 | }); 55 | // If you want to learn more about function invocation in 56 | // JavaScript, I recommend reading: 57 | // http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/ 58 | -------------------------------------------------------------------------------- /_workshop/01-2-arguments.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: A functions arguments 5 | section: 1 6 | prev: 01-1-context 7 | name: 01-2-arguments 8 | next: 01-3-prototype 9 | slides: 10 | info: | 11 | Arguments are what makes functions interesting. Being able to pass data and 12 | information to a function in order to change its result is important. 13 | --- 14 | function helloTo(thing) { 15 | return this + ' says hello ' + thing; 16 | } 17 | 18 | function argCount() { 19 | return arguments.length; 20 | } 21 | describe('a functions arguments', function() { 22 | // Inside a function you will always have access to `arguments`, 23 | // which is an array-like object that contains all the arguments 24 | // passed to the function. 25 | 26 | it('can be counted', function() { 27 | var result = argCount(1, 2, 3); 28 | expect(result).to.equal(3); 29 | }); 30 | 31 | // JavaScript is not strict about the number of 32 | // arguments, so you can for example include more parameters than 33 | // the function expects: 34 | 35 | it('are not strict in number', function() { 36 | var result = helloTo.call('kim', 'world', 'or', 'maybe', 'bekk'); 37 | expect(result).to.equal('kim says hello world'); 38 | }); 39 | 40 | // But JavaScript is strict with the count of arguments regardless of 41 | // wether the argument was used or not. 42 | 43 | it('has a strict count', function() { 44 | var result = argCount(null, 2, 3); 45 | expect(result).to.equal(2); 46 | }); 47 | 48 | }); 49 | 50 | function multiplyFirst() { 51 | // PROBLEM: 52 | // Multiply `this` and the first argument, 53 | // without specifying any parameters 54 | } 55 | 56 | describe('multiplyFirst', function() { 57 | 58 | it('1*1=1', function() { 59 | var result = multiplyFirst.call(1,1); 60 | expect(result).to.equal(1); 61 | }); 62 | 63 | it('2*5=10', function() { 64 | var result = multiplyFirst.call(2,5); 65 | expect(result).to.equal(10); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /_workshop/01-3-prototype.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Functions and prototypes 5 | section: 1 6 | prev: 01-2-arguments 7 | name: 01-3-prototype 8 | next: 02-1-applicative 9 | slides: 10 | info: | 11 | Prototypes are another core concept in JavaScript. Functions and prototypes 12 | interact in many interesting ways. 13 | 14 | There will not be much about prototypes in this workshop, but 15 | there is one thing it is important to understand, especially when 16 | working with `arguments`: In JavaScript you can borrow existing 17 | functions that live on a prototype. 18 | --- 19 | var User = function(age) { 20 | this.age = age; 21 | }; 22 | 23 | User.prototype.getAge = function() { 24 | return this.age; 25 | }; 26 | 27 | describe('prototype-functions', function() { 28 | 29 | it('are usually bound to the context of an object', function() { 30 | var user = new User(25); 31 | var age = user.getAge(); 32 | 33 | expect(age).to.equal(25); 34 | }); 35 | 36 | // However, in JavaScript we can actually invoke `getAge` without 37 | // creating an instance of `User`. 38 | 39 | // We can say that we are "borrowing" the getAge function 40 | // from the User prototype. 41 | it('can be borrowed and have their context bound at will', function() { 42 | var age = User.prototype.getAge.call({ age: 35 }); 43 | expect(age).to.equal(35); 44 | }); 45 | 46 | }); 47 | 48 | // PROBLEM: 49 | // Create a function that "borrow" `Array.prototype.slice` 50 | // and returns all the arguments given, except the first. 51 | 52 | // NOTE: This has changed in ES2015 (aka ES6), but it is 53 | // still a useful exercise. 54 | 55 | function rest() { 56 | } 57 | 58 | describe('rest', function() { 59 | 60 | it('should return all arguments except the first one', function() { 61 | var result = rest(1); 62 | expect(result).to.deep.equal([]); 63 | }); 64 | 65 | it('should return all arguments except the first one', function() { 66 | var result = rest(1, 2, 3); 67 | expect(result).to.deep.equal([2, 3]); 68 | }); 69 | 70 | }); 71 | -------------------------------------------------------------------------------- /_workshop/02-1-applicative.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Applicative programming 5 | section: 2 6 | prev: 01-3-prototype 7 | name: 02-1-applicative 8 | next: 02-2-map 9 | slides: 10 | info: | 11 | Instead of discussing the theory on lexical scoping and closures, 12 | we will just go straight to more code. If you want to read the theory, 13 | we recommend checking out this link after the workshop: 14 | [Eloquent JavaScript chapter 3](http://eloquentjavascript.net/03_functions.html) 15 | 16 | First up is applicative programming. In general, applicative 17 | programming is the pattern of defining a function that takes a 18 | function and then invokes that function for each element in a 19 | collection. We will look at three central functions: map, filter and 20 | reduce. These are central building blocks of what we are learning 21 | today. 22 | 23 | Applicative programming works best with pure functions, i.e. 24 | functions that have no side effects: it references no other mutable 25 | state, does not set any values other than the return value, 26 | and relies only on the parameters given as input. 27 | --- 28 | function square(n) { 29 | return n*n; 30 | } 31 | 32 | describe('applicative programming', function() { 33 | 34 | it('is about applying functions to elements in collections', function() { 35 | var result = [1,2,3].map(function(n) { 36 | return n+1; 37 | }); 38 | 39 | expect(result).to.deep.equal([2,3,4]); 40 | }); 41 | 42 | it('is about reusing already defined functions by passing them as parameters', function() { 43 | var result = [1,2,3].map(square); 44 | 45 | expect(result).to.deep.equal([1,4,9]); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /_workshop/02-2-map.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Make new collections with map 5 | section: 2 6 | prev: 02-1-applicative 7 | name: 02-2-map 8 | next: 02-3-filter 9 | slides: 10 | info: | 11 | A map function accepts a higher-order function and a collection, 12 | then applies the passed function to each element and returns a 13 | new collection. 14 | --- 15 | 16 | describe('map', function() { 17 | // To understand what we're talking about, this is an example of 18 | // using a for loop to go through a collection, performing a 19 | // calculation on each item: 20 | 21 | function squareFor(arr) { 22 | var newArr = []; 23 | for (var i = 0; i < arr.length; i++) { 24 | newArr.push(arr[i] * arr[i]); 25 | } 26 | return newArr; 27 | } 28 | 29 | it('can be implemented as a for-loop', function() { 30 | var result = squareFor([1,2,3]); 31 | expect(result).to.deep.equal([1,4,9]); 32 | }); 33 | 34 | // For-loops involve alot of manual steps, which makes it error prone. 35 | // Thankfully we now have a `map` functions on `Array.prototype`. 36 | 37 | // For each iteration of map it invokes the function with three 38 | // arguments: the current value, the current index, the entire 39 | // collection. So we could have written this instead: 40 | 41 | function square(arr) { 42 | return arr.map(function(value, index, collection) { 43 | return value * value; 44 | }); 45 | } 46 | 47 | it('exists as a method on arrays in JavaScript', function() { 48 | var result = square([1,2,3]); 49 | expect(result).to.deep.equal([1,4,9]); 50 | }); 51 | 52 | // An important characteristic of these kinds of higher order functions is 53 | // that they do not modify the original collection. 54 | it('does not modify the original collection', function() { 55 | var numbers = [1,2,3]; 56 | var result = square(numbers); 57 | 58 | expect(numbers).to.not.equal(result); 59 | }); 60 | 61 | }); 62 | 63 | // PROBLEM: Implement the following function using map, i.e. a 64 | // function that adds the current index to the current value: 65 | // 66 | // for (var i = 0; i < arr.length; i++) { 67 | // arr[i] = arr[i] + i 68 | // } 69 | 70 | function addIndex(arr) { 71 | } 72 | 73 | describe('addIndex', function() { 74 | it('should add the index to the current element', function() { 75 | var result = addIndex([1,2,3]); 76 | expect(result).to.deep.equal([1,3,5]); 77 | }); 78 | 79 | it('should not modify the original collection', function() { 80 | var numbers = [1,2,3]; 81 | var result = addIndex(numbers); 82 | 83 | expect(result).to.deep.equal([1,3,5]); 84 | expect(numbers).to.not.equal(result); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /_workshop/02-3-filter.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Make new collections with filter 5 | section: 2 6 | prev: 02-2-map 7 | name: 02-3-filter 8 | next: 02-4-reduce 9 | slides: 10 | info: | 11 | A filter function accepts a higher-order function and a collection, 12 | then applies the passed function to each element and returns a 13 | new collection which includes a subset of the original collection. 14 | 15 | An element is included in the new collection if the filter-function returns 16 | true and is excluded if the filter-function returns false. 17 | --- 18 | describe('filter', function() { 19 | // A filter-function includes the value for all function invocations that 20 | // return `true`. Here's an example, again using `for`: 21 | 22 | function removeOddIndicesFor(arr) { 23 | var newArr = []; 24 | for (var i = 0; i < arr.length; i++) { 25 | if (i % 2 == 0) { 26 | newArr.push(arr[i]); 27 | } 28 | } 29 | return newArr; 30 | } 31 | 32 | it('can be implemented as a for-loop', function() { 33 | var result = removeOddIndicesFor([1,2,3,4,5]); 34 | expect(result).to.deep.equal([1,3,5]); 35 | }); 36 | 37 | // PROBLEM: Implement this using a `Array.prototype.filter` 38 | // instead: 39 | 40 | function removeOddIndices(arr) { 41 | } 42 | 43 | it('exists as a method on arrays in JavaScript', function() { 44 | var result = removeOddIndices([1,2,3,4,5]); 45 | expect(result).to.deep.equal([1,3,5]); 46 | }); 47 | 48 | }); 49 | 50 | // To be entirely sure that we properly understand how these 51 | // functions work, let's implement our own `map` and `filter` 52 | // functions. The implementation of these still have to concern 53 | // themselves with loops, counters and state. 54 | 55 | // (If you struggle, be sure to take a look at the examples we 56 | // saw earlier.) 57 | 58 | // PROBLEM: Implement `map` 59 | 60 | var map = function(items, fn) { 61 | } 62 | 63 | describe('implemented map', function() { 64 | 65 | it('mapfilter1', function() { 66 | var result = map([1,2,3,4], function(value, index) { 67 | return value * index; 68 | }); 69 | 70 | expect(result).to.deep.equal([0, 2, 6, 12]); 71 | }); 72 | 73 | }); 74 | 75 | // PROBLEM: Implement `filter` 76 | 77 | var filter = function(items, fn) { 78 | } 79 | 80 | describe('implemented filter', function() { 81 | 82 | it('mapfilter2', function() { 83 | var result = ilter([1,2,3,4], function(value, index) { 84 | return value * index > 4; 85 | }); 86 | 87 | expect(result).to.deep.equal([3,4]); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /_workshop/02-4-reduce.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Make new collections with reduce 5 | section: 2 6 | prev: 02-3-filter 7 | name: 02-4-reduce 8 | next: 02-5-lodash 9 | slides: 10 | info: | 11 | The last applicative functions we will look at for now is reduce. 12 | Reduce applies a function against an accumulator and each value 13 | of the array to reduce it to a single value. 14 | 15 | Reduce is different from map and filter in that it returns a value rather than a 16 | collection. However, the value could also be a collection. 17 | --- 18 | 19 | describe('reduce', function() { 20 | // As always, let's start with an example of calculating the sum of 21 | // all items in an array using a `for` loop: 22 | 23 | function sumFor(arr) { 24 | var sum = 0; 25 | for (var i = 0; i < arr.length; i++) { 26 | sum += arr[i]; 27 | } 28 | return sum; 29 | } 30 | 31 | it('can be implemented with a for-loop', function() { 32 | var result = sumFor([1,2,3]); 33 | expect(result).to.equal(6); 34 | }); 35 | 36 | // Using reduce it can look like this: 37 | 38 | function sum(arr) { 39 | return arr.reduce(function(acc, value){ 40 | 41 | // What is returned in this function is used as `acc` for 42 | // the next iteration 43 | return acc + value; 44 | 45 | }, 0); 46 | // 0 is the starting value for `acc` 47 | 48 | // What we return on the last iteration is the result of 49 | // the reduce. 50 | } 51 | 52 | // This illustrates how reduce works: 53 | 54 | // Operation Accumulator List 55 | // + 0 1, 2, 3, 4 56 | // 1 2, 3, 4 57 | // 3 3, 4 58 | // 6 4 59 | // 10 60 | 61 | it('exists as a method on arrays in JavaScript', function() { 62 | var result = sum([1,2,3,4]); 63 | expect(result).to.equal(10); 64 | }); 65 | 66 | it('hands the values in the collection to the reducing-function', function() { 67 | var result = sum([0,0,-1]); 68 | expect(result).to.equal(-1); 69 | }); 70 | 71 | }); 72 | 73 | // PROBLEM: Implement multiplication using reduce 74 | 75 | function multiply(arr) { 76 | } 77 | 78 | describe('multiply', function() { 79 | 80 | it('does multiply all the numbers in the collection', function() { 81 | var result = multiply([1,2,3,4]); 82 | expect(result).to.equal(24); 83 | }); 84 | 85 | it('does work as expected when 0 appears in the collection', function() { 86 | var result = multiply([0,1,2,3]); 87 | expect(result).to.equal(0); 88 | }); 89 | }); 90 | 91 | // We don't always need to specify the initial value, i.e. `0` in `sum` 92 | // above. If we don't specify an initial value, the first item is used as 93 | // the initial value, and the first round with `reduce` is therefore with 94 | // the first and second item. 95 | 96 | // PROBLEM: Implement join using reduce without specifying an initial value 97 | 98 | function join(arr, chr) { 99 | } 100 | 101 | describe('join', function() { 102 | 103 | it('works correctly with only one element', function() { 104 | var result = join(["a"], ":"); 105 | expect(result).to.equal("a"); 106 | }); 107 | 108 | it('works correctly with multiple elements', function() { 109 | var result = join(["a","b","c"], ":"); 110 | expect(result).to.equal("a:b:c"); 111 | }); 112 | 113 | }); 114 | 115 | // PROBLEM: Implement find using reduce 116 | // (think about what we want to get back from such a function) 117 | 118 | function find(arr, el) { 119 | } 120 | 121 | describe('find', function() { 122 | 123 | it('should return true if element exists in the array', function() { 124 | var result = find([1,2,3], 1); 125 | expect(result).to.be.ok; 126 | }); 127 | 128 | it('should return false if element does not exist in the array', function() { 129 | var result = find([1,2,3], 4); 130 | expect(result).to.not.be.ok; 131 | }); 132 | 133 | it('should return false if given an empty collection', function() { 134 | var result = find([], 1); 135 | expect(result).to.not.be.ok; 136 | }); 137 | }); 138 | -------------------------------------------------------------------------------- /_workshop/02-5-lodash.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Using helper liberaries 5 | section: 2 6 | prev: 02-4-reduce 7 | name: 02-5-lodash 8 | next: 02-6-point-free 9 | slides: 10 | info: | 11 | In the examples we have seen so far, we have used methods that live 12 | on an array. We are now going to switch tactics and focus more on 13 | functions instead of methods. For example, in addition to 14 | `Array.prototype.reduce`, there exists a `reduce` functions in 15 | libraries such as Lo-Dash and Underscore. One of the primary values 16 | of using these functions instead is composability. We are going to 17 | look more on what exactly that means later. Another great thing is 18 | that some of these functions are more powerful that the methods on 19 | arrays. 20 | 21 | In this course we will use Lo-Dash, which will be accessible through the `_` 22 | global (however, we could also have chosen Underscore instead). 23 | --- 24 | 25 | describe('_.reduce', function() { 26 | // We'll start by going back to reduce. As for the built-in reduce, 27 | // _.reduce does not need a starting value. (Reduce without an initial 28 | // value is actually a fold, and in fact, in Lo-Dash _.reduce is aliased 29 | // to _.foldl, i.e. fold from the left.) 30 | 31 | function join(arr, chr) { 32 | return _.reduce(arr, function(memo, str) { 33 | return memo + chr + str; 34 | }); 35 | } 36 | 37 | it('works the same way as the array method', function() { 38 | var result = join(['a','b','c'], ':'); 39 | expect(result).to.equal('a:b:c'); 40 | }); 41 | 42 | }); 43 | 44 | // PROBLEM: Determine the longest word using _.reduce 45 | 46 | function longest(arr) { 47 | } 48 | 49 | describe('longest', function() { 50 | 51 | it('finds the longest word in a collection', function() { 52 | 53 | var result = longest(['test', 'kim', 'winning', 'lol']); 54 | expect(result).to.equal('winning'); 55 | 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /_workshop/02-6-point-free.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Point-free style 5 | section: 2 6 | prev: 02-5-lodash 7 | name: 02-6-point-free 8 | next: 02-7-context 9 | slides: 10 | info: | 11 | Every time we see the arguments "match up" and are passed 12 | through to the function in the callback, as with the `x` 13 | below, we do not need to create the callback function at all. 14 | That means that this: 15 | 16 | ``` 17 | _.filter(collection, function(x) { 18 | return exists(x); 19 | }); 20 | ``` 21 | 22 | is the same as: 23 | 24 | ``` 25 | _.filter(collection, exists); 26 | ``` 27 | 28 | This is called point-free style, we will see quite a bit of this today! 29 | (There are some things to think about. We will look at those later.) 30 | --- 31 | describe('point-free style', function() { 32 | 33 | function exists(x) { 34 | return x != null; // i.e. the x is neither `null` nor `undefined` 35 | } 36 | 37 | function truthy(x) { 38 | return exists(x) && x !== false; 39 | } 40 | 41 | var values = ['user', null, false, 0, 'test', 1]; 42 | 43 | it('lets us pass functions as references if they have matching arguments', function() { 44 | var result = values.filter(exists); 45 | expect(result).to.deep.equal(['user', false, 0, 'test', 1]); 46 | }); 47 | 48 | it('works with many different functions', function() { 49 | var result = values.filter(truthy); 50 | expect(result).to.deep.equal(['user', 0, 'test', 1]); 51 | }); 52 | 53 | }); 54 | 55 | // PROBLEM: Sum the array using `_.reduce`, following a point-free style. 56 | // (You might need to create a helper function) 57 | 58 | describe('point-free _.reduce', function() { 59 | it('works as normal _.reduce', function() { 60 | var nums = [1,2,3,4,5]; 61 | 62 | var sum = null; 63 | 64 | expect(sum).to.equal(15); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /_workshop/02-7-context.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Applicative functions with context 5 | section: 2 6 | prev: 02-6-point-free 7 | name: 02-7-context 8 | next: 03-1-factories 9 | slides: 10 | info: | 11 | Sometimes you want to use map, filter, reduce or other functions 12 | inside an object and you want want to access something on 13 | `this`. Thankfully this is very simple on _.filter and friends -- 14 | just add the context, i.e. what you want `this` to be, as the 15 | last parameter. 16 | --- 17 | describe('filter with context', function() { 18 | var ages = [20, 30, 75, 156, 200]; 19 | 20 | var people = { 21 | maxAge: 120, 22 | validAges: function(ages) { 23 | 24 | return _.filter(ages, function(age) { 25 | return age < this.maxAge; 26 | }, this); 27 | 28 | // here we specified that we want `this` inside the function in the 29 | // filter be the same as `this` is inside the current function 30 | 31 | } 32 | }; 33 | 34 | it('works by passing a context to the lodash-function which it can bind to', function() { 35 | var result = people.validAges(ages); 36 | 37 | expect(result).to.deep.equal([20, 30, 75]); 38 | }); 39 | }); 40 | 41 | describe('our filter with context', function() { 42 | 43 | // PROBLEM: Fix our filter implementation below so it handles the 44 | // specified context 45 | 46 | var filter = function(items, fn, context) { 47 | var arr = []; 48 | for (var i = 0; i < items.length; i++) { 49 | if (fn(items[i], i)) { 50 | arr.push(items[i]); 51 | } 52 | } 53 | return arr; 54 | } 55 | 56 | var ages = [20, 30, 75, 156, 200]; 57 | 58 | var people = { 59 | maxAge: 120, 60 | validAges: function(ages) { 61 | return filter(ages, function(age) { 62 | return age < this.maxAge; 63 | }, this); 64 | } 65 | }; 66 | 67 | it('works when we pass a context that we bind the function to', function() { 68 | var result = people.validAges(ages); 69 | expect(result).to.deep.equal([20, 30, 75]); 70 | }); 71 | 72 | }); 73 | -------------------------------------------------------------------------------- /_workshop/03-1-factories.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Function factories 5 | section: 3 6 | prev: 02-7-context 7 | name: 03-1-factories 8 | next: 03-2-higher-order 9 | slides: 10 | info: | 11 | Okey, it is time to take a break from map, filter and reduce, and 12 | start focusing more on higher-order functions and what we can do 13 | with JavaScript. 14 | --- 15 | 16 | // In JavaScript we love factories. Let's create a factory that 17 | // creates adder functions: 18 | 19 | function makeAdder(arg) { 20 | return function(arg2) { 21 | return arg + arg2; 22 | } 23 | } 24 | 25 | describe('makeAdder', function() { 26 | var addTwo = makeAdder(2) 27 | 28 | it('addTwo should add 2', function() { 29 | var result = addTwo(40); 30 | expect(result).to.equal(42); 31 | }); 32 | }); 33 | 34 | // Seems simple enough, but it's a powerful technique that we will 35 | // be having a lot of fun with. 36 | 37 | // Okey, it's your turn to create a factory. 38 | 39 | // PROBLEM: Create a counter that returns a function that increases a 40 | // number every time it's called. 41 | 42 | function counter() { 43 | } 44 | 45 | describe('counter', function() { 46 | var c1 = counter(); 47 | var c2 = counter(); 48 | 49 | it('should increase by one with each invocation', function() { 50 | var result = c1(); 51 | expect(result).to.equal(0); 52 | }); 53 | 54 | it('count = 1', function() { 55 | var result = c1(); 56 | expect(result).to.equal(1); 57 | }); 58 | 59 | it('count = 2', function() { 60 | var result = c1(); 61 | expect(result).to.equal(2); 62 | }); 63 | 64 | it('should not share state between counters', function() { 65 | var result = c2(); 66 | expect(result).to.equal(0); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /_workshop/03-2-higher-order.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Higher order functions 5 | section: 3 6 | prev: 03-1-factories 7 | name: 03-2-higher-order 8 | next: 03-3-functions-with-functions 9 | slides: 10 | info: | 11 | Sometimes we want to take a function as an argument. Functions that take 12 | other functions as arguments are called higher order functions. 13 | --- 14 | // PROBLEM: Create a once factory that receives a function that 15 | // will at most be called once. If already run, return the result 16 | // of the first invocation on every succeeding invocation. 17 | 18 | function once(fn) { 19 | } 20 | 21 | describe('once', function() { 22 | var win = once(function(name) { 23 | return name + ' is winning'; 24 | }); 25 | 26 | it('should declare a winner the first time', function() { 27 | var result = win('kim'); 28 | expect(result).to.equal('kim is winning'); 29 | }); 30 | 31 | it('should not change winner if invoked multiple times', function() { 32 | var result = win('stian'); 33 | expect(result).to.equal('kim is winning'); 34 | }); 35 | 36 | // And we have now decorated a function, i.e. wrapped an existing functions 37 | // with new functionality. 38 | }); 39 | -------------------------------------------------------------------------------- /_workshop/03-3-functions-with-functions.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Functions with functions 5 | section: 3 6 | prev: 03-2-higher-order 7 | name: 03-3-functions-with-functions 8 | next: 03-4-fluent 9 | slides: 10 | info: | 11 | In JavaScript you can actually add functions onto existing 12 | functions. This can create sweet APIs. Let us look at an example. 13 | 14 | I have seen this pattern in many code bases: 15 | 16 | ``` 17 | if (debug) console.log('some text'); 18 | ``` 19 | 20 | When you want to show debug information you set debug to `true`. You of 21 | course need to always remember to write that `if` everywhere in your 22 | code. Let us create a create a better API. 23 | --- 24 | // PROBLEM: We want to guard a function, so that it only calls 25 | // through to the function we pass in once we have called `start` 26 | // on the guard. (See below for the tests to understand how this is 27 | // supposed to work.) 28 | 29 | function guard(fn) { 30 | var guard = function() { 31 | }; 32 | 33 | // in JavaScript you can actually add 34 | // functions to existing functions 35 | 36 | guard.start = function() { 37 | }; 38 | 39 | return guard; 40 | }; 41 | 42 | describe('guard', function() { 43 | // Let's now guard a debug helper. To make it a little bit simpler 44 | // to test, we return a message instead of calling console.log or similar. 45 | 46 | var callCount = 0; 47 | var debug = guard(function(msg) { 48 | callCount += 1; 49 | return msg; 50 | }); 51 | 52 | it('should not return anything if not started', function() { 53 | var result = debug('test 1'); 54 | expect(callCount).to.equal(0); 55 | expect(result).to.equal(undefined); 56 | }); 57 | 58 | it('should not return anything if not started even when invoked multiple times', function() { 59 | var result = debug('test 2'); 60 | expect(callCount).to.equal(0); 61 | expect(result).to.equal(undefined); 62 | }); 63 | 64 | it('should return if started', function() { 65 | // open up the guard 66 | debug.start(); 67 | 68 | var result = debug('test 3'); 69 | expect(callCount).to.equal(1); 70 | expect(result).to.equal('test 3'); 71 | }); 72 | 73 | }); 74 | -------------------------------------------------------------------------------- /_workshop/03-4-fluent.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Fluent interfaces 5 | section: 3 6 | prev: 03-3-functions-with-functions 7 | name: 03-4-fluent 8 | next: 03-5-arity 9 | slides: 10 | info: | 11 | Many of us are used to jQuery and its fluent apis, e.g. 12 | 13 | ``` 14 | $('#test') 15 | .css('color','#333') 16 | .height(200) 17 | .on('click', function() { 18 | console.log('clicked!') 19 | }); 20 | ``` 21 | 22 | Fluent apis is often referred to as method chaining. and we use it to achieve 23 | code that is as fluently readable as possible and thus quicker to understand. 24 | In the jQuery example above, all functions return `this` so we can keep 25 | calling methods that exists on `$('#test')`. 26 | 27 | Let us create a small helper that simplifies the development of 28 | such fluent apis. 29 | --- 30 | // First, to get an understanding of how we can create a simple 31 | // helper for these fluent interfaces, we start with an entirely 32 | // different example, `maybe`: 33 | 34 | function maybe(fn) { 35 | return function(arg) { 36 | if (arg != null) { 37 | return fn(arg); 38 | } 39 | } 40 | } 41 | 42 | describe('maybe', function() { 43 | var exclamate = maybe(function(val) { 44 | return val + '!'; 45 | }); 46 | 47 | it('should return when called with an argument', function() { 48 | var result = exclamate('test'); 49 | expect(result).to.equal('test!'); 50 | }); 51 | 52 | it('should not return when called with null argument', function() { 53 | var result = exclamate(null); 54 | expect(result).to.equal(undefined); 55 | }); 56 | 57 | it('should not return when called without argument', function() { 58 | var result = exclamate(); 59 | expect(result).to.equal(undefined); 60 | }); 61 | 62 | // We have now created a helper than only calls the received function is 63 | // the input is neither null nor undefined. Yet another decorator, that is. 64 | 65 | // Btw, why doesn't this work? 66 | 67 | var user = { 68 | setName: maybe(function(name) { 69 | this.name = name; 70 | }) 71 | }; 72 | 73 | it('to throw', function() { 74 | expect(function() { 75 | user.setName('kim'); 76 | }).to.throw(TypeError); 77 | }); 78 | 79 | // It throws this error at us: 80 | // 81 | // TypeError: Cannot set property 'name' of undefined 82 | }); 83 | 84 | // As is often the case in JavaScript, the problem is `this`. We 85 | // forgot to handle the context when we called `fn` in our `maybe` 86 | // decorator. In decorators we must always use `call` or `apply` -- 87 | // make them context agnostic! 88 | 89 | // PROBLEM: Now it's time to create a `fluent` decorator 90 | 91 | function fluent(fn) { 92 | } 93 | 94 | describe('fluent', function() { 95 | // Here we have our example `$`, containing a field `value` that we 96 | // want to read out last. (You shouldn't change anything below here.) 97 | 98 | var $ = function(el) { 99 | return { 100 | value: 'somevalue', 101 | 102 | // using our fluent helper 103 | css: fluent(function(key, val) {}), 104 | height: fluent(function(height) {}), 105 | on: fluent(function(event, cb) {}) 106 | } 107 | }; 108 | 109 | 110 | it('should enable use of fluent interfaces', function() { 111 | var result = $('#test') 112 | .css('color','#333') 113 | .height(200) 114 | .on('click', function() { 115 | console.log('clicked!') 116 | }) 117 | .value; 118 | 119 | expect(result).to.equal('somevalue'); 120 | }); 121 | }); 122 | -------------------------------------------------------------------------------- /_workshop/03-5-arity.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Function arity 5 | section: 3 6 | prev: 03-4-fluent 7 | name: 03-5-arity 8 | next: 04-1-partial-application 9 | slides: 10 | info: | 11 | The arity of a function is the number of arguments it takes. 12 | 13 | E.g. the arity for the following function is 2: 14 | 15 | ``` 16 | function plus(a, b) { 17 | return a + b; 18 | } 19 | ``` 20 | 21 | --- 22 | describe('arity of parseInt', function() { 23 | // Going from string to int we can use parseInt, e.g. 24 | 25 | it('normal usage', function() { 26 | var result = parseInt('123'); 27 | expect(result).to.equal(123); 28 | }); 29 | 30 | // However, trying to use this function together with map, 31 | // we see a problem: 32 | 33 | it('is funky when mapping over the function', function() { 34 | var parsed = ['1','2','3'].map(parseInt) 35 | 36 | // The first is 1, as expected 37 | expect(parsed[0]).to.equal(1); 38 | 39 | // ... but the two others are not even numbers: 40 | expect(isNaN(parsed[1])).to.be.true; 41 | expect(isNaN(parsed[2])).to.be.true; 42 | }); 43 | 44 | // (we can't use `to.deep.equal` since NaN !== NaN in JavaScript) 45 | }); 46 | 47 | describe('fixed parseInt', function() { 48 | // The problem is that map calls each function with three parameters -- the 49 | // value, the index, and the array. Instead of the above, we could write: 50 | 51 | var parsed = ['1','2','3'].map(function(value, index, arr) { 52 | return parseInt(value); 53 | }) 54 | 55 | it('should work with map', function() { 56 | var result = parsed; 57 | expect(result).to.deep.equal([1,2,3]); 58 | }); 59 | 60 | // However, there are a couple of other solutions. We can for example 61 | // create a helper to do the job for us, and that lets us write: 62 | function unary(fn) { 63 | return function(arg) { 64 | return fn.call(this, arg) 65 | } 66 | } 67 | 68 | var parsed2 = ['1', '2', '3'].map(unary(parseInt)) 69 | 70 | // Here we have created unary, which ensures that a function is only ever 71 | // called with one argument, no matter how many you actually send to it. 72 | 73 | it('should work with unary decorator', function() { 74 | var result = parsed2; 75 | expect(result).to.deep.equal([1,2,3]); 76 | }); 77 | 78 | // However, unary might be to simple in this case, as we actually 79 | // might want to call: 80 | // 81 | // parseInt(val, 10); 82 | // 83 | // To get there, however, we should first learn some things about 84 | // partial application. 85 | }); 86 | -------------------------------------------------------------------------------- /_workshop/04-2-functions-from-functions.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Create functions from functions 5 | section: 4 6 | prev: 04-1-partial-application 7 | name: 04-2-functions-from-functions 8 | next: 05-1-currying 9 | slides: 10 | info: 11 | --- 12 | // Okey, let's keep playing with partial application. The thing about map, 13 | // filter and reduce is that we often have a "static" function as the last 14 | // parameter, and a "dynamic" input that is applied to the function. Take 15 | // for example this function: 16 | 17 | function square(arr) { 18 | return _.map(arr, function(val) { 19 | return val * val; 20 | }); 21 | } 22 | 23 | describe('square', function() { 24 | it('should square numbers', function() { 25 | var result = square([1,2,3]); 26 | expect(result).to.deep.equal([1,4,9]); 27 | }); 28 | }); 29 | 30 | // With partial application this can also be written like this: 31 | var partialSquare = _.partialRight(_.map, function(val) { 32 | return val * val; 33 | }); 34 | 35 | describe('partialSquare', function() { 36 | it('should square numbers like square', function() { 37 | var result = partialSquare([1,2,3]); 38 | expect(result).to.deep.equal([1,4,9]); 39 | }); 40 | }); 41 | 42 | // Note that we never specify the array argument in `square2`, but we need to 43 | // specify it in `square` (where it's named `arr`). Again, point-free style. 44 | 45 | // PROBLEM: Use _.partialRight to create a function that filters 46 | // all odd values from an array 47 | 48 | var onlyEven = null; 49 | 50 | describe('onlyEven', function() { 51 | it('should only return even numbers', function() { 52 | var result = onlyEven([1,2,3,4,5]); 53 | expect(result).to.deep.equal([2,4]); 54 | }); 55 | }); 56 | 57 | // Above we needed to use _.partialRight to create our function based on 58 | // `map` and `filter`. As we touched upon you often want to work in the 59 | // opposite direction of the direction specified by Lo-Dash and 60 | // Underscore.js -- that is, we want to partially apply the last parameter, 61 | // the function, first. So, let's create a function that works the other way 62 | // around: 63 | 64 | function mapWith(fn, arr) { 65 | return _.map(arr, fn); 66 | }; 67 | 68 | var mapWithSquare = _.partial(mapWith, function(val) { 69 | return val * val; 70 | }); 71 | 72 | describe('mapWithSquare', function() { 73 | it('should square numbers', function() { 74 | var result = mapWithSquare([1,2,3]); 75 | expect(result).to.deep.equal([1,4,9]); 76 | }); 77 | }); 78 | 79 | // PROBLEM: Use `mapWith` and `_.partial` to create a function that adds 80 | // the current index to the current value: 81 | 82 | var plusIndex = null; 83 | describe('plusIndex', function() { 84 | it('should add index to number', function() { 85 | var result = plusIndex([1,2,3]); 86 | expect(result).to.deep.equal([1,3,5]); 87 | }); 88 | }); 89 | 90 | // But damn, it would be nice to get away from these call to _.partial! In 91 | // order to get there, let's first do a small generalization then we'll take a 92 | // look at a another powerful technique. 93 | 94 | // So, first the generalization: Instead of flipping the arguments ourselves as 95 | // we did in `mapWith` above we can create a flip method which flips the two 96 | // arguments on the passed function: 97 | 98 | function flip(fn) { 99 | return function(first, second) { 100 | return fn.call(this, second, first); 101 | }; 102 | }; 103 | // We can use this function to create a new `mapWith`: 104 | 105 | var flippedMapWith = flip(_.map); 106 | 107 | // And then, as above: 108 | 109 | var flippedMapWithSquare = _.partial(flippedMapWith, function(val) { 110 | return val * val; 111 | }); 112 | 113 | 114 | describe('flippedMapWithSquare', function() { 115 | it('should square numbers', function() { 116 | var result = flippedMapWithSquare([1,2,3]); 117 | expect(result).to.deep.equal([1,4,9]); 118 | }); 119 | }); 120 | 121 | // PROBLEM: Use flip to create a parseInt that applies in the other 122 | // direction, i.e. the base first. Then partially apply it to create 123 | // parseDigit. (Because flip only works on two arguments, we don't need to 124 | // think about the unary stuff we did earlier.) 125 | 126 | var parseDigit = null; 127 | 128 | var parseDigits = _.partial(mapWith, parseDigit); 129 | 130 | describe('parseDigits', function() { 131 | it('should properly parse digits', function() { 132 | var result = parseDigits(['123', '08', '001']); 133 | expect(result).to.deep.equal([123, 8, 1]); 134 | }); 135 | }); 136 | -------------------------------------------------------------------------------- /_workshop/08-done.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: workshop 3 | collection: workshop 4 | title: Done 5 | section: 7 6 | prev: 07-collections 7 | name: 08-done 8 | slides: 9 | info: | 10 | We have now been on a ride through some of the interesting parts of 11 | functional programming. You have seen some code that doesn't look much like 12 | the JavaScript we normally write. We have also seen that the same code has 13 | interesting properties, such as less focus on state and mutability. 14 | Hopefully you have learned something along the way. 15 | 16 | To wrap up what we have seen today -- basically, functional programming 17 | achieve reuse at a coarser-grained level than object-oriented programming, 18 | extracting common machinery with parameterized behavior. Most applications 19 | do things with lists of elements, so a functional approach is to build reuse 20 | mechanisms around the idea of lists plus contextualized, portable code. 21 | 22 | Btw, want to learn more? 23 | 24 | [https://leanpub.com/javascript-allonge/read](https://leanpub.com/javascript-allonge/read) 25 | and 26 | [http://shop.oreilly.com/product/0636920028857.do](http://shop.oreilly.com/product/0636920028857.do) 27 | --- 28 | // THE END! 29 | -------------------------------------------------------------------------------- /assets/component-tree.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Layer 1 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /assets/font/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font license info 2 | 3 | 4 | ## Font Awesome 5 | 6 | Copyright (C) 2012 by Dave Gandy 7 | 8 | Author: Dave Gandy 9 | License: SIL () 10 | Homepage: http://fortawesome.github.com/Font-Awesome/ 11 | 12 | 13 | ## Fontelico 14 | 15 | Copyright (C) 2012 by Fontello project 16 | 17 | Author: Crowdsourced, for Fontello project 18 | License: SIL (http://scripts.sil.org/OFL) 19 | Homepage: http://fontello.com 20 | 21 | 22 | -------------------------------------------------------------------------------- /assets/font/fontello.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/assets/font/fontello.eot -------------------------------------------------------------------------------- /assets/font/fontello.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2015 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /assets/font/fontello.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/assets/font/fontello.ttf -------------------------------------------------------------------------------- /assets/font/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/assets/font/fontello.woff -------------------------------------------------------------------------------- /assets/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/assets/github.png -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Layer 1 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /css/vendor/base16-mocha-dark.css: -------------------------------------------------------------------------------- 1 | /* 2 | * https://github.com/idleberg/base16-highlight.js/blob/master/base16-mocha.dark.css 3 | 4 | Name: Base16 Mocha Dark 5 | Author: Chris Kempson (http://chriskempson.com) 6 | 7 | highlight.js v8.0 template by Jan T. Sott (https://github.com/idleberg/base16-highlight.js) 8 | Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) 9 | 10 | */ 11 | 12 | /* Mocha Comment */ 13 | .hljs-comment, 14 | .hljs-title { 15 | color: #b8afad; 16 | } 17 | 18 | /* Mocha Red */ 19 | .hljs-variable, 20 | .hljs-attribute, 21 | .hljs-tag, 22 | .hljs-regexp, 23 | .ruby .hljs-constant, 24 | .xml .hljs-tag .hljs-title, 25 | .xml .hljs-pi, 26 | .xml .hljs-doctype, 27 | .html .hljs-doctype, 28 | .css .hljs-id, 29 | .css .hljs-class, 30 | .css .hljs-pseudo { 31 | color: #cb6077; 32 | } 33 | 34 | /* Mocha Orange */ 35 | .hljs-number, 36 | .hljs-preprocessor, 37 | .hljs-built_in, 38 | .hljs-literal, 39 | .hljs-params, 40 | .hljs-constant { 41 | color: #d28b71; 42 | } 43 | 44 | /* Mocha Yellow */ 45 | .ruby .hljs-class .hljs-title, 46 | .css .hljs-rules .hljs-attribute { 47 | color: #f4bc87; 48 | } 49 | 50 | /* Mocha Green */ 51 | .hljs-string, 52 | .hljs-value, 53 | .hljs-inheritance, 54 | .hljs-header, 55 | .ruby .hljs-symbol, 56 | .xml .hljs-cdata { 57 | color: #beb55b; 58 | } 59 | 60 | /* Mocha Aqua */ 61 | .css .hljs-hexcolor { 62 | color:: #7bbda4; 63 | } 64 | 65 | /* Mocha Blue */ 66 | .hljs-function, 67 | .python .hljs-decorator, 68 | .python .hljs-title, 69 | .ruby .hljs-function .hljs-title, 70 | .ruby .hljs-title .hljs-keyword, 71 | .perl .hljs-sub, 72 | .javascript .hljs-title, 73 | .coffeescript .hljs-title { 74 | color: #8ab3b5; 75 | } 76 | 77 | /* Mocha Purple */ 78 | .hljs-keyword, 79 | .javascript .hljs-function { 80 | color: #a89bb9; 81 | } 82 | 83 | .hljs { 84 | display: block; 85 | background: #3B3228; 86 | color: #d0c8c6; 87 | padding: 0.5em; 88 | } 89 | 90 | .coffeescript .javascript, 91 | .javascript .xml, 92 | .tex .hljs-formula, 93 | .xml .javascript, 94 | .xml .vbscript, 95 | .xml .css, 96 | .xml .hljs-cdata { 97 | opacity: 0.5; 98 | } 99 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gulpif = require('gulp-if'); 3 | var sass = require('gulp-sass'); 4 | var path = require('path'); 5 | var prefix = require('gulp-autoprefixer'); 6 | var cp = require('child_process'); 7 | var webpack = require('gulp-webpack'); 8 | var named = require('vinyl-named'); 9 | 10 | gulp.task('jekyll-build', function (done) { 11 | return cp.spawn('jekyll', ['build'], {stdio: 'inherit'}) 12 | .on('close', done); 13 | }); 14 | 15 | gulp.task('sass', function () { 16 | return gulp.src('_sass/main.scss') 17 | .pipe(sass({ 18 | includePaths: ['_sass'] 19 | })) 20 | .on('error', console.error.bind(console)) 21 | .pipe(prefix(['last 15 versions', '> 1%', 'ie 8', 'ie 7'])) 22 | .pipe(gulp.dest('_site/css')) 23 | .pipe(gulp.dest('css')); 24 | }); 25 | 26 | gulp.task('js', js({})); 27 | gulp.task('js-watch', js({ watch: true })); 28 | 29 | gulp.task('watch', ['default'], function () { 30 | gulp.watch([ 31 | '!scripts/*.build.js', 32 | 'scripts/**.js', 33 | 'scripts/**/*.js', 34 | 35 | ], ['js-watch']); 36 | gulp.watch('_sass/**/*.scss', ['sass']); 37 | gulp.watch([ 38 | // 'scripts/**/*.js', 39 | '_workshop/*.js', 40 | '**/*.html', 41 | '!_site/**/*', 42 | '**/*.md'], ['jekyll-build']); 43 | }); 44 | 45 | gulp.task('default', ['sass', 'jekyll-build', 'js']); 46 | 47 | function js (options) { 48 | return function () { 49 | return gulp.src('scripts/entry.js') 50 | .pipe(named(function (file) { 51 | return path.basename(file.path, path.extname(file.path)) + '.build'; 52 | })) 53 | .pipe(webpack(require('./webpack')(options))) 54 | .pipe(gulpif(options.watch, gulp.dest('_site/scripts/'), gulp.dest('scripts/'))); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | Go to workshop 5 | -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | Notes: 2 | 3 | - Normaliser hva som skal endres (ikke måtte endre på testene feks) 4 | - Mer visuell kobling mellom test og test-resultat 5 | - Droppe prototype-oppgavene 6 | - Bedre beskrivelse på testene med multiplikasjon 7 | - map+filter-oppgave mangler skikkelig "it", samt har en skriveleif "ilter" (mangler f) 8 | - Presisere hvilken filter-funksjon som skal brukes (ikke Array.prototype.filter.call) 9 | - Paa reduce-eksempel, burde vi skrive ut tilsvarende for-lokke? 10 | - Beskrive fluent bedre, spesielt mtp function decorators 11 | - Bedre initial values på ting som skal lages (ikke tom funksjon for ting som skal bli variabler, feks partialRight) 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omniscientjs.github.io", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "gulp", 8 | "watch": "gulp watch" 9 | }, 10 | "engines": { 11 | "node": "0.10.x" 12 | }, 13 | "author": "", 14 | "license": "mit", 15 | "dependencies": { 16 | "6to5": "^3.3.2", 17 | "6to5-core": "^3.6.5", 18 | "6to5-loader": "^3.0.0", 19 | "autoprefixer-loader": "^1.1.0", 20 | "chai": "^2.0.0", 21 | "codemirror": "^5.0.0", 22 | "css-loader": "^0.9.1", 23 | "gulp-if": "^1.2.5", 24 | "immstruct": "^1.4.0", 25 | "immutable": "^3.6.2", 26 | "less": "^2.4.0", 27 | "less-loader": "^2.0.0", 28 | "lodash": "^2.0.0", 29 | "mocha": "^2.1.0", 30 | "omniscient": "^3.1.0", 31 | "react": "^0.12.2", 32 | "style-loader": "^0.8.3", 33 | "vinyl-named": "^1.1.0", 34 | "webpack": "^1.5.3" 35 | }, 36 | "devDependencies": { 37 | "gulp": "^3.8.11", 38 | "gulp-autoprefixer": "^2.1.0", 39 | "gulp-sass": "^1.3.3", 40 | "gulp-webpack": "^1.2.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /previous_presentations/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /previous_presentations/dag1/README.md: -------------------------------------------------------------------------------- 1 | Open `1_intro.js` to get started. 2 | -------------------------------------------------------------------------------- /previous_presentations/dag1/agenda.md: -------------------------------------------------------------------------------- 1 | # Utkast til agenda 2 | 3 | - Hei og velkommen 4 | - Intro: Hva er funksjonell programmering 5 | - "Funksjonelle språk" finnes ikke, men språk legger til rette for funksjonell programmering i ulik grad 6 | - Høyere ordens funksjoner 7 | - dvs, komponering av funksjonalitet vha funksjoner 8 | - Immutable state 9 | - mindre kompleksitet 10 | - eksempel med Angular sin run-loop som ikke er immutable? (sammenlign med shouldComponentUpdate i react+immutable.js) 11 | - Begreper vi kommer til å bruke, som deltagerne må kjenne (veldig kort) 12 | - Closures 13 | - Lexical scoping 14 | - Monad: "Monoid in the category of endofunctors." (for LOLs) 15 | + ref: http://james-iry.blogspot.no/2009/05/brief-incomplete-and-mostly-wrong.html 16 | - Praktisk: Hvordan komme i gang med kodingen på en praktisk måte 17 | 18 | - Hva er en funksjon (i JS) 19 | + fn som objekter -> funksjoner kan ha funksjoner som "members" 20 | + `this` 21 | + prototyper 22 | + konstruktør-funksjoner 23 | + `call`, `apply`, `arguments` 24 | 25 | - Høyere ordens funksjoner 26 | - Kort: Hva er en HOF / førsteklasses funksjon 27 | - bruke lodash 28 | - the use of generic functions built on a collection-centric philosophy 29 | - Funksjon som returnerer funksjon: `makeAdder` 30 | - Funksjon som tar funksjon som arg: ?? 31 | - Dekoratorer: `debounce`, `throttle`, `memoize` 32 | - State vha closures: `counter`, `timer`, `uniqeid` 33 | - Presentere `filter`, `map`, `reduce` (fra `_`) 34 | - Oppgaver 35 | + bruke `filter` til ting 36 | + bruke `map` til ting 37 | + bruke `reduce` til ting 38 | + implementere de over selv (optional) 39 | 40 | *(pause)* 41 | 42 | - Partial applicaton 43 | - Teori: Hva er dette / vise megabasic eksempel med _ 44 | - Nyttig bruk: `.on('change', _.partial(fn, 'foo')` 45 | - Tips: flip 46 | - Oppgaver: 47 | - Implementere `partial` selv 48 | 49 | - Rekursjon (trenger vi denne?) 50 | + TCO kommer i ES6 51 | + Eksempel: Traversering av trær 52 | + Kode: 53 | 54 | def reverse(liste): 55 | baklengs = [] 56 | for x in liste: 57 | baklengs.append(x) 58 | return baklengs 59 | 60 | def reverse(liste): 61 | if liste == []: return [] 62 | else: return reverse(liste[1:]) + [liste[0]] 63 | 64 | + Oppgaver: 65 | * ??? 66 | 67 | *(lunchpause)* 68 | 69 | - Tilstand 70 | - Hvorfor immutable state? Enklere å debugge og teste 71 | - Pragmatisk: alt må ikke være immutable, state har en plass 72 | - State kan komme og bite deg i ræva 73 | - Pass by reference vs pass by value 74 | - Farligheten med at andre kan modifisere shit etter at vi er ferdig med det 75 | - KJ finner eksempel, cache 76 | - Muligjør memoisering 77 | - Clone vs deepClone 78 | - object.freeze 79 | - Tips: implementere `deepFreeze` 80 | - Teknikker for å abstrahere bort state 81 | + `timer` 82 | + ??? 83 | - Oppgaver: 84 | + ??? 85 | 86 | - Diverse nyttige funksjoner 87 | + `pluck` 88 | + `find` 89 | + `any`, `all` 90 | + `compose` 91 | + Oppgaver: 92 | * Diverse bruk av funksjonene over 93 | 94 | *(pause)* 95 | 96 | - Idé til større del 97 | + Implementere så mye som mulig av `_` fra bunnen av 98 | + Bruk immutable.js sammen med React.js (til state, props er immutable) 99 | + Litt større ting vha Node 100 | * Presentere data fra et kult API på en ny måte? (som krever en del transformering der funksjonelle konsepter kan passe godt inn) 101 | * Se etter API som er relevant! 102 | -------------------------------------------------------------------------------- /previous_presentations/dag1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "1": "tape 1_intro.js | tap-bail | tap-spec", 4 | "2": "tape 2_applicative.js | tap-bail | tap-spec", 5 | "3": "tape 3_functions.js | tap-bail | tap-spec", 6 | "4": "tape 4_partially.js | tap-bail | tap-spec", 7 | "5": "tape 5_curry_compose.js | tap-bail | tap-spec", 8 | "6": "tape 6_immutability.js | tap-bail | tap-spec", 9 | "7": "tape 7_collections.js | tap-bail | tap-spec", 10 | "test": "tape 1_intro.js 2_applicative.js 3_functions.js 4_partially.js 5_curry_compose.js 6_immutability.js 7_collections.js | tap-bail | tap-spec", 11 | "solutions": "tape solutions/1_intro.js solutions/2_applicative.js solutions/3_functions.js solutions/4_partially.js solutions/5_curry_compose.js solutions/6_immutability.js solutions/7_collections.js | tap-bail | tap-spec" 12 | }, 13 | "dependencies": { 14 | "immutable": "^2.0.16", 15 | "lodash": "^2.4.1", 16 | "tap-bail": "0.0.0", 17 | "tap-spec": "^0.2.1", 18 | "tape": "^2.14.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /previous_presentations/dag1/slides/font/0AKsP294HTD-nvJgucYTaIbN6UDyHWBl620a-IRfuBk.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag1/slides/font/0AKsP294HTD-nvJgucYTaIbN6UDyHWBl620a-IRfuBk.woff -------------------------------------------------------------------------------- /previous_presentations/dag1/slides/font/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag1/slides/font/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff -------------------------------------------------------------------------------- /previous_presentations/dag1/slides/img/functional-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag1/slides/img/functional-map.png -------------------------------------------------------------------------------- /previous_presentations/dag1/slides/img/iterative-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag1/slides/img/iterative-map.png -------------------------------------------------------------------------------- /previous_presentations/dag1/slides/img/plot-languages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag1/slides/img/plot-languages.png -------------------------------------------------------------------------------- /previous_presentations/dag1/slides/remark-styling.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Droid Serif'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('Droid Serif'), local('DroidSerif'), url(font/0AKsP294HTD-nvJgucYTaIbN6UDyHWBl620a-IRfuBk.woff) format('woff'); 6 | } 7 | 8 | @font-face { 9 | font-family: 'Yanone Kaffeesatz'; 10 | font-style: normal; 11 | font-weight: 400; 12 | src: local('Yanone Kaffeesatz Regular'), local('YanoneKaffeesatz-Regular'), url(font/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff) format('woff'); 13 | } 14 | 15 | body { 16 | font-family: 'Droid Serif'; 17 | font-size: 20px; 18 | } 19 | h1, h2, h3 { 20 | font-family: 'Yanone Kaffeesatz'; 21 | font-weight: 400; 22 | margin-bottom: 0; 23 | } 24 | h1 { font-size: 4em; } 25 | h2 { font-size: 2em; } 26 | h3 { font-size: 1.6em; } 27 | .footnote { 28 | position: absolute; 29 | bottom: 3em; 30 | } 31 | li p { line-height: 1.25em; } 32 | .red { color: #fa0000; } 33 | .gray { color: #999; } 34 | .large { font-size: 2em; } 35 | .very-large { font-size: 3em; } 36 | a, a > code { 37 | color: rgb(249, 38, 114); 38 | text-decoration: none; 39 | } 40 | code { 41 | -moz-border-radius: 5px; 42 | -web-border-radius: 5px; 43 | background: #e7e8e2; 44 | border-radius: 5px; 45 | font-size: 16px; 46 | } 47 | .pull-left { 48 | float: left; 49 | width: 47%; 50 | } 51 | .pull-right { 52 | float: right; 53 | width: 47%; 54 | } 55 | .pull-right ~ p { 56 | clear: both; 57 | } 58 | #slideshow .slide .content code { 59 | font-size: 0.8em; 60 | } 61 | #slideshow .slide .content pre code { 62 | font-size: 0.9em; 63 | padding: 15px; 64 | } 65 | .inverse { 66 | background: #272822; 67 | color: #777872; 68 | 69 | } 70 | .inverse h1, .inverse h2 { 71 | color: #f3f3f3; 72 | line-height: 0.8em; 73 | } 74 | 75 | /* Slide-specific styling */ 76 | #slide-inverse .footnote { 77 | bottom: 12px; 78 | left: 20px; 79 | } 80 | #slide-how .slides { 81 | font-size: 0.9em; 82 | position: absolute; 83 | top: 151px; 84 | right: 140px; 85 | } 86 | #slide-how .slides h3 { 87 | margin-top: 0.2em; 88 | } 89 | #slide-how .slides .first, #slide-how .slides .second { 90 | padding: 1px 20px; 91 | height: 90px; 92 | width: 120px; 93 | -moz-box-shadow: 0 0 10px #777; 94 | -webkit-box-shadow: 0 0 10px #777; 95 | box-shadow: 0 0 10px #777; 96 | } 97 | #slide-how .slides .first { 98 | background: #fff; 99 | position: absolute; 100 | top: 20%; 101 | left: 20%; 102 | z-index: 1; 103 | } 104 | #slide-how .slides .second { 105 | position: relative; 106 | background: #fff; 107 | z-index: 0; 108 | } 109 | 110 | /* Two-column layout */ 111 | .left-column { 112 | color: #777; 113 | width: 20%; 114 | height: 92%; 115 | float: left; 116 | } 117 | .left-column h2:last-of-type, .left-column h3:last-child { 118 | color: #000; 119 | } 120 | .right-column { 121 | width: 75%; 122 | float: right; 123 | padding-top: 2em; 124 | } 125 | 126 | 127 | /* custom stuff */ 128 | 129 | .larger-img img { 130 | max-width: 100%; 131 | max-height: 100%; 132 | } 133 | 134 | img { 135 | max-width: 80%; 136 | max-height: 80%; 137 | } 138 | 139 | .leftcol-large { 140 | width: 55%; 141 | float: left; 142 | } 143 | 144 | .leftcol-medium { 145 | width: 45%; 146 | float: left; 147 | } 148 | 149 | .leftcol-small { 150 | width: 35%; 151 | float: left; 152 | } 153 | 154 | .rightcol-large { 155 | width: 55%; 156 | float: right; 157 | } 158 | 159 | .rightcol-medium { 160 | width: 45%; 161 | float: right; 162 | } 163 | 164 | .rightcol-small { 165 | width: 35%; 166 | float: right; 167 | } 168 | 169 | .no-bullets ul { 170 | padding-left: 0; 171 | list-style-type: none; 172 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/agenda.md: -------------------------------------------------------------------------------- 1 | # Utkast til agenda for dag 2 2 | 3 | ## Motivasjon og teoretisk bakgrunn 4 | Ansvarlig: **Felles** 5 | 6 | - Repetisjon av funksjonell programmering (KJ eller Kjetil) 7 | - Motivasjon til FRP (Stian) 8 | - Introduksjon til reactive programming (Mikael) 9 | - Introduksjon til teoretisk FRP (Mikael) 10 | 11 | **(Pause)** 12 | 13 | ## Introduksjon av praktisk FRP 14 | Ansvarlig: **Stian** 15 | 16 | - Nevne forskjellige implementasjoner 17 | - Introdusere Bacon.js (Praktisk I) 18 | - Innkapsling av reaktive datatyper 19 | - Fra event target eller fra data (constant, interval, fromArray) 20 | - Property vs EventStream 21 | - Forskjeller 22 | - Hvordan bytte mellom dem 23 | - Subscribers 24 | - Lazy i utgangspunktet 25 | - onValue og doAction 26 | - log særtilfelle (legger til subscriber!) 27 | - Bacon Love: Introductory 28 | - Gjennomgang av LF 29 | 30 | **(Pause)** 31 | 32 | ## Praktisk FRP 33 | Ansvarlig: **Mikael** 34 | 35 | - Gjennomgang av basic kombinatorer 36 | - Map og Filter 37 | - Fold/Scan/Reduce 38 | - Merge/Combine 39 | - Templates 40 | - Bruke properties som verdier i kombinatorer 41 | - Bacon Love: Combinators 42 | - Gjennomgang av LF 43 | 44 | **(Pause)** 45 | 46 | ## Avansert praktisk FRP del 1 47 | Ansvarlig: **Mikael** 48 | 49 | - Avanserte teknikker for å kombinere reaktive datatyper 50 | - and/or 51 | - sampleby 52 | - debounce/throttle/take/skip 53 | - flatMap 54 | - Bacon Love: Advanced 55 | - Gjennomgang av LF 56 | 57 | **(Pause)** 58 | 59 | ## Avansert pratisk FRP del 2 60 | Ansvarlig: **Stian** 61 | 62 | - Eventuell teori? 63 | - Bacon Love: Beyond 64 | - Gjennomgang av LF 65 | - Enkel case: CRUD-form 66 | 67 | **(Pause)** 68 | 69 | ## Avansert case 70 | Ansvarlig: **Mikael** 71 | 72 | - Presentere case 73 | - Bacon chat? 74 | - Løsing av case. 75 | - LF av case 76 | - Videreutvikling av case basert på forslag/idéer eller egne innslag. 77 | -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/.gitignore: -------------------------------------------------------------------------------- 1 | static/bundle.js 2 | static/main.css 3 | -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/README.md: -------------------------------------------------------------------------------- 1 | # Case: Making Bacon Chat with WebRTC integration 2 | 3 | Start the project by cloning the repo, change directory to `big-case`, 4 | and install dependencies: 5 | 6 | ``` 7 | npm install 8 | ``` 9 | 10 | 11 | ## Running project 12 | 13 | You'll have 3 commands to help you out: 14 | 15 | 16 | ### Starting a static file server at http://localhost:3000 17 | ``` 18 | npm run serve 19 | ``` 20 | 21 | 22 | ### Building all less and JS 23 | ``` 24 | npm run build 25 | ``` 26 | 27 | 28 | ### Building all less and JS on file change (watching) 29 | ``` 30 | npm run watch 31 | ``` 32 | 33 | 34 | ## Working on the case. 35 | 36 | The implementation should be done in [/browser/main.js](./browser/main.js). 37 | 38 | There are some helper modules found in [/browser/lib](./browser/lib): 39 | 40 | - [/browser/lib/chat.js](./browser/lib/chat.js): EventEmitter handling all Chat communication 41 | - [/browser/lib/webrtc.js](./browser/lib/webrtc.js): Converts WebRTC to an FRP EventSource 42 | - [/browser/lib/helpers.js](./browser/lib/helpers.js): Collection of helpers (regexes, templates etc) 43 | 44 | 45 | 46 | ### Result 47 | 48 | We are building a chat for talking about bacon in any size of form: 49 | 50 | ![BaconChat](https://raw.githubusercontent.com/bekkopen/funksjonell-js/gh-pages/dag2/big-case/baconchat.png) 51 | -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/baconchat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/big-case/baconchat.png -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/browser/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ws: 'ws://baconchat.herokuapp.com:80/', 3 | ajax: 'http://baconchat.herokuapp.com/users' 4 | }; -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/browser/lib/chat.js: -------------------------------------------------------------------------------- 1 | 2 | var io = require('socket.io-client'); 3 | var EventEmitter = require('events').EventEmitter; 4 | var inherits = require('util').inherits; 5 | var humanize = require('humanize'); 6 | var config = require('../config'); 7 | var toArray = require('lodash-node/modern/collections/toArray'); 8 | 9 | var reemit = function (client, type) { 10 | return function () { 11 | var args = toArray(arguments); 12 | args.unshift(type) 13 | client.emit.apply(client, args); 14 | }; 15 | }; 16 | 17 | var Chat = function () { 18 | this.connected = false; 19 | var client = this; 20 | client.socket = io(config.ws); 21 | 22 | client.socket.on('connect', function(){ 23 | client.connected = true; 24 | client.emit('connected'); 25 | }); 26 | client.socket.on('message', reemit(client, 'message')); 27 | client.socket.on('part', reemit(client, 'part')); 28 | client.socket.on('join', reemit(client, 'join')); 29 | return client; 30 | }; 31 | inherits(Chat, EventEmitter); 32 | 33 | Chat.prototype.join = function (username) { 34 | if (!this.connected) { 35 | this.emit('error', new Error('Not connected yet.')); 36 | return this; 37 | } 38 | if (this.username) { 39 | this.emit('error', new Error('Already connected and logged in as ' + this.username)); 40 | return this; 41 | } 42 | 43 | this.username = username; 44 | this.socket.emit('join', username); 45 | this.emit('join', username); 46 | return this; 47 | }; 48 | 49 | Chat.prototype.message = function (obj) { 50 | if (!this.connected || !this.username) { 51 | this.emit('error', new Error('Not connected yet. Join by using /join ')); 52 | return this; 53 | } 54 | if (!obj.message) { 55 | this.emit('error', new Error('No message given.')); 56 | return this; 57 | } 58 | var data = { 59 | username: this.username, 60 | message: obj.message, 61 | picture: obj.picture, 62 | time: humanize.date('d.m.Y - H:i:s') 63 | }; 64 | this.socket.emit('message', data); 65 | this.emit('message', data); 66 | return this; 67 | }; 68 | 69 | var chat = module.exports = new Chat(); -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/browser/lib/helpers.js: -------------------------------------------------------------------------------- 1 | var $ = require('jquery'), 2 | bacon = require('baconjs'), 3 | chat = require('./chat'), 4 | template = require('lodash-node/modern/utilities/template'), 5 | messageTemplate = template($('#messageTemplate').html()), 6 | usersTemplate = template($('#usersTemplate').html()), 7 | partingTemplate = template($('#partingTemplate').html()), 8 | errorTemplate = template($('#errorTemplate').html()); 9 | 10 | var joinRegex = /^\/j(?:oin)?\s+([\w]+)/i; 11 | 12 | module.exports.sum = function (acc, message) { 13 | return acc + message; 14 | }; 15 | 16 | module.exports.toUserObject = function (username) { 17 | return { 18 | username: username 19 | }; 20 | }; 21 | 22 | module.exports.resetForm = function() { 23 | $("#input-message").val("").trigger("keyup"); 24 | }; 25 | 26 | var isJoinMessage = module.exports.isJoinMessage = function (val) { 27 | return joinRegex.test(val); 28 | }; 29 | module.exports.notJoinMessage = function (val) { 30 | return !isJoinMessage(val); 31 | }; 32 | 33 | module.exports.toUsername = function (val) { 34 | return joinRegex.exec(val)[1]; 35 | }; 36 | 37 | module.exports.renderOnline = function (allUsers) { 38 | return allUsers.map(usersTemplate); 39 | }; 40 | 41 | module.exports.template = { 42 | message: messageTemplate, 43 | users: usersTemplate, 44 | parting: partingTemplate, 45 | error: errorTemplate 46 | }; -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/browser/lib/webrtc.js: -------------------------------------------------------------------------------- 1 | var Bacon = require('baconjs'); 2 | const INTERVAL_TIME_MS = 1000; 3 | 4 | navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; 5 | 6 | var error = function () { 7 | console.log("error getting camera"); 8 | }; 9 | 10 | module.exports = function (options) { 11 | var bus; 12 | var elVideo = options.elVideo; 13 | var elSnapshot = options.elSnapshot; 14 | var intervalTime = options.intervalTime || INTERVAL_TIME_MS; 15 | 16 | if (!elVideo || !elSnapshot) throw new Error('Invalid arguments given'); 17 | 18 | bus = new Bacon.Bus; 19 | navigator.getUserMedia({ video: true}, function(stream) { 20 | elVideo.src = window.URL.createObjectURL(stream); 21 | 22 | setInterval(function () { 23 | bus.push(getData(elVideo, elSnapshot)); 24 | }, intervalTime); 25 | }, error); 26 | 27 | return bus; 28 | }; 29 | 30 | function getData (elVideo, elSnapshot) { 31 | var c; 32 | 33 | elSnapshot.width = elVideo.clientWidth; 34 | elSnapshot.height = elVideo.clientHeight; 35 | 36 | c = elSnapshot.getContext("2d"); 37 | c.drawImage(elVideo, 0, 0, elSnapshot.width, elSnapshot.height); 38 | return elSnapshot.toDataURL("image/png"); 39 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var gulp = require('gulp'); 3 | var browserify = require('browserify'); 4 | var watchify = require('watchify'); 5 | var source = require('vinyl-source-stream'); 6 | var notify = require('gulp-notify'); 7 | var less = require('gulp-less'); 8 | var path = require('path'); 9 | var autoprefixer = require('gulp-autoprefixer'); 10 | 11 | var css = './style/**/*.less'; 12 | var js = __dirname + '/browser/main.js'; 13 | 14 | var bundle = function (bundler) { 15 | return bundler.bundle() 16 | .on('error', notify.onError('Browserification failed! <%= error.message %>')) 17 | .pipe(source('bundle.js')) 18 | .pipe(gulp.dest(__dirname + '/static/')) 19 | .pipe(notify('Browserification done')); 20 | }; 21 | 22 | gulp.task('js', function () { 23 | var bundler = browserify(js, { debug: true }); 24 | return bundle(browserify(js)); 25 | }); 26 | 27 | gulp.task('js-watch', function () { 28 | var args = watchify.args; 29 | args.debug = true; 30 | var b = browserify(js, args); 31 | var bundler = watchify(b); 32 | bundler.on('update', bundle.bind(this, bundler)); 33 | return bundle(bundler); 34 | }); 35 | 36 | gulp.task('less', function () { 37 | gulp.src('./style/main.less') 38 | .pipe(less({ 39 | paths: [ path.join(__dirname, 'style', 'includes') ] 40 | })) 41 | .on('error', notify.onError('Error with less! <%= error.message %>')) 42 | .pipe(autoprefixer({ cascade: true })) 43 | .pipe(gulp.dest('./static/')) 44 | .pipe(notify({ 45 | message: 'Less compiled', 46 | onLast: true 47 | })); 48 | }); 49 | 50 | // Rerun the task when a file changes 51 | gulp.task('watch', ['js-watch'], function() { 52 | gulp.watch(css, ['less']); 53 | }); 54 | 55 | 56 | gulp.task('default', ['less', 'js']); -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/lib/users.js: -------------------------------------------------------------------------------- 1 | var remove = require('lodash-node/modern/arrays/remove'); 2 | 3 | var onlineUsers = []; 4 | 5 | module.exports = { 6 | route: function (req, res) { 7 | if (req.method !== "GET" || !/^\/users$/i.test(req.url)) { 8 | return false; 9 | } 10 | 11 | var users = JSON.stringify(onlineUsers); 12 | res.writeHead(200, { 13 | 'Content-Length': users.length, 14 | 'Content-Type': 'application/json' 15 | }); 16 | res.end(users); 17 | return true; 18 | }, 19 | 20 | add: function (user) { 21 | return onlineUsers.push({ 22 | username: user 23 | }); 24 | }, 25 | 26 | remove: function (username) { 27 | remove(onlineUsers, function (user) { 28 | return user.username === username; 29 | }); 30 | } 31 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bacon-chat", 3 | "version": "2.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "dependencies": { 7 | "baconjs": "^0.7.22", 8 | "ecstatic": "^0.5.4", 9 | "humanize": "0.0.9", 10 | "jquery": "^2.1.1", 11 | "lodash-node": "^2.4.1", 12 | "socket.io": "^1.0.6", 13 | "socket.io-client": "^1.0.6" 14 | }, 15 | "browserify": { 16 | "transform": [ 17 | "es6-arrow-function" 18 | ] 19 | }, 20 | "devDependencies": { 21 | "browserify": "^5.10.1", 22 | "es6-arrow-function": "^0.3.1", 23 | "gulp": "^3.8.7", 24 | "gulp-autoprefixer": "0.0.9", 25 | "gulp-less": "^1.3.5", 26 | "gulp-notify": "^1.5.0", 27 | "vinyl-source-stream": "^0.1.1", 28 | "watchify": "^1.0.2" 29 | }, 30 | "scripts": { 31 | "build": "gulp", 32 | "watch": "gulp watch", 33 | "serve": "node static-server.js", 34 | "test": "echo \"Error: no test specified\" && exit 1" 35 | }, 36 | "author": "", 37 | "license": "ISC" 38 | } 39 | -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'), 2 | ecstatic = require('ecstatic'), 3 | users = require('./lib/users'), 4 | 5 | port = process.env.PORT || 5001, 6 | staticDir = __dirname + '/static', 7 | 8 | app = http.createServer(serverHandler), 9 | io = require('socket.io').listen(app); 10 | 11 | app.listen(port); 12 | console.log('Started server on port', port); 13 | 14 | function serverHandler (req, res) { 15 | if (users.route(req, res)) { 16 | return; 17 | } 18 | return ecstatic({ 19 | root: staticDir 20 | })(req, res); 21 | }; 22 | 23 | io.sockets.on('connection', function (socket) { 24 | var username = null; 25 | 26 | socket.on('message', function (data) { 27 | if (!username) return; 28 | socket.broadcast.emit('message', data); 29 | }); 30 | 31 | socket.on('join', function (data) { 32 | users.add(data); 33 | username = data; 34 | socket.broadcast.emit('join', data); 35 | }); 36 | 37 | socket.on('disconnect', function() { 38 | if (!username) return; 39 | users.remove(username); 40 | socket.broadcast.emit('part', username); 41 | }); 42 | }); -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/static-server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'), 2 | ecstatic = require('ecstatic'), 3 | 4 | port = process.env.PORT || 3000, 5 | staticDir = __dirname + '/static'; 6 | 7 | http.createServer(ecstatic({ 8 | root: staticDir 9 | })).listen(port); 10 | console.log('Started server on port', port); -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/static/assets/bacon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/big-case/static/assets/bacon.png -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BaconChat 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Bacon logo BaconChat

16 |
17 | 18 |
19 |
    20 |
21 |
22 | 23 |
24 |
    25 |
    26 |
    27 | avatar 28 |
    29 | 30 |
    31 |
    32 |
    33 | 34 | 45 | 52 | 59 | 62 | 63 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/style/colors.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | @black: #1d1d1d; 4 | @white: #f1f1f1; 5 | @red: #fd5157; 6 | @background: #e5e5e5; 7 | @linkColorHover: lighten( @red, 20% ); -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/style/main.less: -------------------------------------------------------------------------------- 1 | @import "reset.less"; 2 | @import "colors.less"; 3 | @import "mixins.less"; 4 | 5 | * { 6 | -webkit-box-sizing: border-box; 7 | -moz-box-sizing: border-box; 8 | box-sizing: border-box; 9 | } 10 | 11 | html, body { 12 | height: 100%; 13 | overflow: hidden; 14 | } 15 | 16 | body { 17 | background: @background; 18 | font-family: Helvetica, Arial; 19 | } 20 | 21 | 22 | a:link, a:visited { 23 | color: @red; 24 | } 25 | 26 | a:hover, a:active { 27 | color: @linkColorHover; 28 | } 29 | 30 | .helper-box { 31 | height: 1px; 32 | width: 1px; 33 | display: block; 34 | margin: 0; 35 | padding: 0; 36 | overflow: hidden; 37 | 38 | video { 39 | height: @inputSize; 40 | } 41 | } 42 | 43 | @import "chat.less"; -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/style/mixins.less: -------------------------------------------------------------------------------- 1 | .clearfix() { 2 | *zoom: 1; 3 | 4 | &:before, 5 | &:after { 6 | content: " "; 7 | display: table; 8 | } 9 | 10 | &:after { 11 | clear: both; 12 | } 13 | } 14 | 15 | .height-minus (@height: 100%, @margin: 40px) { 16 | height: -moz-calc(@height ~"-" @margin); 17 | max-height: -moz-calc(@height ~"-" @margin); 18 | height: -webkit-calc(@height ~"-" @margin); 19 | max-height: -webkit-calc(@height ~"-" @margin); 20 | height: calc(@height ~"-" @margin); 21 | max-height: calc(@height ~"-" @margin); 22 | } 23 | 24 | .width-minus (@width 100%, @margin: 40px) { 25 | width: -moz-calc(@width ~"-" @margin); 26 | width: -webkit-calc(@width ~"-" @margin); 27 | width: calc(@width ~"-" @margin); 28 | max-width: -moz-calc(@width ~"-" @margin); 29 | max-width: -webkit-calc(@width ~"-" @margin); 30 | max-width: calc(@width ~"-" @margin); 31 | } 32 | 33 | .drop-shadow(@x-axis: 0, @y-axis: 1px, @blur: 2px, @alpha: 0.5) { 34 | -webkit-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha); 35 | -moz-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha); 36 | box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha); 37 | } 38 | .rounded(@radius: 2px) { 39 | -webkit-border-radius: @radius; 40 | -moz-border-radius: @radius; 41 | border-radius: @radius; 42 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/big-case/style/reset.less: -------------------------------------------------------------------------------- 1 | /* Reset.less 2 | * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here that cuts out some of the reset HTML elements we will never need here (i.e., dfn, samp, etc). 3 | * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ 4 | 5 | 6 | // ERIC MEYER RESET 7 | // -------------------------------------------------- 8 | 9 | html, body { margin: 0; padding: 0; } 10 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, cite, code, del, dfn, em, img, q, s, samp, small, strike, strong, sub, sup, tt, var, dd, dl, dt, li, ol, ul, fieldset, form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; font-weight: normal; font-style: normal; font-size: 100%; line-height: 1; font-family: inherit; } 11 | table { border-collapse: collapse; border-spacing: 0; } 12 | ol, ul { list-style: none; } 13 | q:before, q:after, blockquote:before, blockquote:after { content: ""; } 14 | 15 | 16 | // Normalize.css 17 | // Pulling in select resets form the normalize.css project 18 | // -------------------------------------------------- 19 | 20 | // Display in IE6-9 and FF3 21 | // ------------------------- 22 | // Source: http://github.com/necolas/normalize.css 23 | html { 24 | overflow-y: scroll; 25 | font-size: 100%; 26 | -webkit-text-size-adjust: 100%; 27 | -ms-text-size-adjust: 100%; 28 | } 29 | // Focus states 30 | a:focus { 31 | outline: thin dotted; 32 | } 33 | // Hover & Active 34 | a:hover, 35 | a:active { 36 | outline: 0; 37 | } 38 | 39 | // Display in IE6-9 and FF3 40 | // ------------------------- 41 | // Source: http://github.com/necolas/normalize.css 42 | article, 43 | aside, 44 | details, 45 | figcaption, 46 | figure, 47 | footer, 48 | header, 49 | hgroup, 50 | nav, 51 | section { 52 | display: block; 53 | } 54 | 55 | // Display block in IE6-9 and FF3 56 | // ------------------------- 57 | // Source: http://github.com/necolas/normalize.css 58 | audio, 59 | canvas, 60 | video { 61 | display: inline-block; 62 | *display: inline; 63 | *zoom: 1; 64 | } 65 | 66 | // Prevents modern browsers from displaying 'audio' without controls 67 | // ------------------------- 68 | // Source: http://github.com/necolas/normalize.css 69 | audio:not([controls]) { 70 | display: none; 71 | } 72 | 73 | // Prevents sub and sup affecting line-height in all browsers 74 | // ------------------------- 75 | // Source: http://github.com/necolas/normalize.css 76 | sub, 77 | sup { 78 | font-size: 75%; 79 | line-height: 0; 80 | position: relative; 81 | vertical-align: baseline; 82 | } 83 | sup { 84 | top: -0.5em; 85 | } 86 | sub { 87 | bottom: -0.25em; 88 | } 89 | 90 | // Img border in a's and image quality 91 | // ------------------------- 92 | // Source: http://github.com/necolas/normalize.css 93 | img { 94 | border: 0; 95 | -ms-interpolation-mode: bicubic; 96 | } 97 | 98 | // Forms 99 | // ------------------------- 100 | // Source: http://github.com/necolas/normalize.css 101 | 102 | // Font size in all browsers, margin changes, misc consistency 103 | button, 104 | input, 105 | select, 106 | textarea { 107 | font-size: 100%; 108 | margin: 0; 109 | vertical-align: baseline; 110 | *vertical-align: middle; 111 | } 112 | button, 113 | input { 114 | line-height: normal; // FF3/4 have !important on line-height in UA stylesheet 115 | *overflow: visible; // Inner spacing ie IE6/7 116 | } 117 | button::-moz-focus-inner, 118 | input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 119 | border: 0; 120 | padding: 0; 121 | } 122 | button, 123 | input[type="button"], 124 | input[type="reset"], 125 | input[type="submit"] { 126 | cursor: pointer; // Cursors on all buttons applied consistently 127 | -webkit-appearance: button; // Style clicable inputs in iOS 128 | } 129 | input[type="search"] { // Appearance in Safari/Chrome 130 | -webkit-appearance: textfield; 131 | -webkit-box-sizing: content-box; 132 | -moz-box-sizing: content-box; 133 | box-sizing: content-box; 134 | } 135 | input[type="search"]::-webkit-search-decoration { 136 | -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 137 | } 138 | textarea { 139 | overflow: auto; // Remove vertical scrollbar in IE6-9 140 | vertical-align: top; // Readability and alignment cross-browser 141 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/presentation.css: -------------------------------------------------------------------------------- 1 | /* Data flow example */ 2 | .slides .dataflow-example { 3 | background: url("../img/data_flow.svg") left top no-repeat; 4 | position: relative; 5 | width: 900px; 6 | height: 364px; 7 | margin: 0 auto; 8 | } 9 | 10 | .node, 11 | .node-result { 12 | border: 0; 13 | background: none; 14 | color: #fff; 15 | position: absolute; 16 | font-size: 2em; 17 | width: 100px; 18 | outline: 0; 19 | text-align: center; 20 | } 21 | 22 | .node-a { 23 | top: 50px; 24 | left: 25px; 25 | } 26 | 27 | .node-b { 28 | bottom: 36px; 29 | left: 25px; 30 | } 31 | 32 | .node-d { 33 | top: 30px; 34 | left: 385px; 35 | } 36 | 37 | .node-c { 38 | bottom: 96px; 39 | left: 385px; 40 | } 41 | 42 | .node-result { 43 | top: calc(50% - 40px); 44 | right: 15px; 45 | } 46 | 47 | .reveal h2.black { 48 | color: #1b1b1b; 49 | } 50 | 51 | .reveal code { 52 | display: inline-block; 53 | background: #666; 54 | padding: 5px 10px; 55 | border-radius: 2px; 56 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/README.md: -------------------------------------------------------------------------------- 1 | ## Dependencies 2 | 3 | Themes are written using Sass to keep things modular and reduce the need for repeated selectors across files. Make sure that you have the reveal.js development environment including the Grunt dependencies installed before proceding: https://github.com/hakimel/reveal.js#full-setup 4 | 5 | 6 | 7 | ## Creating a Theme 8 | 9 | To create your own theme, start by duplicating any ```.scss``` file in [/css/theme/source](https://github.com/hakimel/reveal.js/blob/master/css/theme/source) and adding it to the compilation list in the [Gruntfile](https://github.com/hakimel/reveal.js/blob/master/Gruntfile.js). 10 | 11 | Each theme file does four things in the following order: 12 | 13 | 1. **Include [/css/theme/template/mixins.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/mixins.scss)** 14 | Shared utility functions. 15 | 16 | 2. **Include [/css/theme/template/settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss)** 17 | Declares a set of custom variables that the template file (step 4) expects. Can be overridden in step 3. 18 | 19 | 3. **Override** 20 | This is where you override the default theme. Either by specifying variables (see [settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss) for reference) or by adding full selectors with hardcoded styles. 21 | 22 | 4. **Include [/css/theme/template/theme.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/theme.scss)** 23 | The template theme file which will generate final CSS output based on the currently defined variables. 24 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/moon.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 2 | /** 3 | * Solarized Dark theme for reveal.js. 4 | * Author: Achim Staebler 5 | */ 6 | @font-face { 7 | font-family: 'League Gothic'; 8 | src: url("../../lib/font/league_gothic-webfont.eot"); 9 | src: url("../../lib/font/league_gothic-webfont.eot?#iefix") format("embedded-opentype"), url("../../lib/font/league_gothic-webfont.woff") format("woff"), url("../../lib/font/league_gothic-webfont.ttf") format("truetype"), url("../../lib/font/league_gothic-webfont.svg#LeagueGothicRegular") format("svg"); 10 | font-weight: normal; 11 | font-style: normal; } 12 | 13 | /** 14 | * Solarized colors by Ethan Schoonover 15 | */ 16 | html * { 17 | color-profile: sRGB; 18 | rendering-intent: auto; } 19 | 20 | /********************************************* 21 | * GLOBAL STYLES 22 | *********************************************/ 23 | body { 24 | background: #002b36; 25 | background-color: #002b36; } 26 | 27 | .reveal { 28 | font-family: "Lato", sans-serif; 29 | font-size: 36px; 30 | font-weight: 200; 31 | letter-spacing: -0.02em; 32 | color: #93a1a1; } 33 | 34 | ::selection { 35 | color: white; 36 | background: #d33682; 37 | text-shadow: none; } 38 | 39 | /********************************************* 40 | * HEADERS 41 | *********************************************/ 42 | .reveal h1, 43 | .reveal h2, 44 | .reveal h3, 45 | .reveal h4, 46 | .reveal h5, 47 | .reveal h6 { 48 | margin: 0 0 20px 0; 49 | color: #eee8d5; 50 | font-family: "League Gothic", Impact, sans-serif; 51 | line-height: 0.9em; 52 | letter-spacing: 0.02em; 53 | text-transform: uppercase; 54 | text-shadow: none; } 55 | 56 | .reveal h1 { 57 | text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2); } 58 | 59 | /********************************************* 60 | * LINKS 61 | *********************************************/ 62 | .reveal a:not(.image) { 63 | color: #268bd2; 64 | text-decoration: none; 65 | -webkit-transition: color .15s ease; 66 | -moz-transition: color .15s ease; 67 | -ms-transition: color .15s ease; 68 | -o-transition: color .15s ease; 69 | transition: color .15s ease; } 70 | 71 | .reveal a:not(.image):hover { 72 | color: #78b9e6; 73 | text-shadow: none; 74 | border: none; } 75 | 76 | .reveal .roll span:after { 77 | color: #fff; 78 | background: #1a6091; } 79 | 80 | /********************************************* 81 | * IMAGES 82 | *********************************************/ 83 | .reveal section img { 84 | margin: 15px 0px; 85 | background: rgba(255, 255, 255, 0.12); 86 | border: 4px solid #93a1a1; 87 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); 88 | -webkit-transition: all .2s linear; 89 | -moz-transition: all .2s linear; 90 | -ms-transition: all .2s linear; 91 | -o-transition: all .2s linear; 92 | transition: all .2s linear; } 93 | 94 | .reveal a:hover img { 95 | background: rgba(255, 255, 255, 0.2); 96 | border-color: #268bd2; 97 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 98 | 99 | /********************************************* 100 | * NAVIGATION CONTROLS 101 | *********************************************/ 102 | .reveal .controls div.navigate-left, 103 | .reveal .controls div.navigate-left.enabled { 104 | border-right-color: #268bd2; } 105 | 106 | .reveal .controls div.navigate-right, 107 | .reveal .controls div.navigate-right.enabled { 108 | border-left-color: #268bd2; } 109 | 110 | .reveal .controls div.navigate-up, 111 | .reveal .controls div.navigate-up.enabled { 112 | border-bottom-color: #268bd2; } 113 | 114 | .reveal .controls div.navigate-down, 115 | .reveal .controls div.navigate-down.enabled { 116 | border-top-color: #268bd2; } 117 | 118 | .reveal .controls div.navigate-left.enabled:hover { 119 | border-right-color: #78b9e6; } 120 | 121 | .reveal .controls div.navigate-right.enabled:hover { 122 | border-left-color: #78b9e6; } 123 | 124 | .reveal .controls div.navigate-up.enabled:hover { 125 | border-bottom-color: #78b9e6; } 126 | 127 | .reveal .controls div.navigate-down.enabled:hover { 128 | border-top-color: #78b9e6; } 129 | 130 | /********************************************* 131 | * PROGRESS BAR 132 | *********************************************/ 133 | .reveal .progress { 134 | background: rgba(0, 0, 0, 0.2); } 135 | 136 | .reveal .progress span { 137 | background: #268bd2; 138 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 139 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 140 | -ms-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 141 | -o-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 142 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 143 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/night.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Montserrat:700); 2 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic); 3 | /** 4 | * Black theme for reveal.js. 5 | * 6 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 7 | */ 8 | /********************************************* 9 | * GLOBAL STYLES 10 | *********************************************/ 11 | body { 12 | background: #111111; 13 | background-color: #111111; } 14 | 15 | .reveal { 16 | font-family: "Open Sans", sans-serif; 17 | font-size: 30px; 18 | font-weight: 200; 19 | letter-spacing: -0.02em; 20 | color: #eeeeee; } 21 | 22 | ::selection { 23 | color: white; 24 | background: #e7ad52; 25 | text-shadow: none; } 26 | 27 | /********************************************* 28 | * HEADERS 29 | *********************************************/ 30 | .reveal h1, 31 | .reveal h2, 32 | .reveal h3, 33 | .reveal h4, 34 | .reveal h5, 35 | .reveal h6 { 36 | margin: 0 0 20px 0; 37 | color: #eeeeee; 38 | font-family: "Montserrat", Impact, sans-serif; 39 | line-height: 0.9em; 40 | letter-spacing: -0.03em; 41 | text-transform: none; 42 | text-shadow: none; } 43 | 44 | .reveal h1 { 45 | text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2); } 46 | 47 | /********************************************* 48 | * LINKS 49 | *********************************************/ 50 | .reveal a:not(.image) { 51 | color: #e7ad52; 52 | text-decoration: none; 53 | -webkit-transition: color .15s ease; 54 | -moz-transition: color .15s ease; 55 | -ms-transition: color .15s ease; 56 | -o-transition: color .15s ease; 57 | transition: color .15s ease; } 58 | 59 | .reveal a:not(.image):hover { 60 | color: #f3d7ac; 61 | text-shadow: none; 62 | border: none; } 63 | 64 | .reveal .roll span:after { 65 | color: #fff; 66 | background: #d08a1d; } 67 | 68 | /********************************************* 69 | * IMAGES 70 | *********************************************/ 71 | .reveal section img { 72 | margin: 15px 0px; 73 | background: rgba(255, 255, 255, 0.12); 74 | border: 4px solid #eeeeee; 75 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); 76 | -webkit-transition: all .2s linear; 77 | -moz-transition: all .2s linear; 78 | -ms-transition: all .2s linear; 79 | -o-transition: all .2s linear; 80 | transition: all .2s linear; } 81 | 82 | .reveal a:hover img { 83 | background: rgba(255, 255, 255, 0.2); 84 | border-color: #e7ad52; 85 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 86 | 87 | /********************************************* 88 | * NAVIGATION CONTROLS 89 | *********************************************/ 90 | .reveal .controls div.navigate-left, 91 | .reveal .controls div.navigate-left.enabled { 92 | border-right-color: #e7ad52; } 93 | 94 | .reveal .controls div.navigate-right, 95 | .reveal .controls div.navigate-right.enabled { 96 | border-left-color: #e7ad52; } 97 | 98 | .reveal .controls div.navigate-up, 99 | .reveal .controls div.navigate-up.enabled { 100 | border-bottom-color: #e7ad52; } 101 | 102 | .reveal .controls div.navigate-down, 103 | .reveal .controls div.navigate-down.enabled { 104 | border-top-color: #e7ad52; } 105 | 106 | .reveal .controls div.navigate-left.enabled:hover { 107 | border-right-color: #f3d7ac; } 108 | 109 | .reveal .controls div.navigate-right.enabled:hover { 110 | border-left-color: #f3d7ac; } 111 | 112 | .reveal .controls div.navigate-up.enabled:hover { 113 | border-bottom-color: #f3d7ac; } 114 | 115 | .reveal .controls div.navigate-down.enabled:hover { 116 | border-top-color: #f3d7ac; } 117 | 118 | /********************************************* 119 | * PROGRESS BAR 120 | *********************************************/ 121 | .reveal .progress { 122 | background: rgba(0, 0, 0, 0.2); } 123 | 124 | .reveal .progress span { 125 | background: #e7ad52; 126 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 127 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 128 | -ms-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 129 | -o-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 130 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 131 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/serif.css: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple theme for reveal.js presentations, similar 3 | * to the default theme. The accent color is brown. 4 | * 5 | * This theme is Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed. 6 | */ 7 | .reveal a:not(.image) { 8 | line-height: 1.3em; } 9 | 10 | /********************************************* 11 | * GLOBAL STYLES 12 | *********************************************/ 13 | body { 14 | background: #f0f1eb; 15 | background-color: #f0f1eb; } 16 | 17 | .reveal { 18 | font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif; 19 | font-size: 36px; 20 | font-weight: 200; 21 | letter-spacing: -0.02em; 22 | color: black; } 23 | 24 | ::selection { 25 | color: white; 26 | background: #26351c; 27 | text-shadow: none; } 28 | 29 | /********************************************* 30 | * HEADERS 31 | *********************************************/ 32 | .reveal h1, 33 | .reveal h2, 34 | .reveal h3, 35 | .reveal h4, 36 | .reveal h5, 37 | .reveal h6 { 38 | margin: 0 0 20px 0; 39 | color: #383d3d; 40 | font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif; 41 | line-height: 0.9em; 42 | letter-spacing: 0.02em; 43 | text-transform: none; 44 | text-shadow: none; } 45 | 46 | .reveal h1 { 47 | text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2); } 48 | 49 | /********************************************* 50 | * LINKS 51 | *********************************************/ 52 | .reveal a:not(.image) { 53 | color: #51483d; 54 | text-decoration: none; 55 | -webkit-transition: color .15s ease; 56 | -moz-transition: color .15s ease; 57 | -ms-transition: color .15s ease; 58 | -o-transition: color .15s ease; 59 | transition: color .15s ease; } 60 | 61 | .reveal a:not(.image):hover { 62 | color: #8b7c69; 63 | text-shadow: none; 64 | border: none; } 65 | 66 | .reveal .roll span:after { 67 | color: #fff; 68 | background: #25211c; } 69 | 70 | /********************************************* 71 | * IMAGES 72 | *********************************************/ 73 | .reveal section img { 74 | margin: 15px 0px; 75 | background: rgba(255, 255, 255, 0.12); 76 | border: 4px solid black; 77 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); 78 | -webkit-transition: all .2s linear; 79 | -moz-transition: all .2s linear; 80 | -ms-transition: all .2s linear; 81 | -o-transition: all .2s linear; 82 | transition: all .2s linear; } 83 | 84 | .reveal a:hover img { 85 | background: rgba(255, 255, 255, 0.2); 86 | border-color: #51483d; 87 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 88 | 89 | /********************************************* 90 | * NAVIGATION CONTROLS 91 | *********************************************/ 92 | .reveal .controls div.navigate-left, 93 | .reveal .controls div.navigate-left.enabled { 94 | border-right-color: #51483d; } 95 | 96 | .reveal .controls div.navigate-right, 97 | .reveal .controls div.navigate-right.enabled { 98 | border-left-color: #51483d; } 99 | 100 | .reveal .controls div.navigate-up, 101 | .reveal .controls div.navigate-up.enabled { 102 | border-bottom-color: #51483d; } 103 | 104 | .reveal .controls div.navigate-down, 105 | .reveal .controls div.navigate-down.enabled { 106 | border-top-color: #51483d; } 107 | 108 | .reveal .controls div.navigate-left.enabled:hover { 109 | border-right-color: #8b7c69; } 110 | 111 | .reveal .controls div.navigate-right.enabled:hover { 112 | border-left-color: #8b7c69; } 113 | 114 | .reveal .controls div.navigate-up.enabled:hover { 115 | border-bottom-color: #8b7c69; } 116 | 117 | .reveal .controls div.navigate-down.enabled:hover { 118 | border-top-color: #8b7c69; } 119 | 120 | /********************************************* 121 | * PROGRESS BAR 122 | *********************************************/ 123 | .reveal .progress { 124 | background: rgba(0, 0, 0, 0.2); } 125 | 126 | .reveal .progress span { 127 | background: #51483d; 128 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 129 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 130 | -ms-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 131 | -o-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 132 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 133 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/simple.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); 2 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 3 | /** 4 | * A simple theme for reveal.js presentations, similar 5 | * to the default theme. The accent color is darkblue. 6 | * 7 | * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. 8 | * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 9 | */ 10 | /********************************************* 11 | * GLOBAL STYLES 12 | *********************************************/ 13 | body { 14 | background: white; 15 | background-color: white; } 16 | 17 | .reveal { 18 | font-family: "Lato", sans-serif; 19 | font-size: 36px; 20 | font-weight: 200; 21 | letter-spacing: -0.02em; 22 | color: black; } 23 | 24 | ::selection { 25 | color: white; 26 | background: rgba(0, 0, 0, 0.99); 27 | text-shadow: none; } 28 | 29 | /********************************************* 30 | * HEADERS 31 | *********************************************/ 32 | .reveal h1, 33 | .reveal h2, 34 | .reveal h3, 35 | .reveal h4, 36 | .reveal h5, 37 | .reveal h6 { 38 | margin: 0 0 20px 0; 39 | color: black; 40 | font-family: "News Cycle", Impact, sans-serif; 41 | line-height: 0.9em; 42 | letter-spacing: 0.02em; 43 | text-transform: none; 44 | text-shadow: none; } 45 | 46 | .reveal h1 { 47 | text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2); } 48 | 49 | /********************************************* 50 | * LINKS 51 | *********************************************/ 52 | .reveal a:not(.image) { 53 | color: darkblue; 54 | text-decoration: none; 55 | -webkit-transition: color .15s ease; 56 | -moz-transition: color .15s ease; 57 | -ms-transition: color .15s ease; 58 | -o-transition: color .15s ease; 59 | transition: color .15s ease; } 60 | 61 | .reveal a:not(.image):hover { 62 | color: #0000f1; 63 | text-shadow: none; 64 | border: none; } 65 | 66 | .reveal .roll span:after { 67 | color: #fff; 68 | background: #00003f; } 69 | 70 | /********************************************* 71 | * IMAGES 72 | *********************************************/ 73 | .reveal section img { 74 | margin: 15px 0px; 75 | background: rgba(255, 255, 255, 0.12); 76 | border: 4px solid black; 77 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); 78 | -webkit-transition: all .2s linear; 79 | -moz-transition: all .2s linear; 80 | -ms-transition: all .2s linear; 81 | -o-transition: all .2s linear; 82 | transition: all .2s linear; } 83 | 84 | .reveal a:hover img { 85 | background: rgba(255, 255, 255, 0.2); 86 | border-color: darkblue; 87 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 88 | 89 | /********************************************* 90 | * NAVIGATION CONTROLS 91 | *********************************************/ 92 | .reveal .controls div.navigate-left, 93 | .reveal .controls div.navigate-left.enabled { 94 | border-right-color: darkblue; } 95 | 96 | .reveal .controls div.navigate-right, 97 | .reveal .controls div.navigate-right.enabled { 98 | border-left-color: darkblue; } 99 | 100 | .reveal .controls div.navigate-up, 101 | .reveal .controls div.navigate-up.enabled { 102 | border-bottom-color: darkblue; } 103 | 104 | .reveal .controls div.navigate-down, 105 | .reveal .controls div.navigate-down.enabled { 106 | border-top-color: darkblue; } 107 | 108 | .reveal .controls div.navigate-left.enabled:hover { 109 | border-right-color: #0000f1; } 110 | 111 | .reveal .controls div.navigate-right.enabled:hover { 112 | border-left-color: #0000f1; } 113 | 114 | .reveal .controls div.navigate-up.enabled:hover { 115 | border-bottom-color: #0000f1; } 116 | 117 | .reveal .controls div.navigate-down.enabled:hover { 118 | border-top-color: #0000f1; } 119 | 120 | /********************************************* 121 | * PROGRESS BAR 122 | *********************************************/ 123 | .reveal .progress { 124 | background: rgba(0, 0, 0, 0.2); } 125 | 126 | .reveal .progress span { 127 | background: darkblue; 128 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 129 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 130 | -ms-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 131 | -o-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 132 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 133 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/beige.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Beige theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | 15 | // Include theme-specific fonts 16 | @font-face { 17 | font-family: 'League Gothic'; 18 | src: url('../../lib/font/league_gothic-webfont.eot'); 19 | src: url('../../lib/font/league_gothic-webfont.eot?#iefix') format('embedded-opentype'), 20 | url('../../lib/font/league_gothic-webfont.woff') format('woff'), 21 | url('../../lib/font/league_gothic-webfont.ttf') format('truetype'), 22 | url('../../lib/font/league_gothic-webfont.svg#LeagueGothicRegular') format('svg'); 23 | 24 | font-weight: normal; 25 | font-style: normal; 26 | } 27 | 28 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 29 | 30 | 31 | // Override theme settings (see ../template/settings.scss) 32 | $mainColor: #333; 33 | $headingColor: #333; 34 | $headingTextShadow: none; 35 | $backgroundColor: #f7f3de; 36 | $linkColor: #8b743d; 37 | $linkColorHover: lighten( $linkColor, 20% ); 38 | $selectionBackgroundColor: rgba(79, 64, 28, 0.99); 39 | $heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); 40 | 41 | // Background generator 42 | @mixin bodyBackground() { 43 | @include radial-gradient( rgba(247,242,211,1), rgba(255,255,255,1) ); 44 | } 45 | 46 | 47 | 48 | // Theme template ------------------------------ 49 | @import "../template/theme"; 50 | // --------------------------------------------- -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/default.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Default theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | 15 | // Include theme-specific fonts 16 | @font-face { 17 | font-family: 'League Gothic'; 18 | src: url('../../lib/font/league_gothic-webfont.eot'); 19 | src: url('../../lib/font/league_gothic-webfont.eot?#iefix') format('embedded-opentype'), 20 | url('../../lib/font/league_gothic-webfont.woff') format('woff'), 21 | url('../../lib/font/league_gothic-webfont.ttf') format('truetype'), 22 | url('../../lib/font/league_gothic-webfont.svg#LeagueGothicRegular') format('svg'); 23 | 24 | font-weight: normal; 25 | font-style: normal; 26 | } 27 | 28 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 29 | 30 | // Override theme settings (see ../template/settings.scss) 31 | $heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); 32 | 33 | // Background generator 34 | @mixin bodyBackground() { 35 | @include radial-gradient( rgba(28,30,32,1), rgba(85,90,95,1) ); 36 | } 37 | 38 | 39 | 40 | // Theme template ------------------------------ 41 | @import "../template/theme"; 42 | // --------------------------------------------- -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/moon.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Dark theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @font-face { 16 | font-family: 'League Gothic'; 17 | src: url('../../lib/font/league_gothic-webfont.eot'); 18 | src: url('../../lib/font/league_gothic-webfont.eot?#iefix') format('embedded-opentype'), 19 | url('../../lib/font/league_gothic-webfont.woff') format('woff'), 20 | url('../../lib/font/league_gothic-webfont.ttf') format('truetype'), 21 | url('../../lib/font/league_gothic-webfont.svg#LeagueGothicRegular') format('svg'); 22 | 23 | font-weight: normal; 24 | font-style: normal; 25 | } 26 | 27 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 28 | 29 | /** 30 | * Solarized colors by Ethan Schoonover 31 | */ 32 | html * { 33 | color-profile: sRGB; 34 | rendering-intent: auto; 35 | } 36 | 37 | // Solarized colors 38 | $base03: #002b36; 39 | $base02: #073642; 40 | $base01: #586e75; 41 | $base00: #657b83; 42 | $base0: #839496; 43 | $base1: #93a1a1; 44 | $base2: #eee8d5; 45 | $base3: #fdf6e3; 46 | $yellow: #b58900; 47 | $orange: #cb4b16; 48 | $red: #dc322f; 49 | $magenta: #d33682; 50 | $violet: #6c71c4; 51 | $blue: #268bd2; 52 | $cyan: #2aa198; 53 | $green: #859900; 54 | 55 | // Override theme settings (see ../template/settings.scss) 56 | $mainColor: $base1; 57 | $headingColor: $base2; 58 | $headingTextShadow: none; 59 | $backgroundColor: $base03; 60 | $linkColor: $blue; 61 | $linkColorHover: lighten( $linkColor, 20% ); 62 | $selectionBackgroundColor: $magenta; 63 | 64 | 65 | 66 | // Theme template ------------------------------ 67 | @import "../template/theme"; 68 | // --------------------------------------------- 69 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/night.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Black theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(https://fonts.googleapis.com/css?family=Montserrat:700); 16 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic); 17 | 18 | 19 | // Override theme settings (see ../template/settings.scss) 20 | $backgroundColor: #111; 21 | 22 | $mainFont: 'Open Sans', sans-serif; 23 | $linkColor: #e7ad52; 24 | $linkColorHover: lighten( $linkColor, 20% ); 25 | $headingFont: 'Montserrat', Impact, sans-serif; 26 | $headingTextShadow: none; 27 | $headingLetterSpacing: -0.03em; 28 | $headingTextTransform: none; 29 | $selectionBackgroundColor: #e7ad52; 30 | $mainFontSize: 30px; 31 | 32 | 33 | // Theme template ------------------------------ 34 | @import "../template/theme"; 35 | // --------------------------------------------- -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/serif.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple theme for reveal.js presentations, similar 3 | * to the default theme. The accent color is brown. 4 | * 5 | * This theme is Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed. 6 | */ 7 | 8 | 9 | // Default mixins and settings ----------------- 10 | @import "../template/mixins"; 11 | @import "../template/settings"; 12 | // --------------------------------------------- 13 | 14 | 15 | 16 | // Override theme settings (see ../template/settings.scss) 17 | $mainFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 18 | $mainColor: #000; 19 | $headingFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 20 | $headingColor: #383D3D; 21 | $headingTextShadow: none; 22 | $headingTextTransform: none; 23 | $backgroundColor: #F0F1EB; 24 | $linkColor: #51483D; 25 | $linkColorHover: lighten( $linkColor, 20% ); 26 | $selectionBackgroundColor: #26351C; 27 | 28 | .reveal a:not(.image) { 29 | line-height: 1.3em; 30 | } 31 | 32 | 33 | // Theme template ------------------------------ 34 | @import "../template/theme"; 35 | // --------------------------------------------- 36 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/simple.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple theme for reveal.js presentations, similar 3 | * to the default theme. The accent color is darkblue. 4 | * 5 | * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. 6 | * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 7 | */ 8 | 9 | 10 | // Default mixins and settings ----------------- 11 | @import "../template/mixins"; 12 | @import "../template/settings"; 13 | // --------------------------------------------- 14 | 15 | 16 | 17 | // Include theme-specific fonts 18 | @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); 19 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 20 | 21 | 22 | // Override theme settings (see ../template/settings.scss) 23 | $mainFont: 'Lato', sans-serif; 24 | $mainColor: #000; 25 | $headingFont: 'News Cycle', Impact, sans-serif; 26 | $headingColor: #000; 27 | $headingTextShadow: none; 28 | $headingTextTransform: none; 29 | $backgroundColor: #fff; 30 | $linkColor: #00008B; 31 | $linkColorHover: lighten( $linkColor, 20% ); 32 | $selectionBackgroundColor: rgba(0, 0, 0, 0.99); 33 | 34 | 35 | 36 | // Theme template ------------------------------ 37 | @import "../template/theme"; 38 | // --------------------------------------------- -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/sky.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Sky theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | 15 | // Include theme-specific fonts 16 | @import url(https://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic); 17 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700); 18 | 19 | 20 | // Override theme settings (see ../template/settings.scss) 21 | $mainFont: 'Open Sans', sans-serif; 22 | $mainColor: #333; 23 | $headingFont: 'Quicksand', sans-serif; 24 | $headingColor: #333; 25 | $headingLetterSpacing: -0.08em; 26 | $headingTextShadow: none; 27 | $backgroundColor: #f7fbfc; 28 | $linkColor: #3b759e; 29 | $linkColorHover: lighten( $linkColor, 20% ); 30 | $selectionBackgroundColor: #134674; 31 | 32 | // Fix links so they are not cut off 33 | .reveal a:not(.image) { 34 | line-height: 1.3em; 35 | } 36 | 37 | // Background generator 38 | @mixin bodyBackground() { 39 | @include radial-gradient( #add9e4, #f7fbfc ); 40 | } 41 | 42 | 43 | 44 | // Theme template ------------------------------ 45 | @import "../template/theme"; 46 | // --------------------------------------------- 47 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/source/solarized.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Light theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @font-face { 16 | font-family: 'League Gothic'; 17 | src: url('../../lib/font/league_gothic-webfont.eot'); 18 | src: url('../../lib/font/league_gothic-webfont.eot?#iefix') format('embedded-opentype'), 19 | url('../../lib/font/league_gothic-webfont.woff') format('woff'), 20 | url('../../lib/font/league_gothic-webfont.ttf') format('truetype'), 21 | url('../../lib/font/league_gothic-webfont.svg#LeagueGothicRegular') format('svg'); 22 | 23 | font-weight: normal; 24 | font-style: normal; 25 | } 26 | 27 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 28 | 29 | 30 | /** 31 | * Solarized colors by Ethan Schoonover 32 | */ 33 | html * { 34 | color-profile: sRGB; 35 | rendering-intent: auto; 36 | } 37 | 38 | // Solarized colors 39 | $base03: #002b36; 40 | $base02: #073642; 41 | $base01: #586e75; 42 | $base00: #657b83; 43 | $base0: #839496; 44 | $base1: #93a1a1; 45 | $base2: #eee8d5; 46 | $base3: #fdf6e3; 47 | $yellow: #b58900; 48 | $orange: #cb4b16; 49 | $red: #dc322f; 50 | $magenta: #d33682; 51 | $violet: #6c71c4; 52 | $blue: #268bd2; 53 | $cyan: #2aa198; 54 | $green: #859900; 55 | 56 | // Override theme settings (see ../template/settings.scss) 57 | $mainColor: $base00; 58 | $headingColor: $base01; 59 | $headingTextShadow: none; 60 | $backgroundColor: $base3; 61 | $linkColor: $blue; 62 | $linkColorHover: lighten( $linkColor, 20% ); 63 | $selectionBackgroundColor: $magenta; 64 | 65 | // Background generator 66 | // @mixin bodyBackground() { 67 | // @include radial-gradient( rgba($base3,1), rgba(lighten($base3, 20%),1) ); 68 | // } 69 | 70 | 71 | 72 | // Theme template ------------------------------ 73 | @import "../template/theme"; 74 | // --------------------------------------------- 75 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/template/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin vertical-gradient( $top, $bottom ) { 2 | background: $top; 3 | background: -moz-linear-gradient( top, $top 0%, $bottom 100% ); 4 | background: -webkit-gradient( linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom) ); 5 | background: -webkit-linear-gradient( top, $top 0%, $bottom 100% ); 6 | background: -o-linear-gradient( top, $top 0%, $bottom 100% ); 7 | background: -ms-linear-gradient( top, $top 0%, $bottom 100% ); 8 | background: linear-gradient( top, $top 0%, $bottom 100% ); 9 | } 10 | 11 | @mixin horizontal-gradient( $top, $bottom ) { 12 | background: $top; 13 | background: -moz-linear-gradient( left, $top 0%, $bottom 100% ); 14 | background: -webkit-gradient( linear, left top, right top, color-stop(0%,$top), color-stop(100%,$bottom) ); 15 | background: -webkit-linear-gradient( left, $top 0%, $bottom 100% ); 16 | background: -o-linear-gradient( left, $top 0%, $bottom 100% ); 17 | background: -ms-linear-gradient( left, $top 0%, $bottom 100% ); 18 | background: linear-gradient( left, $top 0%, $bottom 100% ); 19 | } 20 | 21 | @mixin radial-gradient( $outer, $inner, $type: circle ) { 22 | background: $outer; 23 | background: -moz-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 24 | background: -webkit-gradient( radial, center center, 0px, center center, 100%, color-stop(0%,$inner), color-stop(100%,$outer) ); 25 | background: -webkit-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 26 | background: -o-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 27 | background: -ms-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 28 | background: radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 29 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/template/settings.scss: -------------------------------------------------------------------------------- 1 | // Base settings for all themes that can optionally be 2 | // overridden by the super-theme 3 | 4 | // Background of the presentation 5 | $backgroundColor: #2b2b2b; 6 | 7 | // Primary/body text 8 | $mainFont: 'Lato', sans-serif; 9 | $mainFontSize: 36px; 10 | $mainColor: #eee; 11 | 12 | // Headings 13 | $headingMargin: 0 0 20px 0; 14 | $headingFont: 'League Gothic', Impact, sans-serif; 15 | $headingColor: #eee; 16 | $headingLineHeight: 0.9em; 17 | $headingLetterSpacing: 0.02em; 18 | $headingTextTransform: uppercase; 19 | $headingTextShadow: 0px 0px 6px rgba(0,0,0,0.2); 20 | $heading1TextShadow: $headingTextShadow; 21 | 22 | // Links and actions 23 | $linkColor: #13DAEC; 24 | $linkColorHover: lighten( $linkColor, 20% ); 25 | 26 | // Text selection 27 | $selectionBackgroundColor: #FF5E99; 28 | $selectionColor: #fff; 29 | 30 | // Generates the presentation background, can be overridden 31 | // to return a background image or gradient 32 | @mixin bodyBackground() { 33 | background: $backgroundColor; 34 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/css/theme/template/theme.scss: -------------------------------------------------------------------------------- 1 | // Base theme template for reveal.js 2 | 3 | /********************************************* 4 | * GLOBAL STYLES 5 | *********************************************/ 6 | 7 | body { 8 | @include bodyBackground(); 9 | background-color: $backgroundColor; 10 | } 11 | 12 | .reveal { 13 | font-family: $mainFont; 14 | font-size: $mainFontSize; 15 | font-weight: 200; 16 | letter-spacing: -0.02em; 17 | color: $mainColor; 18 | } 19 | 20 | ::selection { 21 | color: $selectionColor; 22 | background: $selectionBackgroundColor; 23 | text-shadow: none; 24 | } 25 | 26 | /********************************************* 27 | * HEADERS 28 | *********************************************/ 29 | 30 | .reveal h1, 31 | .reveal h2, 32 | .reveal h3, 33 | .reveal h4, 34 | .reveal h5, 35 | .reveal h6 { 36 | margin: $headingMargin; 37 | color: $headingColor; 38 | 39 | font-family: $headingFont; 40 | line-height: $headingLineHeight; 41 | letter-spacing: $headingLetterSpacing; 42 | 43 | text-transform: $headingTextTransform; 44 | text-shadow: $headingTextShadow; 45 | } 46 | 47 | .reveal h1 { 48 | text-shadow: $heading1TextShadow; 49 | } 50 | 51 | 52 | /********************************************* 53 | * LINKS 54 | *********************************************/ 55 | 56 | .reveal a:not(.image) { 57 | color: $linkColor; 58 | text-decoration: none; 59 | 60 | -webkit-transition: color .15s ease; 61 | -moz-transition: color .15s ease; 62 | -ms-transition: color .15s ease; 63 | -o-transition: color .15s ease; 64 | transition: color .15s ease; 65 | } 66 | .reveal a:not(.image):hover { 67 | color: $linkColorHover; 68 | 69 | text-shadow: none; 70 | border: none; 71 | } 72 | 73 | .reveal .roll span:after { 74 | color: #fff; 75 | background: darken( $linkColor, 15% ); 76 | } 77 | 78 | 79 | /********************************************* 80 | * IMAGES 81 | *********************************************/ 82 | 83 | .reveal section img { 84 | margin: 15px 0px; 85 | background: rgba(255,255,255,0.12); 86 | border: 4px solid $mainColor; 87 | 88 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); 89 | 90 | -webkit-transition: all .2s linear; 91 | -moz-transition: all .2s linear; 92 | -ms-transition: all .2s linear; 93 | -o-transition: all .2s linear; 94 | transition: all .2s linear; 95 | } 96 | 97 | .reveal a:hover img { 98 | background: rgba(255,255,255,0.2); 99 | border-color: $linkColor; 100 | 101 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); 102 | } 103 | 104 | 105 | /********************************************* 106 | * NAVIGATION CONTROLS 107 | *********************************************/ 108 | 109 | .reveal .controls div.navigate-left, 110 | .reveal .controls div.navigate-left.enabled { 111 | border-right-color: $linkColor; 112 | } 113 | 114 | .reveal .controls div.navigate-right, 115 | .reveal .controls div.navigate-right.enabled { 116 | border-left-color: $linkColor; 117 | } 118 | 119 | .reveal .controls div.navigate-up, 120 | .reveal .controls div.navigate-up.enabled { 121 | border-bottom-color: $linkColor; 122 | } 123 | 124 | .reveal .controls div.navigate-down, 125 | .reveal .controls div.navigate-down.enabled { 126 | border-top-color: $linkColor; 127 | } 128 | 129 | .reveal .controls div.navigate-left.enabled:hover { 130 | border-right-color: $linkColorHover; 131 | } 132 | 133 | .reveal .controls div.navigate-right.enabled:hover { 134 | border-left-color: $linkColorHover; 135 | } 136 | 137 | .reveal .controls div.navigate-up.enabled:hover { 138 | border-bottom-color: $linkColorHover; 139 | } 140 | 141 | .reveal .controls div.navigate-down.enabled:hover { 142 | border-top-color: $linkColorHover; 143 | } 144 | 145 | 146 | /********************************************* 147 | * PROGRESS BAR 148 | *********************************************/ 149 | 150 | .reveal .progress { 151 | background: rgba(0,0,0,0.2); 152 | } 153 | .reveal .progress span { 154 | background: $linkColor; 155 | 156 | -webkit-transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); 157 | -moz-transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); 158 | -ms-transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); 159 | -o-transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); 160 | transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); 161 | } 162 | 163 | 164 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/img/avengers2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/slides/img/avengers2.gif -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/img/batman.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/slides/img/batman.gif -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/img/kevin_bacon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/slides/img/kevin_bacon.gif -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/lib/css/zenburn.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov 4 | based on dark.css by Ivan Sagalaev 5 | 6 | */ 7 | 8 | pre code { 9 | display: block; padding: 0.5em; 10 | background: #3F3F3F; 11 | color: #DCDCDC; 12 | } 13 | 14 | pre .keyword, 15 | pre .tag, 16 | pre .django .tag, 17 | pre .django .keyword, 18 | pre .css .class, 19 | pre .css .id, 20 | pre .lisp .title { 21 | color: #E3CEAB; 22 | } 23 | 24 | pre .django .template_tag, 25 | pre .django .variable, 26 | pre .django .filter .argument { 27 | color: #DCDCDC; 28 | } 29 | 30 | pre .number, 31 | pre .date { 32 | color: #8CD0D3; 33 | } 34 | 35 | pre .dos .envvar, 36 | pre .dos .stream, 37 | pre .variable, 38 | pre .apache .sqbracket { 39 | color: #EFDCBC; 40 | } 41 | 42 | pre .dos .flow, 43 | pre .diff .change, 44 | pre .python .exception, 45 | pre .python .built_in, 46 | pre .literal, 47 | pre .tex .special { 48 | color: #EFEFAF; 49 | } 50 | 51 | pre .diff .chunk, 52 | pre .ruby .subst { 53 | color: #8F8F8F; 54 | } 55 | 56 | pre .dos .keyword, 57 | pre .python .decorator, 58 | pre .class .title, 59 | pre .haskell .label, 60 | pre .function .title, 61 | pre .ini .title, 62 | pre .diff .header, 63 | pre .ruby .class .parent, 64 | pre .apache .tag, 65 | pre .nginx .built_in, 66 | pre .tex .command, 67 | pre .input_number { 68 | color: #efef8f; 69 | } 70 | 71 | pre .dos .winutils, 72 | pre .ruby .symbol, 73 | pre .ruby .symbol .string, 74 | pre .ruby .symbol .keyword, 75 | pre .ruby .symbol .keymethods, 76 | pre .ruby .string, 77 | pre .ruby .instancevar { 78 | color: #DCA3A3; 79 | } 80 | 81 | pre .diff .deletion, 82 | pre .string, 83 | pre .tag .value, 84 | pre .preprocessor, 85 | pre .built_in, 86 | pre .sql .aggregate, 87 | pre .javadoc, 88 | pre .smalltalk .class, 89 | pre .smalltalk .localvars, 90 | pre .smalltalk .array, 91 | pre .css .rules .value, 92 | pre .attr_selector, 93 | pre .pseudo, 94 | pre .apache .cbracket, 95 | pre .tex .formula { 96 | color: #CC9393; 97 | } 98 | 99 | pre .shebang, 100 | pre .diff .addition, 101 | pre .comment, 102 | pre .java .annotation, 103 | pre .template_comment, 104 | pre .pi, 105 | pre .doctype { 106 | color: #7F9F7F; 107 | } 108 | 109 | pre .xml .css, 110 | pre .xml .javascript, 111 | pre .xml .vbscript, 112 | pre .tex .formula { 113 | opacity: 0.5; 114 | } 115 | 116 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/lib/font/league_gothic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/slides/lib/font/league_gothic-webfont.eot -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/lib/font/league_gothic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/slides/lib/font/league_gothic-webfont.ttf -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/lib/font/league_gothic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/slides/lib/font/league_gothic-webfont.woff -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/lib/font/league_gothic_license: -------------------------------------------------------------------------------- 1 | SIL Open Font License (OFL) 2 | http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL 3 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/lib/js/classList.js: -------------------------------------------------------------------------------- 1 | /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/ 2 | if(typeof document!=="undefined"&&!("classList" in document.createElement("a"))){(function(j){var a="classList",f="prototype",m=(j.HTMLElement||j.Element)[f],b=Object,k=String[f].trim||function(){return this.replace(/^\s+|\s+$/g,"")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p 3 | Copyright Tero Piirainen (tipiirai) 4 | License MIT / http://bit.ly/mit-license 5 | Version 0.96 6 | 7 | http://headjs.com 8 | */(function(a){function z(){d||(d=!0,s(e,function(a){p(a)}))}function y(c,d){var e=a.createElement("script");e.type="text/"+(c.type||"javascript"),e.src=c.src||c,e.async=!1,e.onreadystatechange=e.onload=function(){var a=e.readyState;!d.done&&(!a||/loaded|complete/.test(a))&&(d.done=!0,d())},(a.body||b).appendChild(e)}function x(a,b){if(a.state==o)return b&&b();if(a.state==n)return k.ready(a.name,b);if(a.state==m)return a.onpreload.push(function(){x(a,b)});a.state=n,y(a.url,function(){a.state=o,b&&b(),s(g[a.name],function(a){p(a)}),u()&&d&&s(g.ALL,function(a){p(a)})})}function w(a,b){a.state===undefined&&(a.state=m,a.onpreload=[],y({src:a.url,type:"cache"},function(){v(a)}))}function v(a){a.state=l,s(a.onpreload,function(a){a.call()})}function u(a){a=a||h;var b;for(var c in a){if(a.hasOwnProperty(c)&&a[c].state!=o)return!1;b=!0}return b}function t(a){return Object.prototype.toString.call(a)=="[object Function]"}function s(a,b){if(!!a){typeof a=="object"&&(a=[].slice.call(a));for(var c=0;c 2 | 3 | 4 | 5 | 6 | 7 | reveal.js - Markdown Demo 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 | 17 |
    18 | 19 | 20 |
    21 | 22 | 23 |
    24 | 34 |
    35 | 36 | 37 |
    38 | 52 |
    53 | 54 | 55 |
    56 | 67 |
    68 | 69 |
    70 |
    71 | 72 | 73 | 74 | 75 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/markdown/example.md: -------------------------------------------------------------------------------- 1 | # Markdown Demo 2 | 3 | 4 | 5 | ## External 1.1 6 | 7 | Content 1.1 8 | 9 | Note: This will only appear in the speaker notes window. 10 | 11 | 12 | ## External 1.2 13 | 14 | Content 1.2 15 | 16 | 17 | 18 | ## External 2 19 | 20 | Content 2.1 21 | 22 | 23 | 24 | ## External 3.1 25 | 26 | Content 3.1 27 | 28 | 29 | ## External 3.2 30 | 31 | Content 3.2 32 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/math/math.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A plugin which enables rendering of math equations inside 3 | * of reveal.js slides. Essentially a thin wrapper for MathJax. 4 | * 5 | * @author Hakim El Hattab 6 | */ 7 | var RevealMath = window.RevealMath || (function(){ 8 | 9 | var options = Reveal.getConfig().math || {}; 10 | options.mathjax = options.mathjax || 'http://cdn.mathjax.org/mathjax/latest/MathJax.js'; 11 | options.config = options.config || 'TeX-AMS_HTML-full'; 12 | 13 | loadScript( options.mathjax + '?config=' + options.config, function() { 14 | 15 | MathJax.Hub.Config({ 16 | messageStyle: 'none', 17 | tex2jax: { inlineMath: [['$','$'],['\\(','\\)']] }, 18 | skipStartupTypeset: true 19 | }); 20 | 21 | // Typeset followed by an immediate reveal.js layout since 22 | // the typesetting process could affect slide height 23 | MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub ] ); 24 | MathJax.Hub.Queue( Reveal.layout ); 25 | 26 | // Reprocess equations in slides when they turn visible 27 | Reveal.addEventListener( 'slidechanged', function( event ) { 28 | 29 | MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, event.currentSlide ] ); 30 | 31 | } ); 32 | 33 | } ); 34 | 35 | function loadScript( url, callback ) { 36 | 37 | var head = document.querySelector( 'head' ); 38 | var script = document.createElement( 'script' ); 39 | script.type = 'text/javascript'; 40 | script.src = url; 41 | 42 | // Wrapper for callback to make sure it only fires once 43 | var finish = function() { 44 | if( typeof callback === 'function' ) { 45 | callback.call(); 46 | callback = null; 47 | } 48 | } 49 | 50 | script.onload = finish; 51 | 52 | // IE 53 | script.onreadystatechange = function() { 54 | if ( this.readyState === 'loaded' ) { 55 | finish(); 56 | } 57 | } 58 | 59 | // Normal browsers 60 | head.appendChild( script ); 61 | 62 | } 63 | 64 | })(); 65 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/notes-server/client.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | // don't emit events from inside the previews themselves 3 | if ( window.location.search.match( /receiver/gi ) ) { return; } 4 | 5 | var socket = io.connect(window.location.origin); 6 | var socketId = Math.random().toString().slice(2); 7 | 8 | console.log('View slide notes at ' + window.location.origin + '/notes/' + socketId); 9 | window.open(window.location.origin + '/notes/' + socketId, 'notes-' + socketId); 10 | 11 | // Fires when a fragment is shown 12 | Reveal.addEventListener( 'fragmentshown', function( event ) { 13 | var fragmentData = { 14 | fragment : 'next', 15 | socketId : socketId 16 | }; 17 | socket.emit('fragmentchanged', fragmentData); 18 | } ); 19 | 20 | // Fires when a fragment is hidden 21 | Reveal.addEventListener( 'fragmenthidden', function( event ) { 22 | var fragmentData = { 23 | fragment : 'previous', 24 | socketId : socketId 25 | }; 26 | socket.emit('fragmentchanged', fragmentData); 27 | } ); 28 | 29 | // Fires when slide is changed 30 | Reveal.addEventListener( 'slidechanged', function( event ) { 31 | var nextindexh; 32 | var nextindexv; 33 | var slideElement = event.currentSlide; 34 | 35 | if (slideElement.nextElementSibling && slideElement.parentNode.nodeName == 'SECTION') { 36 | nextindexh = event.indexh; 37 | nextindexv = event.indexv + 1; 38 | } else { 39 | nextindexh = event.indexh + 1; 40 | nextindexv = 0; 41 | } 42 | 43 | var notes = slideElement.querySelector('aside.notes'); 44 | var slideData = { 45 | notes : notes ? notes.innerHTML : '', 46 | indexh : event.indexh, 47 | indexv : event.indexv, 48 | nextindexh : nextindexh, 49 | nextindexv : nextindexv, 50 | socketId : socketId, 51 | markdown : notes ? typeof notes.getAttribute('data-markdown') === 'string' : false 52 | 53 | }; 54 | 55 | socket.emit('slidechanged', slideData); 56 | } ); 57 | }()); 58 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/notes-server/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var fs = require('fs'); 3 | var io = require('socket.io'); 4 | var _ = require('underscore'); 5 | var Mustache = require('mustache'); 6 | 7 | var app = express.createServer(); 8 | var staticDir = express.static; 9 | 10 | io = io.listen(app); 11 | 12 | var opts = { 13 | port : 1947, 14 | baseDir : __dirname + '/../../' 15 | }; 16 | 17 | io.sockets.on('connection', function(socket) { 18 | socket.on('slidechanged', function(slideData) { 19 | socket.broadcast.emit('slidedata', slideData); 20 | }); 21 | socket.on('fragmentchanged', function(fragmentData) { 22 | socket.broadcast.emit('fragmentdata', fragmentData); 23 | }); 24 | }); 25 | 26 | app.configure(function() { 27 | [ 'css', 'js', 'images', 'plugin', 'lib' ].forEach(function(dir) { 28 | app.use('/' + dir, staticDir(opts.baseDir + dir)); 29 | }); 30 | }); 31 | 32 | app.get("/", function(req, res) { 33 | res.writeHead(200, {'Content-Type': 'text/html'}); 34 | fs.createReadStream(opts.baseDir + '/index.html').pipe(res); 35 | }); 36 | 37 | app.get("/notes/:socketId", function(req, res) { 38 | 39 | fs.readFile(opts.baseDir + 'plugin/notes-server/notes.html', function(err, data) { 40 | res.send(Mustache.to_html(data.toString(), { 41 | socketId : req.params.socketId 42 | })); 43 | }); 44 | // fs.createReadStream(opts.baseDir + 'notes-server/notes.html').pipe(res); 45 | }); 46 | 47 | // Actually listen 48 | app.listen(opts.port || null); 49 | 50 | var brown = '\033[33m', 51 | green = '\033[32m', 52 | reset = '\033[0m'; 53 | 54 | var slidesLocation = "http://localhost" + ( opts.port ? ( ':' + opts.port ) : '' ); 55 | 56 | console.log( brown + "reveal.js - Speaker Notes" + reset ); 57 | console.log( "1. Open the slides at " + green + slidesLocation + reset ); 58 | console.log( "2. Click on the link your JS console to go to the notes page" ); 59 | console.log( "3. Advance through your slides and your notes will advance automatically" ); 60 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/notes-server/notes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | reveal.js - Slide Notes 9 | 10 | 90 | 91 | 92 | 93 | 94 |
    95 | 96 |
    97 | 98 |
    99 | 100 | UPCOMING: 101 |
    102 |
    103 | 104 | 105 | 106 | 107 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/notes/notes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handles opening of and synchronization with the reveal.js 3 | * notes window. 4 | */ 5 | var RevealNotes = (function() { 6 | 7 | function openNotes() { 8 | var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path 9 | jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path 10 | var notesPopup = window.open( jsFileLocation + 'notes.html', 'reveal.js - Notes', 'width=1120,height=850' ); 11 | 12 | // Fires when slide is changed 13 | Reveal.addEventListener( 'slidechanged', post ); 14 | 15 | // Fires when a fragment is shown 16 | Reveal.addEventListener( 'fragmentshown', post ); 17 | 18 | // Fires when a fragment is hidden 19 | Reveal.addEventListener( 'fragmenthidden', post ); 20 | 21 | /** 22 | * Posts the current slide data to the notes window 23 | */ 24 | function post() { 25 | var slideElement = Reveal.getCurrentSlide(), 26 | slideIndices = Reveal.getIndices(), 27 | messageData; 28 | 29 | var notes = slideElement.querySelector( 'aside.notes' ), 30 | nextindexh, 31 | nextindexv; 32 | 33 | if( slideElement.nextElementSibling && slideElement.parentNode.nodeName == 'SECTION' ) { 34 | nextindexh = slideIndices.h; 35 | nextindexv = slideIndices.v + 1; 36 | } else { 37 | nextindexh = slideIndices.h + 1; 38 | nextindexv = 0; 39 | } 40 | 41 | messageData = { 42 | notes : notes ? notes.innerHTML : '', 43 | indexh : slideIndices.h, 44 | indexv : slideIndices.v, 45 | indexf : slideIndices.f, 46 | nextindexh : nextindexh, 47 | nextindexv : nextindexv, 48 | markdown : notes ? typeof notes.getAttribute( 'data-markdown' ) === 'string' : false 49 | }; 50 | 51 | notesPopup.postMessage( JSON.stringify( messageData ), '*' ); 52 | } 53 | 54 | // Navigate to the current slide when the notes are loaded 55 | notesPopup.addEventListener( 'load', function( event ) { 56 | post(); 57 | }, false ); 58 | } 59 | 60 | // If the there's a 'notes' query set, open directly 61 | if( window.location.search.match( /(\?|\&)notes/gi ) !== null ) { 62 | openNotes(); 63 | } 64 | 65 | // Open the notes when the 's' key is hit 66 | document.addEventListener( 'keydown', function( event ) { 67 | // Disregard the event if the target is editable or a 68 | // modifier is present 69 | if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return; 70 | 71 | if( event.keyCode === 83 ) { 72 | event.preventDefault(); 73 | openNotes(); 74 | } 75 | }, false ); 76 | 77 | return { open: openNotes }; 78 | })(); 79 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/postmessage/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 |
    11 | 12 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/postmessage/postmessage.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | simple postmessage plugin 4 | 5 | Useful when a reveal slideshow is inside an iframe. 6 | It allows to call reveal methods from outside. 7 | 8 | Example: 9 | var reveal = window.frames[0]; 10 | 11 | // Reveal.prev(); 12 | reveal.postMessage(JSON.stringify({method: 'prev', args: []}), '*'); 13 | // Reveal.next(); 14 | reveal.postMessage(JSON.stringify({method: 'next', args: []}), '*'); 15 | // Reveal.slide(2, 2); 16 | reveal.postMessage(JSON.stringify({method: 'slide', args: [2,2]}), '*'); 17 | 18 | Add to the slideshow: 19 | 20 | dependencies: [ 21 | ... 22 | { src: 'plugin/postmessage/postmessage.js', async: true, condition: function() { return !!document.body.classList; } } 23 | ] 24 | 25 | */ 26 | 27 | (function (){ 28 | 29 | window.addEventListener( "message", function ( event ) { 30 | var data = JSON.parse( event.data ), 31 | method = data.method, 32 | args = data.args; 33 | 34 | if( typeof Reveal[method] === 'function' ) { 35 | Reveal[method].apply( Reveal, data.args ); 36 | } 37 | }, false); 38 | 39 | }()); 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/print-pdf/print-pdf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * phantomjs script for printing presentations to PDF. 3 | * 4 | * Example: 5 | * phantomjs print-pdf.js "http://lab.hakim.se/reveal-js?print-pdf" reveal-demo.pdf 6 | * 7 | * By Manuel Bieh (https://github.com/manuelbieh) 8 | */ 9 | 10 | // html2pdf.js 11 | var page = new WebPage(); 12 | var system = require( 'system' ); 13 | 14 | page.viewportSize = { 15 | width: 1024, 16 | height: 768 17 | }; 18 | 19 | page.paperSize = { 20 | format: 'letter', 21 | orientation: 'landscape', 22 | margin: { 23 | left: '0', 24 | right: '0', 25 | top: '0', 26 | bottom: '0' 27 | } 28 | }; 29 | 30 | var revealFile = system.args[1] || 'index.html?print-pdf'; 31 | var slideFile = system.args[2] || 'slides.pdf'; 32 | 33 | if( slideFile.match( /\.pdf$/gi ) === null ) { 34 | slideFile += '.pdf'; 35 | } 36 | 37 | console.log( 'Printing PDF...' ); 38 | 39 | page.open( revealFile, function( status ) { 40 | console.log( 'Printed succesfully' ); 41 | page.render( slideFile ); 42 | phantom.exit(); 43 | } ); 44 | 45 | -------------------------------------------------------------------------------- /previous_presentations/dag2/slides/plugin/remotes/remotes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Touch-based remote controller for your presentation courtesy 3 | * of the folks at http://remotes.io 4 | */ 5 | 6 | (function(window){ 7 | 8 | /** 9 | * Detects if we are dealing with a touch enabled device (with some false positives) 10 | * Borrowed from modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touch.js 11 | */ 12 | var hasTouch = (function(){ 13 | return ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch; 14 | })(); 15 | 16 | /** 17 | * Detects if notes are enable and the current page is opened inside an /iframe 18 | * this prevents loading Remotes.io several times 19 | */ 20 | var remotesAndIsNotes = (function(){ 21 | return !(window.RevealNotes && self == top); 22 | })(); 23 | 24 | if(!hasTouch && !remotesAndIsNotes){ 25 | head.ready( 'remotes.ne.min.js', function() { 26 | new Remotes("preview") 27 | .on("swipe-left", function(e){ Reveal.right(); }) 28 | .on("swipe-right", function(e){ Reveal.left(); }) 29 | .on("swipe-up", function(e){ Reveal.down(); }) 30 | .on("swipe-down", function(e){ Reveal.up(); }) 31 | .on("tap", function(e){ Reveal.next(); }) 32 | .on("zoom-out", function(e){ Reveal.toggleOverview(true); }) 33 | .on("zoom-in", function(e){ Reveal.toggleOverview(false); }) 34 | ; 35 | } ); 36 | 37 | head.js('https://raw.github.com/Remotes/Remotes/master/dist/remotes.ne.min.js'); 38 | } 39 | })(window); -------------------------------------------------------------------------------- /previous_presentations/dag2/small-case/api.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | 3 | var random = function (min, max) { 4 | return (Math.random() * (max - min)) + min; 5 | }; 6 | 7 | var recordCollection = [ 8 | { 9 | "album": "Crystal Logic", 10 | "artist": "Manilla Road", 11 | "year": "1983", 12 | "genre": "Epic Heavy/Power Metal" 13 | }, 14 | { 15 | "album": "Funeral Circle", 16 | "artist": "Funeral Circle", 17 | "year": "2013", 18 | "genre": "Doom Metal" 19 | } 20 | ]; 21 | 22 | module.exports.records = function () { 23 | var deferred = Q.defer(); 24 | 25 | setTimeout(function () { 26 | if(Math.random() < 0.15) { 27 | deferred.reject(new Error('Whops, there was a communication problem')); 28 | } else { 29 | deferred.resolve(recordCollection); 30 | } 31 | }, random(100, 1000)); 32 | 33 | return deferred.promise; 34 | }; 35 | 36 | module.exports.newRecord = function (record) { 37 | var deferred = Q.defer(); 38 | 39 | setTimeout(function () { 40 | if(Math.random() < 0.15) { 41 | deferred.reject(new Error('Whops, there was a communication problem')); 42 | } else { 43 | deferred.resolve(record); 44 | } 45 | }, random(100, 1000)); 46 | 47 | return deferred.promise; 48 | } -------------------------------------------------------------------------------- /previous_presentations/dag2/small-case/app.js: -------------------------------------------------------------------------------- 1 | var Bacon = require('baconjs'); 2 | var $ = require('jquery'); 3 | var _ = require('lodash'); 4 | 5 | var api = require('./api.js'); 6 | 7 | /* 8 | HELPER FUNCTIONS 9 | 10 | See their respective comments for clarifications 11 | */ 12 | 13 | //Takes a record and produces a html string 14 | var renderRecord = function (record) { 15 | return '
  1. ' + 16 | '

    ' + record.album + '

    ' + 17 | '

    Artist: ' + record.artist + '

    ' + 18 | '

    Year: ' + record.year + '

    ' + 19 | '

    Genre: ' + record.genre + '

    ' + 20 | '
  2. '; 21 | }; 22 | 23 | //Takes a recor collection and produces a html string 24 | var renderRecords = function(records) { 25 | return _.reduce(records, function(acc, record) { 26 | return acc + renderRecord(record); 27 | }, ''); 28 | }; 29 | 30 | //Takes a regex pattern as a string and returns a function that tests a value 31 | var testRegex = function(pattern) { 32 | return function(value) { 33 | if(!value) return false; 34 | return new RegExp(pattern, 'i').test(value); 35 | }; 36 | }; 37 | 38 | //Takes a record collection and a filter 39 | //Returns a filtered collection with regex matching on all fields of all records 40 | var filterRecords = function(records, recordFilter) { 41 | return _.filter(records, function(record) { 42 | return _(record).values().any(testRegex(recordFilter)); 43 | }); 44 | }; 45 | 46 | //Takes an input-value and a valid-predicate and produces the approperiate icon 47 | var mapToInputIcon = function(input, valid) { 48 | if(!input) return '*'; 49 | if(!valid) return '!'; 50 | return '✔'; 51 | }; 52 | 53 | //Resets the form by setting all values to '' and triggering keyup 54 | var resetForm = function() { 55 | $('#add-record input').val('').trigger('keyup'); 56 | }; 57 | 58 | /* 59 | THIS IS WHERE YOU IMPLEMENT STUFF 60 | */ 61 | 62 | //Make a convenience function to get properties from input fields 63 | var propertyFromInput = function(field) { 64 | }; 65 | 66 | //Define your initial sources 67 | var recordFilter; //The current value of the filter input 68 | 69 | var album = propertyFromInput($('#album')); 70 | var artist = propertyFromInput($('#artist')); 71 | var year = propertyFromInput($('#year')); 72 | var genre = propertyFromInput($('#genre')); 73 | 74 | var add; //A stream of clicks on the add button 75 | 76 | var records; //The result of a call to the API for record collection 77 | 78 | //Make a representation of a record model 79 | var record; 80 | 81 | //Get a stream of added records 82 | //Remember to use the API! 83 | var addedRecord; 84 | 85 | //Collect all added records in a list 86 | var addedRecords; 87 | 88 | //Make a representation of all added records and all exisiting records 89 | var allRecords; 90 | 91 | //Show a spinner when loading the record collection 92 | var showLoadingRecordsSpinner; 93 | 94 | //Show an error message when fetching records fails 95 | var showLoadingRecordsError; 96 | 97 | //Define the validity of the form inputs 98 | var validAlbum; //Valid if it has a value and album does not exist already 99 | var validArtist;//Always valid if it has a value 100 | var validYear; //Valid only if it has a value and is 4 digits 101 | var validGenre; //Always valid if it has a value 102 | 103 | //Assign the correct indicator to the form input for all inputs 104 | var albumIcon; 105 | 106 | var artistIcon; 107 | 108 | var yearIcon; 109 | 110 | var genreIcon; 111 | 112 | //Assign some indicator for the validity of the whole form 113 | var validRecord;//Only valid if all fields are valid 114 | 115 | //Show a spinner while waiting for a reply from the server when adding records 116 | //Remember the observable you defined a while back for addedRecord 117 | var showAddingRecordSpinner; 118 | 119 | //Show an error if the API replies with an error 120 | var showAddingRecordError; 121 | 122 | //Finally assign all the records to the DOM 123 | //Remember to use the recordfilter! 124 | var filteredAllRecords; -------------------------------------------------------------------------------- /previous_presentations/dag2/small-case/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FRP CRUD Case 6 | 7 | 8 | 9 |

    Welcome to my awesome record collection

    10 |

    A sample application for keeping track of records.

    11 |
    12 |
    13 |

    Add Record

    14 |
    15 | 16 |
    17 |
    18 | 19 | 20 | 21 |
    22 | 23 |
    24 | 25 | 26 | 27 |
    28 | 29 |
    30 | 31 | 32 | 33 |
    34 | 35 |
    36 | 37 | 38 | 39 |
    40 | 41 |
    42 | 43 |
    44 |
    45 |
    46 |
    47 |
    48 |

    Registered Records

    49 |
    50 | 51 |
    52 |
    53 | 54 |
    55 |
      56 |
      57 |
      58 |
      59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /previous_presentations/dag2/small-case/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "baconjs": "^0.7.22", 4 | "beefy": "^2.1.1", 5 | "ecstatic": "^0.5.4", 6 | "jquery": "^2.1.1", 7 | "lodash": "^2.4.1", 8 | "q": "^1.0.1" 9 | }, 10 | "scripts": { 11 | "start": "beefy app.js --index=index.html --open --live" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /previous_presentations/dag2/small-case/readme.md: -------------------------------------------------------------------------------- 1 | # Case: Making a simple Record Collection App 2 | 3 | Start the project by cloning the repo, change directory to `small-case`, 4 | and install dependencies: 5 | 6 | ``` 7 | npm install 8 | ``` 9 | 10 | 11 | ## Running project 12 | 13 | You only need to run one command, it will take care of everything and open the 14 | approperiate page in your browser. 15 | 16 | ``` 17 | npm start 18 | ``` 19 | 20 | 21 | ## Working on the case. 22 | 23 | The implementation should be done in [/app.js](./app.js). 24 | 25 | A mock API has been written for this case, and is located in 26 | [/api.js](./api.js). It has the following methods: 27 | 28 | - **records()** Returns a promise which resolves to the contents of the record collection. 29 | - **newRecord(record)** Returns a promise which resolves to the newly added record. 30 | 31 | Both methods can be rejected with an Error. 32 | 33 | ### Result 34 | 35 | The result should be a fully functional app for storing records in memory. 36 | 37 | - It should validate each field and the whole form 38 | - It should fetch the existing records 39 | - It should add new records to the existing records (in memory only) 40 | - It should show spinners for async tasks 41 | - It should display error-messages 42 | 43 | ![BaconChat](https://raw.githubusercontent.com/bekkopen/funksjonell-js/gh-pages/dag2/small-case/recordapp.png) 44 | -------------------------------------------------------------------------------- /previous_presentations/dag2/small-case/recordapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bekk/functional-js/4db2ef67f32c905952a5067f649de852d1e8ca20/previous_presentations/dag2/small-case/recordapp.png -------------------------------------------------------------------------------- /previous_presentations/dag2/small-case/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | body { 5 | font-family: 'sans-serif'; 6 | } 7 | 8 | form div:last-child { 9 | text-align: center; 10 | } 11 | 12 | label { 13 | display: inline-block; 14 | min-width: 15%; 15 | } 16 | 17 | .error { 18 | padding: 0.25em 1em; 19 | background: red; 20 | color: #000; 21 | width: 75%; 22 | border: 3px inset darkred; 23 | border-radius: 5px; 24 | } 25 | 26 | .add { 27 | width: 45%; 28 | margin-right: 5%; 29 | float: left; 30 | } 31 | 32 | .list { 33 | width: 50%; 34 | float: left; 35 | } 36 | 37 | .loader-small { 38 | height: 10px; 39 | width: 10px; 40 | border-radius: 20px; 41 | border: 3px solid #fff; 42 | border-left-color: transparent; 43 | border-top-color: #000; 44 | border-bottom-color: #000; 45 | border-right-color: transparent; 46 | margin-left: 5px; 47 | display: inline-block; 48 | animation: rotation 1s linear infinite; 49 | } 50 | 51 | .loader { 52 | position: relative; 53 | height: 50px; 54 | width: 50px; 55 | left: 25%; 56 | margin-top: 20px; 57 | border-radius: 75px; 58 | border: 3px solid #fff; 59 | border-left-color: transparent; 60 | border-top-color: #000; 61 | border-bottom-color: #000; 62 | border-right-color: transparent; 63 | animation: rotation 1s linear infinite; 64 | } 65 | 66 | @keyframes rotation { 67 | 0% { 68 | transform: rotate(0deg); 69 | } 70 | 71 | 50% { 72 | transform: rotate(180deg); 73 | } 74 | 75 | 100% { 76 | transform: rotate(360deg); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /scripts/components/codemirror-editor.js: -------------------------------------------------------------------------------- 1 | import component from './component'; 2 | import React from 'react'; 3 | 4 | import CodeMirror from 'codemirror'; 5 | import 'codemirror/mode/javascript/javascript'; 6 | 7 | import 'codemirror/addon/edit/closebrackets'; 8 | import 'codemirror/addon/edit/matchbrackets'; 9 | 10 | const throttledReplaceState = throttle(replaceStateValue, 2000); 11 | 12 | export default component([{ 13 | 14 | componentDidMount: function () { 15 | const isLarge = this.props.statics.isLarge; 16 | 17 | const options = { 18 | autoCloseBrackets: true, 19 | matchBrackets: true, 20 | lineNumbers: isLarge, 21 | lineWrapping: false, 22 | viewportMargin: Infinity, 23 | theme: 'base16-mocha-dark', 24 | tabSize: 2, 25 | extraKeys: { Tab } 26 | }; 27 | 28 | const onCodeMirrorChange = editor => { 29 | const source = editor.doc.getValue(); 30 | this.props.source.update(_ => source); 31 | 32 | if (isLarge) { 33 | throttledReplaceState(source); 34 | } 35 | }; 36 | 37 | this.editor = CodeMirror.fromTextArea(this.getDOMNode(), options); 38 | this.editor.on('change', onCodeMirrorChange); 39 | 40 | if (isLarge) { 41 | let initialCode = location.hash.replace(/^#/, ''); 42 | try { 43 | initialCode = decodeURIComponent(initialCode); 44 | } 45 | catch (ignore) { } 46 | const source = initialCode || this.props.source.deref(); 47 | this.editor.setValue(source); 48 | } 49 | }, 50 | 51 | shouldComponentUpdate: function () { 52 | return false; 53 | } 54 | 55 | }], function CodeMirrorEditor ({source}) { 56 | return ; 57 | }); 58 | 59 | function Tab (cm) { 60 | if (cm.somethingSelected()) { 61 | cm.indentSelection("add"); 62 | } else { 63 | cm.execCommand('insertSoftTab') 64 | } 65 | } 66 | 67 | function replaceStateValue (value) { 68 | history.replaceState(null, 'playground', '#' + encodeURIComponent(value)); 69 | } 70 | 71 | function throttle (fn, ms) { 72 | let timeout; 73 | return function () { 74 | const self = this, args = [].slice.call(arguments); 75 | if (timeout) { 76 | clearTimeout(timeout); 77 | timeout = undefined; 78 | } 79 | timeout = setTimeout(function () { 80 | fn.apply(self, args); 81 | }, ms); 82 | }; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /scripts/components/component.js: -------------------------------------------------------------------------------- 1 | var omniscient = require('omniscient'); 2 | 3 | const jsx = true; 4 | const component = omniscient.withDefaults({ jsx }); 5 | 6 | // component.debug(); 7 | 8 | export default component; 9 | -------------------------------------------------------------------------------- /scripts/components/editor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import omniscient from 'omniscient'; 3 | 4 | import component from './component'; 5 | import CodeMirrorEditor from './codemirror-editor'; 6 | import RunCode from './run-code'; 7 | 8 | export default component(function Editor ({ source }, { isLarge, timers }) { 9 | 10 | return
      11 |
      12 | 16 |
      17 |
      18 | 22 |
      23 |
      ; 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /scripts/components/run-result.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import component from './component'; 3 | 4 | export default component(function Result ({ stats, failures, errorResult }) { 5 | 6 | const tests = stats.get('tests'), 7 | passes = tests && stats.get('passes'), 8 | pending = tests && stats.get('pending'), 9 | failed = tests && stats.get('failures'); 10 | 11 | const passesSummary = passes 12 | ? {passes} of {tests} test{tests > 1 ? 's' : ''} passed 13 | : null; 14 | 15 | const pendingPrefix = (passes && pending) ? ', ' : ''; 16 | 17 | const pendingSummary = pending 18 | ? {pending} pending 19 | : null; 20 | 21 | const failedPrefix = failed 22 | ? (passes || pending) ? ', ' : '' 23 | : null; 24 | 25 | const failedSummary = failed 26 | ? (passes || pending) 27 | ? {failed} failed! 28 | : {failed} of {tests} test{tests > 1 ? 's' : ''} failed! 29 | : null; 30 | 31 | const testResults = failures.toArray().map(test => { 32 | const suiteTitle = test.parent ? test.parent.title : ''; 33 | return
      ✘ {suiteTitle} {test.title}
      {test.err.message}
      34 | }); 35 | 36 | const punctuation = !failed ? '.' : ''; 37 | 38 | const errors = errorResult.deref(); 39 | 40 | return
      41 | {tests 42 | ?
      {passesSummary}{pendingPrefix}{pendingSummary}{failedPrefix}{failedSummary}{punctuation}
      43 | : null} 44 | {tests 45 | ?
      {testResults}
      46 | : null } 47 | {errors 48 | ?
      {errors}
      49 | : null} 50 |
      ; 51 | }); 52 | 53 | 54 | -------------------------------------------------------------------------------- /scripts/entry.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import immstruct from 'immstruct'; 3 | 4 | import Editor from './components/editor'; 5 | 6 | const runnables = document.querySelectorAll('.editor'); 7 | for (let i = 0; i < runnables.length; i++) { 8 | const runnable = runnables[i]; 9 | 10 | const textarea = runnable.querySelector('textarea'); 11 | const source = textarea.value; 12 | runnable.removeChild(textarea); 13 | 14 | const isLarge = runnable.dataset.isLarge; 15 | createEditorRenderLoop(runnable, source, isLarge); 16 | } 17 | 18 | function createEditorRenderLoop (container, source, isLarge) { 19 | 20 | const data = immstruct({ source }); 21 | const timers = { intervals: [], timeouts: [] }; 22 | const render = () => 23 | React.render( 24 | , 27 | container); 28 | 29 | data.on('swap', () => render()); 30 | render(); 31 | } 32 | -------------------------------------------------------------------------------- /scripts/playground-reporter.js: -------------------------------------------------------------------------------- 1 | module.exports = PlaygroundReporter; 2 | 3 | function PlaygroundReporter (runner) { 4 | var self = this 5 | , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } 6 | , failures = this.failures = []; 7 | 8 | if (!runner) return; 9 | this.runner = runner; 10 | 11 | runner.stats = stats; 12 | 13 | runner.on('start', function () { 14 | stats.start = new Date; 15 | }); 16 | 17 | runner.on('suite', function (suite) { 18 | stats.suites = stats.suites || 0; 19 | suite.root || stats.suites++; 20 | }); 21 | 22 | runner.on('test end', function (test) { 23 | stats.tests = stats.tests || 0; 24 | stats.tests++; 25 | }); 26 | 27 | runner.on('pass', function (test) { 28 | stats.passes = stats.passes || 0; 29 | 30 | var medium = test.slow() / 2; 31 | test.speed = test.duration > test.slow() 32 | ? 'slow' 33 | : test.duration > medium 34 | ? 'medium' 35 | : 'fast'; 36 | 37 | stats.passes++; 38 | }); 39 | 40 | runner.on('fail', function (test, err) { 41 | stats.failures = stats.failures || 0; 42 | stats.failures++; 43 | test.err = err; 44 | failures.push(test); 45 | }); 46 | 47 | runner.on('end', function () { 48 | stats.end = new Date; 49 | stats.duration = new Date - stats.start; 50 | }); 51 | 52 | runner.on('pending', function () { 53 | stats.pending++; 54 | }); 55 | } 56 | 57 | PlaygroundReporter.prototype.done = function (failures, fn) { 58 | return fn(this, failures); 59 | }; 60 | -------------------------------------------------------------------------------- /scripts/vendor/codemirror-base16-mocha-dark.css: -------------------------------------------------------------------------------- 1 | /* 2 | * https://github.com/idleberg/base16-codemirror/blob/master/base16-mocha-dark.css 3 | * 4 | Name: Base16 Mocha Dark 5 | Author: Chris Kempson (http://chriskempson.com) 6 | CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) 7 | Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) 8 | */ 9 | 10 | .cm-s-base16-mocha-dark.CodeMirror {background: #3B3228; color: #e9e1dd;} 11 | .cm-s-base16-mocha-dark div.CodeMirror-selected {background: #534636 !important;} 12 | .cm-s-base16-mocha-dark .CodeMirror-gutters {background: #3B3228; border-right: 0px;} 13 | .cm-s-base16-mocha-dark .CodeMirror-linenumber {color: #7e705a;} 14 | .cm-s-base16-mocha-dark .CodeMirror-cursor {border-left: 1px solid #b8afad !important;} 15 | 16 | .cm-s-base16-mocha-dark span.cm-comment {color: #bb9584;} 17 | .cm-s-base16-mocha-dark span.cm-atom {color: #a89bb9;} 18 | .cm-s-base16-mocha-dark span.cm-number {color: #a89bb9;} 19 | 20 | .cm-s-base16-mocha-dark span.cm-property, .cm-s-base16-mocha-dark span.cm-attribute {color: #beb55b;} 21 | .cm-s-base16-mocha-dark span.cm-keyword {color: #cb6077;} 22 | .cm-s-base16-mocha-dark span.cm-string {color: #f4bc87;} 23 | 24 | .cm-s-base16-mocha-dark span.cm-variable {color: #beb55b;} 25 | .cm-s-base16-mocha-dark span.cm-variable-2 {color: #8ab3b5;} 26 | .cm-s-base16-mocha-dark span.cm-def {color: #d28b71;} 27 | .cm-s-base16-mocha-dark span.cm-error {background: #cb6077; color: #b8afad;} 28 | .cm-s-base16-mocha-dark span.cm-bracket {color: #e9e1dd;} 29 | .cm-s-base16-mocha-dark span.cm-tag {color: #cb6077;} 30 | .cm-s-base16-mocha-dark span.cm-link {color: #a89bb9;} 31 | 32 | .cm-s-base16-mocha-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} 33 | -------------------------------------------------------------------------------- /scripts/vendor/codemirror-kimbie-dark.css: -------------------------------------------------------------------------------- 1 | /* 2 | Name: Kimbie (dark) 3 | Author: Jan T. Sott 4 | License: Creative Commons Attribution-ShareAlike 4.0 Unported License 5 | URL: https://github.com/idleberg/Kimbie-CodeMirror 6 | */ 7 | 8 | .cm-s-kimbie-dark.CodeMirror {background: #141414; color: #e4c6a5;} 9 | .cm-s-kimbie-dark div.CodeMirror-selected {background: #5e452b !important;} 10 | .cm-s-kimbie-dark .CodeMirror-gutters {background: #141414; border-right: 0px;} 11 | .cm-s-kimbie-dark .CodeMirror-linenumber {color: #a57a4c;} 12 | .cm-s-kimbie-dark .CodeMirror-cursor {border-left: 1px solid #d6baad !important;} 13 | 14 | .cm-s-kimbie-dark span.cm-comment {color: #088649;} 15 | .cm-s-kimbie-dark span.cm-atom {color: #98676a;} 16 | .cm-s-kimbie-dark span.cm-number {color: #98676a;} 17 | 18 | .cm-s-kimbie-dark span.cm-property, .cm-s-kimbie-dark span.cm-attribute {color: #889b4a;} 19 | .cm-s-kimbie-dark span.cm-keyword {color: #dc3958;} 20 | .cm-s-kimbie-dark span.cm-string {color: #f06431;} 21 | 22 | .cm-s-kimbie-dark span.cm-variable {color: #889b4a;} 23 | .cm-s-kimbie-dark span.cm-variable-2 {color: #8ab1b0;} 24 | .cm-s-kimbie-dark span.cm-def {color: #f79a32;} 25 | .cm-s-kimbie-dark span.cm-error {background: #dc3958; color: #d6baad;} 26 | .cm-s-kimbie-dark span.cm-bracket {color: #e4c6a5;} 27 | .cm-s-kimbie-dark span.cm-tag {color: #dc3958;} 28 | .cm-s-kimbie-dark span.cm-link {color: #98676a;} 29 | 30 | .cm-s-kimbie-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} 31 | 32 | -------------------------------------------------------------------------------- /webpack.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = function (options) { 4 | return { 5 | plugins: options.watch ? [] : [], 6 | watch: options.watch, 7 | module: { 8 | loaders: [ 9 | { 10 | test: /\.js$/, 11 | exclude: /node_modules/, 12 | loaders: [ 13 | // 'react-hot', 14 | '6to5-loader' 15 | //'6to5-loader?experimental&optional=selfContained' // http://6to5.org/docs/usage/experimental/ 16 | ] 17 | }, 18 | { 19 | test: /\.less$/, 20 | loaders: [ 21 | "style-loader", 22 | "css-loader", 23 | "autoprefixer-loader?browsers=last 2 version", 24 | "less-loader?strictMath&cleancss" 25 | ] 26 | } 27 | ] 28 | } 29 | }; 30 | }; 31 | --------------------------------------------------------------------------------