forked from jimschubert/masteringnode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbook.html
More file actions
2450 lines (1706 loc) · 158 KB
/
book.html
File metadata and controls
2450 lines (1706 loc) · 158 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<title>Mastering Node</title>
<meta name="description" content="Mastering Node" />
<meta name="keywords" content="node.js,node,Mastering Node,JavaScript" />
<meta name="author" content="TJ Holowaychuk, et al." />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script type="text/javascript" src="https://raw.github.com/jimschubert/masteringnode/master/pages/prettify.js"></script>
<style type="text/css">
/*--------------------- Layout and Typography ----------------------------*/
body {
font-family: "Helvetica Neue", Helvetica, FreeSans, Arial, sans-serif;
/* font-family: Georgia, FreeSerif, Times, serif; */
font-size: 0.9375em;
line-height: 1.4667em;
color: #222;
margin: 0; padding: 0;
}
a {
color: #0050c0;
text-decoration: underline;
}
a:visited {
color: #b950b7;
text-decoration: underline;
}
a:hover, a:focus {
text-decoration: none;
}
code a:hover {
background: none;
color: #b950b7;
}
#changelog #gtoc {
display: none;
}
.notice {
display: block;
padding: 1em;
margin: 1.4667em 0 2.9334em;
background:#FFF6BF;
color:#514721;
border:1px solid #FFD324;
}
.notice p {
margin: 0;
}
ul.plain {
list-style: none;
}
abbr {
border-bottom: 1px dotted #454545;
}
p {
margin: 0 0 1.4667em 0;
position: relative;
text-rendering: optimizeLegibility;
}
ol, ul, dl {
margin: 0 0 1em 0;
padding: 0;
}
ol ul, ol ol, ol dl,
ul ul, ul ol, ul dl,
dl ul, dl ol, dl dl {
margin-bottom: 0;
}
ol p:first-child, ul p:first-child, dl p:first-child {
margin-bottom: 0;
}
ul, ol {
margin-left: 2em;
}
dl dt {
position: relative;
margin: 1.5em 0 0;
}
dl dd {
position: relative;
margin: 0 1em 0;
}
dd + dt.pre {
margin-top: 1.6em;
}
h1, h2, h3, h4, h5, h6 {
font-family: Georgia, FreeSerif, Times, serif;
color: #000;
text-rendering: optimizeLegibility;
position: relative;
}
h1 {
font-size: 2.55em;
line-height: 1.375em;
}
h2 {
font-size: 1.9em;
line-height: 1.227em;
margin: 0 0 0.5em;
}
h3 {
font-size: 1.5em;
line-height: 1.0909em;
margin: 1.5em 0 0.5em;
}
h3 + h3 {
margin: 0 0 0.5em;
}
h4 {
font-size: 1.3em;
line-height: 1.1282em;
margin: 2.2em 0 0.5em;
}
h4 + h4 {
margin: 0 0 0.5em;
}
h5 {
font-size: 1.125em;
line-height: 1.4em;
}
h6 {
font-size: 1em;
line-height: 1.4667em;
}
pre, tt, code {
font-size: 0.95em;
line-height: 1.5438em;
font-family: Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
.pre {
font-family: Monaco, Consolas, "Lucida Console", monospace;
line-height: 1.5438em;
font-size: 0.95em;
}
pre {
padding: 2em 1.6em 2em 1.2em;
vertical-align: top;
background: #f8f8f8;
border: 1px solid #e8e8e8;
border-width: 1px 1px 1px 6px;
margin: -0.5em 0 1.1em;
}
pre + h3 {
margin-top: 2.225em;
}
code.pre {
white-space: pre;
}
#container {
position: relative;
padding: 6em;
max-width: 50em;
text-align: left;
}
#container header {
margin: 1.25em -0.5em 1.3em;
padding: 0 0.5em 0.225em;
}
hr {
background: none;
border: medium none;
border-bottom: 1px solid #ccc;
margin: 5em 0 2em;
}
#container header hr {
margin: 0;
padding: 0;
}
#toc {
}
#toc h2 {
font-size: 1em;
line-height: 1.4em;
}
#toc h2 a {
float: right;
}
#toc hr {
margin: 1em 0 2em;
}
p tt, p code {
background: #f8f8ff;
border: 1px solid #dedede;
padding: 0 0.2em;
}
a.octothorpe {
text-decoration: none;
color: #777;
position: absolute;
top: 0; left: -1.4em;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
p:hover > a.octothorpe,
dt:hover > a.octothorpe,
dd:hover > a.octothorpe,
h1:hover > a.octothorpe,
h2:hover > a.octothorpe,
h3:hover > a.octothorpe,
h4:hover > a.octothorpe,
h5:hover > a.octothorpe,
h6:hover > a.octothorpe {
opacity: 1;
}
/* Pretty printing styles. Used with prettify.js. */
/* SPAN elements with the classes below are added by prettyprint. */
.pln { color: #000 } /* plain text */
@media screen {
.str { color: #080 } /* string content */
.kwd { color: #008 } /* a keyword */
.com { color: #800 } /* a comment */
.typ { color: #606 } /* a type name */
.lit { color: #066 } /* a literal value */
/* punctuation, lisp open bracket, lisp close bracket */
.pun, .opn, .clo { color: #660 }
.tag { color: #008 } /* a markup tag name */
.atn { color: #606 } /* a markup attribute name */
.atv { color: #080 } /* a markup attribute value */
.dec, .var { color: #606 } /* a declaration; a variable name */
.fun { color: red } /* a function name */
}
/* Use higher contrast and text-weight for printable form. */
@media print, projection {
.str { color: #060 }
.kwd { color: #006; font-weight: bold }
.com { color: #600; font-style: italic }
.typ { color: #404; font-weight: bold }
.lit { color: #044 }
.pun, .opn, .clo { color: #440 }
.tag { color: #006; font-weight: bold }
.atn { color: #404 }
.atv { color: #060 }
}
/* Put a border around prettyprinted code snippets. */
pre.prettyprint { padding: 2px; border: 1px solid #888 }
/* Specify class=linenums on a pre to get line numbering */
ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */
li.L0,
li.L1,
li.L2,
li.L3,
li.L5,
li.L6,
li.L7,
li.L8 { list-style-type: none }
/* Alternate shading for lines */
li.L1,
li.L3,
li.L5,
li.L7,
li.L9 { background: #eee }
</style>
</head>
<body>
<img style="display:none;" width="810" height="813" title="" alt="" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMtAyoDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0uikzRmvzozuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuLRSZozQFxaKTNGaAuNzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigAzRmiigBKKbRTEOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQAlFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAmaM0lFMBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooASikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAWikooAbRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUAJRSZozTsMWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WAWikzRmiwC0UmaM0WATNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoAXNGaTNGaAFzRmkzRmgBc0ZpM0ZoASikzRmmAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ANoozRmgQUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAUUZozQAlFNopgOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQA6im0UAOoptFADqKbRQAlFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQAtFJRQA2ikopgLRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUALRSUUAJRTaKdgHUU2iiwDqKbRRYB1FNoosA6im0UWAdRTaKLAOoptFFgHUU2iiwDqKbRRYB1FNoosA6im0UWAdRTaKLAOoptFFgHUU2iiwDqKbRRYB1FNoosA6im0UWAdRTaKLAOoptFFgHUU2iiwDqKbR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AdRTc0ZoAdRTc0ZoAdRTc0ZoAdRTc0ZoAdRTc0ZoAdRTc0ZoAdRTc0ZoAdRTc0ZoAdRTc0ZoASikzRmmAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0AMzRmkopgLmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFACUUlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFAC0UlFACZozTc0ZpgOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADs0ZpuaM0AOzRmm5ozQA7NGabmjNADc0ZpKKYxc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAbRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0ALRSZozQAtFJmjNAC0UmaM0AJmjNJmjNMQuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNACUUlFMBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBaKSigBM0ZpM0ZoGLmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQA3NGaTNGaYC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0AJmjNJRTAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAEzRmkzRmgQuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNAC5ozSZozQAuaM0maM0ALmjNJmjNACZozSUUwFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBc0ZpKKAFzRmkooAXNGaSigBM0ZpKKBi5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAmaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAuaM0lFAC5ozSUUALmjNJRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB//Z" />
<div id="container">
<div style="display:none"><!-- all --></div>
<h1>Mastering Node</h1>
<p><a href="http://nodejs.org">Node</a> is an exciting new platform developed by <em>Ryan Dahl</em>, allowing JavaScript developers to create extremely high performance servers by leveraging <a href="http://code.google.com/p/v8/">Google V8</a> JavaScript engine, and asynchronous I/O. In <em>Mastering Node</em>) we will discover how to write high concurrency web servers, utilizing the CommonJS module system, node's core libraries, third party modules, high level web development and more.</p>
<h2 id="why_Node_">Why Node?</h2>
<p>Node is an evented I/O framework for server-side JavaScript. What does that mean, though? In many programming languages, I/O operations are blocking. This means that when you open a file, no other code executes until that file is fully opened. </p>
<p>Using a busy office environment as an example, blocking I/O operations are like a very busy and very focussed desk worker name Frank. Work may pile up on the desk, but Frank finishes every task that he starts (however, when he finds the smallest problem, he gives up). This is traditionally how procedural programming languages perform tasks.</p>
<p>Node.js is more like an office manager. Sure, there are management tasks, but all of those I/O operations are handled fairly well by the operating system or node addons. So, the manager sees a task, assigns it to Frank. The manager may check back on Frank from time to time to see how he's doing, but he doesn't need to waste his time on the task because he knows that when it's completed, Frank will give it back.</p>
<p>Don't worry, though. Node.js isn't a jerk, so look forward to a healthy relationship.</p>
<h2 id="why_JavaScript_">Why JavaScript?</h2>
<p><strong>JavaScript is a well-known dynamic language.</strong></p>
<p>In fact, many people who don't consider themselves programmers know JavaScript. Node.js uses <a href="http://code.google.com/apis/v8/intro.html">Google's V8 JavaScript engine</a>. V8 is an implementation of the JavaScript standards specified in <a href="http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf">ECMA-262, Version 3</a>. It is a high-performance, garbage-collected execution environment which can be embedded in any stand-alone application.</p>
<p><strong>Everything in JavaScript is an <code>Object</code>.</strong></p>
<p>Arrays are <code>Objects</code>. Object literals are <code>Object</code>s. Even functions are <code>Object</code>s.</p>
<p><strong>JavaScript supports some fairly advanced functional programming concepts. <a href="http://www.ibm.com/developerworks/library/wa-javascript.html#functional">?</a></strong></p>
<p>Currying, closures, functions-as-arguments, and anonymous functions are concepts typically found in functional programming languages. There are libraries available, such as <a href="http://documentcloud.github.com/underscore/">underscore.js</a>, which provider more functional programming functionality without changing JavaScript itself.</p>
<p><strong>It's awesome. I had to say it.</strong></p>
<p>For a deep understanding of what JavaScript really has to offer, check out <a href="http://oreilly.com/catalog/9780596806767">JavaScript Patterns</a>.</p>
<h2 id="hello_World_">Hello World!</h2>
<p><strong>Becuase it has to be done</strong></p>
<pre class="prettyprint"><code>// hello.js
sys = require('sys');
sys.puts("Hello, World!");</code></pre>
<p>To run the 'Hello, World!' example, execute <code>node hello.js</code> on the command line.</p>
<h2 id="conventions_in_this_book">Conventions in this book</h2>
<p><strong>Code Blocks</strong></p>
<p>There are a few conventions used in the code example blocks (such as the Hello, World! example above).</p>
<p>First, if the example is a script (or a part of a script) that needs to be run from the command line, it will begin with a <code>//</code> styled comment of the filename. These files are located under the <code>./src</code> directory of the <em>Mastering Node</em> project. Running these examples is fairly simple: open a terminal (CTRL+SHIFT+T might do it) and type <code>node</code> followed by a space and the relative path of the script. In other words, if you're in <em>/home/jim/masteringnode</em> and you want to run a script under <em>/home/jim/masteringnode/scripts/</em> which is called <em>hello.js</em>, you would run <code>node scripts/hello.js</code> or <code>node ./scripts/hello.js</code>. For an example of how this code snippet is displayed, see the Hello, World! example above.</p>
<p>Second, if the example is a command to be entered directly into what will be referred to as a 'node terminal', you should first open a terminal then type <code>node</code> and ENTER (assuming the node executable is in your PATH variable, and is called node). At the prompt, you should enter the commands following the <code>></code> character. Text following the <code>></code> character are commands you should enter, while text on a line that does not begin with <code>></code> is the output. This is done to closely match what you should see in your terminal. These examples are not included in files under the <em>src</em> directory. For instance:</p>
<pre class="prettyprint"><code>> console.log("Hello, World!")
Hello, World.</code></pre>
<p>Third, if an example is to be run from the terminal itself, it is prefixed by a <code>$</code>. This represents a bash environment, and may look differently depending on your configuration. For instance, my bash terminal displays:</p>
<pre class="prettyprint"><code>jim@cr-48:~/projects/masteringnode$</code></pre>
<p>These code examples will look like this:</p>
<pre class="prettyprint"><code>$ ruby -e "puts 'Hello, World'"</code></pre>
<p>Finally, code without a prefix is a sample of a possible solution or expected output from <em>stdout</em>. This is not necessarily code you should type into your terminal or run as a script, unless of course you want to experiment. For example, suppose we're discussing CommonJS and we'd like to show how something <em>would</em> be done in CommonJS, we might show an example such as:</p>
<pre class="prettyprint"><code>var utils = {};
utils.merge = function(obj, other) {};</code></pre>
<p>This wouldn't contain a filename unless there is a working example (in which case, it's a concrete example and no longer hypothetical).</p>
<p><strong>Inline Code</strong></p>
<p>Occasionally, there will be code or commands that are being explained and displayed inline to separate them visually from the rest of the sentence. For instance, if we were talking about how to include modules into your code, we may say to add a <code>var fs = require('fs');</code> line to the top of your file. Code displayed like this is generally accompanied by an explanation of the code itself or instructions for where to add the code. </p>
<p>Functions may be displayed as <code>require()</code> or <code>require</code>, depending on the context for readability. That is, when we're talking about any JavaScript objects, we'll most likely use <code>require</code> since a function is also an object. </p>
<p>If we're talking about multiple functions, we may say "use the functions: <code>doSomething1</code> and <code>doSomething2</code>" instead of "use the functions: <code>doSomething1()</code> and <code>doSomething2()</code>" because the parentheses can be implied and the absence of parentheses is easier on the eyes.</p>
<p><strong>Files and Directories</strong></p>
<p>Files and directories will be displayed in italics when inline, or as a relative path to the <em>Mastering Node</em> source directory in code comments when in a code example block. For instance, if we reference <em>/home/jim/masteringnode/src/modules/fake.js</em> in a code example, it will look like:</p>
<pre class="prettyprint"><code>// modules/fake.js
var num = 1;</code></pre>
<h1>Installing Node</h1>
<p>In this chapter we will be looking at the installation and compilation of node. Although there are several ways we may install node, we will be looking at <a href="http://github.com/mxcl/homebrew">homebrew</a>, and the most flexible method, of course - compiling from source.</p>
<h3 id="homebrew">Homebrew</h3>
<p>Homebrew is a package management system for <em>OSX</em> written in Ruby, is extremely well adopted, and easy to use. Homebrew can be installed in a number of ways. Possibly the easiest way is to perform a quick install to <code>/usr/local/</code>:</p>
<pre class="prettyprint"><code>$ ruby -e "$(curl -fsSL https://gist.github.com/raw/323731/install_homebrew.rb)"</code></pre>
<p>Next, to install node via the <code>brew</code> executable, simply run:</p>
<pre class="prettyprint"><code>$ brew install node.js</code></pre>
<p>For more information on packages and commands available to homebrew, checkout the README at github.</p>
<h2 id="building_From_Source">Building From Source</h2>
<p>To build and install node from source, we first need to obtain the code. The first method of doing so is
via <code>git</code>, if you have git installed you can execute:</p>
<pre class="prettyprint"><code>$ git clone http://github.com/joyent/node.git && cd node
$ git checkout v0.4.0</code></pre>
<p>For those without <em>git</em>, or who prefer not to use it, we can also download the source via <em>curl</em>, <em>wget</em>, or similar:</p>
<pre class="prettyprint"><code>$ curl -# http://nodejs.org/dist/node-v0.4.0.tar.gz > node.tar.gz
$ tar -zxf node.tar.gz</code></pre>
<p>Now that we have the source on our machine, we can run <code>./configure</code> which discovers which libraries are available for node to utilize such as <em>OpenSSL</em> for transport security support, C and C++ compilers, etc. <code>make</code> which builds node, and finally <code>make install</code> which will install node.</p>
<pre class="prettyprint"><code>$ ./configure && make && sudo make install</code></pre>
<h2 id="installing_from_Distribution_Sources">Installing from Distribution Sources</h2>
<p>Installing node.js from a distribution's repositories is not highly recommended. This is because the version included with your distribution may be very outdated. As an example, the original version of this document was written to target node.js 0.1.99. In Ubuntu 10.10, the version of node.js included in the official repository is 0.1.97-1build1. Because node.js is a relatively young project with a large community, changes to the API occur quickly and often.</p>
<p>If you still wish to install nodejs from an official repository, it can be done in the usual way:</p>
<pre class="prettyprint"><code>$ sudo apt-get install nodejs
$ yum install nodejs</code></pre>
<p>Refer to your distribution's documention or wiki for the proper commannd for installation from the official repository.</p>
<h3 id="npm_Node_Package_Manager">npm: Node Package Manager</h3>
<p>npm is a node package manager with a relatively large category of available modules. To install directly in one line, run:</p>
<pre class="prettyprint"><code>$ curl http://npmjs.org/install.sh | sh</code></pre>
<p>If this one-liner fails, run:</p>
<pre class="prettyprint"><code>$ git clone http://github.com/isaacs/npm.git
$ cd npm
$ sudo make install</code></pre>
<p>For more information on npm, check out the <a href="https://github.com/isaacs/npm">repo</a>.</p>
<h2 id="installing_other_packages">Installing other packages</h2>
<p>Using npm, we'll install other packages needed for the examples in this book.</p>
<pre class="prettyprint"><code>$ sudo npm install connect express nodeunit geddy zombie node-inspector</code></pre>
<p>Let npm do it's thing. It will install these modules any any dependencies. You'll see output similar to the following:</p>
<pre class="prettyprint"><code>npm info activate jsdom@0.1.23
npm info postactivate jsdom@0.1.23
npm info build Success: express@1.0.7
npm info build Success: nodeunit@0.5.1
npm info build Success: mime@1.2.1
npm info build Success: geddy@0.1.3
npm info build Success: websocket-client@1.0.0
npm info build Success: connect@1.0.1</code></pre>
<h2 id="setting_up_an_editor">Setting up an editor</h2>
<p>Part of setting up a development environment is using the right tools. While some may prefer a full IDE, others will go with a very simple text editor. I enjoy using <em>vim</em>, and this is my <em>~/.vimrc</em> file's contents:</p>
<pre class="prettyprint"><code>syntax on " enabled syntax highlighting
:set number " line numbers
:set ai " autoindent
:set tabstop=4 " sets tabs to 4 characters
:set shiftwidth=4
:set expandtab
:set softtabstop=4 " makes the spaces feel like real tabs
" CSS (tabs = 2, lines = 79)
autocmd FileType css set omnifunc=csscomplete#CompleteCSS
autocmd FileType css set sw=2
autocmd FileType css set ts=2
autocmd FileType css set sts=2
" JavaScript (tabs = 4, lines = 79)
autocmd FileType javascript set omnifunc=javascriptcomplete#CompleteJS
autocmd FileType javascript set sw=4
autocmd FileType javascript set ts=4
autocmd FileType javascript set sts=4
" autocmd FileType javascript set tw=79
" Jade
autocmd FileType jade set omnifunc=jadecomplete#CompleteJade
autocmd FileType jade set sw=2
autocmd FileType jade set ts=2
autocmd FileType jade set sts=2
" ejs
autocmd FileType ejs set sw=2
autocmd FileType ejs set ts=2
autocmd FileType ejs set sts=2
" Highlight current line only in insert mode
autocmd InsertLeave * set nocursorline
autocmd InsertEnter * set cursorline
" Makefiles require TAB instead of whitespace
autocmd FileType make setlocal noexpandtab
" Highlight cursor
highlight CursorLine ctermbg=8 cterm=NONE</code></pre>
<p>If your install of <em>vim</em> doesn't include the <em>*complete</em> functions, you can download them from <a href="http://www.vim.org/scripts/index.php">vim.org/scripts</a>. Most likely, you'll need the <a href="http://www.vim.org/scripts/script.php?script_id=3192">jade.vim</a> script.</p>
<p>Other excellent IDEs include:</p>
<ol><li><a href="http://cloud9ide.com/">cloud9 IDE</a></li><li><a href="http://www.geany.org/">geany</a></li><li><a href="http://aptana.org/">Aptana Studio</a></li></ol>
<h1>Debugging</h1>
<p>One of the most important aspects of programming in any language is the ability to debug code.</p>
<h2 id="node_inspector">node-inspector</h2>
<p><a href="https://github.com/dannycoates/node-inspector">node-inspector</a> is a Web Inspector node.js debugger. This means you'll need a WebKit browser like Chrome or Safari to run node-inspector.</p>
<h2 id="installation">Installation</h2>
<p>If you've performed the npm installation from the previous section, you should be ready to go. If not, you can install node-inspector from source or through npm.</p>
<pre class="prettyprint"><code>$ npm install node-inspector</code></pre>
<p>If you'd like to install from source, check out the <a href="https://github.com/dannycoates/node-inspector/wiki/Getting-Started---from-scratch">Getting Started from scratch</a> wiki entry from the node-inspector repository.</p>
<h2 id="usage">Usage</h2>
<p>Open one terminal to host a node-inspector server. This terminal will remain open and provide a debug listener.</p>
<pre class="prettyprint"><code>$ node-inspector&
> visit http://0.0.0.0:8080/debug?port=5858 to start debugging</code></pre>
<p>You will see output directing you to open a browser and point it to the node-inspector server at the default port (8080).</p>
<p>Next, open another terminal and navigate to <code>./src/events</code> and run node with the <code>--debug-brk</code> switch. This will connect to the debugger on port 5858.</p>
<pre class="prettyprint"><code>$ node --debug-brk basic.js
> debugger listening on port 5858</code></pre>
<p>Now, open a browser to <a href="http://127.0.0.1:8080/debug?port=5858">http://127.0.0.1:8080/debug?port=5858</a> and you will see a breakpoint on what would be the first line of your file. I phrased it like this intentionally because the debugger shows you how node.js sees your file:</p>
<pre class="prettyprint"><code>(function (exports, require, module, filename, dirname) {
/* Your code here */
});</code></pre>
<p>If you've used the Web Inspector view in Google Chrome, you should be familiar with using node-inspector's version of Web Inspector. There is a console drawer if you click on the bottom-left icon which allows you to evaluate JavaScript and filter log messages by type (Errors, Warnings, Logs). There is also a 'Console' tab if you need a full view of the console.</p>
<p>Expand the <code>Watch Expressions</code> section on the right of the Web Inspector's Scripts tab. Click the 'Add' button and you can add variables which will be updated as you step through code. In version 0.1.6 of node-inspector, when I click the 'Add' button, it automatically adds two single-quotes. If this happens to you, delete the quotes and enter your text.</p>
<p>You'll see as you step through the code that you step directly into node.js functions. This is very useful if you are exploring node.js or if you want to see how something is implemented, like when you call something like <code>console.log("%d days without incident", 5);</code>.</p>
<h1>CommonJS Module System</h1>
<p><a href="http://commonjs.org">CommonJS</a> is a community driven effort to standardize packaging of JavaScript libraries, known as <em>modules</em>. Modules written which comply to this standard provide portability between other compliant frameworks such as narwhal, and in some cases even browsers. </p>
<p>Although this is ideal, in practice modules are often not portable due to relying on apis that are currently only provided by, or are tailored to node specifically. As the framework matures, and additional standards emerge our modules will become more portable. </p>
<h2 id="creating_Modules">Creating Modules</h2>
<p>Let's create a utility module named <em>utils</em>, which will contain a <code>merge()</code> function to copy the properties of one object to another. Typically in a browser, or environment without CommonJS module support, this may look similar to below, where <code>utils</code> is a global variable. </p>
<pre class="prettyprint"><code>var utils = {};
utils.merge = function(obj, other) {};</code></pre>
<p>Although namespacing can lower the chance of collisions, it can still become an issue, and when further namespacing is applied it can look flat-out silly. CommonJS modules aid in removing this issue by "wrapping" the contents of a JavaScript file with a closure similar to what is shown below, however more pseudo globals are available to the module in addition to <code>exports</code>, <code>require</code>, and <code>module</code>. The <code>exports</code> object is then returned when a user invokes <code>require('utils')</code>.</p>
<pre class="prettyprint"><code>var module = { exports: {}};
(function(module, exports){
function merge(){};
exports.merge = merge;
})(module, module.exports);</code></pre>
<p>First create the file <em>./modules/utils.js</em>, and define the <code>merge()</code> function as seen below. The implied anonymous wrapper function shown above allows us to seemingly define globals, however these are not accessible until exported. </p>
<pre class="prettyprint"><code>function merge(obj, other) {
var keys = Object.keys(other);
for (var i = 0, len = keys.length; i < len; ++i) {
var key = keys[i];
obj[key] = other[key];
}
return obj;
};
exports.merge = merge;</code></pre>
<p>The typical pattern for public properties is to simply define them on the <code>exports</code> object like so:</p>
<pre class="prettyprint"><code>// modules/utils.js
exports.merge = function(obj, other) {
var keys = Object.keys(other);
for (var i = 0, len = keys.length; i < len; ++i) {
var key = keys[i];
obj[key] = other[key];
}
return obj;
};</code></pre>
<p>Next we will look at utilizing out new module in other libraries.</p>
<h2 id="requiring_Modules">Requiring Modules</h2>
<p>To get started with requiring modules, first create a second file named <em>./modules/app.js</em> with the code shown below. The first line <code>require('./utils')</code> fetches the contents of <em>./modules/utils.js</em> and returns the <code>exports</code> of which we later utilize our <code>merge()</code> method and display the results of our merged object using <code>console.dir()</code>.</p>
<pre class="prettyprint"><code>// modules/app.js
var utils = require('./utils');
var a = { one: 1 };
var b = { two: 2 };
utils.merge(a, b);
console.dir(a);</code></pre>
<p>Core modules such as the <em>sys</em> which are bundled with node can be required without a path, such as <code>require('sys')</code>, however 3rd-party modules will iterate the <code>require.paths</code> array in search of a module matching the given path. By default <code>require.paths</code> includes <em>~/.node_libraries</em>, so if <em>~/.node_libraries/utils.js</em> exists we may simply <code>require('utils')</code>, instead of our relative example <code>require('./utils')</code> shown above.</p>
<p>Node also supports the concept of <em>index</em> JavaScript files. To illustrate this example lets create a <em>math</em> module that will provide the <code>math.add()</code>, and <code>math.sub()</code> methods. For organizational purposes we will keep each method in their respective <em>./modules/math/add.js</em> and <em>./modules/math/sub.js</em> files. So where does <em>index.js</em> come into play? we can populate <em>./modules/math/index.js</em> with the code shown below, which is used when <code>require('./math')</code> is invoked, which is conceptually identical to invoking <code>require('./math/index')</code>.</p>
<pre class="prettyprint"><code>// modules/util.js
module.exports = {
add: require('./add'),
sub: require('./sub')
};</code></pre>
<p>The contents of <em>./modules/math/add.js</em> show us a new technique; here we use <code>module.exports</code> instead of <code>exports</code>. As previously mentioned, <code>exports</code> is not the only object exposed to the module file when evaluated. We also have access to <code>__dirname</code>, <code>__filename</code>, and <code>module</code> which represents the current module. We simply define the module export object to a new object, which happens to be a function. </p>
<pre class="prettyprint"><code>// modules/math/add.js
module.exports = function add(a, b){
return a + b;
};</code></pre>
<p>This technique is usually only helpful when your module has one aspect that it wishes to expose, be it a single function, constructor, string, etc. Below is an example of how we could provide the <code>Animal</code> constructor:</p>
<pre class="prettyprint"><code>exports.Animal = function Animal(){};</code></pre>
<p>which can then be utilized as shown:</p>
<pre class="prettyprint"><code>var Animal = require('./animal').Animal;</code></pre>
<p>if we change our module slightly, we can remove <code>.Animal</code>:</p>
<pre class="prettyprint"><code>module.exports = function Animal(){};</code></pre>
<p>which can now be used without the property:</p>
<pre class="prettyprint"><code>var Animal = require('./animal');</code></pre>
<h2 id="require_Paths">Require Paths</h2>
<p>We talked about <code>require.paths</code>, the <code>Array</code> utilized by node's module system in order to discover modules. By default, node checks the following directories for modules:</p>
<ul><li><code><node binary></code>/../../lib/node</li><li><strong>$HOME</strong>/.node_libraries</li><li><strong>$NODE_PATH</strong></li></ul>
<p>The <strong>NODE_PATH</strong> environment variable is much like <strong>PATH</strong>, as it allows several paths delimited by the colon (<code>:</code>) character.</p>
<h3 id="runtime_Manipulation">Runtime Manipulation</h3>
<p>Since <code>require.paths</code> is just an array, we can manipulate it at runtime in order to expose libraries. In our previous example we defined the libraries <em>./math/{add,sub}.js</em>, in which we would typically <code>require('./math')</code> or <code>require('./math/add')</code> etc. Another approach is to prepend or "unshift" a directory onto <code>require.paths</code> as shown below, after which we can simply <code>require('add')</code> since node will iterate the paths in order to try and locate the module.</p>
<pre class="prettyprint"><code>require.paths.unshift(__dirname + '/math');
var add = require('add'),
sub = require('sub');
console.log(add(1,2));
console.log(sub(1,2));</code></pre>
<h2 id="pseudo_Globals">Pseudo Globals</h2>
<p>As mentioned above, modules have several pseudo globals available to them, these are as follows:</p>
<ul><li><code>require</code> the require function itself </li><li><code>module</code> the current <code>Module</code> instance</li><li><code>exports</code> the current module's exported properties</li><li><code>__filename</code> absolute path to the current module's file</li><li><code>__dirname</code> absolute path to the current module's directory</li></ul>
<p>To examine the functionality of <code>require</code>, <code>module</code>, and <code>exports</code>, open a node console by running the command <code>node</code>. You should then enter a node prompt as seen below:</p>
<pre class="prettyprint"><code>$ node
> </code></pre>
<p>To view these objects, enter the following commands into node:</p>
<pre class="prettyprint"><code>> require
> module
> module.exports
> module.filename</code></pre>
<p>If you'd like to examine other objects, the node console supports the well-known <code><TAB></code><code><TAB></code> auto-completion. </p>
<h3 id="require">require()</h3>
<p>Although not obvious at first glance, the <code>require()</code> function is actually re-defined for the current module, and calls an internal function <code>loadModule</code> with a reference to the current <code>Module</code> to resolve relative paths and to populate <code>module.parent</code>.</p>
<h3 id="module">module</h3>
<p>When we <code>require()</code> a module, typically we only deal with the module's <code>exports</code>, however the <code>module</code> variable references the current module's <code>Module</code> instance. This is why the following is valid, as we may re-assign the module's <code>exports</code> to any object, even something trivial like a string:</p>
<pre class="prettyprint"><code>// modules/css.js
module.exports = 'body { background: blue; }';</code></pre>
<p>To obtain this string we would simply <code>require('./css')</code>. The <code>module</code> object also contains these useful properties:</p>
<ul><li><code>id</code> the module's id, consisting of a path. Ex: <code>./app</code></li><li><code>parent</code> the parent <code>Module</code> (which required this one) or <code>undefined</code></li><li><code>filename</code> absolute path to the module</li><li><code>moduleCache</code> an object containing references to all cached modules</li></ul>
<h2 id="registering_Module_Compilers">Registering Module Compilers</h2>
<p>Another cool feature that node provides us is the ability to register compilers for a specific file extension. A good example of this is the CoffeeScript language, which is a ruby/python inspired language compiling to vanilla JavaScript. By using <code>require.registerExtension()</code> we can have node compile CoffeeScript to JavaScript in an automated fashion. </p>
<p>To illustrate its usage, let's create a small (and useless) Extended JavaScript language, or "ejs" for our example which will live at <em>./modules/compiler/example.ejs</em>, its syntax will look like this:</p>
<pre class="prettyprint"><code>// modules/compiler/example.ejs
::min(a, b) a < b ? a : b
::max(a, b) a > b ? a : b</code></pre>
<p>which will be compiled to:</p>
<pre class="prettyprint"><code>exports.min = function min(a, b) { return a < b ? a : b }
exports.max = function max(a, b) { return a > b ? a : b }</code></pre>
<p>First let's create the module that will actually be doing the ejs to JavaScript compilation. In this example it is located at <em>./modules/compiler/extended.js</em>, and exports a single method named <code>compile()</code>. This method accepts a string, which is the raw contents of what node is requiring, transformed to vanilla JavaScript via regular expressions.</p>
<pre class="prettyprint"><code>// modules/compiler/extended.js
exports.compile = function(str){
return str
.replace(/(\w+)\(/g, '$1 = function $1(')
.replace(/\)(.+?)\n/g, '){ return $1 }\n')
.replace(/::/g, 'exports.');
};</code></pre>
<p>Next we have to "register" the extension to assign out compiler. As previously mentioned our compiler lives at <em>./modules/compiler/extended.js</em> so we are requiring it in. Prior to node.js 0.3.0, we would pass the <code>compile()</code> method to <code>require.registerExtension()</code> which simply expects a function accepting a string, and returning a string of JavaScript.</p>
<pre class="prettyprint"><code>require.registerExtension('.ejs', require('./compiler/extended').compile);</code></pre>
<p>The new way to register an extension is to add a key to the require.extensions object with a function which specifies how to process the file. For compatibility, we can use <code>require.extensions</code> and fallback to <code>require.registerExtension</code>.</p>
<pre class="prettyprint"><code>// modules/compiler.js
if(require.extensions) {
require.extensions['.ejs'] = function(module,filename){
var content = require('fs').readFileSync(filename, 'utf8');
var newContent = require('./compiler/extended').compile(content);
module._compile(newContent, filename);
};
} else {
require.registerExtension('.ejs', require('./compiler/extended').compile);
}</code></pre>
<p>Now when we require our example, the ".ejs" extension is detected, and will pass the contents through our compiler, and everything works as expected.</p>
<pre class="prettyprint"><code>// modules/compiler.js
var example = require('./compiler/example');
console.dir(example)
console.log(example.min(2, 3));
console.log(example.max(10, 8));</code></pre>
<p>This should display the following output when run with <code>node ./src/modules/compiler.js</code> in a terminal:</p>
<pre class="prettyprint"><code>$ node compiler.js
{ min: [Function: min], max: [Function: max] }
2
10</code></pre>
<h2 id="patterns">Patterns</h2>
<p> ...</p>
<h2 id="best_Practices">Best Practices</h2>
<p> ...</p>
<h1>Addons</h1>
<p>The node documentation for addons is self-admittedly pretty weak as of v0.4.0.</p>
<p>This chapter doesn't aim to be a replacement for the official documentation. Instead, we'd hope this can expand on some of the basics a little more than a simple "Hello, World!" and drive you as a developer more on the path toward mastering node through its source code.</p>
<p>In fact, for now, we're only going to cover some shortcuts for creating properties on an object, functions, and interacting with function prototypes. This doesn't reach the evented level of node's awesomeness, but you should be able to look at examples in node's source and the documention for <em>libev</em> and <em>libeio</em> to find answers.</p>
<h2 id="pre_requisites">Pre-requisites</h2>
<ul><li>Some C/C++ knowledge</li><li>V8 JavaScript</li><li>Internal Node libraries</li><li><a href="http://cvs.schmorp.de/libev/ev.html">libev</a></li><li>libeio</li></ul>
<h2 id="hello.node">hello.node</h2>
<p>Our first example is the very same one from node's docs. We're going to include it for those who haven't read through the docs and have instead trusted in the knowledge of this ebook's authors (thanks, by the way).</p>
<p>A node addon begins with a source file containing a single entry point: </p>
<pre class="prettyprint"><code>// addons/hello/hello.cc
#include <v8.h>
using namespace v8;
extern "C" void
init (Handle<Object> target)
{
HandleScope scope;
target->Set(String::New("hello"), String::New("world"));
}</code></pre>
<p>This is a C/C++ file which begins by including the <em>v8.h</em> header. It then uses the <em>v8</em> namespace to make the code a little cleaner. Finally, the entry point accepts a single parameter, <code>Handle<Object> target</code>. If you don't use the <em>v8</em> namespace as we've done here, your parameter will read <code>v8::Handle<v8::Object> target</code>. As you can see, <code>Object</code> is a <em>v8</em> class. This is actually the same object we would otherwise refer to using <code>exports</code> in a regular node source file.</p>
<p>Within the <code>init</code> method, we do two things. First, we create a scope. Again, this is the same as is done with the <code>exports</code> object in a JavaScript file. Then we set a property on the <code>target</code> called <code>hello</code> which returns the string "world".</p>
<p>If you were to perform the same actions as this source file (ignoring the scope part) in a node REPL console, it would look like:</p>
<pre class="prettyprint"><code>$ node
> var target = {};
> target.hello = "world";
'world'</code></pre>
<h3 id="building_hello.node">Building hello.node</h3>
<p>Building a node addon requires <a href="http://code.google.com/p/waf">WAF</a>. <em>node-waf</em> should be installed if you've installed node.js from source or distro. </p>
<pre class="prettyprint"><code>// addons/hello/wscript
srcdir = '.'
blddir = 'build'
VERSION = '0.0.1'
def set_options(opt):
opt.tool_options('compiler_cxx')
def configure(conf):
conf.check_tool('compiler_cxx')
conf.check_tool('node_addon')
def build(bld):
obj = bld.new_task_gen('cxx', 'shlib', 'node_addon')
obj.target = 'hello'
obj.source = 'hello.cc'</code></pre>
<p>This file is relatively simple, there are two tasks: <em>configure</em> and <em>build</em>. To run this script:</p>
<pre class="prettyprint"><code>$ cd src/addons/hello/wscript && node-waf configure build</code></pre>
<p>Notice how you have to run node-waf from the directory of the <code>wscript</code> build script. Afterward, your built addon will be located at <em>./build/default/hello.node</em>. You can load and play with the addon when you're finished.</p>
<pre class="prettyprint"><code>$ cd build/default && node
> var hello = require('./hello.node');
> hello
{ hello: 'world' }
> </code></pre>
<h2 id="basic_Functions">Basic Functions</h2>
<p>The world of functions begins with an object that will resemble the following object:</p>
<pre class="prettyprint"><code>{ version: '0.1', echo: [Function] }</code></pre>
<p>As you can imagine, node is already coding functions in the same way as you would for an addon. Luckily, <em>node.h</em> provides a helper definition for setting a function to a callback, or method defined within your source file. If you open <em>node.h</em> and look at line 33, you'll see:</p>
<pre class="prettyprint"><code>// [node repo]/src/node.h
#define NODE\_SET\_METHOD(obj, name, callback) \
obj->Set(v8::String::NewSymbol(name), \
v8::FunctionTemplate::New(callback)->GetFunction())</code></pre>
<p>Let's reuse this bit of code. One thing to note here is that since node is already defining how to set a method on a target object, changes to this functionality in v8 will most likely be reflected in this macro. Because the addon compilation process links node anyway, including the header here shouldn't be an issue. Plus, reusing the macro ensures that we're creating functions in the same way as the rest of the framework.</p>
<p>The following example will compile our desired object mentioned earlier.</p>
<pre class="prettyprint"><code>// addons/functions/v0.1/func.cc
#include <v8.h>
#include <node.h>
using namespace v8;
static Handle<Value> Echo(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1) {
return ThrowException(Exception::TypeError(String::New("Bad argument")));
}
return scope.Close(args[0]);
}
extern "C" void
init (Handle<Object> target)
{
HandleScope scope;
target->Set(String::New("version"), String::New("0.1"));
NODE_SET_METHOD(target, "echo", Echo);
}</code></pre>
<p>This example differs in a couple of ways from the <em>Hello, World!</em> example. First, it includes the <em>node.h</em> header containing the <code>NODE_SET_METHOD</code> macro. Second, this contains a callback which is providing the functionality of our function.</p>
<p>Just as you would expect in a JavaScript function, the entrance and exit points of the function define a <code>scope</code> in which the <em>context</em> of the function executes (i.e. 'this'). Our function will throw an error if it doesn't receive the proper number of arguments, then returns the first argument regardless of how many others are passed.</p>
<p>The <em>WAF</em> script used to build this file is nearly identical to the one used for the <em>Hello, World!</em> example. </p>
<p>Now, build the source and toy with it. Here's a dump of my console, run from <em>./src/addons/functions/v0.1</em>. </p>
<pre class="prettyprint"><code>$ node-waf configure build && cd build/default && node
Checking for program g++ or c++ : /usr/bin/g++
Checking for program cpp : /usr/bin/cpp
Checking for program ar : /usr/bin/ar
Checking for program ranlib : /usr/bin/ranlib
Checking for g++ : ok
Checking for node path : ok /home/jim/.node_libraries
Checking for node prefix : ok /usr/local
'configure' finished successfully (0.164s)
Waf: Entering directory `/media/16GB/projects/masteringnode/src/addons/functions/v0.1/build'
[1/2] cxx: func.cc -> build/default/func_1.o
Waf: Leaving directory `/media/16GB/projects/masteringnode/src/addons/functions/v0.1/build'
'build' finished successfully (0.587s)
> var func = require('./func');
> func
{ version: '0.1', echo: [Function] }
> func.echo
[Function]
> func.echo()
TypeError: Bad argument
at [object Context]:1:6
at Interface.<anonymous> (repl.js:144:22)
at Interface.emit (events.js:42:17)
at Interface._onLine (readline.js:132:10)
at Interface._line (readline.js:387:8)
at Interface._ttyWrite (readline.js:564:14)
at ReadStream.<anonymous> (readline.js:52:12)
at ReadStream.emit (events.js:59:20)
at ReadStream._emitKey (tty_posix.js:280:10)
at ReadStream.onData (tty_posix.js:43:12)
> func.echo(1)
1
> func.echo("asdf", 20)
'asdf'
> func.echo(function() { return 1; }, 222)
[Function]
> func.echo(function() { return 1; }, 222)()
1</code></pre>
<p>Notice the construct of the last line is <code>func.echo()()</code>, which executes the function that is passed as the first argument.</p>
<h2 id="functionTemplate">FunctionTemplate</h2>
<p>In v8, a FunctionTemplate is used to create the equivalent to:</p>
<pre class="prettyprint"><code>var template = function() { }</code></pre>
<p>The function at this point is an object and not an <em>instance</em> of the function. </p>
<p>As an example, we will use the linux package <em>uuid</em> to generate a uuid. We will define the header for this addon as:</p>
<pre class="prettyprint"><code>// addons/uuid/v0.1/uuid.h
#ifndef __node_uuid_h__
#define __node_uuid_h__
#include <string>
#include <v8.h>
#include <node.h>
#include "uuid/uuid.h"
using namespace v8;
using namespace node;
class Uuid : public node::ObjectWrap {
public:
Uuid() { }
static Persistent<FunctionTemplate> constructor;
static void Init(Handle<Object> target);
static Handle<Value> New(const Arguments &args);
static Handle<Value> Generate(const Arguments &args);
static Handle<Value> GenerateRandom(const Arguments &args);
static Handle<Value> GenerateTime(const Arguments &args);
private:
~Uuid();
static std::string GetString(uuid_t id);
};
#endif // __node_uuid_h__</code></pre>
<p>This addon will showcase three methods, <code>Generate</code>, <code>GenerateRandom</code>, and <code>GenerateTime</code>. It will also include a trivial private <code>GetString</code> method to demonstrate how to <em>Unwrap</em> a <code>node::ObjectWrap</code> object and interact with C++ code that is not specific to node or v8.</p>
<p>A lot of the public function definitions should look similar to the <em>Echo</em> example. One notable difference is that instead of using a macro and hiding the <code>FunctionTemplate</code> method, we are defining <code>static Persistent<FunctionTemplate> constructor;</code>. The <code>Persistent<T></code> type is used "when you need to keep a reference to an object for more than one function call, or when handle lifetimes do not correspond to C++ scopes." <a href="http://code.google.com/apis/v8/embed.html">source</a>. Since we'd expect our object's constructor to last longer than a single function, we declare it separately and as a persistent handle. Another point to notice is that all of the method we're pulling from <em>uuid.h</em> have the signature <code>static Handle<Value> Method(const Arguments &args)</code> even though we will plan to call it as <code>uuid.generate()</code>. This is because we will be accessing the <em>scope</em> of the call via <code>args.This()</code>.</p>
<p>Although more methods are implemented in <em>uuid.cc</em>, we will look at three: </p>
<ul><li><code>Uuid::Init(Handle<Object> target)</code></li><li><code>Handle<Value> Uuid::New(const Arguments &args)</code></li><li><code>Handle<Value> Uuid::Generate(const Arguments &args)</code></li></ul>
<p>Just as before, node expects to find a signature of <code>extern "C" void init(Handle<Object> target)</code> in order to initialize the addon. Inside this method, we may set parameters such as the version number from the previous example. We may also pass-through initialization to any modules within our node addon. In this example, our addon will be <em>uuid.node</em> and contain a single module, <em>Uuid</em>. There is no reason we can't later add <em>Uuid2</em> which, instead of returning a normalized string value might return a <code>Buffer</code> object. To initialize the Uuid module, we pass the <code>target</code> object along to <code>Uuid::Init</code> and add the module definition to <code>target</code>:</p>
<pre class="prettyprint"><code>// addons/uuid/v0.1/uuid.cc
void Uuid::Init(Handle<Object> target) {
HandleScope scope;
// Setup the constructor
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Uuid::New));
constructor->InstanceTemplate()->SetInternalFieldCount(1); // for constructors
constructor->SetClassName(String::NewSymbol("Uuid"));
// Setup the prototype
NODE_SET_PROTOTYPE_METHOD(constructor, "generate", Generate);
NODE_SET_PROTOTYPE_METHOD(constructor, "generateRandom", GenerateRandom);
NODE_SET_PROTOTYPE_METHOD(constructor, "generateTime", GenerateTime);