├── .gitignore ├── .ruby-gemset ├── .ruby-version ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── README.md ├── _config.yml ├── _includes └── toc.html ├── _layouts ├── index.html └── page.html ├── dinky.html ├── docs ├── arguments.md ├── calling-native.md ├── getting-started.md ├── globals.md ├── jsclasses.md ├── native-common-code.md ├── objects.md └── returning.md ├── getting-started ├── binding.gyp ├── index.js ├── src │ └── hello.cc └── wscript ├── images ├── arrow-down.png ├── arrow-down.svg ├── octocat-small.png └── octocat.svg ├── index.md ├── javascripts └── scale.fix.js └── stylesheets ├── pygment_trac.css └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | node-bindings-guide 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.1.3 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Contributions are highly appreciated, please just follow these rules: 4 | 5 | 1. Do the fork / pull request dance with your changes 6 | 2. For consistency sake, please follow the [Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) 7 | 3. That's it! Thanks for your help. 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "jekyll" 4 | gem "rdiscount" 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | albino (1.3.3) 5 | posix-spawn (>= 0.3.6) 6 | classifier (1.3.3) 7 | fast-stemmer (>= 1.0.0) 8 | directory_watcher (1.4.1) 9 | fast-stemmer (1.0.1) 10 | jekyll (0.11.2) 11 | albino (~> 1.3) 12 | classifier (~> 1.3) 13 | directory_watcher (~> 1.1) 14 | kramdown (~> 0.13) 15 | liquid (~> 2.3) 16 | maruku (~> 0.5) 17 | kramdown (0.14.1) 18 | liquid (2.4.1) 19 | maruku (0.6.1) 20 | syntax (>= 1.0.0) 21 | posix-spawn (0.3.6) 22 | rdiscount (1.6.8) 23 | syntax (1.0.0) 24 | 25 | PLATFORMS 26 | ruby 27 | 28 | DEPENDENCIES 29 | jekyll 30 | rdiscount 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-bindings-guide 2 | 3 | You are looking at the _Node/V8 native bindings guide_ source. For the actual guide take a loot at [http://luismreis.github.com/node-bindings-guide/](http://luismreis.github.com/node-bindings-guide/). 4 | 5 | The guide uses [Dinky theme](https://github.com/broccolini/dinky) and is build by the [github pages](http://pages.github.com/)'s [jekyll](https://github.com/mojombo/jekyll) site generator. 6 | 7 | To build the site locally: 8 | 9 | Use bundler to install jekyll: 10 | 11 | bundle 12 | 13 | And then jekyll to generate the site: 14 | 15 | jekyll --safe --auto --server --base-url /node-bindings-guide/ 16 | 17 | To access it point your browser to `http://localhost:4000/node-bindings-guide/`. 18 | 19 | The `_config.yml` file is already configured with the same settings as gh-pages. 20 | 21 | For contributions, please check [contributing](https://github.com/luismreis/node-bindings-guide/blob/gh-pages/CONTRIBUTING.md). 22 | 23 | ------ 24 | 25 | Have fun building your own native libraries! 26 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | lsi: false 2 | pygments: true 3 | markdown: rdiscount 4 | -------------------------------------------------------------------------------- /_includes/toc.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /_layouts/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ title }} 7 | 8 | 9 | 10 | 11 | 12 | 15 | 25 | 26 | 27 |
28 |
29 | 34 |

This project is maintained by luismreis

35 |
36 |
37 | {{ content }} 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ title }} 7 | 8 | 9 | 10 | 11 | 12 | 15 | 25 | 26 | 27 |
28 |
29 | {% include toc.html %} 30 |
31 |
32 | {{ content }} 33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /dinky.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Awesome Project by Harrison Ford 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 29 | 30 | 31 | 32 |
33 |
34 |

My Awesome Project

35 |

This is an amazing project description.

36 | 41 |

This project is maintained by Harrison Ford

42 |
43 |
44 |

GitHub Pages

45 |

View the source of this content.

46 |

Let's get the whole "linebreak" thing out of the way. The next paragraph contains two phrases separated by a single newline character:

47 |

Roses are red
Violets are blue

48 |

The next paragraph has the same phrases, but now they are separated by two spaces and a newline character:

49 |

Roses are emphasized
Violets are strong

50 |

A bit of the GitHub spice

51 |

In addition to the changes in the previous section, certain references are auto-linked:

52 | 60 |

These are dangerous goodies though, and we need to make sure email addresses don't get mangled:

61 |

My email addy is tom@github.com.

62 |

Math is hard, let's go shopping

63 |

In first grade I learned that 5 > 3 and 2 < 7. Maybe some arrows. 1 -> 2 -> 3. 9 <- 8 <- 7.

64 |

Triangles man! a^2 + b^2 = c^2

65 |
66 |
require 'redcarpet'
 67 | markdown = Redcarpet.new("Hello World!")
 68 | puts markdown.to_html
 69 | 
70 |
71 |

We all like making lists

72 |

The above header should be an H2 tag. Now, for a list of fruits:

73 | 78 |

Let's get crazy:

79 |
    80 |
  1. This is a list item with two paragraphs. Lorem ipsum dolor
    sit amet, consectetuer adipiscing elit. Aliquam hendrerit
    mi posuere lectus.

    81 |

    Vestibulum enim wisi, viverra nec, fringilla in, laoreet
    vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
    sit amet velit.

  2. 82 |
  3. Suspendisse id sem consectetuer libero luctus adipiscing.

  4. 83 |
84 |

What about some code in a list? That's insane, right?

85 |
    86 |
  1. In Ruby you can map like this:

    87 |
    ['a', 'b'].map { |x| x.uppercase }
     88 | 
  2. 89 |
  3. In Rails, you can do a shortcut:

    90 |
    ['a', 'b'].map(&:uppercase)
     91 | 
  4. 92 |
93 |

Some people seem to like definition lists

94 |
95 |
Lower cost
96 |
The new version of this product costs significantly less than the previous one!
97 |
Easier to use
98 |
We've changed the product so that it's much easier to use!
99 |
100 |

I am a robot

101 |

Maybe you want to print robot to the console 1000 times. Why not?

102 |
def robot_invasion
103 |   puts("robot " * 1000)
104 | end
105 | 
106 |

You see, that was formatted as code because it's been indented by four spaces.

107 |

How about we throw some angle braces and ampersands in there?

108 |
<div class="footer">
109 |     &copy; 2004 Foo Corporation
110 | </div>
111 | 
112 |

Playing the blame game

113 |

If you need to blame someone, the best way to do so is by quoting them:

114 |
115 |

I, at any rate, am convinced that He does not throw dice.

116 |
117 |

Or perhaps someone a little less eloquent:

118 |
119 |

I wish you'd have given me this written question ahead of time so I
could plan for it... I'm sure something will pop into my head here in
the midst of this press conference, with all the pressure of trying to
come up with answer, but it hadn't yet...

120 |

I don't want to sound like
I have made no mistakes. I'm confident I have. I just haven't - you
just put me under the spot here, and maybe I'm not as quick on my feet
as I should be in coming up with one.

121 |
122 |

Table for two

123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 |
IDNameRank
1Tom Preston-WernerAwesome
2Albert EinsteinNearly as awesome
134 | 135 |

Play by the rules

136 |

Let's not forget the horizontal rule

137 |
138 | 139 |

Crazy linking action

140 |

I get 10 times more traffic from Google than from
Yahoo or MSN.

141 |

Headlines

142 |

Headline 1

143 |

Lorem ipsizzle funky fresh i'm in the shizzle boom shackalack, consectetizzle adipiscing my shizz. Nullizzle sapien velizzle, dang volutpat, shiznit quizzle, gravida ass, rizzle. Pot get down get down tortor. Sed erizzle. Black go to hizzle dolizzle dapibizzle turpis fo shizzle my nizzle yo. Maurizzle pellentesque nibh et check it out. Bow wow wow check it out tortizzle. Pellentesque for sure rhoncizzle bow wow wow. In owned habitasse brizzle dictumst. Nizzle dapibizzle. Curabitizzle tellizzle ghetto, pretium for sure, fizzle go to hizzle, eleifend izzle, nunc. Dope suscipizzle. Integizzle boom shackalack velit ass purus.

144 |

Headline 2

145 |

Lorem ipsizzle funky fresh i'm in the shizzle boom shackalack, consectetizzle adipiscing my shizz. Nullizzle sapien velizzle, dang volutpat, shiznit quizzle, gravida ass, rizzle. Pot get down get down tortor. Sed erizzle. Black go to hizzle dolizzle dapibizzle turpis fo shizzle my nizzle yo. Maurizzle pellentesque nibh et check it out. Bow wow wow check it out tortizzle. Pellentesque for sure rhoncizzle bow wow wow. In owned habitasse brizzle dictumst. Nizzle dapibizzle. Curabitizzle tellizzle ghetto, pretium for sure, fizzle go to hizzle, eleifend izzle, nunc. Dope suscipizzle. Integizzle boom shackalack velit ass purus.

146 |

Headline 3

147 |

Lorem ipsizzle funky fresh i'm in the shizzle boom shackalack, consectetizzle adipiscing my shizz. Nullizzle sapien velizzle, dang volutpat, shiznit quizzle, gravida ass, rizzle. Pot get down get down tortor. Sed erizzle. Black go to hizzle dolizzle dapibizzle turpis fo shizzle my nizzle yo. Maurizzle pellentesque nibh et check it out. Bow wow wow check it out tortizzle. Pellentesque for sure rhoncizzle bow wow wow. In owned habitasse brizzle dictumst. Nizzle dapibizzle. Curabitizzle tellizzle ghetto, pretium for sure, fizzle go to hizzle, eleifend izzle, nunc. Dope suscipizzle. Integizzle boom shackalack velit ass purus.

148 |

Headline 4

149 |

Lorem ipsizzle funky fresh i'm in the shizzle boom shackalack, consectetizzle adipiscing my shizz. Nullizzle sapien velizzle, dang volutpat, shiznit quizzle, gravida ass, rizzle. Pot get down get down tortor. Sed erizzle. Black go to hizzle dolizzle dapibizzle turpis fo shizzle my nizzle yo. Maurizzle pellentesque nibh et check it out. Bow wow wow check it out tortizzle. Pellentesque for sure rhoncizzle bow wow wow. In owned habitasse brizzle dictumst. Nizzle dapibizzle. Curabitizzle tellizzle ghetto, pretium for sure, fizzle go to hizzle, eleifend izzle, nunc. Dope suscipizzle. Integizzle boom shackalack velit ass purus.

150 |
Headline 5
151 |

Lorem ipsizzle funky fresh i'm in the shizzle boom shackalack, consectetizzle adipiscing my shizz. Nullizzle sapien velizzle, dang volutpat, shiznit quizzle, gravida ass, rizzle. Pot get down get down tortor. Sed erizzle. Black go to hizzle dolizzle dapibizzle turpis fo shizzle my nizzle yo. Maurizzle pellentesque nibh et check it out. Bow wow wow check it out tortizzle. Pellentesque for sure rhoncizzle bow wow wow. In owned habitasse brizzle dictumst. Nizzle dapibizzle. Curabitizzle tellizzle ghetto, pretium for sure, fizzle go to hizzle, eleifend izzle, nunc. Dope suscipizzle. Integizzle boom shackalack velit ass purus.

152 |
Headline 6
153 |

Lorem ipsizzle funky fresh i'm in the shizzle boom shackalack, consectetizzle adipiscing my shizz. Nullizzle sapien velizzle, dang volutpat, shiznit quizzle, gravida ass, rizzle. Pot get down get down tortor. Sed erizzle. Black go to hizzle dolizzle dapibizzle turpis fo shizzle my nizzle yo. Maurizzle pellentesque nibh et check it out. Bow wow wow check it out tortizzle. Pellentesque for sure rhoncizzle bow wow wow. In owned habitasse brizzle dictumst. Nizzle dapibizzle. Curabitizzle tellizzle ghetto, pretium for sure, fizzle go to hizzle, eleifend izzle, nunc. Dope suscipizzle. Integizzle boom shackalack velit ass purus.

154 |
155 | 158 |
159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/arguments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Receiving arguments 4 | --- 5 | # Receiving function call arguments 6 | 7 | * Arguments are always passed as arrays via the `const Arguments& args` parameter 8 | * The args parameters exposes each argument as an array element (see below). 9 | 10 | ## Argument count 11 | 12 | Use the Length method to get the argument count: 13 | 14 | args.Length() 15 | 16 | Reference: 17 | 18 | * [nodejs addons](http://nodejs.org/api/addons.html) 19 | 20 | ## Scalar values 21 | 22 | v = args[n]->BooleanValue(); 23 | v = args[n]->NumberValue(); 24 | v = args[n]->IntegerValue(); 25 | v = args[n]->Uint32Value(); 26 | v = args[n]->Int32Value(); 27 | 28 | Reference: 29 | 30 | * [nodejs addons](http://nodejs.org/api/addons.html) 31 | 32 | ## Native enums 33 | 34 | Native enums (previously returned by another native function) are casted back to C++ via: 35 | 36 | v = static_cast(args[n]->Uint32Value()) 37 | 38 | ## Javascript objects 39 | 40 | Local obj = arg[n]->ToObject(); 41 | 42 | or 43 | 44 | Local obj = args[n].As(); 45 | 46 | ## Strings 47 | 48 | String::AsciiValue v(args[n]->ToString()); 49 | 50 | Reference Code: 51 | 52 | * [png module](https://github.com/pkrumins/node-png/blob/master/src/png.cpp#L67) 53 | 54 | ## Buffers (node.js only) 55 | 56 | Local bufferObj = args[n]->ToObject(); 57 | char* bufferData = Buffer::Data(bufferObj); 58 | size_t bufferLength = Buffer::Length(bufferObj); 59 | 60 | ## NativeArrays (node.js only) 61 | 62 | V8 source code includes a runtime called D8 that also declares native arrays, however, these objects do not make part of V8. node.js provides its own implementation for those objects. 63 | 64 | Local array = args[n]->ToObject(); 65 | Handle buffer = array->Get(String::New("buffer"))->ToObject(); 66 | unsigned int offset = array->Get(String::New("byteOffset"))->Uint32Value(); 67 | int length = array->Get(String::New("byteLength"))->Uint32Value(); 68 | 69 | // Actual data 70 | ptr = (MyType*) &((char*) buffer->GetIndexedPropertiesExternalArrayData())[offset] 71 | 72 | ## Wrapped values 73 | 74 | The main purpose of wrapped values is to encapsulate opaque native values, such as file handles, graphics context handles or even C++ object references. 75 | 76 | MyType v = (MyType) External::Unwrap(args[n]); 77 | 78 | Reference: 79 | 80 | * [node.js addons - Object Factory](http://nodejs.org/api/addons.html#addons_object_factory) 81 | -------------------------------------------------------------------------------- /docs/calling-native.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Calling other native functions 4 | --- 5 | # Calling other native functions 6 | 7 | Factory* factory = Isolate::Current()->factory(); 8 | Handle argArray = factory->NewFixedArray(argCount); 9 | argArray->set(i, v); 10 | //... 11 | Handle arguments = 12 | factory->NewArgumentsObject(inlined_function, argCount); 13 | 14 | for (int j = 0; j < js_args.argc(); j++) { 15 | i::Handle arg = 16 | FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j])); 17 | arguments_array->set(j, *arg); 18 | } 19 | i::Handle arguments_jsarray = 20 | FACTORY->NewJSArrayWithElements(arguments_array); 21 | 22 | (To Do: Review this code sample.) 23 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Getting Started 4 | --- 5 | # Getting started 6 | 7 | This section describes how to build a _hello world_ node.js module equivalent to: 8 | 9 | exports.hello = function() { return 'world'; }; 10 | 11 | This is the same example as the [addons](http://nodejs.org/api/addons.html) section on node's documentation, with a slightly different organization. 12 | 13 | ## Project layout 14 | 15 | Node modules have a common directory layout, typically with an `index.js` as the main module and a `lib` directory for the submodules. 16 | 17 | Native code in node modules usually resides in a `src` subdirectory in the project. 18 | 19 | To build the project a configuration file for GYP - `binding.gyp` - or WAF - `wscript` - is necessary. Note that WAF is currently deprecated as a build system for node's native modules (and node itself). 20 | 21 | The directory layout for a node module with native bindings is: 22 | 23 | hello-world 24 | + src 25 | - hello.cc 26 | - index.js 27 | - binding.gyp // See building with GYP below. 28 | - wscript // See building with WAF below. 29 | 30 | For this example, the contents of `index.js` should be: 31 | 32 | var addon = require('./build/Release/hello'); 33 | 34 | console.log(addon.hello()); // 'world' 35 | 36 | And the contents of `hello.cc`: 37 | 38 | 39 | #include 40 | #include 41 | 42 | using namespace v8; 43 | 44 | Handle Method(const Arguments& args) { 45 | HandleScope scope; 46 | return scope.Close(String::New("world")); 47 | } 48 | 49 | void init(Handle target) { 50 | NODE_SET_METHOD(target, "hello", Method); 51 | } 52 | NODE_MODULE(hello, init) 53 | 54 | To run this example (don't do it yet) run: 55 | 56 | node index.js 57 | 58 | ## Building with GYP 59 | 60 | GYP is the current (as of node 0.8.x) way of building node native modules and node itself. To build node modules using GYP, [node-gyp](https://github.com/TooTallNate/node-gyp) must be installed: 61 | 62 | npm install -g node-gyp 63 | 64 | Installing node-gyp will pull lots of modules from npm. 65 | 66 | GYP is configured through the binding.gyp file. For this example it should contain: 67 | 68 | { 69 | "targets": [ 70 | { 71 | "target_name": "hello", 72 | "sources": [ "src/hello.cc" ] 73 | } 74 | ] 75 | } 76 | 77 | To setup node-gyp do: 78 | 79 | node-gyp configure 80 | 81 | The first time `node-gyp configure` is executed, it will pull node's source code. This is OK. 82 | 83 | To do the actual build: 84 | 85 | node-gyp build 86 | 87 | To run the example: 88 | 89 | node index.js 90 | 91 | The output should be: 92 | 93 | world 94 | 95 | 96 | ## Building with WAF 97 | 98 | WAF is the _old way_ of building node's native modules and is included on its distribution. 99 | 100 | *Use WAF only if you need to support old versions of node (below 0.8).* 101 | 102 | WAF is configured through the `wscript`. 103 | 104 | For the hello world example it sould contain: 105 | 106 | #!/usr/bin/env python 107 | 108 | from os import popen 109 | 110 | srcdir = '.' 111 | blddir = 'build' 112 | VERSION = '0.0.1' 113 | 114 | def set_options(opt): 115 | opt.tool_options('compiler_cxx') 116 | 117 | def configure(conf): 118 | conf.check_tool('compiler_cxx') 119 | conf.check_tool('node_addon') 120 | 121 | def build(bld): 122 | obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') 123 | obj.target = "hello" 124 | obj.cxxflags = ["-Wall", "-g"] 125 | obj.source = ["src/hello.cc"] 126 | 127 | Now, to setup WAF do: 128 | 129 | node-waf configure 130 | 131 | It will produce an output similar to: 132 | 133 | Checking for program g++ or c++ : /usr/bin/g++ 134 | Checking for program cpp : /usr/bin/cpp 135 | Checking for program ar : /usr/bin/ar 136 | Checking for program ranlib : /usr/bin/ranlib 137 | Checking for g++ : ok 138 | Checking for node path : not found 139 | Checking for node prefix : ok /Users/me/opt/node 140 | 'configure' finished successfully (0.236s) 141 | 142 | The following files will be added to your project 143 | 144 | hello-world 145 | + build 146 | + c4che 147 | - Release.cache.py 148 | - build.config.py 149 | - build.log 150 | 151 | To actually build the project, run: 152 | 153 | node-waf build 154 | 155 | This will output: 156 | 157 | Waf: Entering directory `/Users/me/node-bindings-guide/getting-started/build' 158 | [1/2] cxx: src/hello.cc -> build/Release/src/hello_1.o 159 | [2/2] cxx_link: build/Release/src/hello_1.o -> build/Release/hello.node 160 | Waf: Leaving directory `/Users/me/node-bindings-guide/getting-started/build' 161 | 'build' finished successfully (0.439s) 162 | 163 | The following files will be generated: 164 | 165 | hello-world 166 | + build 167 | + Release 168 | + src 169 | - hello_1.o 170 | - hello.node 171 | 172 | To execute the code: 173 | 174 | node index.js 175 | 176 | Output: 177 | 178 | world 179 | 180 | Reference: 181 | 182 | * [nodejs addons](http://nodejs.org/api/addons.html) 183 | * [github / jchia / waf-example](https://github.com/jchia/waf-example) 184 | * [github / luismreis / node-openvg](https://github.com/luismreis/node-openvg) 185 | -------------------------------------------------------------------------------- /docs/globals.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Accessing the global scope 4 | --- 5 | # Accessing the global scope 6 | 7 | Handle variable_name = String::New("global_variable_name"); 8 | Handle global_variable = 9 | Context::GetCurrent()->Global()->Get(variable_name); 10 | 11 | Reference 12 | 13 | * See the `samples/lineprocessor.cc` file included in the V8 source code 14 | -------------------------------------------------------------------------------- /docs/jsclasses.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Creating a JavaScript Class 4 | --- 5 | 6 | # Creating a JavaScript Class 7 | (by [@pgte](https://github.com/pgte)) 8 | 9 | In the main `.cc` of your module declare the module initializer: 10 | 11 | void init(Handle target) { 12 | my_namespace::Initialize(target); 13 | } 14 | NODE_MODULE(my_module, init) 15 | 16 | Declare a C++ class inside your own namespace) - preferably in a `.h` file: 17 | 18 | ### `MyClass.h`: 19 | 20 | namespace my_namespace { 21 | 22 | class MyClass : ObjectWrap { 23 | public: 24 | // Static module initializer 25 | static void Initialize(v8::Handle target); 26 | 27 | // Constructor: 28 | MyClass (); 29 | 30 | // Destructor: 31 | virtual ~Context (); 32 | 33 | private: 34 | // Instance Methods 35 | Handle DoStuff (); 36 | static Handle DoStuff (const Arguments &args); 37 | Handle DoMoreStuff (); 38 | static Handle DoMoreStuff (const Arguments &args); 39 | } 40 | 41 | } 42 | 43 | Then, back in the main `.cc` file, declare the constructor, destructor and initialization methods. 44 | 45 | namespace my_namespace { 46 | 47 | //// Life-cycle functions 48 | 49 | // Destructor 50 | Context::~Context() { 51 | Close(); 52 | } 53 | 54 | // Module Initializer 55 | void MyClass::Initialize(v8::Handle target) { 56 | HandleScope scope; 57 | 58 | // Create constructor 59 | Local t = FunctionTemplate::New(New); 60 | t->InstanceTemplate()->SetInternalFieldCount(1); 61 | 62 | // Set prototype methods on the constructor: 63 | NODE_SET_PROTOTYPE_METHOD(t, "doStuff", DoStuff); 64 | NODE_SET_PROTOTYPE_METHOD(t, "doMoreStuff", DoMoreStuff); 65 | 66 | // Set constructor function on the module 67 | target->Set(String::NewSymbol("MyClass"), t->GetFunction()); 68 | } 69 | 70 | void Initialize(Handle target) { 71 | MyClass::Initialize(target); 72 | } 73 | 74 | } 75 | 76 | You also need to implement the class methods `doStuff` and `doMoreStuff`. These methods come in pairs, one static and one instance method for each JS class method. 77 | 78 | First we need an utility method for getting the context to get the instance from a static call: 79 | 80 | namespace my_namespace { 81 | 82 | // Utility Function for getting a context 83 | MyClass* MyClass::GetContext(const Arguments &args) { 84 | return ObjectWrap::Unwrap(args.This()); 85 | } 86 | 87 | } 88 | 89 | Then we are ready to implement the instance methods 90 | 91 | namespace my_namespace { 92 | 93 | // Do Stuff: 94 | 95 | Handle MyClass::DoStuff() { 96 | // TODO: Actually do stuff here... 97 | } 98 | 99 | Handle MyClass::DoStuff(const Arguments& args) { 100 | HandleScope scope; 101 | return GetContext(args)->DoStuff(); 102 | } 103 | 104 | // Do More Stuff: 105 | 106 | Handle MyClass::DoMoreStuff() { 107 | // TODO: Actually do stuff here... 108 | } 109 | 110 | Handle MyClass::DoMoreStuff(const Arguments& args) { 111 | HandleScope scope; 112 | return GetContext(args)->DoMoreStuff(); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /docs/native-common-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Native method template 4 | --- 5 | # Common code for V8 native methods 6 | 7 | ## For each c++ header file (.h): 8 | 9 | * Use the #ifndef/#define c/c++ pattern 10 | * Create a namespace for your methods 11 | * Declare all javascript callable methods as: 12 | * C++ `static Handle MethodName(const Arguments& args);` 13 | * Note that this name is not visible to javascript (see below) 14 | * If you want to adhere to the [Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml), use CamelCasing 15 | 16 | Sample code: 17 | 18 | #ifndef MY_NATIVE_LIB_H_ 19 | #define MY_NATIVE_LIB_H_ 20 | 21 | #include 22 | #include 23 | 24 | using namespace v8; 25 | 26 | namespace my_namespace { 27 | static Handle MethodAlpha(const Arguments& args); 28 | static Handle MethodBeta(const Arguments& args); 29 | static Handle MethodGamma(const Arguments& args); 30 | //... 31 | } 32 | 33 | #endif 34 | 35 | ## Prefix for each c++ code file (.cc/.cpp): 36 | 37 | * Import node and V8 relevant headers. 38 | * Import your own headers. 39 | * Use the `using namespace` cautiously (importing node and v8 namespaces is generally safe). 40 | * Declare an init function (see sample code), that: 41 | * Exposes your C++ functions to javascript: 42 | * Performs other necessary initialization 43 | 44 | Sample code: 45 | 46 | 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | #include "my_other_include.h" 53 | 54 | using namespace node; 55 | using namespace v8; 56 | 57 | void init(Handle target) { 58 | NODE_SET_METHOD(target, "methodAlpha" , my_namespace::MethodAlpha); 59 | NODE_SET_METHOD(target, "methodBeta" , my_namespace::MethodBeta); 60 | NODE_SET_METHOD(target, "methodGamma" , my_namespace::MethodGama); 61 | // ... 62 | } 63 | NODE_MODULE(my_module, init) 64 | 65 | ## Method/Function template: 66 | 67 | * Always declare a local HandleScope 68 | * Always return using the Close clause 69 | 70 | Sample code: 71 | 72 | Handle my_namespace::MethodAlpha(const Arguments& args) { 73 | HandleScope scope; 74 | 75 | // My stuff goes here 76 | 77 | return scope.Close(something); 78 | } 79 | 80 | See [arguments](arguments.html) and [returning values](returning.html). 81 | 82 | Reference: 83 | 84 | * [V8 embedder's guide - Handles and Garbage Collection](https://developers.google.com/v8/embed#handles) 85 | * [nodejs addons](http://nodejs.org/api/addons.html) 86 | -------------------------------------------------------------------------------- /docs/objects.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Creating javascript objects in native code 4 | --- 5 | # Creating javascript objects in native code 6 | 7 | ## Creating and accessing objects 8 | 9 | Local obj = Object::New(); 10 | obj->Get(String::NewSymbol("key")); 11 | obj->Get(index); 12 | obj->Set(String::NewSymbol("key"), value); 13 | obj->Set(index, value); 14 | 15 | ## Creating and accessing arrays 16 | 17 | Handle array = Array::New(length); 18 | array->Set(n, v); 19 | -------------------------------------------------------------------------------- /docs/returning.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Returning values from native code 4 | --- 5 | # Returning values from native code 6 | 7 | Returning values should always be done through the scope's Close method. 8 | 9 | Note that Undefined, Null and some scalar values may be returned without going through the Close method, but this nay eventually break in the future. 10 | 11 | ## Undefined / Null 12 | 13 | return scope.Close(Undefined()); 14 | // or 15 | return scope.Close(Null()); 16 | 17 | ## Scalar values 18 | 19 | return scope.Close(Boolean::New(v)); // or 20 | return scope.Close(True()); // or 21 | return scope.Close(False()); 22 | 23 | return scope.Close(Number::New(v)); 24 | return scope.Close(Integer::New(v)); 25 | return scope.Close(Uint32::New(v)); 26 | return scope.Close(Int32::New(v)); 27 | 28 | ## Native enums 29 | 30 | return scope.Close(Integer::New(v)); 31 | 32 | ## Objects 33 | 34 | Local obj = Object::New(); 35 | // Set stuff (see below) 36 | return scope.Close(obj); 37 | 38 | ## Buffers (node.js only) 39 | 40 | Buffer *slowBuffer = Buffer::New(length); 41 | memcpy(Buffer::Data(slowBuffer), data, length); 42 | 43 | Local globalObj = Context::GetCurrent()->Global(); 44 | Local bufferConstructor = Local::Cast(globalObj->Get(String::New("Buffer"))); 45 | Handle constructorArgs[3] = { slowBuffer->handle_, v8::Integer::New(length), v8::Integer::New(0) }; 46 | Local actualBuffer = bufferConstructor->NewInstance(3, constructorArgs); 47 | return scope.Close(actualBuffer); 48 | 49 | Reference: 50 | 51 | * [Creating a proper Buffer in a Node C++ Addon](http://sambro.is-super-awesome.com/2011/03/03/creating-a-proper-buffer-in-a-node-c-addon/) 52 | 53 | ## Native arrays (node.js only) 54 | 55 | V8 source code includes a runtime called D8 that also declares native arrays, however, these objects do not make part of V8. node.js provides its own implementation for those objects. 56 | 57 | The code below actually acts as if it was javascript calling the public native array creation functions. 58 | 59 | Handle fun_val = Context::GetCurrent()->Global()->Get(name); 60 | Handle fun = Handle::Cast(fun_val); 61 | 62 | const unsigned argc = 1; 63 | Local argv[argc] = { Local::New(Uint32::New(length)) }; 64 | 65 | Local result = fun->NewInstance(argc, argv); 66 | return scope.Close(result); 67 | 68 | Where name is one of: 69 | 70 | String::New("Int8Array") 71 | String::New("Uint8Array") 72 | String::New("Uint8ClampedArray") 73 | String::New("Int16Array") 74 | String::New("Uint16Array") 75 | String::New("Int32Array") 76 | String::New("Uint32Array") 77 | String::New("Float32Array") 78 | String::New("Float64Array") 79 | 80 | ## Wrapped values 81 | 82 | External::Wrap(v) 83 | 84 | Reference: 85 | 86 | * [node.js addons - Object Factory](http://nodejs.org/api/addons.html#addons_object_factory) 87 | -------------------------------------------------------------------------------- /getting-started/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "hello", 5 | "sources": [ "src/hello.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /getting-started/index.js: -------------------------------------------------------------------------------- 1 | var addon = require('./build/Release/hello'); 2 | 3 | console.log(addon.hello()); // 'world' 4 | -------------------------------------------------------------------------------- /getting-started/src/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace v8; 5 | 6 | Handle Method(const Arguments& args) { 7 | HandleScope scope; 8 | return scope.Close(String::New("world")); 9 | } 10 | 11 | void init(Handle target) { 12 | NODE_SET_METHOD(target, "hello", Method); 13 | } 14 | NODE_MODULE(hello, init) 15 | -------------------------------------------------------------------------------- /getting-started/wscript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from os import popen 4 | 5 | srcdir = '.' 6 | blddir = 'build' 7 | VERSION = '0.0.1' 8 | 9 | def set_options(opt): 10 | opt.tool_options('compiler_cxx') 11 | 12 | def configure(conf): 13 | conf.check_tool('compiler_cxx') 14 | conf.check_tool('node_addon') 15 | 16 | def build(bld): 17 | obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') 18 | obj.target = "hello" 19 | obj.cxxflags = ["-Wall", "-g"] 20 | obj.source = ["src/hello.cc"] 21 | -------------------------------------------------------------------------------- /images/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eendeego/node-bindings-guide/5301fef24e6038c716fe72a3bb9cb0fafc5f7df9/images/arrow-down.png -------------------------------------------------------------------------------- /images/arrow-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 13 | 14 | 15 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /images/octocat-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eendeego/node-bindings-guide/5301fef24e6038c716fe72a3bb9cb0fafc5f7df9/images/octocat-small.png -------------------------------------------------------------------------------- /images/octocat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 17 | 18 | 19 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: index 3 | title: Node/V8 native binding guide 4 | --- 5 | # Node/V8 native binding guide 6 | 7 | This guide started as a place to consolidate random scratch notes from information on node / v8 native bindings that is currently scattered through many locations. 8 | 9 | ## Sections 10 | 11 | * [Getting started](docs/getting-started.html) 12 | * [Common code for native methods](docs/native-common-code.html) 13 | * [Receiving arguments](docs/arguments.html) 14 | * [Returning values](docs/returning.html) 15 | * [Creating and accessing objects](docs/objects.html) 16 | * [Calling other native functions](docs/calling-native.html) 17 | * [Declaring/Accessing globals](docs/globals.html) 18 | * [Creating a JavaScript Class](docs/jsclasses.html) 19 | -------------------------------------------------------------------------------- /javascripts/scale.fix.js: -------------------------------------------------------------------------------- 1 | fixScale = function(doc) { 2 | 3 | var addEvent = 'addEventListener', 4 | type = 'gesturestart', 5 | qsa = 'querySelectorAll', 6 | scales = [1, 1], 7 | meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : []; 8 | 9 | function fix() { 10 | meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1]; 11 | doc.removeEventListener(type, fix, true); 12 | } 13 | 14 | if ((meta = meta[meta.length - 1]) && addEvent in doc) { 15 | fix(); 16 | scales = [.25, 1.6]; 17 | doc[addEvent](type, fix, true); 18 | } 19 | 20 | }; -------------------------------------------------------------------------------- /stylesheets/pygment_trac.css: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; } 2 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .highlight .k { font-weight: bold } /* Keyword */ 5 | .highlight .o { font-weight: bold } /* Operator */ 6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 14 | .highlight .gh { color: #999999 } /* Generic.Heading */ 15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .highlight .go { color: #888888 } /* Generic.Output */ 18 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 19 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 20 | .highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ 21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .highlight .kn { font-weight: bold } /* Keyword.Namespace */ 25 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 26 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 27 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 28 | .highlight .m { color: #009999 } /* Literal.Number */ 29 | .highlight .s { color: #d14 } /* Literal.String */ 30 | .highlight .na { color: #008080 } /* Name.Attribute */ 31 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 32 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 33 | .highlight .no { color: #008080 } /* Name.Constant */ 34 | .highlight .ni { color: #800080 } /* Name.Entity */ 35 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 36 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 37 | .highlight .nn { color: #555555 } /* Name.Namespace */ 38 | .highlight .nt { color: #000080 } /* Name.Tag */ 39 | .highlight .nv { color: #008080 } /* Name.Variable */ 40 | .highlight .ow { font-weight: bold } /* Operator.Word */ 41 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 42 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 43 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 44 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 45 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 46 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 47 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 48 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 49 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 50 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 51 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 52 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 53 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 54 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 55 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 56 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 57 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 58 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 59 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 60 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 61 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 62 | 63 | .type-csharp .highlight .k { color: #0000FF } 64 | .type-csharp .highlight .kt { color: #0000FF } 65 | .type-csharp .highlight .nf { color: #000000; font-weight: normal } 66 | .type-csharp .highlight .nc { color: #2B91AF } 67 | .type-csharp .highlight .nn { color: #000000 } 68 | .type-csharp .highlight .s { color: #A31515 } 69 | .type-csharp .highlight .sc { color: #A31515 } 70 | -------------------------------------------------------------------------------- /stylesheets/styles.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Arvo:400,700,400italic); 2 | 3 | /* MeyerWeb Reset */ 4 | 5 | html, body, div, span, applet, object, iframe, 6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 7 | a, abbr, acronym, address, big, cite, code, 8 | del, dfn, em, img, ins, kbd, q, s, samp, 9 | small, strike, strong, sub, sup, tt, var, 10 | b, u, i, center, 11 | dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, canvas, details, embed, 15 | figure, figcaption, footer, header, hgroup, 16 | menu, nav, output, ruby, section, summary, 17 | time, mark, audio, video { 18 | margin: 0; 19 | padding: 0; 20 | border: 0; 21 | font: inherit; 22 | vertical-align: baseline; 23 | } 24 | 25 | 26 | /* Base text styles */ 27 | 28 | body { 29 | padding:10px 50px 0 0; 30 | font-family:"Helvetica Neue", Helvetica, Arial, sans-serif; 31 | font-size: 14px; 32 | color: #232323; 33 | background-color: #FBFAF7; 34 | margin: 0; 35 | line-height: 1.8em; 36 | -webkit-font-smoothing: antialiased; 37 | 38 | } 39 | 40 | h1, h2, h3, h4, h5, h6 { 41 | color:#232323; 42 | margin:36px 0 10px; 43 | } 44 | 45 | p, ul, ol, table, dl { 46 | margin:0 0 22px; 47 | } 48 | 49 | h1, h2, h3 { 50 | font-family: 'Arvo', Monaco, serif; 51 | line-height:1.3; 52 | font-weight: normal; 53 | } 54 | 55 | h1,h2, h3 { 56 | display: block; 57 | border-bottom: 1px solid #ccc; 58 | padding-bottom: 5px; 59 | } 60 | 61 | h1 { 62 | font-size: 30px; 63 | } 64 | 65 | h2 { 66 | font-size: 24px; 67 | } 68 | 69 | h3 { 70 | font-size: 18px; 71 | } 72 | 73 | h4, h5, h6 { 74 | font-family: 'Arvo', Monaco, serif; 75 | font-weight: 700; 76 | } 77 | 78 | a { 79 | color:#C30000; 80 | font-weight:200; 81 | text-decoration:none; 82 | } 83 | 84 | a:hover { 85 | text-decoration: underline; 86 | } 87 | 88 | a small { 89 | font-size: 12px; 90 | } 91 | 92 | em { 93 | font-style: italic; 94 | } 95 | 96 | strong { 97 | font-weight:700; 98 | } 99 | 100 | ul li { 101 | list-style: inside; 102 | padding-left: 25px; 103 | } 104 | 105 | ol li { 106 | list-style: decimal inside; 107 | padding-left: 20px; 108 | } 109 | 110 | blockquote { 111 | margin: 0; 112 | padding: 0 0 0 20px; 113 | font-style: italic; 114 | } 115 | 116 | dl, dt, dd, dl p { 117 | font-color: #444; 118 | } 119 | 120 | dl dt { 121 | font-weight: bold; 122 | } 123 | 124 | dl dd { 125 | padding-left: 20px; 126 | font-style: italic; 127 | } 128 | 129 | dl p { 130 | padding-left: 20px; 131 | font-style: italic; 132 | } 133 | 134 | hr { 135 | border:0; 136 | background:#ccc; 137 | height:1px; 138 | margin:0 0 24px; 139 | } 140 | 141 | /* Images */ 142 | 143 | img { 144 | position: relative; 145 | margin: 0 auto; 146 | max-width: 650px; 147 | padding: 5px; 148 | margin: 10px 0 32px 0; 149 | border: 1px solid #ccc; 150 | } 151 | 152 | 153 | /* Code blocks */ 154 | 155 | code, pre { 156 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; 157 | font-size:14px; 158 | } 159 | 160 | pre { 161 | padding: 4px 12px; 162 | background: #FDFEFB; 163 | border-radius:4px; 164 | border:1px solid #D7D8C8; 165 | overflow: auto; 166 | overflow-y: hidden; 167 | margin-bottom: 32px; 168 | } 169 | 170 | 171 | /* Tables */ 172 | 173 | table { 174 | width:100%; 175 | } 176 | 177 | table { 178 | border: 1px solid #ccc; 179 | margin-bottom: 32px; 180 | text-align: left; 181 | } 182 | 183 | th { 184 | font-family: 'Arvo', Helvetica, Arial, sans-serif; 185 | font-size: 18px; 186 | font-weight: normal; 187 | padding: 10px; 188 | background: #232323; 189 | color: #FDFEFB; 190 | } 191 | 192 | td { 193 | padding: 10px; 194 | background: #ccc; 195 | } 196 | 197 | 198 | /* Wrapper */ 199 | .wrapper { 200 | width:960px; 201 | } 202 | 203 | 204 | /* Header */ 205 | 206 | header { 207 | background-color: #171717; 208 | color: #FDFDFB; 209 | width: 190px; 210 | float:left; 211 | position:fixed; 212 | border: 1px solid #000; 213 | -webkit-border-top-right-radius: 4px; 214 | -webkit-border-bottom-right-radius: 4px; 215 | -moz-border-radius-topright: 4px; 216 | -moz-border-radius-bottomright: 4px; 217 | border-top-right-radius: 4px; 218 | border-bottom-right-radius: 4px; 219 | padding: 34px 15px 22px 20px; 220 | margin: 30px 25px 0 0; 221 | -webkit-font-smoothing: antialiased; 222 | } 223 | 224 | header.index { 225 | width:170px; 226 | padding: 34px 25px 22px 50px; 227 | margin: 30px 25px 0 0; 228 | } 229 | 230 | p.header { 231 | font-size: 10px; 232 | } 233 | 234 | h1.header { 235 | font-family: 'Arvo', sans-serif; 236 | font-size: 30px; 237 | font-weight: 300; 238 | line-height: 1.3em; 239 | border-bottom: none; 240 | margin-top: 0; 241 | } 242 | 243 | 244 | h1.header, a.header, a.name, header a{ 245 | color: #fff; 246 | } 247 | 248 | a.header { 249 | text-decoration: underline; 250 | } 251 | 252 | a.name { 253 | white-space: nowrap; 254 | } 255 | 256 | header ul { 257 | list-style:none; 258 | padding:0; 259 | } 260 | 261 | header li { 262 | list-style-type: none; 263 | width:132px; 264 | height:15px; 265 | margin-bottom: 12px; 266 | line-height: 1em; 267 | padding: 6px 6px 6px 7px; 268 | } 269 | 270 | header.index li { 271 | background: #AF0011; 272 | background: -moz-linear-gradient(top, #AF0011 0%, #820011 100%); 273 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); 274 | background: -webkit-linear-gradient(top, #AF0011 0%,#820011 100%); 275 | background: -o-linear-gradient(top, #AF0011 0%,#820011 100%); 276 | background: -ms-linear-gradient(top, #AF0011 0%,#820011 100%); 277 | background: linear-gradient(top, #AF0011 0%,#820011 100%); 278 | 279 | border-radius:4px; 280 | border:1px solid #0D0D0D; 281 | 282 | -webkit-box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); 283 | box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); 284 | 285 | } 286 | 287 | header.index li:hover { 288 | background: #C3001D; 289 | background: -moz-linear-gradient(top, #C3001D 0%, #950119 100%); 290 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); 291 | background: -webkit-linear-gradient(top, #C3001D 0%,#950119 100%); 292 | background: -o-linear-gradient(top, #C3001D 0%,#950119 100%); 293 | background: -ms-linear-gradient(top, #C3001D 0%,#950119 100%); 294 | background: linear-gradient(top, #C3001D 0%,#950119 100%); 295 | } 296 | 297 | a.buttons { 298 | -webkit-font-smoothing: antialiased; 299 | background: url(../images/arrow-down.svg) no-repeat 2px 1px; 300 | background: url(../images/arrow-down.png) no-repeat 2px 1px\9; 301 | background-size: 12px auto; 302 | font-weight: normal; 303 | text-shadow: rgba(0, 0, 0, 0.4) 0 -1px 0; 304 | padding: 2px 2px 2px 22px; 305 | height: 30px; 306 | } 307 | 308 | a.github { 309 | background: url(../images/octocat.svg) no-repeat 1px; 310 | background: url(../images/octocat-small.png) no-repeat 1px\9; 311 | background-size: 14px auto; 312 | } 313 | 314 | a.buttons:hover { 315 | color: #fff; 316 | text-decoration: none; 317 | } 318 | 319 | 320 | /* Section - for main page content */ 321 | 322 | section { 323 | width:650px; 324 | float:right; 325 | padding-bottom:50px; 326 | } 327 | 328 | 329 | /* Footer */ 330 | 331 | footer { 332 | width:170px; 333 | float:left; 334 | position:fixed; 335 | bottom:10px; 336 | padding-left: 50px; 337 | } 338 | 339 | @media print, screen and (max-width: 960px) { 340 | 341 | div.wrapper { 342 | width:auto; 343 | margin:0; 344 | } 345 | 346 | header, section, footer { 347 | float:none; 348 | position:static; 349 | width:auto; 350 | } 351 | 352 | footer { 353 | border-top: 1px solid #ccc; 354 | margin:0 84px 0 50px; 355 | padding:0; 356 | } 357 | 358 | header { 359 | padding-right:320px; 360 | } 361 | 362 | section { 363 | padding:20px 84px 20px 50px; 364 | margin:0 0 20px; 365 | } 366 | 367 | header a small { 368 | display:inline; 369 | } 370 | 371 | header ul { 372 | position:absolute; 373 | right:130px; 374 | top:84px; 375 | } 376 | } 377 | 378 | @media print, screen and (max-width: 720px) { 379 | body { 380 | word-wrap:break-word; 381 | } 382 | 383 | header { 384 | padding:10px 20px 0; 385 | margin-right: 0; 386 | } 387 | 388 | section { 389 | padding:10px 0 10px 20px; 390 | margin:0 0 30px; 391 | } 392 | 393 | footer { 394 | margin: 0 0 0 30px; 395 | } 396 | 397 | header ul, header p.view { 398 | position:static; 399 | } 400 | } 401 | 402 | @media print, screen and (max-width: 480px) { 403 | 404 | header ul li.download { 405 | display:none; 406 | } 407 | 408 | footer { 409 | margin: 0 0 0 20px; 410 | } 411 | 412 | footer a{ 413 | display:block; 414 | } 415 | 416 | } 417 | 418 | @media print { 419 | body { 420 | padding:0.4in; 421 | font-size:12pt; 422 | color:#444; 423 | } 424 | } --------------------------------------------------------------------------------