├── .gitignore ├── app.coffee ├── app.js ├── config.sample.js ├── package.json ├── public ├── apple-touch-icon.png ├── css │ ├── book.css │ ├── home.css │ └── scss │ │ ├── _base.scss │ │ ├── _mixins.scss │ │ ├── _tricolore.scss │ │ ├── _variables.scss │ │ ├── book.scss │ │ └── home.scss ├── favicon.ico ├── images │ └── arrow.png └── js │ ├── book.js │ ├── chapter.3.js │ ├── coffee-script.js │ ├── coffee │ └── chapter.3.coffee │ └── jquery.mailcheck.js ├── readme.md ├── src ├── config.coffee ├── helpers.coffee ├── routes.coffee ├── server.coffee └── store.coffee └── views ├── chapters └── en │ ├── 1.ejs │ ├── 2.ejs │ ├── 3.ejs │ ├── 4.ejs │ ├── 5.ejs │ ├── 6.ejs │ ├── 7.ejs │ └── _old_syntax_chapter.ejs ├── index.ejs ├── layouts ├── book.ejs └── home.ejs ├── shared ├── footer.ejs ├── ga.ejs ├── ie6.ejs ├── paging.ejs └── toc.ejs ├── subscribe.ejs ├── unsubscribe.ejs └── unsubscribed.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | /config/deploy.rb 2 | Capfile 3 | /lib 4 | /node_modules 5 | config.js 6 | .sass-cache 7 | -------------------------------------------------------------------------------- /app.coffee: -------------------------------------------------------------------------------- 1 | source = if /app\.coffee$/.test(process.argv[1]) then './src/' else './lib/' 2 | config = require('./config') 3 | require(source + 'server')(config) -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.2 2 | (function() { 3 | var config, source; 4 | 5 | source = /app\.coffee$/.test(process.argv[1]) ? './src/' : './lib/'; 6 | 7 | config = require('./config'); 8 | 9 | require(source + 'server')(config); 10 | 11 | }).call(this); 12 | -------------------------------------------------------------------------------- /config.sample.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | site: {port: 80}, 3 | redis: {port: 6379, host: '127.0.0.1', database: 0}, 4 | chapters: [ 5 | 'introduction', 6 | 'learning the basics', 7 | 'understanding languages' 8 | ] 9 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Karl Seguin (http://openmymind.net/)", 3 | "name": "tlip", 4 | "version": "0.0.1", 5 | "description": "The Little Introduction To Programming", 6 | "engines": { "node": ">= v0.6.17" }, 7 | "dependencies": { 8 | "ejs": "= 0.7.1", 9 | "express": "= 2.5.9", 10 | "redis": "= 0.7.1", 11 | "bcrypt": "= 0.5.0", 12 | "coffee-script": "= 1.3.3" 13 | }, 14 | "devDependencies": { 15 | "jasmine-node": "= 1.0.25" 16 | }, 17 | "scripts": { 18 | "test": "node_modules/jasmine-node/bin/jasmine-node --coffee spec/" 19 | } 20 | } -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/karlseguin/the-little-introduction-to-programming/dc0f588d5504608612a68da326f903d8e1f3d274/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/css/book.css: -------------------------------------------------------------------------------- 1 | pre { 2 | background: #FFF; 3 | word-wrap: break-word; 4 | color: #000; 5 | line-height: 30px; 6 | margin: 0 0 20px; 7 | padding: 10px; } 8 | pre .comment { 9 | color: #7E7E7E; 10 | font-style: italic; } 11 | pre .constant { 12 | color: #18838A; 13 | font-weight: 700; } 14 | pre .storage { 15 | color: #0000A1; } 16 | pre .string { 17 | color: #8E0022; } 18 | pre .keyword, pre .selector { 19 | color: #0000A1; 20 | font-weight: 700; } 21 | pre .inherited-class { 22 | font-style: italic; } 23 | pre .support { 24 | color: #192140; } 25 | pre .entity, pre .variable.global, pre .variable.class, pre .variable.instance { 26 | color: #3E853F; } 27 | 28 | pre, code { 29 | font-family: "Monaco", "Consolas", monospace; } 30 | 31 | * { 32 | padding: 0; 33 | margin: 0; } 34 | 35 | body { 36 | font-family: 'Open Sans',sans-serif; 37 | color: #444; 38 | background: #f9f9f9; } 39 | 40 | p { 41 | line-height: 2em; } 42 | 43 | a { 44 | color: #229; 45 | text-decoration: none; } 46 | 47 | #footer { 48 | background: #222; 49 | margin-top: 45px; 50 | padding: 20px 0; 51 | font-size: 85%; 52 | border-top: 1px solid #000; 53 | overflow: auto; } 54 | 55 | .addthis_toolbox { 56 | float: left; } 57 | 58 | #links { 59 | float: right; } 60 | 61 | #links a { 62 | color: #fff; 63 | text-decoration: none; 64 | padding: 10px 20px; 65 | border-radius: 4px; 66 | border: 1px solid transparent; } 67 | 68 | #links a:hover { 69 | background: #444; 70 | border: 1px solid #000; } 71 | 72 | #ie6 { 73 | border: 1px solid #faa; 74 | background: #fcc; 75 | border-radius: 5px; 76 | padding: 3px; 77 | text-align: center; 78 | width: 700px; 79 | margin: 0 auto; } 80 | 81 | h1 { 82 | font-size: 1.5em; 83 | position: absolute; 84 | top: 2px; 85 | text-shadow: 1px 1px 2px #000; } 86 | 87 | h1 a { 88 | color: #fff; } 89 | 90 | h2 { 91 | font-size: 1.6em; 92 | margin-top: 15px; } 93 | 94 | h3 { 95 | font-size: 1.2em; 96 | padding-top: 30px; 97 | margin: 30px 0 15px; 98 | border-top: 1px solid #aaa; } 99 | 100 | h2 a, h3 a, h4 a { 101 | color: #222; } 102 | 103 | code { 104 | background: #fff; 105 | padding: 2px; 106 | border: 1px solid #aaa; 107 | border-radius: 4px; } 108 | 109 | ul { 110 | margin-bottom: 20px; } 111 | 112 | li { 113 | margin-left: 20px; } 114 | 115 | ol { 116 | margin-left: 20px; } 117 | 118 | ol li { 119 | padding: 7px; } 120 | 121 | pre { 122 | padding: 20px; 123 | border: 1px solid #eee; 124 | border-radius: 5px; 125 | margin-bottom: 20px; } 126 | 127 | #header { 128 | height: 40px; 129 | background: #333333; 130 | background: -webkit-gradient(linear, left top, left bottom, from(#4a4a4a), to(#333333)); 131 | background: -moz-linear-gradient(-90deg, #4a4a4a, #333333); 132 | filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr='#4a4a4a', endColorstr='#333333'); 133 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#4a4a4a', endColorstr='#333333')"; 134 | position: fixed; 135 | left: 0; 136 | width: 100%; 137 | z-index: 10; } 138 | 139 | #toc { 140 | position: absolute; 141 | right: 0; 142 | height: 40px; 143 | line-height: 40px; 144 | border: solid #000; 145 | border-width: 0 1px; 146 | color: #fff; 147 | background: #444444; 148 | background: -webkit-gradient(linear, left top, left bottom, from(#555555), to(#444444)); 149 | background: -moz-linear-gradient(-90deg, #555555, #444444); 150 | filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr='#555555', endColorstr='#444444'); 151 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#444444')"; 152 | -moz-user-select: none; 153 | -khtml-user-select: none; 154 | user-select: none; 155 | cursor: pointer; 156 | width: 250px; 157 | text-align: center; 158 | font-size: 1em; 159 | margin: 0; 160 | text-shadow: 1px 1px 3px #000; } 161 | 162 | #toc:after { 163 | content: "\25BC"; 164 | margin-left: 20px; 165 | font-size: 0.8em; 166 | text-shadow: 1px 1px 3px #000; } 167 | 168 | #toc:hover { 169 | background: #222; } 170 | 171 | #menu { 172 | z-index: 10; 173 | position: fixed; 174 | right: 5%; 175 | top: 40px; 176 | display: none; 177 | margin: 0; 178 | padding: 0; 179 | list-style: none; 180 | background: #222; 181 | border: 1px solid #000; 182 | width: 250px; 183 | border-bottom-left-radius: 3px; 184 | border-bottom-right-radius: 3px; } 185 | 186 | #menu li { 187 | border-bottom: 1px solid #000; 188 | margin: 0; } 189 | 190 | #menu li:last-child { 191 | border-radius: 5px; } 192 | 193 | #menu a { 194 | color: #fff; 195 | text-decoration: none; 196 | display: block; 197 | padding: 10px; } 198 | 199 | #menu a:hover { 200 | background: #444; } 201 | 202 | #content { 203 | padding-top: 60px; } 204 | 205 | .content, #content { 206 | width: 90%; 207 | margin: 0 auto; 208 | position: relative; } 209 | 210 | #paging { 211 | margin: 10px 0 100px; 212 | padding-top: 10px; 213 | border-top: 2px solid #aaa; 214 | position: relative; } 215 | 216 | #paging a { 217 | padding: 4px 10px; 218 | font-size: 80%; 219 | background: #444; 220 | border-radius: 4px; 221 | color: #fff; } 222 | 223 | #paging a:hover { 224 | background: #777; } 225 | 226 | #next { 227 | position: absolute; 228 | right: 0; } 229 | 230 | .code, p { 231 | margin-bottom: 15px; } 232 | 233 | #book { 234 | margin-right: 250px; 235 | padding-right: 50px; 236 | border-right: 1px solid #aaa; } 237 | 238 | #runner { 239 | position: fixed; 240 | right: 25px; 241 | top: 60px; 242 | width: 265px; } 243 | 244 | #runner + #paging { 245 | margin-right: 250px; } 246 | 247 | .codingArea { 248 | margin-top: 10px; 249 | font-family: "Monaco", "Consolas", monospace; 250 | font-size: 0.95em; } 251 | 252 | .codingArea > div { 253 | width: 100%; 254 | padding: 4px; } 255 | 256 | .codingArea .goal { 257 | border: 1px solid transparent; 258 | background: #ddd; 259 | border-top-left-radius: 4px; 260 | border-top-right-radius: 4px; } 261 | 262 | .codingArea .buttons { 263 | overflow: auto; 264 | position: relative; 265 | padding-left: 0; 266 | padding-right: 10px; } 267 | 268 | .codingArea .buttons a { 269 | padding: 4px 10px; 270 | border: 1px solid #eee; 271 | border-radius: 4px; 272 | background: #444; 273 | color: #fff; } 274 | 275 | .codingArea .buttons a:hover { 276 | background: #111; } 277 | 278 | .codingArea .buttons .run { 279 | float: left; } 280 | 281 | .codingArea .buttons .reset { 282 | position: absolute; 283 | right: 100px; } 284 | 285 | .codingArea .buttons .answer { 286 | position: absolute; 287 | right: 0; } 288 | 289 | textarea { 290 | padding: 4px; 291 | height: 125px; 292 | border: 1px solid #afa; 293 | width: 100%; 294 | color: #444; 295 | font-family: "Monaco", "Consolas", monospace; 296 | font-size: 0.95em; 297 | background: #efe; 298 | outline: none; } 299 | 300 | textarea.answer { 301 | background: #eee; 302 | border: 1px solid #ccc; 303 | display: none; } 304 | 305 | .codingArea.taller textarea { 306 | height: 175px; } 307 | 308 | .codingArea.error textarea.input { 309 | border-color: #faa; 310 | background: #fee; } 311 | 312 | .codingArea.error .goal { 313 | background: #fcc; } 314 | 315 | #items.error { 316 | border: 1px solid #faa; 317 | background: #fee; } 318 | 319 | #items > div { 320 | padding: 3px; 321 | border-bottom: 1px solid #ccc; } 322 | 323 | #items > div:last-child { 324 | border-bottom: none; } 325 | 326 | #funcList { 327 | margin-top: 30px; 328 | display: none; 329 | border-top: 1px solid #aaa; 330 | padding-top: 30px; 331 | padding: 10px 0; 332 | font-family: "Monaco", "Consolas", monospace; 333 | font-size: 0.9em; } 334 | 335 | #funcList .function { 336 | margin-top: 10px; 337 | border-bottom: 1px solid #eee; 338 | padding-bottom: 10px; } 339 | 340 | #funcList .desc { 341 | padding-bottom: 5px; } 342 | 343 | .sidelegend { 344 | position: fixed; 345 | overflow: hidden; 346 | font-size: small; 347 | padding-left: 20px; } 348 | 349 | .sidelegend a { 350 | border-top-left-radius: 10px; 351 | border-bottom-left-radius: 10px; 352 | padding: 1px 10px; 353 | opacity: 0.2; 354 | background: #697983; 355 | color: white; 356 | display: block; } 357 | 358 | .sidelegend a:hover { 359 | text-decoration: none; 360 | background: #495963; } 361 | 362 | .anchor { 363 | height: 0; 364 | display: block; } 365 | 366 | a:target + h3 { 367 | color: #886; } 368 | -------------------------------------------------------------------------------- /public/css/home.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; } 4 | 5 | body { 6 | font-family: 'Open Sans',sans-serif; 7 | color: #444; 8 | background: #f9f9f9; } 9 | 10 | p { 11 | line-height: 2em; } 12 | 13 | a { 14 | color: #229; 15 | text-decoration: none; } 16 | 17 | #footer { 18 | background: #222; 19 | margin-top: 45px; 20 | padding: 20px 0; 21 | font-size: 85%; 22 | border-top: 1px solid #000; 23 | overflow: auto; } 24 | 25 | .addthis_toolbox { 26 | float: left; } 27 | 28 | #links { 29 | float: right; } 30 | 31 | #links a { 32 | color: #fff; 33 | text-decoration: none; 34 | padding: 10px 20px; 35 | border-radius: 4px; 36 | border: 1px solid transparent; } 37 | 38 | #links a:hover { 39 | background: #444; 40 | border: 1px solid #000; } 41 | 42 | #ie6 { 43 | border: 1px solid #faa; 44 | background: #fcc; 45 | border-radius: 5px; 46 | padding: 3px; 47 | text-align: center; 48 | width: 700px; 49 | margin: 0 auto; } 50 | 51 | html { 52 | background: #222; } 53 | 54 | h1 { 55 | padding-top: 30px; 56 | text-align: center; 57 | color: #444; } 58 | 59 | ul { 60 | list-style: none; 61 | margin: 0 0 50px 15px; } 62 | 63 | li { 64 | padding: 5px 10px; 65 | background: url(/images/arrow.png) no-repeat 0 12px; } 66 | 67 | #tagline { 68 | margin: 15px 0 10px 0; 69 | text-align: right; 70 | font-style: italic; 71 | font-size: 80%; } 72 | 73 | .alt { 74 | background: #fff; 75 | padding: 30px 0; 76 | border-top: 2px solid #ccc; 77 | border-bottom: 1px solid #aaa; 78 | color: #666; 79 | margin: 40px 0; } 80 | 81 | #info { 82 | overflow: auto; } 83 | 84 | p { 85 | margin-bottom: 15px; } 86 | 87 | #desc { 88 | width: 425px; 89 | float: left; 90 | line-height: 28px; 91 | padding-right: 50px; 92 | border-right: 1px solid #ccc; } 93 | 94 | #quick { 95 | width: 425px; 96 | margin-left: 530px; } 97 | 98 | #quick h2 { 99 | font-size: 1em; 100 | font-weight: normal; } 101 | 102 | #backhome, #subscribe, #go { 103 | padding: 10px 20px; 104 | border: 1px solid #555; 105 | background: #333333; 106 | background: -webkit-gradient(linear, left top, left bottom, from(#4a4a4a), to(#333333)); 107 | background: -moz-linear-gradient(-90deg, #4a4a4a, #333333); 108 | filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr='#4a4a4a', endColorstr='#333333'); 109 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#4a4a4a', endColorstr='#333333')"; 110 | border-radius: 5px; 111 | color: #fff; 112 | line-height: 25px; } 113 | 114 | #backhome:hover, #subscribe:hover, #go:hover { 115 | background: #888; } 116 | 117 | .content { 118 | width: 960px; 119 | margin: 0 auto; } 120 | 121 | #subscribe { 122 | overflow: auto; } 123 | 124 | form { 125 | margin: 10px 0 0 25px; } 126 | 127 | label { 128 | display: block; } 129 | 130 | #email { 131 | padding: 8px; 132 | border: 1px solid #ddd; 133 | border-radius: 4px; 134 | width: 240px; } 135 | 136 | #subscribe { 137 | padding: 2px 10px; } 138 | 139 | #suggestion { 140 | display: none; 141 | font-size: 0.80em; 142 | margin: 5px 0 0 20px; } 143 | 144 | #suggestLink { 145 | text-decoration: underline; } 146 | 147 | #suggestLink:hover { 148 | color: #aa9; } 149 | 150 | .high { 151 | height: 500px; } 152 | 153 | .high h1 { 154 | margin-bottom: 75px; } 155 | 156 | #backhome { 157 | position: relative; 158 | top: 25px; } 159 | -------------------------------------------------------------------------------- /public/css/scss/_base.scss: -------------------------------------------------------------------------------- 1 | @import 'mixins'; 2 | @import 'variables'; 3 | 4 | *{padding:0;margin:0;} 5 | body{font-family:'Open Sans',sans-serif;color:#444;background:#f9f9f9;} 6 | p{line-height:2em;} 7 | a{color:#229;text-decoration:none;} 8 | 9 | #footer{background:#222;margin-top:45px;padding:20px 0;font-size:85%;border-top:1px solid #000;overflow:auto;} 10 | .addthis_toolbox{float:left;} 11 | #links {float:right;} 12 | #links a{color:#fff;text-decoration:none;padding:10px 20px;border-radius:4px;border:1px solid transparent;} 13 | #links a:hover{background:#444;border:1px solid #000;} 14 | #ie6{border:1px solid #faa;background:#fcc;border-radius:5px;padding:3px;text-align:center;width:700px;margin:0 auto;} 15 | -------------------------------------------------------------------------------- /public/css/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin gradient($from, $to) { 2 | background: $to; 3 | background: -webkit-gradient(linear, left top, left bottom, from($from), to($to)); 4 | background: -moz-linear-gradient(-90deg, $from, $to); 5 | filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr='#{$from}', endColorstr='#{$to}'); 6 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$from}', endColorstr='#{$to}')"; 7 | } 8 | 9 | @mixin noselect() { 10 | -moz-user-select: none; 11 | -khtml-user-select: none; 12 | user-select: none; 13 | } -------------------------------------------------------------------------------- /public/css/scss/_tricolore.scss: -------------------------------------------------------------------------------- 1 | @import 'variables'; 2 | 3 | pre{background:#FFF;word-wrap:break-word;color:#000;line-height:30px;margin:0 0 20px;padding:10px; 4 | .comment{color:#7E7E7E;font-style:italic;} 5 | .constant{color:#18838A;font-weight:700;} 6 | .storage{color:#0000A1;} 7 | .string{color:#8E0022;} 8 | .keyword, .selector{color:#0000A1;font-weight:700;} 9 | .inherited-class{font-style:italic;} 10 | .support{color:#192140;} 11 | .entity, .variable.global, .variable.class, .variable.instance{color:#3E853F;} 12 | } 13 | pre,code{font-family:$code-font;} -------------------------------------------------------------------------------- /public/css/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | $code-font:'Monaco','Consolas',monospace -------------------------------------------------------------------------------- /public/css/scss/book.scss: -------------------------------------------------------------------------------- 1 | @import 'tricolore'; 2 | @import 'base'; 3 | @import 'variables'; 4 | 5 | h1{font-size:1.5em;position:absolute;top:2px;text-shadow:1px 1px 2px #000;} 6 | h1 a{color:#fff;} 7 | h2{font-size:1.6em;margin-top:15px;} 8 | h3{font-size:1.2em;padding-top:30px;margin:30px 0 15px;border-top:1px solid #aaa;} 9 | h2 a, h3 a, h4 a{color:#222;} 10 | code{background:#fff;padding:2px;border:1px solid #aaa;border-radius:4px;} 11 | ul{margin-bottom:20px;} 12 | li{margin-left:20px;} 13 | ol{margin-left:20px;} 14 | ol li {padding:7px;} 15 | pre{padding:20px;border:1px solid #eee;border-radius:5px;margin-bottom:20px;} 16 | 17 | #header{height:40px;@include gradient(#4a4a4a, #333333);position:fixed;left:0;width:100%;z-index:10;} 18 | #toc{position:absolute;right:0;height:40px;line-height:40px;border:solid #000;border-width:0 1px;color:#fff;@include gradient(#555555, #444444);@include noselect();cursor:pointer;width:250px;text-align:center;font-size:1em;margin:0;text-shadow:1px 1px 3px #000;} 19 | #toc:after{content:"\25BC";margin-left:20px;font-size:0.8em;text-shadow:1px 1px 3px #000;} 20 | #toc:hover{background:#222;} 21 | #menu{z-index:10;position:fixed;right:5%;top:40px;display:none;margin:0;padding:0;list-style:none;background:#222;border:1px solid #000;width:250px;border-bottom-left-radius:3px;border-bottom-right-radius:3px;} 22 | #menu li{border-bottom:1px solid #000;margin:0;} 23 | #menu li:last-child{border-radius:5px;} 24 | #menu a{color:#fff;text-decoration:none;display:block;padding:10px;} 25 | #menu a:hover{background:#444;} 26 | #content{padding-top:60px;} 27 | .content, #content{width:90%;margin:0 auto;position:relative;} 28 | #paging{margin:10px 0 100px;padding-top:10px;border-top:2px solid #aaa;position:relative;} 29 | #paging a{padding:4px 10px;font-size:80%;background:#444;border-radius:4px;color:#fff;} 30 | #paging a:hover{background:#777;} 31 | #next{position:absolute;right:0;} 32 | 33 | .code, p{margin-bottom:15px;} 34 | 35 | #book{margin-right:250px;padding-right:50px;border-right:1px solid #aaa;} 36 | #runner{position:fixed;right:25px;top:60px;width:265px;} 37 | #runner + #paging{margin-right:250px;} 38 | .codingArea{margin-top:10px;font-family:$code-font;font-size:0.95em;} 39 | .codingArea > div{width:100%;padding:4px;} 40 | .codingArea .goal{border:1px solid transparent;background:#ddd;border-top-left-radius:4px;border-top-right-radius:4px;} 41 | .codingArea .buttons{overflow:auto;position:relative;padding-left:0;padding-right:10px;} 42 | .codingArea .buttons a{padding:4px 10px;border:1px solid #eee;border-radius:4px;background:#444;color:#fff;} 43 | .codingArea .buttons a:hover{background:#111;} 44 | .codingArea .buttons .run{float:left;} 45 | .codingArea .buttons .reset{position:absolute;right:100px;} 46 | .codingArea .buttons .answer{position:absolute;right:0;} 47 | 48 | textarea{padding:4px;height:125px;border:1px solid #afa;width:100%;color:#444;font-family:$code-font;font-size:0.95em;background:#efe;outline: none;} 49 | textarea.answer{background:#eee;border:1px solid #ccc;display:none;} 50 | .codingArea.taller textarea{height:175px;} 51 | .codingArea.error textarea.input{border-color:#faa;background:#fee;} 52 | .codingArea.error .goal{background:#fcc;} 53 | 54 | #items.error{border:1px solid #faa;background:#fee;} 55 | #items > div{padding:3px;border-bottom:1px solid #ccc;} 56 | #items > div:last-child{border-bottom:none;} 57 | #funcList{margin-top:30px;display:none;border-top:1px solid #aaa;padding-top:30px;padding:10px 0;font-family:$code-font;font-size:0.9em;} 58 | #funcList .function{margin-top:10px;border-bottom:1px solid #eee;padding-bottom:10px;} 59 | #funcList .desc{padding-bottom:5px;} 60 | 61 | 62 | .sidelegend{position:fixed;overflow:hidden;font-size:small;padding-left:20px;} 63 | .sidelegend a{border-top-left-radius:10px;border-bottom-left-radius:10px;padding:1px 10px;opacity:0.2;background:#697983;color:white;display:block;} 64 | .sidelegend a:hover{text-decoration: none;background:#495963;} 65 | .anchor {height: 0;display: block;} 66 | a:target + h3 {color: #886;} -------------------------------------------------------------------------------- /public/css/scss/home.scss: -------------------------------------------------------------------------------- 1 | @import 'base'; 2 | 3 | html{background:#222;} 4 | h1{padding-top:30px;text-align:center;color:#444;} 5 | ul{list-style:none;margin:0 0 50px 15px;} 6 | li{padding:5px 10px;background:url(/images/arrow.png) no-repeat 0 12px;} 7 | #tagline{margin:15px 0 10px 0;text-align:right;font-style:italic;font-size:80%;} 8 | .alt{background:#fff;padding:30px 0;border-top:2px solid #ccc;border-bottom:1px solid #aaa;color:#666;margin:40px 0;} 9 | #info{overflow:auto;} 10 | p{margin-bottom:15px;} 11 | #desc{width:425px;float:left;line-height:28px;padding-right:50px;border-right:1px solid #ccc;} 12 | #quick{width:425px;margin-left:530px} 13 | #quick h2{font-size:1em;font-weight:normal;} 14 | #backhome, #subscribe, #go{padding:10px 20px;border:1px solid #555;@include gradient(#4a4a4a, #333333);border-radius:5px;color:#fff;line-height:25px;} 15 | #backhome:hover, #subscribe:hover, #go:hover{background:#888;} 16 | .content{width:960px;margin:0 auto;} 17 | 18 | #subscribe{overflow:auto;} 19 | form{margin:10px 0 0 25px;} 20 | label{display:block;} 21 | #email{padding:8px;border:1px solid #ddd;border-radius:4px;width:240px;} 22 | #subscribe{padding:2px 10px;} 23 | #suggestion{display:none;font-size:0.80em;margin:5px 0 0 20px;} 24 | #suggestLink{text-decoration:underline;} 25 | #suggestLink:hover{color:#aa9}; 26 | 27 | .high{height:500px;} 28 | .high h1{margin-bottom:75px;} 29 | #backhome{position:relative;top:25px;} -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/karlseguin/the-little-introduction-to-programming/dc0f588d5504608612a68da326f903d8e1f3d274/public/favicon.ico -------------------------------------------------------------------------------- /public/images/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/karlseguin/the-little-introduction-to-programming/dc0f588d5504608612a68da326f903d8e1f3d274/public/images/arrow.png -------------------------------------------------------------------------------- /public/js/book.js: -------------------------------------------------------------------------------- 1 | window.Rainbow=function(){function q(a,b,c,d){var e=a.getAttribute&&a.getAttribute(b)||0;if(!e){c=a.attributes;for(d=0;d=d;d&&(delete j[f][c],delete i[f][c]);d=j[f][c];d=a>=c&&ac&&b'+b+""}function s(a,b,c,d){var e=a.exec(c);if(!e)return d();++t;!b.name&&"string"==typeof b.matches[0]&&(b.name=b.matches[0],delete b.matches[0]);var l=e[0],h=e.index,u=e[0].length+h,g=function(){var e=function(){s(a,b,c,d)};return t%100>0?e():setTimeout(e,0)};if(E(h,u))return g();var m=v(b.matches),k=function(a,c,d){if(a>=c.length)return d(l);var f=e[c[a]];if(f){var h=b.matches[c[a]],j=h.language,i=h.name&&h.matches?h.matches:h,g=function(b,f,h){var i=0,g;for(g=1;g/g,">").replace(/&(?![\w\#]+;)/g,"&"),b,c)}function o(a,b,c){if(b').addClass(this.css).appendTo('body'); 41 | this.link = $('').text(this.title) 42 | .attr('href', '#'+this.id) 43 | .appendTo(this.node); 44 | this.node.css('right', '-'+(this.node.outerWidth()-this.peak)+'px'); 45 | this.refresh(); 46 | this.node.mouseenter(function() { POI.show(); }); 47 | this.node.mouseleave(function() { POI.hide(POI.delay); }); 48 | } 49 | 50 | POI.prototype.refresh = function() { 51 | // Re-arrange the anchors 52 | var dsize = $(document).height(); 53 | var wsize = $(window).height(); 54 | var pos = this.anchor.offset().top; 55 | var hpos = Math.round(wsize*(pos/dsize)); 56 | if (hpos < 60) { hpos += 60; } 57 | this.node.css('top', hpos+'px'); 58 | } 59 | 60 | POI.prototype.show = function() { 61 | // Show the handle 62 | if(this.visible) return; 63 | this.node.stop(true).animate({'right': '0px'}, 250); 64 | this.link.css({opacity: 1}); 65 | this.visible = true; 66 | } 67 | 68 | POI.prototype.hide = function() { 69 | // Hide the handle 70 | if(this.pinned) return; 71 | if(! this.visible) return; 72 | this.node.stop(true).animate({ 73 | 'right': '-'+(this.node.outerWidth()-this.peak-10)+'px' 74 | }, 250); 75 | this.link.css({opacity: 0.2}); 76 | this.visible = false; 77 | } 78 | 79 | 80 | 81 | // Static attributes and methods. 82 | 83 | POI.all = Array(); 84 | POI.peak = 30; 85 | POI.delay = 500; 86 | POI.css = 'sidelegend'; 87 | POI.hide_timeout = null; 88 | 89 | POI.refresh = function() { 90 | // Refresh all at once 91 | jQuery.each(POI.all, function() { 92 | this.refresh(); 93 | }) 94 | } 95 | 96 | POI.show = function() { 97 | // Show all at once 98 | if(POI.hide_timeout) window.clearTimeout(POI.hide_timeout); 99 | POI.hide_timeout = null; 100 | jQuery.each(POI.all, function() { 101 | this.show(); 102 | }) 103 | } 104 | 105 | POI.hide = function(delay) { 106 | // Hide all at once after a specific delay 107 | if(POI.hide_timeout) window.clearTimeout(POI.hide_timeout); 108 | if(delay) { 109 | POI.hide_timeout = window.setTimeout(function() { 110 | POI.hide_timeout = null; 111 | POI.hide(); 112 | }, delay) 113 | } else { 114 | jQuery.each(POI.all, function() { 115 | this.hide(); 116 | }) 117 | } 118 | } -------------------------------------------------------------------------------- /public/js/chapter.3.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | var Runner, config; 4 | 5 | Runner = (function() { 6 | 7 | function Runner() {} 8 | 9 | Runner.run = function(e) { 10 | var config, input, value; 11 | config = Runner.getConfig(this); 12 | input = Runner.getInput(this, '.input'); 13 | Runner.setContext(config); 14 | Runner.ok(this); 15 | try { 16 | value = input.val().replace(/function *(.*?)(\(.*?\))/, '$1 = $2 ->'); 17 | with(Runner.context) { eval(CoffeeScript.compile(value)) }; 18 | 19 | } catch (error) { 20 | Runner.error(this, error.toString()); 21 | } 22 | return e.preventDefault(); 23 | }; 24 | 25 | Runner.answer = function(e) { 26 | var answer, config; 27 | config = Runner.getConfig(this); 28 | answer = Runner.getInput(this, '.answer').toggle(); 29 | if (answer.is(':visible')) { 30 | $(this).text('hide'); 31 | } else { 32 | $(this).text('answer'); 33 | } 34 | return e.preventDefault(); 35 | }; 36 | 37 | Runner.reset = function(e) { 38 | var config, item, list, _i, _len, _ref; 39 | config = Runner.getConfig(this); 40 | list = Runner.shopList.empty(); 41 | Runner.getCodingArea(this).find('.goal').removeClass('incorrect correct'); 42 | Runner.ok(); 43 | _ref = config.reset; 44 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 45 | item = _ref[_i]; 46 | list.append($('
').text(item)); 47 | } 48 | return e.preventDefault(); 49 | }; 50 | 51 | Runner.focus = function() { 52 | var $list, config, f, _i, _len, _ref, _results; 53 | config = Runner.getConfig(this); 54 | $list = $('#funcList').show().children('div:first').empty(); 55 | _ref = config.functions; 56 | _results = []; 57 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 58 | f = _ref[_i]; 59 | _results.push($list.append(Runner.buildFunctionInfo(Runner.config.functions[f]))); 60 | } 61 | return _results; 62 | }; 63 | 64 | Runner.setContext = function(config) { 65 | var func, n, name, _i, _len, _ref, _results; 66 | Runner.context = {}; 67 | _ref = config.functions; 68 | _results = []; 69 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 70 | n = _ref[_i]; 71 | _results.push((function() { 72 | var _ref1, _results1; 73 | _ref1 = Runner.getFunction(n).define; 74 | _results1 = []; 75 | for (name in _ref1) { 76 | func = _ref1[name]; 77 | _results1.push(Runner.context[name] = func); 78 | } 79 | return _results1; 80 | })()); 81 | } 82 | return _results; 83 | }; 84 | 85 | Runner.getConfig = function(element) { 86 | return this.config.steps[Runner.getCodingArea(element).data('id')]; 87 | }; 88 | 89 | Runner.getInput = function(element, type) { 90 | return Runner.getCodingArea(element).find('textarea').filter(type); 91 | }; 92 | 93 | Runner.getCodingArea = function(element) { 94 | return $(element).closest('.codingArea'); 95 | }; 96 | 97 | Runner.getFunction = function(f) { 98 | return this.config.functions[f]; 99 | }; 100 | 101 | Runner.buildFunctionInfo = function(f) { 102 | var $div, parameter, _i, _len, _ref; 103 | $div = $('
').addClass('function').text(f.display); 104 | _ref = f.parameters; 105 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 106 | parameter = _ref[_i]; 107 | $('
').addClass('type').text(parameter[0]).appendTo($div); 108 | $('
').addClass('desc').text(parameter[1]).appendTo($div); 109 | } 110 | return $div; 111 | }; 112 | 113 | Runner.ok = function(element) { 114 | Runner.getCodingArea(element).removeClass('error'); 115 | Runner.shopList.removeClass('error').find('.error').remove(); 116 | return Runner.shopList.siblings('h4').show(); 117 | }; 118 | 119 | Runner.error = function(element, error) { 120 | Runner.getCodingArea(element).addClass('error'); 121 | return Runner.shopList.addClass('error').append($('
').text(error)).siblings('h4').hide(); 122 | }; 123 | 124 | return Runner; 125 | 126 | })(); 127 | 128 | config = {}; 129 | 130 | config.steps = [ 131 | { 132 | answer: 'addItem("milk")', 133 | functions: ['addItem'], 134 | reset: [] 135 | }, { 136 | answer: 'item = prompt("What do you need to buy?")\raddItem(item)', 137 | functions: ['addItem', 'prompt'], 138 | reset: ['milk'] 139 | }, { 140 | answer: 'item = prompt("What do you need to buy?")\rif item == null || item == "" #prompt returns null when the user hits cancel\r alert("Please enter a value")\relse\r addItem(item)\r', 141 | functions: ['addItem', 'prompt', 'alert'], 142 | reset: ['milk', 'eggs'] 143 | }, { 144 | answer: '#removed the empty/null check for simplicity\ritem = prompt("What do you need to buy?")\rif itemExists(item) == true\r alert("This item was already added")\relse\r addItem(item)\r', 145 | functions: ['addItem', 'prompt', 'alert', 'itemExists'], 146 | reset: ['milk', 'eggs'] 147 | }, { 148 | answer: 'function itemExists(itemToFind)\r items = getItems()\r for item in items \r if item == itemToFind\r return true\r return false\r\ralert(itemExists("milk"))', 149 | functions: ['alert', 'getItems'], 150 | reset: ['milk', 'eggs'] 151 | } 152 | ]; 153 | 154 | config.functions = { 155 | addItem: { 156 | display: "addItem(item)", 157 | parameters: [['item - string', 'the item to add to the list']], 158 | define: { 159 | addItem: function(item) { 160 | return $('#items').append($('
').text(item)); 161 | } 162 | } 163 | }, 164 | prompt: { 165 | display: "prompt(message)", 166 | parameters: [['message - string', 'the message to display'], ['returns the value entered by the user']], 167 | define: { 168 | prompt: function(message) { 169 | return window.prompt(message); 170 | } 171 | } 172 | }, 173 | alert: { 174 | display: "alert(message)", 175 | parameters: [['message - string', 'the message to display']], 176 | define: { 177 | alert: function(message) { 178 | return window.alert(message); 179 | } 180 | } 181 | }, 182 | itemExists: { 183 | display: "itemExists(item)", 184 | parameters: [['item - string', 'the item to check'], ['returs true if the item exists, false otherwise']], 185 | define: { 186 | itemExists: function(item) { 187 | var element, _i, _len, _ref; 188 | _ref = $('#items').children(); 189 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 190 | element = _ref[_i]; 191 | if (element.innerHTML.toLowerCase() === item) { 192 | return true; 193 | } 194 | } 195 | return false; 196 | } 197 | } 198 | }, 199 | getItems: { 200 | display: "getItems()", 201 | parameters: [['returns a collection of the items in the list']], 202 | define: { 203 | getItems: function() { 204 | var element, _i, _len, _ref, _results; 205 | _ref = $('#items').children(); 206 | _results = []; 207 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 208 | element = _ref[_i]; 209 | _results.push(element.innerHTML); 210 | } 211 | return _results; 212 | } 213 | } 214 | } 215 | }; 216 | 217 | Runner.config = config; 218 | 219 | $(function() { 220 | $('textarea').on('focus', Runner.focus); 221 | $('a.run').on('click', Runner.run); 222 | $('a.answer').on('click', Runner.answer); 223 | $('a.reset').on('click', Runner.reset); 224 | return Runner.shopList = $('#items'); 225 | }); 226 | 227 | }).call(this); 228 | -------------------------------------------------------------------------------- /public/js/coffee/chapter.3.coffee: -------------------------------------------------------------------------------- 1 | class Runner 2 | @run: (e) -> 3 | config = Runner.getConfig(this) 4 | input = Runner.getInput(this, '.input') 5 | Runner.setContext(config) 6 | Runner.ok(this) 7 | try 8 | value = input.val().replace(/function *(.*?)(\(.*?\))/, '$1 = $2 ->') 9 | `with(Runner.context) { eval(CoffeeScript.compile(value)) }` 10 | catch error 11 | Runner.error(this, error.toString()) 12 | e.preventDefault() 13 | 14 | @answer: (e) -> 15 | config = Runner.getConfig(this) 16 | answer = Runner.getInput(this, '.answer').toggle().text(config.answer) 17 | if answer.is(':visible') 18 | $(this).text('hide') 19 | else 20 | $(this).text('answer') 21 | e.preventDefault() 22 | 23 | @reset: (e) -> 24 | config = Runner.getConfig(this) 25 | list = Runner.shopList.empty() 26 | Runner.getCodingArea(this).find('.goal').removeClass('incorrect correct') 27 | Runner.ok() 28 | for item in config.reset 29 | list.append($('
').text(item)) 30 | e.preventDefault() 31 | 32 | @focus: -> 33 | config = Runner.getConfig(this) 34 | $list = $('#funcList').show().children('div:first').empty() 35 | for f in config.functions 36 | $list.append(Runner.buildFunctionInfo(Runner.config.functions[f])) 37 | 38 | @setContext: (config) -> 39 | Runner.context = {}; 40 | for n in config.functions 41 | for name, func of Runner.getFunction(n).define 42 | Runner.context[name] = func 43 | 44 | @getConfig: (element) -> 45 | @config.steps[Runner.getCodingArea(element).data('id')] 46 | 47 | @getInput: (element, type) -> 48 | Runner.getCodingArea(element).find('textarea').filter(type) 49 | 50 | @getCodingArea: (element) -> 51 | $(element).closest('.codingArea') 52 | 53 | @getFunction: (f) -> 54 | @config.functions[f] 55 | 56 | @buildFunctionInfo: (f) -> 57 | $div = $('
').addClass('function').text(f.display) 58 | for parameter in f.parameters 59 | $('
').addClass('type').text(parameter[0]).appendTo($div); 60 | $('
').addClass('desc').text(parameter[1]).appendTo($div); 61 | return $div 62 | 63 | @ok: (element) -> 64 | Runner.getCodingArea(element).removeClass('error') 65 | Runner.shopList.removeClass('error').find('.error').remove() 66 | Runner.shopList.siblings('h4').show() 67 | 68 | @error: (element, error) -> 69 | Runner.getCodingArea(element).addClass('error') 70 | Runner.shopList.addClass('error').append($('
').text(error)).siblings('h4').hide() 71 | 72 | config = {} 73 | config.steps = [ 74 | { 75 | answer: 'addItem("milk")' 76 | functions: ['addItem'] 77 | reset: [] 78 | }, { 79 | answer: 'item = prompt("What do you need to buy?")\raddItem(item)' 80 | functions: ['addItem', 'prompt'] 81 | reset: ['milk'] 82 | }, { 83 | answer: 'item = prompt("What do you need to buy?")\rif item == null || item == "" #prompt returns null when the user hits cancel\r alert("Please enter a value")\relse\r addItem(item)\r' 84 | functions: ['addItem', 'prompt', 'alert'] 85 | reset: ['milk', 'eggs'] 86 | }, { 87 | answer: '#removed the empty/null check for simplicity\ritem = prompt("What do you need to buy?")\rif itemExists(item) == true\r alert("This item was already added")\relse\r addItem(item)\r' 88 | functions: ['addItem', 'prompt', 'alert', 'itemExists'] 89 | reset: ['milk', 'eggs'] 90 | }, { 91 | answer: 'function itemExists(itemToFind)\r items = getItems()\r for item in items \r if item == itemToFind\r return true\r return false\r\ralert(itemExists("milk"))' 92 | functions: ['alert', 'getItems'] 93 | reset: ['milk', 'eggs'] 94 | } 95 | ] 96 | 97 | config.functions = 98 | addItem: 99 | display: "addItem(item)" 100 | parameters: [['item - string', 'the item to add to the list']] 101 | define: 102 | addItem: (item) -> $('#items').append($('
').text(item)) 103 | prompt: 104 | display: "prompt(message)" 105 | parameters: [['message - string', 'the message to display'], ['returns the value entered by the user']] 106 | define: 107 | prompt: (message) -> window.prompt(message) 108 | alert: 109 | display: "alert(message)" 110 | parameters: [['message - string', 'the message to display']] 111 | define: 112 | alert: (message) -> window.alert(message) 113 | itemExists: 114 | display: "itemExists(item)" 115 | parameters: [['item - string', 'the item to check'], ['returs true if the item exists, false otherwise']] 116 | define: 117 | itemExists: (item) -> 118 | for element in $('#items').children() 119 | return true if element.innerHTML.toLowerCase() == item 120 | return false 121 | getItems: 122 | display: "getItems()" 123 | parameters: [['returns a collection of the items in the list']] 124 | define: 125 | getItems: -> (element.innerHTML for element in $('#items').children()) 126 | 127 | Runner.config = config 128 | 129 | $ -> 130 | $('textarea').on 'focus', Runner.focus 131 | $('a.run').on 'click', Runner.run 132 | $('a.answer').on 'click', Runner.answer 133 | $('a.reset').on 'click', Runner.reset 134 | Runner.shopList = $('#items') -------------------------------------------------------------------------------- /public/js/jquery.mailcheck.js: -------------------------------------------------------------------------------- 1 | /*1.0.3*/(function(b){b.fn.mailcheck=function(a,b){var d="yahoo.com,google.com,hotmail.com,gmail.com,me.com,aol.com,mac.com,live.com,comcast.net,googlemail.com,msn.com,hotmail.co.uk,yahoo.co.uk,facebook.com,verizon.net,sbcglobal.net,att.net,gmx.com,mail.com".split(","),e="co.uk,com,net,org,info,edu,gov,mil".split(",");if("object"===typeof a&&void 0===b)a.domains=a.domains||d;else{var g=a,a=b;a.domains=g||d}a.topLevelDomains=a.topLevelDomains||e;a.distanceFunction=Kicksend.sift3Distance;(d=Kicksend.mailcheck.suggest(encodeURI(this.val()), 2 | a.domains,a.topLevelDomains,a.distanceFunction))?a.suggested&&a.suggested(this,d):a.empty&&a.empty(this)}})(jQuery); 3 | var Kicksend={mailcheck:{threshold:3,suggest:function(b,a,c,d){b=b.toLowerCase();b=this.splitEmail(b);if(a=this.findClosestDomain(b.domain,a,d)){if(a!=b.domain)return{address:b.address,domain:a,full:b.address+"@"+a}}else if(c=this.findClosestDomain(b.topLevelDomain,c),b.domain&&c&&c!=b.topLevelDomain)return a=b.domain,a=a.substring(0,a.lastIndexOf(b.topLevelDomain))+c,{address:b.address,domain:a,full:b.address+"@"+a};return!1},findClosestDomain:function(b,a,c){var d,e=99,g=null;if(!b||!a)return!1; 4 | c||(c=this.sift3Distance);for(var f=0;ff;f++){if(c+fb.length)return!1;for(var a=0;a 2 | config.chapters = [ 3 | 'introduction', 4 | 'learning the basics', 5 | 'your first program', 6 | 'data structures', 7 | 'more on languages', 8 | 'more on types', 9 | 'next steps' 10 | ] -------------------------------------------------------------------------------- /src/helpers.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (app, config) -> 2 | app.helpers 3 | chapters: config.chapters 4 | development: app.settings.env == 'development' 5 | chapter_link: (language, chapter) -> 6 | "/chapter/#{language}/#{chapter}/#{config.chapters[chapter-1].replace(/\ /g, '_').replace(/'/g, '')}" 7 | -------------------------------------------------------------------------------- /src/routes.coffee: -------------------------------------------------------------------------------- 1 | Store = require('./store'); 2 | 3 | class Routes 4 | @routes: (app) -> 5 | app.get '/chapter/:language/:chapter/:name', (req, res) -> 6 | res.setHeader('Cache-Control', 'public, max-age=60') 7 | res.render "chapters/#{req.params.language}/#{req.params.chapter}", {layout: 'layouts/book', locals: {language: req.params.language, chapter: parseInt(req.params.chapter)}} 8 | 9 | app.get '/', (req, res) -> 10 | res.setHeader('Cache-Control', 'public, max-age=60') 11 | res.render 'index', layout: 'layouts/home' 12 | 13 | app.post '/subscribe', (req, res) -> 14 | Store.subscribe req.body.email, (err) -> 15 | res.render 'subscribe', { layout: 'layouts/home', locals: {ok: !err?}} 16 | 17 | app.get '/unsubscribe', (req, res) -> 18 | res.render 'unsubscribe', { layout: 'layouts/home', locals: {email: req.query.email || ''}} 19 | 20 | app.post '/unsubscribe', (req, res) -> 21 | Store.unsubscribe req.body.email, (err) -> 22 | res.render 'unsubscribed', { layout: 'layouts/home', locals: {ok: !err?}} 23 | 24 | 25 | module.exports = Routes.routes -------------------------------------------------------------------------------- /src/server.coffee: -------------------------------------------------------------------------------- 1 | express = require('express') 2 | store = require('./store') 3 | 4 | run = (config) -> 5 | store.initialize config.redis, (err) -> 6 | if err? 7 | console.log('store initialization error: %s', err) 8 | process.exit(1) 9 | 10 | require('./config')(config) 11 | 12 | app = module.exports = express.createServer() 13 | app.configure -> 14 | app.set('views', __dirname + '/../views') 15 | app.set('view engine', 'ejs') 16 | app.use(express.bodyParser()) 17 | app.use(app.router) 18 | if app.settings.env == 'development' 19 | app.use(express.static(__dirname + '/../public/')); 20 | 21 | require('./routes')(app) 22 | require('./helpers')(app, config) 23 | app.listen(config.site.port) 24 | 25 | module.exports = run -------------------------------------------------------------------------------- /src/store.coffee: -------------------------------------------------------------------------------- 1 | redis = require('redis') 2 | 3 | class Store 4 | @client = null 5 | 6 | @initialize: (config, callback) -> 7 | @client = redis.createClient(config.port, config.host, {return_buffers: true}) 8 | @client.select(config.database, callback) 9 | 10 | @subscribe: (email, cb) => 11 | @client.sadd('ci:subscriptions', email, cb) 12 | 13 | @unsubscribe: (email, cb) => 14 | @client.srem('ci:subscriptions', email, cb) 15 | 16 | module.exports = Store -------------------------------------------------------------------------------- /views/chapters/en/1.ejs: -------------------------------------------------------------------------------- 1 | 2 |

Introduction

3 |

Programming is the process of writing instructions for computers to produce software for users. It's the combining of minute details to form a cohesive whole. More than anything, it is a creative and problem-solving activity. The problem solving aspect of programming will become self-evident as we move forward. For now, I'd like to talk about the creative side.

4 | 5 |

At a high level, it's obvious that creating software requires creativity. You are building something for people to use. It must therefore be clever without being complex. It must be intuitive and elegant. What isn't obvious to most people is that creativity plays an equally important role at the micro level of building software. Every instruction that you type requires consideration. In this respect, I've always likened programming to writing a book or painting a picture. Ultimately you have a finished product, but it's the sentences and the strokes, and how they are combined, which is where the book, painting or program truly comes to life.

6 | 7 |

I sincerely believe that programming is a beautiful thing. However, I warn you that learning to program isn't trivial. You should be able to learn the basics with relative ease. Unfortunately, going from these basics to being able to write a useful program isn't easy. In fact, it can be quite frustrating. I tell you this so that you know what to expect, not to discourage you. How far you take this journey is up to you, this is but a start.

8 | 9 |
10 |

What's a Program

11 |

You already know what a program is. You use an email program, surf the web in a browser and interact with various websites every day. You text, take pictures, and check the weather on your phone. A program is the output, or goal, of programming.

12 | 13 |

Much like a book is made up of chapters, paragraphs, sentences, phrases, words and finally punctuation and letters, so too is a program broken down into smaller and smaller components. For now, the most important is a statement. A statement is analogous to a sentence in a book. On its own, it has structure and purpose, but without the context of the other statements around it, it isn't that meaningful.

14 | 15 |

A statement is more casually (and commonly) known as a line of code. That's because statements tend to be written on individual lines. As such, programs are read from top to bottom, left to right. You might be wondering what code (also called source code) is. That happens to be a broad term which can refer to the whole of the program or the smallest part. Therefore, a line of code is simply a line of your program.

16 | 17 |

I think this would be a good time to introduce our first little program. There are more concepts and terms to learn, but it will be useful to have something to visualize.

18 | 19 |
deck = ["2 of Hearts", "3 of Hearts", "4 of Hearts", "5 of Hearts"]
20 | shuffled_deck = shuffle(deck)
21 | first = shuffled_deck.first
22 | print first
23 | 24 |

Although it's rather short, there's a lot going on here. We won't go into any of this in great detail. For now what's important is that our program is made up of four lines of code and that the program is read from top to bottom. The purpose of this program is to pick a random card from a partial deck.

25 | 26 |

The first line collects a limited number of cards into a container, our deck. Next, we shuffle the deck. Finally, we pick the first card (which at this point could have any value) and print it out on the screen. You might be tempted to analyze this deeper. For example, maybe you are curious about the meaning of the square brackets [] in the first line of code. Or maybe you're wondering about the implication of the equal sign =. Those are all things we'll eventually cover. For now, this is a program made up of four lines of code which create a deck, shuffles it, picks the first card and prints it.

27 | 28 |

There are a lot of ways to write this program. The approach shown above is similar to how it works in the real-world, which makes it easy to understand. This is where creativity, at a micro level, comes into play. A good programmer wants to write code which is understandable to other programmers (and to his or her future self), which is correct (or bug free), and which performs efficiently. Balancing these three aspects of programming is fundamental. But there's no shortcut to mastering this, one must learn through experience.

29 | 30 | 31 |

Programming Languages

32 |

We have an idea of what a simple program looks like: a collection of lines of code. But that's still quite vague, so let's peel away the layers.

33 | 34 |

When you write a program you do so using a programming language. A programming language defines the syntax that you use to write your program. In our above example, we used square brackets [] to group together our cards. A different programming language might insist that you use parenthesis (). We used print to output the picked card, while another language might use echo. You could say that different programming languages are like different spoken and written languages. The same book written in different languages tells the same story; much like a program written in different programming languages would have the same purpose. However, programming languages tend to be more similar than dissimilar and a more accurate comparison might be to dialects.

35 | 36 |

Programming languages define more than just the syntax, but for now, that's all we'll concern ourselves with. Thankfully even though some languages are vastly different than others, most share a lot of common ground, so that once you know your first language, other languages are much easier to pick up.

37 | 38 |

The processor in your computer, or smartphone, doesn't know anything about a deck, card or even about printing something on the screen. These processors speak a basic language and require detailed instructions on what to do and how to do it. Writing our above sample in this low-level language might require 50 or more individual statements, none of which is obvious to read or write. This means that on the one hand, you have programming languages that humans can understand, on the other you have languages that computers understand. What's needed is a translation process to go from the code that we write, to the code that a computer reads. This process is known as compiling your code. A compiler takes your high-level program as input and outputs a low-level program which your computer will understand.

39 | 40 |

Even as your knowledge progresses, you'll probably never have to know the details of assembly or compilers. They are both advanced topics which an increasingly rare number of programmers focus on. Why bring it up at all then? First, because learning to program is more than learning the correct sequence of statements to write down. It's also about understanding, even at a high level, the metamorphosis of your code from what you write to what ends up actually being executed. Secondly, and more importantly, it introduces the important topic of abstraction.

41 | 42 |

We've already seen that the code we'll write and the code that the CPU will execute aren't the same thing. The details of assembly are abstracted away from us by the compiler. This is only one of many layers of abstraction. These layers of abstraction help programmers deal with the ever-increasing complexity of programming. It's abstraction that makes it possible for us to write a few understandable lines of code to shuffle a deck, without having to worry about the various building blocks which others have provided for us; like, how does shuffle randomly mix up our deck? But abstractions aren't perfect, and ignorance isn't always bliss. Sometimes a lower level concept will break through the abstraction. Sometimes we'll need to get our hands dirty to achieve what we want.

43 | 44 |

The point is that while we'll focus on writing programs using modern techniques, know that there's an entire foundation which makes it all possible. Sometimes, those underlying elements will become visible, say by means of a cryptic error message. Also, rather than sugar-coating what programming is, you now hopefully have a more meaningful sense of it beyond simply being a list of written statements for the computer to follow.

45 | 46 | 47 |

In This Chapter

48 |

This chapter served to introduce some basic concepts of programming. If it seemed overwhelming, don't worry. Most of what we talked about is rather broad and it isn't until we start filling in the pieces that the picture will sharpen. Having said that, let's recap what we have learned.

49 | 50 |

First, a program is made up of sub-components, which themselves are made up of sub-components. The most interesting, for now, is the statement or line of code. This tends to represent a cohesive instruction; for example, add two numbers, shuffle these values, or print this value to the screen.

51 | 52 |

Secondly, there are many programming languages, which define the syntax and rules that we'll follow, but most share common ground. Our focus will be on learning this common ground.

53 | 54 |

Finally, in order to be executed, our program leverages building blocks written by other programmers and gets transformed into assembly, which is the language understood by a computer. As new programmers, this is a fairly minor detail that we can safely ignore. However, professional programmers who completely ignore their foundation do so at their own peril.

55 | -------------------------------------------------------------------------------- /views/chapters/en/2.ejs: -------------------------------------------------------------------------------- 1 | 2 |

Learning the Basics

3 |

In the previous chapter we broke a program down into the vague concept of lines of code. In this chapter, we'll start to explore some of the more frequent parts which go into making a line of code.

4 | 5 |

Before jumping directly into a list of terms with an accompanying description and small code samples, let's first try to think about a program's components abstractly.

6 | 7 |

Consider the scenario of registering a user on a website. A basic implementation might ask for an email and password. What might the code to register this user look like? First we'll collect the two provided pieces of information: the email and password. Next we'll probably want our program to verify this data: is the password long enough and is the email valid? If either of these things aren't true, we'll display an error message. Otherwise, we can save the information so that it can be used at a later point.

8 | 9 |

What about withdrawing money from your bank? First you enter your card and security pin. Again, the program collects this information and verifies it. If it's invalid, it'll display an error and repeat until the information provided is valid. Once valid, you provide a third piece of information, the amount you wish to withdraw. If the amount is too large, it'll once again display an error. Otherwise, the amount if subtracted from your account balance (a forth piece of information which, sadly, isn't supplied by you, but stored in the bank's system) and the requested funds made available.

10 | 11 |

Neither of these descriptions tell us how to actually write programs. However, they both expose 3 core aspects of programming. First, both deal with data or values. The first deals with an email and password, the second with an account number (retrieved from the card), your pin, your withdrawal amount and your account balance. Second, they both apply conditional logic. If the password is too short, or the withdrawal amount too large, display an error; otherwise, proceed to the next step. Finally, they both perform actions. For our account withdrawal, this is a simple subtraction of the withdrawn amount from our account balance. For the user registration, it's the process of saving the new user information for later use.

12 | 13 |

In other words, programs:

14 |
    15 |
  • Deal with data from various sources (user input, file, the internet, ...),
  • 16 |
  • Determine a course of action based on this data, and
  • 17 |
  • Perform the appropriate action
  • 18 |
19 | 20 |

This isn't too different than how we perform many day to day tasks. As you approach a traffic light, you collect data about your environment. At its simplest, you care about the color of the traffic light. If it's red or yellow, you stop. If it's green, you go. In reality, there are considerably more data points that you consider: the condition of the road, your current speed, what the cars and pedestrians around you are doing, how anxious you are to get home and so on and so forth. Our brain's ability to quickly consider all of these things and make such a absolute stop-or-go decision is impressive. A program isn't any different, except that every condition has to be explicitly expressed. There's no intuition, only the defined rules that we, as programmers, specified.

21 | 22 | 23 |

Dealing With Data - Types

24 |

The first thing we need to do is understand the basics of how a program deals with data. If you think about it, data can be broken into types. For example the make and model of your car is a string. Your age is a number. Whether you find this book is interesting or not is either true or false (known as a boolean). Strings, numbers and booleans represent the three types we'll concern ourselves with for now. However there are certainly other, more complex types. An address, for example, can be broken down into smaller components (street number, street name, city and country) but it often makes sense to think of an address as a single cohesive type.

25 | 26 |

In a program, telling what type of data we are dealing with isn't difficult:

27 | 28 |
"A string is enclosed in quotes"
 29 | 3.1415
 30 | true
31 | 32 |

Above we have a string, followed by a number, followed by a boolean. Anything enclosed in quotes is a string. While neither a number nor a boolean is enclosed in strings, it's always clear which is which. What about a string that looks like a number or a boolean, for example:

33 | 34 |
"false"
 35 | "9001"
36 | 37 |

These are still strings, because they are enclosed in quotes. However our programming language allows us to convert the first to a boolean and the second to a number. At this point, this isn't important but it's explained in case you were wondering what happens if a number is enclosed in quotes.

38 | 39 |

Why is the type of data so important? The type is what defines what we can and can't do with the data. For example, adding two numbers together or even two strings together make sense:

40 | 41 |
4 + 8
 42 | "Hello " + "World"
43 | 44 |

The first line will result in 12 while the second line will result in "Hello World". However, it doesn't make sense to divide one string by another or to make a number lowercase.

45 | 46 |

There's one final value worth considering: null. null should be thought of as no-value, which is definitely different than an empty string or 0

47 | 48 |

We'll revisit types in throughout the book. What's important for now is that you can tell a string from a number from a boolean and that you understand that what you can do with one type of data isn't necessarily valid for another type.

49 | 50 | 51 |

Dealing With Data - Variables

52 |

Much of the data that your program will make use of isn't going to be known ahead of time. Data can come from many sources, such as user inputs or by reading it from files stored on the computer. In our user registration example, we know that we'll be dealing with an email and password, but we don't know exactly what those values will be.

53 | 54 |

In a program we need a way to label our data, which is where variables come in. Variables, which are very important, basically just hold data. Consider these two examples:

55 | 56 |
email = "leto@dune.gov"
 57 | password = "ghanima"
58 | 59 |

The above code introduces two variables: email and password. A variable and its value are interchangeable. Just like we could add two strings together, so too can we add two variables which hold strings:

60 | 61 |
joined = email + password
62 | 63 |

This introduces a 3rd variable named joined - which likely serves no purpose other than to show that variables and their values are interchangeable. The value of joined is leto@dune.govghanima

64 | 65 |

To understand the role that variables play, you need to remember that not all data is known ahead of time. Rather than creating a variable named email with a specific value, we'd be much more likely to do:

66 | 67 |
email = get_the_value_entered_by_the_user
68 | 69 |

Exactly how get_the_value_entered_by_the_user works or what it does isn't important. What is important is that the email's value isn't determined by us when we program, but rather determined as the program is running.

70 | 71 |

In the next couple of sections, you'll see how important, yet simple, variables are. It's hard to grasp them until we've introduced a few more concepts. What might be obvious already though is that properly naming your variables is crucial to making your code readable. Although you don't know the exact value held by email, if we printed it out, you probably wouldn't be surprised. However, if we named our variable a or the or even string your guess about the contents would be as good as mine.

72 | 73 |

Finally, in most languages, variable names are case-sensitive. Name, name and NAME are all different variables. It's good practice to avoid relying on case to differentiate variables. When code contains both an address and an Address variable, it isn't obvious which should be used or how they differ.

74 | 75 | 76 |

Determining A Course Of Action

77 |

In chapter 1 we learned that a program is read from top to bottom. The reality is more complex. When we described our two examples, we saw how a program needs to execute different code based on various conditions. This aspect of programming is known as control flow, because it controls which part of code will be executed.

78 | 79 |

The simplest control flow is an if condition:

80 | 81 |
if password.length < 8
 82 |   print "invalid password"
83 | 84 |

Building on top of this, we have an if/else condition:

85 | 86 |
if withdraw_amount > account_balance
 87 |   print "Amount too large"
 88 | else
 89 |   account_balance = account_balance - withdraw_amount
 90 |   print "Withdrawal request accepted"
91 | 92 |

Finally we have an if/else if/else:

93 | 94 |
if withdraw_amount < 0
 95 |   print "Nice try, but you can't withdraw a negative amount"
 96 | else if withdraw_amount > account_balance
 97 |   print "Amount too large"
 98 | else
 99 |   account_balance = account_balance - withdraw_amount
100 |   print "Withdrawal request accepted
101 | 102 |

You can have as many else if sections as you want, but only the first valid condition, going from top to bottom, will be executed.

103 | 104 |

The other common type of control flow are loops. These execute the same piece of code multiple times. That might seem silly, and indeed, our first example is silly:

105 | 106 |
for i in [1..10]
107 |   print i
108 | 109 |

The above would print 12345678910.

110 | 111 |

One thing that loops are very handy for is to iterate (or loop) over a collection of values. Earlier we talked about three data types: string, numbers and booleans. We've always seen these as individual values. However, it often makes sense to have a collection of values. In fact, the very first example we saw, back in chapter 1, had a collection of playing cards:

112 | 113 |
deck = ["2 of Hearts", "3 of Hearts", "4 of Hearts", "5 of Hearts"]
114 | 115 |

The square brackets [] means collection. With the knowledge we've gained, we know that the above is a collection of strings, represented by the deck variable. Collections and loops go hand-in-hand:

116 | 117 |
for card in deck
118 |   if card is "Joker"
119 |     print "Please remove the jokers from the deck!"
120 | 121 |

Notice in the above that we introduce a variable named card as part of our loop. The word variable was aptly chosen as the value of card varies with each iteration of our loop.

122 | 123 |

This example is similar to how we'd check for jokers in the real world. It's true that our eyes and brain might be able to look at multiple cards at once, but it isn't a stretch to imagine scanning each card one at a time, and taking a certain action if we spot a joker.

124 | 125 |

Finally, you'll often need conditions based on more than a single fact. For example, we might want to display the above message if the card is "Joker" or the card is "Fool". This is am or condition and will be true if one or the other part is true. The sister to an or condition is the and condition, which will be true only when both parts are true. In some languages the words "or" and "and" are used, but in most "or" is represented by || and "and" by &&. 126 | 127 |

Control flow can get more complicated, but it almost always comes down to taking an action based on some condition, or looping over code. Often, these two concepts are combined, say by looping over code until a certain condition is met. For now, it's sufficient that you understand that given a condition, it's possible to control what, if any, part of code is executed.

128 | 129 | 130 |

Performing Actions

131 |

We know how to manage data, and how to make decisions based on that data, now it's time to take action. If you go back through the examples in this chapter, you'll notice that we've already taken a number of actions. For example, we've printed messages to the user and subtracted one amount from another. Let's break it down further.

132 | 133 |

Programming languages contain a number of operators. The most basic are +, -, / and *. These operators, amongst others, represent the simplest actions we can take: add, subtract, divide or multiply two values. Another important operator is the assignment operator, which assigns a value to a variable. We've seen this plenty of times already, it's the equal sign =. If we go back to an earlier example, we'll find this specific line:

134 | 135 |
account_balance = account_balance - withdraw_amount
136 | 137 |

It's fair to say that this line involves two actions: subtract the two numbers, then assign the results into the account_balance variable. You might be wondering how the order is determined. Just like in mathematic operators, programming operators have an order of precedence and can be controlled with parenthesis (). Thankfully, this order is pretty intuitive. The above is the same as doing:

138 | 139 |
account_balance = (account_balance - withdraw_amount)
140 | 141 |

We could do the following, but it wouldn't make much sense:

142 | 143 |
(account_balance = account_balance) - withdraw_amount
144 | 145 |

This would assign the value of account_balance into account_balance (effectively a meaningless operation) and subtract withdraw_amount but not store that result anywhere.

146 | 147 |

Some operators are frequently used with control flow. We already saw how the greater than > operator can be used to check if one value is greater than another. The other common comparison operators are >=, <, <= and !=, or greater than or equal, less than, less than or equal and not equal. The last and probably most-used comparison operator is the equal operator, or ==. In most programming languages it's represented by a double-equal sign to distinguish it from the assignment operator. The result of comparison operators is a boolean value: true or false.

148 | 149 |

In a previous example we used is to check for equality. This was done because we hadn't covered operators yet. In most languages, you'd write:

150 | 151 |
if card == "Joker"
152 | 153 |

The assignment = and equality == operators might seem similar, but they really have little relation. The first makes the left-hand variable equal to the right hand value. The second results in true of the two values are equal, or false otherwise.

154 | 155 | 156 |

Custom Actions: Functions

157 |

The last, and most advanced topic we'll cover in this chapter are functions. Much like a variable can be thought of as giving a label to a value, a function gives a label to a group of lines of code. Functions are powerful and important. They also serve a number of purposes. First, they help us organize our code. Rather than having a long series of code, we can break it down into functions with meaningful names. Secondly, they help us reuse code. You'll commonly have a task that you'll want to execute over the course of your program.

158 | 159 |

In its simplest form, a function looks like:

160 | 161 |
function sayHello()
162 |   print "Hello"
163 | 164 |

Our new function, named sayHello can be executed by adding parenthesis to the name:

165 | 166 |
sayHello()
167 | 168 |

Functions can also be passed in variables. For a function these variables are called parameters:

169 | 170 |
function sayHello(name)
171 |   print "Hello " + name
172 | 173 |

Finally, functions can return a value:

174 | 175 |
function hasJoker(deck)
176 |   for card in deck
177 |     if card == "Joker"
178 |       return true
179 |   return false
180 | 181 |

The return keyword is powerful as it exits the function immediately. The value returned is no different than any other value we've seen so far. It can be assigned to a variable, compared via an operator as well as other things we haven't looked at.

182 | 183 |

Our hasJoker function can be used like so:

184 | 185 |
if hasJoker(deck) == true
186 |   print "Please remove the jokers from the deck!"
187 | 188 |

As a side note, conditions work by evaluating boolean values (true/false). There's no difference between true == true and just true. Similarly, there's no difference between true == false and just false. Therefore, the above, while more clear, can be rewritten :

189 | 190 |
if hasJoker(deck)
191 |   print "Please remove the jokers from the deck!"
192 | 193 |

In order to make hasJoker more reusable, we might change it like so:

194 | 195 |
function hasCard(deck, card)
196 |   for c in deck
197 |     if c == card
198 |       return true
199 |   return false
200 | 201 |

Which can be invoked like so:

202 | 203 |
exists = hasCard(deck, "2 of Hearts")
204 | 205 |

Notice that we had to change the name of card variable created in our for loop so that it wouldn't be confused with the card parameter. Depending on the language that you were using, you'd either get error or some weird behavior. Also, c isn't the best variable name, but given that it has a very short existence, it's probably ok.

206 | 207 |

Like variable names, function names are also case-sensitive.

208 | 209 | 210 |

In This Chapter

211 |

This chapter introduced the concept of data types and variables, control flow via if/else and loops, as well as operators and functions. Everything was broken down into small chunks, making it hard to see how they all fit together to form a program, but our last few examples, which were more complex, started to give us some insight on how it all fits together.

212 | 213 |

If it feels like a lot of things are still shrouded in mystery, it's because they are. How do the email and password variables actually get populated with what the user entered in his or her browser, and how do we get an account_balance based on the account_number on the card? These are good questions with complicated answers. But understanding the topics we've covered so far is the first step.

214 | -------------------------------------------------------------------------------- /views/chapters/en/3.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Your First Program

4 |

This chapter is different than the ones we've seen so far. It'll let us apply what we've learned interactively. We'll be putting together a shopping list to build up our knowledge through small and simple steps. We'll also introduce new and more powerful concepts.

5 | 6 |

In this chapter you'll be asked to provide some code in order to fufill a certain purpose. The output of this code will be diplayed on the right. Don't be afraid to try different solutions; and if you aren't sure what to type, you can always view the answer via the answer button. Do as much or as little as you want - we all learn differently and at a different pace.

7 | 8 |

We haven't talked about comments yet, but almost all languages allow developers to add comments to their code. These have no impact on the application, but can be useful as reminders or explanations for other developers or even yourself.

9 | 10 |

Most languages use one or two characters to mark the start of a comment. The two most common are # and //. You'll see some comments in the example below.

11 | 12 | 13 | 14 |

Lay Of The Land

15 |

The first thing we'll do is get comfortable with this new interactive environment. Every interactive section has the same six components. You should familiarize yourself with all six.

16 | 17 |
    18 |
  1. First, in the top right is your shopping list. This area will get updated with new items when you run your code. This is also where errors will be displayed.
  2. 19 |
  3. Next, you have an coding area, which is where you can program. The coding area is easy to spot because of how green it is.
  4. 20 |
  5. Below the coding area you'll find the run button. Clicking it will run the code found inside the coding area (again, feel free to play around, no one's watching!)
  6. 21 |
  7. Since each excercise builds on top of the previous one, a reset button allows you to ensure your shopping list is properly setup. This is useful if you skip a step or if you played around and your shopping list is a mess.
  8. 22 |
  9. Next to the run button you'll find the an answer button which will show you a possible answer (there's always more than one way solve a programming problem).
  10. 23 |
  11. Finally, whenever you are typing inside your coding area, you'll see a functions list below your shopping list. This represents a list of functions you are allowed to use in this particular section. You can think of these as a 3rd party library - there to help you with common tasks.
  12. 24 |
25 | 26 |

Let's give it a try. Below you'll find your first coding area. Once you click in it, you'll see that you have 1 function avaible (in the functions list). Since there are many ways to achieve the same thing, it's up to you to decide if your answer is correct. If you aren't sure, compare it to the provided answer (via the answer button).

27 | 28 |
29 |
You need to buy milk. Add it to your list.
30 | 31 | 32 |
33 | run 34 | reset 35 | answer 36 |
37 |
38 | 39 | 40 |

Getting Input

41 |

While a program may have many hard-coded values, most data comes from external sources: like a file or user input. In our example above, it doesn't make sense to hard-code the value milk. Instead, we'd prefer to ask the user using the newly available prompt function:

42 | 43 |
44 |
Ask the user what to add and add the value to the list
45 | 46 | 47 |
48 | run 49 | reset 50 | answer 51 |
52 |
53 | 54 | 55 |

addItem, prompt, What Are These?

56 |

This is just a little detour to remind you of the conversation we had about libraries and framework from chapter 3. You might very well be wondering where addItem and prompt come from and might even feel like you are cheating a bit. prompt is actually a function built-into your browser. I wouldn't even know where to begin if we had to build it ourselves. addItem is a function written specifically for this tutorial and can be simply thought of as a third-party library.

57 | 58 | 59 |

Some Basic Validation

60 |

Currently, our little program allows users to answer the prompt without actually entering a value. It would be nice to catch this and display a message. Try it by using an if/else condition and the new alert function:

61 | 62 |
63 |
If the entered value is empty, alert an warning
64 | 65 | 66 |
67 | run 68 | reset 69 | answer 70 |
71 |
72 | 73 | 74 |

Avoiding Duplicates, Part 1

75 |

The last task that we'll look at is making sure we can't add the same item twice. We'll do this in two separate steps. First, we'll use the new function itemExists to see if the item already exists. This is very similar to our above null or empty check. Go ahead and try:

76 | 77 |
78 |
Display a message if the item already exists
79 | 80 | 81 |
82 | run 83 | reset 84 | answer 85 |
86 |
87 | 88 | 89 |

Avoiding Duplicates, Bonus Step

90 |

The last step that we'll look at in this chapter is to write our own itemExists function. In order to be able to do this we'll use the new getItems function which returns a collection of existing items. In chapter 2 we saw how to use a for loop to iterate over each value in a collection, such as for card in deck.

91 | 92 |
93 |
As a bonus, write your own itemExists function
94 | 102 | 103 |
104 | run 105 | reset 106 | answer 107 |
108 |
109 | 110 | 111 |

In This Chapter

112 |

This chapter had two purposes. First and foremost, to reinforce what you've learned in the previous chapters by having you actually code. Hopefully you felt somewhat adventurous and tried to come up with various solutions, or tried doing something completely different. For example, what happens if you go back to the first example and leave out the closing quote addItem("milk) or tried to call a function which does not exist?.

113 | 114 |

Don't worry if you had to use the answers often, or even if the answers didn't make too much sense. The next chapter will be dedicated to understanding some of the more advanced concepts that we've seen here, as well as introducing a few new ones.

115 |
116 | 117 | 118 | 119 | 120 |
121 |
122 |

Your Shopping List

123 |
124 |
125 |
126 |

Available Functions

127 |
128 |
129 |
-------------------------------------------------------------------------------- /views/chapters/en/4.ejs: -------------------------------------------------------------------------------- 1 | 2 |

Data Structures

3 |

Up until now, whenever we wanted to group values together, we've used the term collection. For example, our deck variable held a collection of cards. However, to be accurate, our deck is actually an array, which is just one of many collections. An alternative word for collection is data structure.

4 | 5 |

In this chapter we are going to look at a few data structures, including arrays, in order to properly understand them. There are countless data structures but it isn't important to know them all. What is important is to understand the common ones, and to understand why so many exist. So far we've only needed arrays, so it can be hard to imagine problems where arrays aren't ideal or even sufficient.

6 | 7 |

Data structures are important as they provide the mechanism for defining what we can do with our data. Other aspects, such as the type system (strings, numbers, booleans, ...), deal with what our data is. Also, data structures can have certain performance characteristics, for example retrieving the value of an array at a specified index will always be the same no matter how small or large the index is. Put simply though, data structures communicate a lot about the code. They define a common terminology so that when a programmer sees code using an array he or she can automatically infer both how the data can be manipulated and how those manipulations will perform.

8 | 9 | 10 |

Arrays

11 |

We've already seen arrays enough to know quite a bit about them. Ultimately an array allows the values within it to be accessed by an index. Given the following code, we'd expect the value sun to be displayed:

12 | 13 |
landscape = ["hills", "clouds", "sun", "birds"]
 14 | alert(landscape[2])
15 | 16 |

In most languages, the first element of an array starts at index 0 because the index represents the offset from the start. We can also write a value at a specific index:

17 | 18 |
landscape[3] = "seagulls"
19 | 20 |

Another important characteristic of arrays is that the order of elements is preserved. In the following example, where we start with a blank array and add two items, we know for sure that the 2nd item will be cat:

21 | 22 |
pets = []
 23 | pets.push("dog")
 24 | pets.push("cat")
 25 | alert(pet[1]) # will display cat
26 | 27 |

This might seem obvious, but we'll soon see data structures which don't make such guarantees. The real power of array ordering is that you can control the order yourself. Initially the values in an array are arranged based on how they were inserted. However, you can rearrange the order to suit your needs - say by sorting them from most awesome pet to least awesome pet (thus making cat the first item in the array!)

28 | 29 |

Sadly, there's some ambiguity over what an array actually is. In many languages, an array is fixed-sized. That is, we can only create an array by specifying a size (the number of elements to hold) and cannot expand the array beyond this size. If we need more room, we must create a larger array and copy over the values ourself. This is the traditional and proper meaning of array. Arrays which don't require that we specify an initial size and can grow as needed, are often called dynamic arrays. This is one of the few cases where data structure terminology is ambiguous.

30 | 31 |

We won't worry about fixed-sized arrays. In fact, for day-to-day programming, fixed-sized arrays, although often used, feel like a relic from the past. New languages tend to favor dynamic arrays (and simply call them arrays.). Whatever type of array we are talking about, the important point is that they are ordered and accessed by indexed.

32 | 33 | 34 |

Queues and Stacks

35 |

Queues and stacks aren't data structures that you'll use often, but we'll learn them to understand how data structures differ from one and other, and why so many exist in the first place.

36 | 37 |

Both are very well named, and to understand how they work, you must simply think of a real life queue and stack. Imagine a line of people waiting at the checkout counter. The behavior of this line is simple: you get into the queue, then move closer to the front and then get out of the queue. In computer science terms, a queue is also known as a FIFO, or first-in first-out. That is, the first person to enter the queue will be the first person to leave the queue.

38 | 39 |

A stack on the other hand is like a stack of chips in a poker game. Chips get added and removed from the top of the pile. A stack is known as a LIFO, or last-in first out. Because the most recently added chips are the ones that get used up the soonest.

40 | 41 |

Knowing this, we can implement a queue with just two functions: enqueue and dequeue. Similarly, a stack can be implemented with: push and pop. The names of the functions don't matter as much as what they do, but these names are commonly used.

42 | 43 |

Both queues and stacks can be, and often are, built using arrays. For example, if we were to build a queue using the arrays that your browser supports, we can use the push function to add, or queue, values and the shift function to dequeue values:

44 | 45 |
queue = []
 46 | queue.push("Custom 1")
 47 | queue.push("Custom 2")
 48 | queue.push("Custom 3")
 49 | queue.shift() #returns Customer 1
 50 | queue.shift() #returns Customer 2
 51 | queue.shift() #returns Customer 3
52 | 53 |

For stacks, we can use unshift to push values at the front and again use shift to pop values from the front:

54 | 55 |
stack = []
 56 | stack.unshift("Chip 1")
 57 | stack.unshift("Chip 2")
 58 | stack.unshift("Chip 3")
 59 | stack.shift() #returns Chip 3
 60 | stack.shift() #returns Chip 2
 61 | stack.shift() #returns Chip 1
62 | 63 |

At this point, it wouldn't be unreasonable for you to wonder whether stacks and queues really serve a purpose. It just seems like we are limiting the functionality available to arrays! But we've only looked at the simplest implementation. A queue for example can be enhanced to handle priorioty (often called a priority queue). Items get enqueued normally but also include an additional piece of information: their priority. Items are then dequeued first based on priority, then in the order they were enqueued. Another enhancement has to do with an empty queue or stack. Our above code simply returns an undefined value if we shift when our collection is empty. Many implementations can be made to wait (or block) until sometimes else adds items to the queue.

64 | 65 |

Queues and stacks serve specific but not entirely uncommon goals. However, they aren't something we need to master. We introduced them to show how data structures define what we can do with our data. It isn't just about being able to do more or less, but also about doing things differently (such as waiting until a value is present before we shift.)

66 | 67 | 68 |

Sets

69 |

Arrays are great if you want to preserve the order of values, or if you want to randomly access values by index. However, as we've already seen, to check if a value exists within the array, we have to loop through it. This may be fine for small arrays, but for large arrays with thousands of values and checks happening hundreds of times per second, it's quite inneficient. The performance characteristic of searching an array is described as linear because the time it takes to find an item grows linearly with the number of values in the array.

70 | 71 |

If rather than accessing a value by a numeric positional index, we want to access it by the value itself, we can use a set. Since the way we access our data (or, the key) is the value itself, sets don't allow duplicate values. These properties make sets ideal for a number of use cases: such as a shopping list. The reason we didn't use a set in the previous chapter is because browsers don't yet support them, but newer versions will.

72 | 73 |

The way sets will probably end up looking is:

74 | 75 |
list = new Set()
 76 | list.set("milk")
 77 | list.set("eggs")
 78 | list.set("milk") #doesn't do anything
 79 | alert(list.exists("milk")) # will display true
80 | 81 |

In theory, we could use plain old arrays to create sets. In fact, in chapter 3 we could have modified the addItem function to make use of the itemExists and not allow duplicates to be added. However there are certain performance characteristics that one expects from a set. Namely, the speed of adding an item and checking for the existence of an item should not vary based on the size of a set. This is a good example of how data structures not only define the behavior of a collection, but also their performance characteristics.

82 | 83 |

As a final point, a properly implemented set should allow for set-based operation (in the mathematical sense). For example, you should be able to create a union of two sets (to get all the values contained in both), or an intersection (to get only the value which exist in both). That may seem academic, but it's actually quite useful. Imagine having a set with the list of movies Jane has seen and intesecting it with the set of movies Matt has seen. The result is a list of movies that both have seen.

84 | 85 |

Sets are very powerful; but what you gain in terms of functionality and perfomance for some things, you lose in terms of other. In comparison to arrays, you've lost ordering and the ability to hold duplicate values.

86 | 87 | 88 |

Hashes

89 |

So far all the collections that we've looked at deal with a single value. Hashes on the other hand deal with a key and a value. Hashes are also known as dictionaries and hash sets. Most of the time the key is a string, while the value can be any other piece of data. As an example, if we wanted to track how many items to buy, we could use a hash:

90 | 91 |
list = {}
 92 | list["milk"] = 1
 93 | list["milk"] = list["milk"] + 1
 94 | alert(list["milk"]) # will display 2
95 | 96 |

Notice that we create a hash with braces {}. The value of a hash isn't limited to a simple string, number or boolean. It can be something more complex, like an array, or another hash:

97 | 98 |
list = {};
 99 | list['milk'] = {quantity: 1, section: "dairy"}
100 | alert("You need to buy " + list["milk"]["quantity"] + " milk")
101 | 102 |

Above we see an inline method for creating a hash. Sets and hashes share a lot in common. We can actually create a set using hashes. Our above set example could be rewritten like so:

103 | 104 |
list = {}
105 | list["milk"] = true
106 | list["eggs"] = true
107 | list["milk"] = true
108 | alert(list["milk"] == true) # will display true
109 | 110 |

However, we don't have access to any set-based operations, like a union (which we might not need).

111 | 112 |

Hashes are powerful and are used often. They conveniently let you represent more complex data. For example, we could represent a spreadsheet using an array of hashes:

113 | 114 |
rows = []
115 | rows.push({type: "cat", name: "fluffy", age: 5})
116 | rows.push({type: "dog", name: "hunter", age: 6})
117 | rows.push({type: "fish", name: "jorge", age: 2})
118 | alert(rows[1]["name"] + " is " + rows[1]["age"] + " years old"); # hunter is 6 years old
119 | 
120 | 121 |

Like many things, the role played by hashes has changed over time. They were once used mostly to quickly access data by key. While still used frequently for this purpose, we see hashes being used more and more as simple containers of values, such as the animal data shown above. In a later chapter, we'll learn about classes which are a more structured way to contain and represent such data.

122 | 123 | 124 |

In This Chapter

125 |

In this chapter we learned about arrays as well as hashes. These are two data structures that you'll make heavy use of. We also saw queues, stacks and sets. While all three serve useful purposes, we mostly explored them as a means to learn about different data structures. There are other classes of data structures available, but they tend to be more complex, more specialized and thus less often used.

126 | -------------------------------------------------------------------------------- /views/chapters/en/5.ejs: -------------------------------------------------------------------------------- 1 | 2 |

More on Languages

3 |

Our goal thus far has been to learn about programming in general, regardless of the language and its libraries. For this reason, we've looked at things that exist no matter what language you use. How you define a variable, or the exact syntax of for loop is secondary to the concept of variables and looping.

4 | 5 |

In this chapter we'll continue down this same path, but with a slightly broader perspective. Specifically, we want to familiarize ourselves with some of the other common things we are likely to see in a program. Some of these are just shortcuts provided by the language, or different approaches some languages take. Hopefully by learning these you'll not only be in a better position to write more complex programs, but also be better able to understand other people's code.

6 | 7 | 8 |

Incrementing and Decrementing

9 |

We've already seen a number of examples where we increment and decrement a value by some number:

10 | 11 |
i = i + 1
 12 | # or
 13 | account_balance = account_balance - withdrawal_amount
14 | 15 |

Incrementing and decrementing values is such a common thing, that most languages provide alternative syntax:

16 | 17 |
i += 1
 18 | # or
 19 | account_balance -= withdrawal_amount
20 | 21 |

The two versions are identical, the second one is simply less verbose by making use of the += and -= operators. Not only is incrementing so common that we have this special syntax, but incrementing and decrementing by 1 is itself so common that many languages give us special syntax for that specific purpose:

22 | 23 |
i++
 24 | 
 25 | i--
26 | 27 |

This is known as post-incrementing and post-decrementing. An alternative is to pre-increment or pre-decerement. he difference between them is all about the operator's precedence with respect to other operators. Consider: 28 | 29 |

i = 5
 30 | total = i++
 31 | //vs
 32 | i = 5
 33 | total = ++i
34 | 35 |

In both cases i will be equal to 6. However, in the first case, i is assigned to total and then incremented. Thus, total is 5. In the second case, i is incremented and then assigned to total. Thus, total is 6.

36 | 37 | 38 |

Strings With Values

39 |

You'll often want to display a message which includes variable values. There are three common ways to do this, but not all languages provide all three mechanisms.

40 | 41 |

The simplest to understand, and the one we've used so far, is to join the pieces together with the + operator:

42 | 43 |
name = prompt("What is your name?")
 44 | alert("Hello " + name)
45 | 46 |

This works well for simple a message, but it can get quite messy for something even slightly complicated.

47 | 48 |

Another common approach is to have some type of string formatting function. Every language seems to have its own version, but it normally ends up looking something like:

49 | 50 |
name = prompt("What is your name?")
 51 | formatted = format("Hello %s", name)
 52 | alert(formatted)
 53 | 
 54 | # or, a more terse version:
 55 | name = prompt("What is your name?")
 56 | alert(format("Hello %s", name))
57 | 58 |

Again, this varies a lot from one language to another, but in the above %s is a string placeholder, as opposed to a %d which is a digit placeholder. Writing such a format function in most languages wouldn't be too difficult (assuming one didn't already exist).

59 | 60 |

The last approach that you'll often see is the ability to put variables directly in your string, by wrapping it in a special sequence of characters:

61 | 62 |
name = prompt("What is your name?")
 63 | alert("Hello #{name}")
64 | 65 |

The exact syntax will vary from language to language, and many languages don't even support this approach.

66 | 67 | 68 |

Strings and Escape Sequences

69 |

Sometimes you'll want to include a special character within a string. The most common example is a double quote. However, a computer can't make sense of the following since it means something special within the language itself (the start or end of a string). It might be obvious to you and me where the following string meant to end, but a computer can't tell:

70 | 71 |
message = "And he said "to get to the other side""
72 | 73 |

To avoid this ambiguity, languages tend to have an escape character, and that tends to be the backslash \:

74 | 75 |
message = "And he said \"to get to the other side\""
76 | 77 |

When you want to print an actual backslash, you simply escape it:

78 | 79 |
message = "I'm printing a backslash like so \\"
80 | 81 |

Finally, if you want to output a tab or new line, you can use the special \t or \n sequence. \n is a line feed. To get a new line to display properly on some operating systems, you'll have to print out a carriage return \r followed by a line feed: \r\n.

82 | 83 | 84 |

Loops

85 |

for loops aren't the only type of looping mechanism available in most languages. Two other common ones are the while and do/while loop. In general, a for loop can be thought of as iterating through a collection of values. A while and do/while loop iterate so long as a condition is true. They are both similar in that, the for loop's condition is implied to be: is there another value?. For example, we could iterate through a collection of values using a while loop like so:

86 | 87 |
i = 0
 88 | while i < deck.length
 89 |   if deck[i] == 'Joker'
 90 |     # .. do something
 91 |   i += 1
92 | 93 | 94 |

With both a while and for loop it is possible for no iterations to take place if the condition is initially false or the collection is empty. A do/while places the condition at the end, and thus will execute at least once:

95 | 96 |
do
 97 |   name = prompt("What is your name?")
 98 |   alert("Hello " + name)
 99 | while name != "Joker"
100 | 101 |

Generally speaking you'll see for the most often, then while and finally do/while.

102 | 103 | 104 |

In This Chapter

105 |

This chapter introduced new keywords and operations which many languages make available. Some of these may seem minor, that's because some are. Understanding the concepts behind variables and conditions to control execution is a lot more important than knowing that i++ is a quick way to do i = i + 1. However, as soon as you start exploring other guides and sample programs, these are things that you'll imediately run into.

106 | 107 |

For the time being, you might be uncertain about what's the best approach to use for a given piece of code. What loop should you use, or how should you mix strings and values? At first, worry about making your code do what you want it to do. With experience, both from reading other people's code, and expanding your own, you'll gain a feel for what improves and what detracts from your code's readability.

108 | -------------------------------------------------------------------------------- /views/chapters/en/6.ejs: -------------------------------------------------------------------------------- 1 | 2 |

More On Types

3 | In chapter 2 we talked about types, focusing on three main types: strings, numbers and booleans. In following chapters we used arrays and talked about other data structures. However, throughout our coding, types haven't played big role. Besides knowing that a value was a string or a number, and knowing that some operations only work on some types (like conditions are expressed as booleans), it has all seemed rather academic.

4 | 5 | 6 |

Dynamic vs Static Typing

7 |

Types truly are important as they define what we can and can't do with our data. How much in-your-face this fact is largely depends on the language. With respect to types, languages fall into one of two categories: types are either explicitly stated or they are implied. The proper terms are: static typed languages and dynamic typed languages.

8 | 9 |

So far we've only seen dynamic typing. In a static typed language, you'll see code peppered with type information. If we were to rewrite our itemExists function in such a language, it would look something like:

10 | 11 |
bool function itemExists(string itemToFind)
12 |   string[] items = getItems()
13 |   for item in items
14 |     if item == itemToFind
15 |       return true
16 |   return false
17 | 18 |

Notice that our variables are now declared with explicit type information - such as string[]). Furthermore, we've had to state the type of parameter our function expects as well as the type it returns.

19 | 20 |

In a static language, once a variable is declared to be a certain type, the values assigned to it can only be of that type. This isn't true of a dynamic language. Below we have code written in a dynamic language, followed by code written in a static language. The static language version will not compile - you'll get an error because name is defined as a string and cannot hold a number:

21 | 22 |
name = "Goku"
23 | name = 9001
24 | 
25 | # vs
26 | string name = "Goku"
27 | name = 9001 # error!
28 | 29 |

Many programmers passionately prefer one type system versus the other. Proponents of dynamic languages say they are more productive. Developers who prefer static languages think their code is less likely to contain errors and run faster.

30 | 31 |

This is a good time to point out that the type system isn't just about having to enter fewer characters. Languages that are dynamic tend to have other common properties; and static languages share many similarties with each other. As a simple example, arrays in dynamic languages tend to be dynamic, while arrays in static languages tend to be fixed.

32 | 33 |

Professional programmers should strive to master at least one of each. As someone learning to program, I don't think it matters too much which one you pick. Dynamic languages are probably easier to learn. The choice may very well be forced upon you based on what you want to program. For example, if you want to write applications for Android mobile devices you only have one language choice, Java, which is statically typed.

34 | 35 | 36 |

Numbers

37 |

So far we've treated all numbers the same. However, numbers actually come in a variety of shapes and sizes. At the very least, most languages support two types of numbers: integer and floats. Integers don't support decimals and typically support a range of -4 billion to +4 billion (plus or minus a couple hundred million). 0, 5, -1495 and 9001 are all examples of integers. Floats on the other hand support a much wider range and support fractions. 0.1, -29394.49 and 2003.9 are all examples of floats.

38 | 39 |

Static languages tend to take this even further by introducing different types of integers and floats. The different integers represent different minimum and maximum ranges. A byte can go from 0 to 255 while a long can go into the quintillions. Integers can also be made to disallow negative values (and thus increasing the maximum positive value). Finally, floats can also be decimals. The difference between a float and a decimal has to do with accuracy. When you manipulate floats (such as multiplying or dividing them) you can lose precision (think of it as rounding errors) which is bad if you are dealing with things like money. Decimals don't suffer from this problem. The downside is that they don't perform as well

40 | 41 |

For now, you just need to know that numbers are categorized as integers and floats. The main difference being that floats support fractions.

42 | 43 | 44 |

Type Conversion

45 |

Whatever type system you are dealing with, you'll often want to convert data from one type to another. Even in a dynamically typed language, a value still has a type. For example, the value returned by the prompt function is always a string. If the user enters 5 when prompted, what do you think the value of sum will be?:

46 | 47 |
sum = 4
48 | sum += prompt("Enter price")
49 | 50 |

This depends on the language you are using. Some will generate an error. Others will convert the sum to a string and append it to the 4 already stored in it - resulting in "45". To get the desired answer of 9 we need to convert the value to an integer. Different languages have different functions for doing this. In your browser the functions parseInt and parseFloat convert a value to an integer or float:

51 | 52 |
sum = 4
53 | sum += parseInt(prompt("Enter price"))
54 | 55 |

What happens if the value we are trying to convert isn't a valid integer? Again, this depends on the language. Many will generate an error. Some may return special values that indicate that the conversion failed.

56 | 57 |

Similarly, values can be converted to a string. This is often done via a method called toString. Again, it's worth pointing out that not all languages behave the same. For example, your browser will gladly execute the following:

58 | 59 |
power = 9001
60 | alert("It's over " + power)
61 | 62 |

Whereas another language, even a dynamic language, might insist that power be explicatly converted to a string.

63 | 64 |

In addition to conversions, static languages allow some types to be coerced into other types. For example, we said that a byte can hold a value from 0 to 255 while a long has a much larger range. Despite this difference, there is some overlap. In some cases, a long could be a valid byte. We can only turn a long into a byte by explicitly telling the compiler yes, we really mean to do this. This coercion is done by casting:

65 | 66 |
long large = 200
67 | byte small = (byte)large
68 | 69 |

Finally, you might be surprised by the result you get when dividing integers. In some languages, dividing the integer 1 by the integer 3 will give you an expected float 0.333333. In static languages, however, operations involving two integers will result in an integer, as will operations involving two decimals result in a decimal. Therefore, 1 / 3 will result in 0. This is true for many dynamic languages as well. To get the 0.3333, one or both values must be a float: 1 / 3.0.

70 | 71 | 72 | 73 |

Getting The Type

74 |

It's always possible to get a value's type. This is often achieved via the typeof, or similarly named, operator. The following code will display string.

75 | 76 |
alert(typeof "i love unicorns")
77 | 78 |

This is handy in cases where we don't know what type of data we are dealing with. Futhermore, in many other languages, types themselves are complex objects supporting many advanced functions. This isn't something you are likely to need as you get started. But it should give you some idea of just how big a role types play - in both dynamic and static languages.

79 | 80 | 81 |

In This Chapter

82 |

This chapter expanded our initial concept of types into a much more comprehensive version. The most important thing to know is that static typed languages exist and are very popular. If you are looking at code and you see the words string and int (to name a few), you are looking at a static typed language.

83 | 84 |

We also broke down numbers into two main groups. It's normally obvious if you want an integer or a float. The breakdown from that point on isn't as important. The only exception is if you are dealing with money, in which case you'll want to make sure you are using a type that won't lose precision.

85 | -------------------------------------------------------------------------------- /views/chapters/en/7.ejs: -------------------------------------------------------------------------------- 1 | 2 |

Next Steps

3 |

The world of programming is vast, but you've taken the first step. There are a number of advanced, yet fundamental, topics still worth exploring. There's an even greater number of higher-level concepts and tools that might interest you. Even though you could continue to learn about programming in general, a more specific route would yield more tangible benefits.

4 | 5 |

In this chapter we'll look at where you can go from here. Generally speaking, where you go is defined by what you want to do. Do you want to build mobile applications or websites? Do you need to deal with data and report or maybe weave some spreadsheet magic? Each of these fields tend to have their own languages. But learning a new language isn't the challenge. What's truly difficult about learning a new field of programming are the libraries and constraints specific to that field or technology. The way that you display an input field on a website is different than how you do it on an iPhone. Similarly, the challenges of dealing with different browsers and slow internet speeds are different than those of dealing with limited battery life and a touch-based interface.

6 | 7 | 8 |

A Tip On Learning

9 |

We all learn differently. Some like to read, some like videos, others have to get their hands dirty. There's one strategy that I've used which I'd like to share with you: learn by helping. Whenever I'm learning something new, I join the forums and hang around in the groups and try to answer whatever questions I can. At first, I can't answer anything. But I read the questions people have, spend a bit of time trying to figure it out, and read the replies they get. Eventually, someone asks a question that I know the answer to. That first "thanks" reply is quite satisfying; as is the pace at which you find yourself able to answer additional questions.

10 | 11 |

Maybe this trick won't work for you, but I suggest you try it. Many communities have their own forums and groups where anybody can ask questions and anybody can answer. Alternatively, you can try a more generic help site like StackOverflow. You can follow only those topics which interest you, ask questions when you need help, and answer questions when you can.

12 | 13 |

Also, practice! Programming is about experience and practicing is the key. Don't worry about making mistakes, as it's one of the best ways to learn.

14 | 15 |

Finally, most of the day-to-day programming that goes on isn't a hard science. Despite what you might read, there isn't necessarily one best way to solve a problem. There certainly isn't one best tool, or one best language. Keep this in mind when getting advice.

16 | 17 | 18 |

Websites

19 |

Of all the technologies that may interest you, programming websites is likely the most daunting for two important reasons. First of all, there's so much choice in technologies and tools, that it's simply overwhelming. Which do you pick and where do you start? Secondly, in order to create a meaningful website, you need to know 5 different technologies. HTML, CSS and JavaScript can be thought of controlling everything the user sees and interacts with. You then need a language that does all the behind the scenes work - like saving users. Finally, most websites rely on some type of database to store data. Individually, these aren't hard to learn (you can put together a simpe HTML page in a few minutes). But combined, it's a bit crazy.

20 | 21 |

However, of all the technologies, you won't find better resources than those available to web programmers. Using Google you can find endless guides, tutorials, videos and blog posts that cover each of these technologies - both separately as well as how they come together. It's a passionate and mature community. Furthermore, the web is the most accessible platform available. Build something for the web and anyone can use it.

22 | 23 |

While there truly is too much choice, I feel comfortable in recommending two specific technologies: PHP and Python.

24 | 25 |

PHP is the most established and most popular language for the web. It will be the simplest thing to learn, and also one of the best documented. The downside of PHP is that it isn't particularly elegant and many of the concepts are dated. Also, PHP is almost exclusively used for the web. While much of the core experience you gain using it is transferable, the language and libraries itself aren't. The official PHP website, while intimidating at first, is a good place to start.

26 | 27 |

Unlike PHP, which is both a language and a framework, Python is just the language. For web-based applications, you'll want to pair it with an appropriate framework. Django is a popular choice with excellent documentation. Python is modern and popular for tasks other than websites, making it a more useful language than PHP. Python web frameworks, like Django, are more elegant and promote good approaches to programming. Furthermore, the Python community as a whole tend to write excellent documentation and guides.

28 | 29 |

Learn Python The Hard Way is a great ebook you can use to master Python. You can read the book online for free, or pay for a pdf or epub.

30 | 31 | 32 |

Mobile Applications

33 |

If you are interested in writing mobile applications, the choice is much simpler. If you want to target Apple-based devices (iPhones and iPads), you'll want to learn the Objective-C language and the Cocoa framework. Apple's developer center is the right place to start. To write iOS applications you'll need an Apple computer as well as XCode, which you can download for free from the app store.

34 | 35 |

For Android-based devices, you can head over to Google's Android developer zone. Android applications are built using Java (which has no relationship to JavaScript). The tools are free and can be run on all popular operating systems.

36 | 37 | 38 |

Windows

39 |

For anything relating to Windows, you'll likely want to learn C# and check out MSDN. Of all the technologies listed here, Microsoft's documentation is the worst - likely because it's such a large ecosystem. Microsoft has a number of free tools under its Express brand, which are a great way to get started.

40 | 41 | 42 |

Database

43 |

There are a number of databases available, but thankfully they all use a standard language known as SQL (Structured Query Language). Different databases do extend SQL with their own extensions, but once you know the fundamentals, everything else easily falls into place. A big part of learning a database isn't the language, but rather how to model your data and how to effectively query it.

44 | 45 |

It doesn't matter which database you pick, but if you don't have any existing preferences, I'd suggest you look at PostgreSQL. It's free, runs on most operating systems, has good documentation and a strong community.

46 | 47 | 48 | 49 |

Conclusion

50 |

A challenge of learning and teaching programming is how long it takes before something tangible can be created. In this respect, this book has failed you. You didn't create anything meaningful and there's still much to learn before you can do so.

51 | 52 |

Despite this, I'm hopeful that you don't feel like your time has been wasted; nor that you are discouraged. Even if you've spent all this time and many things remain unclear, don't be dissapointed. As you start to turn this theory into practical solutions, much will become clear. In some ways, we've barely taken a step forward. But we have oriented ourselves, ensured that we have the basic provisions, and properly readied ourselves for our journey.

53 | 54 |

Thank you.

55 | -------------------------------------------------------------------------------- /views/chapters/en/_old_syntax_chapter.ejs: -------------------------------------------------------------------------------- 1 | 2 |

Understanding Languages

3 |

Now that we've learned the basics, it'd be wonderful if we could start putting all the pieces together and slowly program an application. Before we can do that though, we need to talk about some details that we previous glossed over, and correct some over-simplifications.

4 | 5 |

In chapter 1 we mentioned that there are a lot of programming languages and that programming languages define the syntax that we use (amongst other things). Now that we've seen more code and we've seen the components which are common to almost all programming languages, it's time to show concrete examples of how one language might be different than another.

6 | 7 |

Also, since programmers use programming language and language interchangeably, we will too.

8 | 9 |

Finally, programming languages tend to have a long life. A number of today's most popular languages are over 30 years old and almost all mainstream languages are at least a decade old. When you see something strange about a language, it very well could have to do with a problem or limitation long-since solved.

10 | 11 | 12 |

Syntax

13 |

In chapter 2 we saw a number of operators, such as the assignment operator =, the equality operator == and the addition operator +. But there are no rules that say that these symbols must be used for these actions. A language designer could decide to use % to compare values and # to add them. Furthermore, there's no rule that defines what features a language must support. Maybe it isn't possible to add strings with an operator or to compare two values. Of course a language that didn't follow the most basic common sense or provide the most basic functionality, probably wouldn't be very popular.

14 | 15 |

However, while we can all agree that + is the best symbol for the addition operation, and that a language should allow us to compare values, there are a number of things which are very subjective.

16 | 17 | 18 |

Variable Declaration

19 |

In chapter 2, we declared and assigned variables like so:

20 | 21 |
name = "Leto"
22 | 23 |

It isn't uncommon that languages require slightly more explicit syntax:

24 | 25 |
var name = "Leto"
26 | 27 |

Again, some languages might opt for something different than var. One of the benefits to this is that variables can be declared but uninitialized:

28 | 29 |
var name;
30 | 31 |

This, of course, brings up the question what value is name?. Most languages have some concept of no value, which is typically identified by the null keyword, though nil and None are also common.

32 | 33 |
if name == null
 34 |   print "Please enter a name"
35 | 36 |

While we are talking about variables, it's worth pointing out languages put restrictions on the characters you can use to name your variables, or functions. Thankfully, if you are naming things to be meaningful, this is rarely a problem.

37 | 38 | 39 |

Strings

40 |

In most languages, strings are exactly as we've explained them - a value enclosed in double quotes. However, some languages also allow you to use single quotes. The two often behave slightly differently, but don't worry about that. For now, it's safe to think of the two as being interchangeable (assuming the language supports both).

41 | 42 | 43 |

Statement Termination

44 |

Many languages require an explicit character to mark the end of a statement and in many languages this symbol is a semicolon ;:

45 | 46 |
name = "Leto";
 47 | account_balance = account_balance - withdrawal_amount;
48 | 49 |

Although newlines are often meaningless in these languages, developers still write a statement-per-line. Languages with a statement terminator are more popular than those without, but this does seem to be changing with time. This isn't to say having an explicit statement terminator is useless. How should the following behave?

50 | 51 |
return
 52 | ["Ace of Clubs", "2 of Hearts"]
53 | 54 |

Should it return nothing, or should it return the collection of cards? In situations like these, languages without explicit statement terminators will always behave predictably, but unless you know what that behavior you can't just look at this code and know how it'll behave.

55 | 56 | 57 |

Scope

58 |

When we introduced the if/else control flow, we used indentation to indicate the lines of code that belonged to each branch:

59 | 60 |
if withdraw_amount > account_balance
 61 |   print "Amount too large"
 62 | else
 63 |   account_balance = account_balance - withdraw_amount
 64 |   print "Withdrawal request accepted"
 65 | end
66 | 67 |

A common alternative is to use braces {}. This tends to be seen in languages which also require statement termination ; - probably because they are all more or less descendants of a very popular language called C.

68 | 69 |
if (withdraw_amount > account_balance) {
 70 |   print "Amount too large"
 71 | } else {
 72 |   account_balance = account_balance - withdraw_amount
 73 |   print "Withdrawal request accepted"
 74 | }
75 | 76 |

There are two things to notice her. First, even though the braces, and not the indentation, identifies our scope, we still indent for the sake of readability. Second, notice that our if condition is is surrounded by parenthesis. This is yet another common requirement from this class of languages.

77 | 78 |

In these languages, braces are also used for functions:

79 | 80 |
function sayHello()
 81 |   print "Hello"
 82 | end
83 | 84 |

Turns into:

85 | 86 |
function sayHello() {
 87 |   print "Hello";
 88 | }
89 | 90 | 91 |

Comments

92 |

We haven't talked about comments yet, but almost all languages allow developers to add comments to their code. These have no impact on the application, but can be useful as reminders or explanations for other developers or even yourself.

93 | 94 |

Most languages use a character to mark the start of a comment. The two most common are # and // (which is actually two characters). Comments can be on their own line, or they can be at the end of the line:

95 | 96 |
# don't let them enter a negative amount
 97 | if withdraw_amount < 0
 98 |   ...
 99 | end
100 | 101 |

Or:

102 | 103 |
if (withdraw_amount < 0) { // don't let them enter a negative amount
104 |   ...
105 | }
106 | 107 | 108 |

Libraries and Frameworks

109 |

When we first talked about programming languages, we spoke of compilers which turn the code that we write into code that computers understand. The idea is to make programming more efficient by giving us higher-level tools. To further increase productivity, program languages often incude a set of standard libraries (also called a framework).

110 | 111 |

These stardard libraries include a number of functions for every-day tasks, such as reading and writing files, accessing the internet, shuffling collections, and so on. These are all things we could write ourselves, but they are so common and so necessary, that robust implementations are provided for us. In addition, you'll find a community of programmers who are eager to share their own libraries which extend and enhance a language's standard library.

112 | 113 |

You might think this takes the fun out of programming. Afterall, what's the point if everything's already written for you? Sure, reading a file is easy, but what you do with the files contents is all up to you.

114 | 115 | 116 |

In This Chapter

117 |

The goal of this chapter was to show that, while syntaxes might change, the core components of programming don't. A variable, whether prefixed with var, nothing, or something else is still a variable. A condition, whether wrapped in parentheses, or not, is still a condition. From this point on we'll settle on a single language, but hopefully you'll now be better equipped to see beyond that language's idiosyncrasies.

118 | 119 |

Don't let these details overwhelm you. In chapter 2 we saw a hasCard function. Look at this same function written in a different language:

120 | 121 |
function hasCard(deck, card) {
122 |   foreach(c in deck) {
123 |     if (c == card) {
124 |       return true;
125 |     }
126 |   }
127 |   return false;
128 | }
129 | 130 |

You probably prefer one over the other, but they are both understandable, because they both rely on the same fundamentals: variables, functions, operators and control-flow. Also, you won't be asked to remember all of these different rules.

131 | 132 |

You may be sad to hear this, but the the language that we'll be using will be of the more cryptic variety (with semi-colons ; and braces {}). There are good reasons for this, which will be explained at the start of the next chapter. This chapter therefore served as an introduction to this new syntax.

133 | 134 |

You may be wondering how professional programmers deal with this variety - some of which is quite subtle. First, most programmers only deal with 2 or 3 languages on a day to day basis. Secondly, most of the mainstream languages tend to have more in common than not. Finally, consider that we do this for hours every day, so it becomes quite natural to us. Despite these facts, most of us get tripped up quite frequently, especially if we've been using the same languages for days at a time and suddenly switch. My own personal nemesis is else if. Every language seems to have its own version else if, elseif, elsif, elif, ...) and I seem to always pick the wrong one.

135 | 136 |

You might also be wondering why we need so many languages in the first place? Some languages are invented to solve specific problems. Some of it has to do with legacy. An old language which was used to create millions of applications can't be thrown away (otherwise we'd have to rewrite all those applications), so the language is kept around. At the same time new applications are built using newer languages. Some programmers just like to write new languages and explore the world of language design to try and come up with better techniques and patterns. Finally, politics play a part in the creation of new languages: company X releases a new language and company Y releases its own variation.

137 | 138 | 139 |

FOR LOOP PULLED FROM OLD chapter 4

140 |

In chapter 2 we saw how to iterate over a collection, but that syntax isn't valid in JavaScript. In JavaScript we use a for loop. While common, the for loop syntax is a little tricky, largely because its 1 line of code containing 3 separate statement. Here's what it looks like:

141 | 142 |
for (initial statement; condition to continue; step statement) {...}
143 | 144 |

Although all three parts are typically provided, any, or all, can be blank. The following will loop endlessly:

145 | 146 |
for (;;) {...}
147 | 148 |

The initial statement lets us define some initial conditions. These will be executed once before the loop starts. The condition to continue is just like the conditions found in an if or else if and when true, the loop will continue. The step statement is executed once after every iteration. An example should clear things up:

149 | 150 |
for (var i = 1; i <= 10; i = i + 1) {
151 |   addItem(i);
152 | }
153 | 154 |

The above will add 10 items, named 1 through to 10, to our list. As long as i, which starts at 1, is less than 10, we continue to loop. However, after each iteration, i is incremented by 1.

155 | 156 |

There are three other things to know. First, in JavaScript the first value of a collection starts at 0 (this is extremly common). Second, we can get the collection's size by calling collection.length. Third, we can get the value at a certain position via square brackets collection[3]. Hopefully this last example will help you write your own itemExists function:

157 | 158 |
//this will duplicate every item in our list
159 | var items = getItems();
160 | for (var i = 0; i < items.length; i = i + 1) {
161 |   addItems(items[i]);
162 | }
163 | 164 |

If we have 3 items, we'll first add items[0], then items[1] and finally items[2]. At this point, i will get incremented to 3, which will no longer be smaller than our length (also 3), and thus our loop will stop.

-------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 |
2 |

The Little Introduction To Programming

3 |
A free online book that gently introduces the art of programming
4 |
5 | 6 |
7 |
8 |
9 |

Programming isn't something that you can learn in an hour. But you can begin to appreciate it.

10 |

This book will teach you the fundamentals of programming and act as a foundation for whatever your programming goals may be.

11 |

Rather than ignore complexities, we will face them head-on, in small steps, and unshroud the mysteries of computer language.

12 |
13 |
14 |

Ideal for...

15 |
    16 |
  • Beginners and Students
  • 17 |
  • Parents with children who program
  • 18 |
  • Occasional coders (spreadsheets / reports)
  • 19 |
  • Insomniacs
  • 20 |
21 | Start reading 22 |
23 |
24 |
25 |
26 |

More To Come

27 |

We hope to add at least a few more chapters in the near future. You can be notified via email by subscribing below. We promise to treat your email with respect. We won't disclose nor sell it or do anything other than email you about meaningful updates to the book.

28 |

29 | 30 | 31 | 32 |
did you mean
33 |
34 |
35 | 36 |
37 |
38 |

If You Need Help

39 |

If you run into any problems or something isn't clear, you can leave a comment at the bottom of the chapter.

40 |

For more generic questions about programming, consider using StackOverflow, a popular and free website where programmers ask and answer questions. Spending time on StackOverflow is actually a great way to learn more about programming.

41 |
42 |
43 | 44 |
45 |

About

46 |

The website and its contents are available on github.

47 |

The contents are available under the Attribution-NonCommercial 3.0 Unported license. You should not have paid for this book. You are free to copy, distribute, modify or display any or all of the material. However you may not use it, in any way, for commercial purposes.

48 |

You can see the full text of the license at: http://creativecommons.org/licenses/by-nc/3.0/legalcode

49 |
50 | -------------------------------------------------------------------------------- /views/layouts/book.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | The Little Introduction To Programming 6 | 7 | 8 | 9 | 10 | <%- partial('shared/ga') %> 11 | 12 | 13 | 19 | <%- partial('shared/toc') %> 20 |
21 | <%- partial('shared/ie6') %> 22 | <%- body %> 23 | <%- partial('shared/paging') %> 24 |
25 | 33 | 34 | comments powered by Disqus 35 |
36 | <%- partial('shared/footer') %> 37 | 38 | -------------------------------------------------------------------------------- /views/layouts/home.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | The Little Introduction To Programming 6 | 7 | 8 | 9 | 10 | <%- partial('shared/ga') %> 11 | 12 | 13 | <%- partial('shared/ie6') %> 14 | <%- body %> 15 | <%- partial('shared/footer') %> 16 | 17 | -------------------------------------------------------------------------------- /views/shared/footer.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/shared/ga.ejs: -------------------------------------------------------------------------------- 1 | <% if (!development) { -%> 2 | 13 | <% } -%> -------------------------------------------------------------------------------- /views/shared/ie6.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/shared/paging.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (chapter > 1) { -%> 3 | 4 | <% } %> 5 | <% if (chapter < chapters.length) { -%> 6 | 7 | <% } -%> 8 |
-------------------------------------------------------------------------------- /views/shared/toc.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/subscribe.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (ok === true) { %> 3 |

Thanks for subscribing!

4 |

We'll let you know when we update the book!

5 | <% } else { %> 6 |

There was a problem subscribing

7 |

Please try again later

8 | <% } %> 9 |

back home

10 |
11 | -------------------------------------------------------------------------------- /views/unsubscribe.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Unsubscribe your email

3 |

To remove your email from our list, please fill out the following form

4 |
5 | 6 | 7 | 8 |
did you mean
9 |
10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /views/unsubscribed.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (ok === true) { %> 3 |

Sorry to see you go

4 | <% } else { %> 5 |

There was a problem unsubscribing

6 |

Please try again later

7 | <% } %> 8 |

back home

9 |
10 | --------------------------------------------------------------------------------