Full Code of genekogan/p5js-osc for AI

master 42e1a698f3a5 cached
40 files
5.5 MB
1.4M tokens
835 symbols
1 requests
Download .txt
Showing preview only (5,738K chars total). Download the full file or copy to clipboard to get everything.
Repository: genekogan/p5js-osc
Branch: master
Commit: 42e1a698f3a5
Files: 40
Total size: 5.5 MB

Directory structure:
gitextract_v0gih5tc/

├── .gitignore
├── Applications.md
├── README.md
├── bridge.js
├── p5-ableton/
│   ├── basic-percussion/
│   │   ├── Ableton Project Info/
│   │   │   └── Project8_1.cfg
│   │   ├── Icon
│   │   ├── basic-percussion.als
│   │   └── receive-osc.amxd
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-basic/
│   ├── ProcessingOSC/
│   │   └── ProcessingOSC.pde
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-faceOsc/
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-faceOsc-flocking/
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-kinect/
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
└── package.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules/
.DS_Store
package-lock.json


================================================
FILE: Applications.md
================================================
### osc in p5.js

adapted from [osc-web](https://github.com/automata/osc-web).

#### setup

1) install [node](https://nodejs.org/)

2)

	$ git https://github.com/genekogan/p5js-osc
	$ cd p5js-osc/
	$ npm install

3)

    $ node bridge.js

This command runs the file in this repo called "bridge.js", it runs on the server. Is is a javascript file that creates a connection using <a href="http://socket.io/">socket.io.</a> This file creates a listener on the server, which is where the computer is listening for packets sent using UDP. Any computer can support sending and receiving network packets, eg. it can request info, by sending an http request (UDP).  

(What is socket.io? Socket is one of the most common node modules which facilitates communication between the client and the server. bridge.js converts into socket which then passes it to OSC)  

We need to use something like OSC because p5js (unlike processing) does not have access to the drivers in your computer. This is for good reason, we wouldn't want javascript on a server to be able to access your drivers eh? So if you want to use something like p5 and the kinect, you need to send the data from the device, which needs access to your computer's drivers, and then send it to p5js over OSC (which is actually via UDP). So your computer is being both the server (node) and the client (p5).  

If you then open any of the index.html pages in the folders of the repo. You may need to <a href="http://www.pythonforbeginners.com/modules-in-python/how-to-use-simplehttpserver/">start a local server</a> if you start using video or images etc. in your sketch.  

When you open index.html from a sketch in a browser, it connects to bridge.js.  

Note: if you try to reload the index.html page in the browser. You'll notice you get an error and node will stop running. When you start node, the server communicates with your application over a particular port. It only allows one application to connect over a single port and it won't let anything else connect to it. So when you reload, you are not actually closing the connection, and node thinks you are another application trying to connect and will crash. So for now, you have to restart node everytime you refresh your browser (do this in the terminal where you are running bridge CRL-c to quit and then relaunch using as before:  

	$node bridge.js

4) send OSC to p5 via port 3333. send OSC from p5 via port 3334  


###examples

 - basic (done)
 - in: kinect
 - in: leap-motion
 - in: faceosc
 - in: midi device?
 - out: ableton?

####Example sending OSC data from Processing and receiving in p5js:
*In Processing:*  
- Install the osvP5 library from the import library menu in Processing.
- Take a look at the simple Processing example called oscP5sendReceive.
- Modify it to send the mouse coordinates over OSC everytime the mouse is pressed.
*Getting this talking to p5:*  
- To get this running. Run the Processing sketch. Then, make sure you are running bridge.js in your terminal (always launch this on the server before you launch the p5 sketch). Then open index.html (from the p5-app folder) in your browser.
- In your browser javascript console, you should then see the mouse coordinates print out when you click in the Processing sketch.
- Note: The order you start everything here is really important. If you get an error. Close the p5 sketch in the browser. Kill node with CTRL c. Then launch the server (bridge.js) again and then open the p5 sketch again.
- A quick way to do this in chrome is using the shortcut CMD + SHIFT + T (reopens the last tab, this helps to relaunch your p5)
- In p5 you can animate something with these mouse coordinates.

####Example sending OSC data from OpenFrameworks Face tracker and receiving in p5js:
*FaceOSC*  
- (SORRY at the moment facetracker is only released for mac)
- Javascript is slow for facetracking so we can use OF facetracker to do the face work and send the data to javascript over OSC.
- Download facetracker in OF from <a href="https://github.com/kylemcdonald/ofxFaceTracker/releases">here. Get v 1.1 a the bottom of the page.</a>
- See the documentation of this in the repo.
- Fun things to try with this. Draw a face on a piece of paper, can facetracker recognize it?
*Facetracker options*
- Pose and gesture refers to pose and gesture of the face. Direction of the face, size of eyes, width of mouth etc.
- If you have raw on, you are sending raw data (the coordinates of the facial mesh) and it sends 1032 numbers 30 times a second. A lot of data! Note, if you are not using this it is a waste to send all this data unless you need it.
- Syphon sends the image (but keep this off for now).
- Now start index.html of p5-faceOsc. You should see the wireframe of your face in your browser.   
*FaceOSC-flocking*  
- try this, this is an example from Dan Shiffman to see more of what's possible.  
- See inside this example for more info on the data that faceOSC provides.  

####Example using the Kinect
- Download the OSC kinect 1 application made by jpbellona. Get the zip from the [repo here.](https://github.com/jpbellona/simpleKinect)
- (If you have a windows machine you can use a kinect 2 and use [this repo.](https://github.com/microcosm/ofxKinectV2-OSC))
- Find the Processing sketch called simpleKinect in this repo.  
- This sketch sends kinect data to OSC. We can then use this in p5.  
- Careful, this still has some bugs.  

####Example using Ableton
- To get this working you need to download and install [Max for Live (M4L)](https://www.ableton.com/en/live/max-for-live/). M4L is a somewhat truncated version of MaxMSP.  Ableton doesn't support OSC directly, but it does support M4L devices which can convert our OSC to midi so that ableton can receive data from our p5 app.
- The example in this repo will play a note each time our ball in p5 hits a wall.
- So you can create a p5 app and control ableton from it.

*These are very rough notes from the p5 OSC workshop held at ITP in January 2016.  Ableton example updated May 2021 by Billy Bennett*


================================================
FILE: README.md
================================================
### osc in p5.js

adapted from [osc-web](https://github.com/automata/osc-web).

#### setup

Install [node](https://nodejs.org/)

Clone this repo and run npm to get required libraries.

	$ git clone https://github.com/genekogan/p5js-osc
	$ cd p5js-osc/
	$ npm install

Start node.

    $ node bridge.js

Then run any of the sketches in a browser or from the editor. Can also be run locally (i.e. just open index.html).

Inside each sketch, when you run `setupOSC` you give it the input and output ports (default 3333, 3334).

### Applications

Thanks [Tega Brain](https://github.com/tegacodes) for extended [notes on the included applications](https://github.com/genekogan/p5js-osc/blob/master/Applications.md).

There is a [demo video](https://vimeo.com/157024760) of the included examples.

Examples:
 - Processing (needs [oscP5](www.sojamo.de/oscP5))
 - Ableton Live (needs [M4L (Max For Live)](https://www.ableton.com/en/live/max-for-live/) and [KinectOSC](https://github.com/genekogan/KinectOSC/releases))
 - FaceTracker (needs [FaseOSC](https://github.com/kylemcdonald/ofxFaceTracker/releases))
 - Kinect (needs [KinectOSC](https://github.com/genekogan/KinectOSC/releases))

Low-hanging fruits.
 - [TouchOSC](http://hexler.net/software/touchosc) to control p5 from a phone/tablet

### p5.js - arduino bridge

[@lorenzoromagnoli](https://github.com/lorenzoromagnoli) made this into a [standalone application](https://github.com/lorenzoromagnoli/p5js-osc) using [electron](https://electron.atom.io/) which bridges p5.js to arduino over OSC.


================================================
FILE: bridge.js
================================================
var osc = require('node-osc');
var io = require('socket.io')(8081);


var oscServer, oscClient;

var isConnected = false;

io.sockets.on('connection', function (socket) {
	console.log('connection');
	socket.on("config", function (obj) {
		isConnected = true;
    	oscServer = new osc.Server(obj.server.port, obj.server.host);
	    oscClient = new osc.Client(obj.client.host, obj.client.port);
	    oscClient.send('/status', socket.sessionId + ' connected');
		oscServer.on('message', function(msg, rinfo) {
			socket.emit("message", msg);
		});
		socket.emit("connected", 1);
	});
 	socket.on("message", function (obj) {
		oscClient.send.apply(oscClient, obj);
  	});
	socket.on('disconnect', function(){
		if (isConnected) {
			oscServer.kill();
			oscClient.kill();
		}
  	});
});

================================================
FILE: p5-ableton/basic-percussion/Icon
================================================


================================================
FILE: p5-ableton/index.html
================================================
<html>

<head>
  	<meta charset="UTF-8">
	<script src="http://127.0.0.1:8081/socket.io/socket.io.js"></script>
  	<script language="javascript" type="text/javascript" src="libraries/p5.js"></script>
  	<script language="javascript" type="text/javascript" src="sketch.js"></script>
  	<style> body {padding: 0; margin: 0;} </style>
</head>

<body>
</body>

</html>

================================================
FILE: p5-ableton/libraries/p5.dom.js
================================================
/*! p5.dom.js v0.2.6 November 10, 2015 */
/**
 * <p>The web is much more than just canvas and p5.dom makes it easy to interact
 * with other HTML5 objects, including text, hyperlink, image, input, video,
 * audio, and webcam.</p>
 * <p>There is a set of creation methods, DOM manipulation methods, and
 * an extended p5.Element that supports a range of HTML elements. See the
 * <a href="https://github.com/processing/p5.js/wiki/Beyond-the-canvas">
 * beyond the canvas tutorial</a> for a full overview of how this addon works.
 *
 * <p>Methods and properties shown in black are part of the p5.js core, items in
 * blue are part of the p5.dom library. You will need to include an extra file
 * in order to access the blue functions. See the
 * <a href="http://p5js.org/libraries/#using-a-library">using a library</a>
 * section for information on how to include this library. p5.dom comes with
 * <a href="http://p5js.org/download">p5 complete</a> or you can download the single file
 * <a href="https://raw.githubusercontent.com/lmccart/p5.js/master/lib/addons/p5.dom.js">
 * here</a>.</p>
 * <p>See <a href="https://github.com/processing/p5.js/wiki/Beyond-the-canvas">tutorial: beyond the canvas</a>
 * for more info on how to use this libary.</a>
 *
 * @module p5.dom
 * @submodule p5.dom
 * @for p5.dom
 * @main
 */

(function (root, factory) {
  if (typeof define === 'function' && define.amd)
    define('p5.dom', ['p5'], function (p5) { (factory(p5));});
  else if (typeof exports === 'object')
    factory(require('../p5'));
  else
    factory(root['p5']);
}(this, function (p5) {
// =============================================================================
//                         p5 additions
// =============================================================================

  /**
   * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
   * prefixes to specify an ID or class respectively, and none for a tag) and returns it as
   * a p5.Element. If a class or tag name is given with more than 1 element,
   * only the first element will be returned.
   * The DOM node itself can be accessed with .elt.
   * Returns null if none found. You can also specify a container to search within.
   *
   * @method select
   * @param  {String} name id, class, or tag name of element to search for
   * @param  {String} [container] id, p5.Element, or HTML element to search within
   * @return {Object/p5.Element|Null} p5.Element containing node found
   * @example
   * <div ><code class='norender'>
   * function setup() {
   *   createCanvas(100,100);
   *   //translates canvas 50px down
   *   select('canvas').translate(0,50);
   * }
   * </code></div>
   * <div ><code class='norender'>
   * // these are all valid calls to select()
   * var a = select('#moo');
   * var b = select('#blah', '#myContainer');
   * var c = select('#foo', b);
   * var d = document.getElementById('beep');
   * var e = select('p', d);
   * </code></div>
   *
   */
  p5.prototype.select = function (e, p) {
    var res = null;
    var container = getContainer(p);
    if (e[0] === '.'){
      e = e.slice(1);
      res = container.getElementsByClassName(e);
      if (res.length) {
        res = res[0];
      } else {
        res = null;
      }
    }else if (e[0] === '#'){
      e = e.slice(1);
      res = container.getElementById(e);
    }else {
      res = container.getElementsByTagName(e);
      if (res.length) {
        res = res[0];
      } else {
        res = null;
      }
    }
    if (res) {
      return wrapElement(res);
    } else {
      return null;
    }
  };

  /**
   * Searches the page for elements with the given class or tag name (using the '.' prefix
   * to specify a class and no prefix for a tag) and returns them as p5.Elements
   * in an array.
   * The DOM node itself can be accessed with .elt.
   * Returns an empty array if none found.
   * You can also specify a container to search within.
   *
   * @method selectAll
   * @param  {String} name class or tag name of elements to search for
   * @param  {String} [container] id, p5.Element, or HTML element to search within
   * @return {Array} Array of p5.Elements containing nodes found
   * @example
   * <div ><code class='norender'>
   * function setup() {
   *   createButton('btn');
   *   createButton('2nd btn');
   *   createButton('3rd btn');
   *   var buttons = selectAll('button');
   *
   *   for (var i = 0; i < buttons.length; i++){
   *     buttons[i].size(100,100);
   *   }
   * }
   * </code></div>
   * <div ><code class='norender'>
   * // these are all valid calls to selectAll()
   * var a = selectAll('.moo');
   * var b = selectAll('div');
   * var c = selectAll('button', '#myContainer');
   * var d = select('#container');
   * var e = selectAll('p', d);
   * var f = document.getElementById('beep');
   * var g = select('.blah', f);
   * </code></div>
   *
   */
  p5.prototype.selectAll = function (e, p) {
    var arr = [];
    var res;
    var container = getContainer(p);
    if (e[0] === '.'){
      e = e.slice(1);
      res = container.getElementsByClassName(e);
    } else {
      res = container.getElementsByTagName(e);
    }
    if (res) {
      for (var j = 0; j < res.length; j++) {
        var obj = wrapElement(res[j]);
        arr.push(obj);
      }
    }
    return arr;
  };

  /**
   * Helper function for select and selectAll
   */
  function getContainer(p) {
    var container = document;
    if (typeof p === 'string' && p[0] === '#'){
      p = p.slice(1);
      container = document.getElementById(p) || document;
    } else if (p instanceof p5.Element){
      container = p.elt;
    } else if (p instanceof HTMLElement){
      container = p;
    }
    return container;
  }

  /**
   * Helper function for getElement and getElements.
   */
  function wrapElement(elt) {
    if(elt.tagName === "INPUT" && elt.type === "checkbox") {
      var converted = new p5.Element(elt);
      converted.checked = function(){
      if (arguments.length === 0){
        return this.elt.checked;
      } else if(arguments[0]) {
        this.elt.checked = true;
      } else {
        this.elt.checked = false;
      }
      return this;
      };
      return converted;
    } else if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
      return new p5.MediaElement(elt);
    } else {
      return new p5.Element(elt);
    }
  }

  /**
   * Removes all elements created by p5, except any canvas / graphics
   * elements created by createCanvas or createGraphics.
   * Event handlers are removed, and element is removed from the DOM.
   * @method removeElements
   * @example
   * <div class='norender'><code>
   * function setup() {
   *   createCanvas(100, 100);
   *   createDiv('this is some text');
   *   createP('this is a paragraph');
   * }
   * function mousePressed() {
   *   removeElements(); // this will remove the div and p, not canvas
   * }
   * </code></div>
   *
   */
  p5.prototype.removeElements = function (e) {
    for (var i=0; i<this._elements.length; i++) {
      if (!(this._elements[i].elt instanceof HTMLCanvasElement)) {
        this._elements[i].remove();
      }
    }
  };

  /**
   * Helpers for create methods.
   */
  function addElement(elt, pInst, media) {
    var node = pInst._userNode ? pInst._userNode : document.body;
    node.appendChild(elt);
    var c = media ? new p5.MediaElement(elt) : new p5.Element(elt);
    pInst._elements.push(c);
    return c;
  }

  /**
   * Creates a &lt;div&gt;&lt;/div&gt; element in the DOM with given inner HTML.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createDiv
   * @param  {String} html inner HTML for element created
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var myDiv;
   * function setup() {
   *   myDiv = createDiv('this is some text');
   * }
   * </code></div>
   */

  /**
   * Creates a &lt;p&gt;&lt;/p&gt; element in the DOM with given inner HTML. Used
   * for paragraph length text.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createP
   * @param  {String} html inner HTML for element created
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var myP;
   * function setup() {
   *   myP = createP('this is some text');
   * }
   * </code></div>
   */

  /**
   * Creates a &lt;span&gt;&lt;/span&gt; element in the DOM with given inner HTML.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createSpan
   * @param  {String} html inner HTML for element created
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var mySpan;
   * function setup() {
   *   mySpan = createSpan('this is some text');
   * }
   * </code></div>
   */
  var tags = ['div', 'p', 'span'];
  tags.forEach(function(tag) {
    var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
    p5.prototype[method] = function(html) {
      var elt = document.createElement(tag);
      elt.innerHTML = typeof html === undefined ? "" : html;
      return addElement(elt, this);
    }
  });

  /**
   * Creates an &lt;img /&gt; element in the DOM with given src and
   * alternate text.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createImg
   * @param  {String} src src path or url for image
   * @param  {String} [alt] alternate text to be used if image does not load
   * @param  {Function} [successCallback] callback to be called once image data is loaded
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var img;
   * function setup() {
   *   img = createImg('http://p5js.org/img/asterisk-01.png');
   * }
   * </code></div>
   */
  p5.prototype.createImg = function() {
    var elt = document.createElement('img');
    var args = arguments;
    var self;
    var setAttrs = function(){
      self.width = elt.offsetWidth;
      self.height = elt.offsetHeight;
      if (args.length > 1 && typeof args[1] === 'function'){
        self.fn = args[1];
        self.fn();
      }else if (args.length > 1 && typeof args[2] === 'function'){
        self.fn = args[2];
        self.fn();
      }
    };
    elt.src = args[0];
    if (args.length > 1 && typeof args[1] === 'string'){
      elt.alt = args[1];
    }
    elt.onload = function(){
      setAttrs();
    }
    self = addElement(elt, this);
    return self;
  };

  /**
   * Creates an &lt;a&gt;&lt;/a&gt; element in the DOM for including a hyperlink.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createA
   * @param  {String} href       url of page to link to
   * @param  {String} html       inner html of link element to display
   * @param  {String} [target]   target where new link should open,
   *                             could be _blank, _self, _parent, _top.
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var myLink;
   * function setup() {
   *   myLink = createA('http://p5js.org/', 'this is a link');
   * }
   * </code></div>
   */
  p5.prototype.createA = function(href, html, target) {
    var elt = document.createElement('a');
    elt.href = href;
    elt.innerHTML = html;
    if (target) elt.target = target;
    return addElement(elt, this);
  };

  /** INPUT **/


  /**
   * Creates a slider &lt;input&gt;&lt;/input&gt; element in the DOM.
   * Use .size() to set the display length of the slider.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createSlider
   * @param  {Number} min minimum value of the slider
   * @param  {Number} max maximum value of the slider
   * @param  {Number} [value] default value of the slider
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div><code>
   * var slider;
   * function setup() {
   *   slider = createSlider(0, 255, 100);
   *   slider.position(10, 10);
   *   slider.style('width', '80px');
   * }
   *
   * function draw() {
   *   var val = slider.value();
   *   background(val);
   * }
   * </code></div>
   */
  p5.prototype.createSlider = function(min, max, value, step) {
    var elt = document.createElement('input');
    elt.type = 'range';
    elt.min = min;
    elt.max = max;
    if (step) elt.step = step;
    if (typeof(value) === "number") elt.value = value;
    return addElement(elt, this);
  };

  /**
   * Creates a &lt;button&gt;&lt;/button&gt; element in the DOM.
   * Use .size() to set the display size of the button.
   * Use .mousePressed() to specify behavior on press.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createButton
   * @param  {String} label label displayed on the button
   * @param  {String} [value] value of the button
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var button;
   * function setup() {
   *   createCanvas(100, 100);
   *   background(0);
   *   button = createButton('click me');
   *   button.position(19, 19);
   *   button.mousePressed(changeBG);
   * }
   *
   * function changeBG() {
   *   var val = random(255);
   *   background(val);
   * }
   * </code></div>
   */
  p5.prototype.createButton = function(label, value) {
    var elt = document.createElement('button');
    elt.innerHTML = label;
    elt.value = value;
    if (value) elt.value = value;
    return addElement(elt, this);
  };

  /**
   * Creates a checkbox &lt;input&gt;&lt;/input&gt; element in the DOM.
   * Calling .checked() on a checkbox returns if it is checked or not
   *
   * @method createCheckbox
   * @param  {String} [label] label displayed after checkbox
   * @param  {boolean} [value] value of the checkbox; checked is true, unchecked is false.Unchecked if no value given
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var checkbox;
   *
   * function setup() {
   *   checkbox = createCheckbox('label', false);
   *   checkbox.changed(myCheckedEvent);
   * }
   *
   * function myCheckedEvent() {
   *   if (this.checked()) {
   *     console.log("Unchecking!");
   *   } else {
   *     console.log("Checking!");
   *   }
   *
   * </code></div>
   */
  p5.prototype.createCheckbox = function() {
    var elt = document.createElement('input');
    elt.type = 'checkbox';
    //checkbox must be wrapped in p5.Element before label so that label appears after
    var self = addElement(elt, this);
    self.checked = function(){
      if (arguments.length === 0){
        return self.elt.checked;
      }else if(arguments[0]){
        self.elt.checked = true;
      }else{
        self.elt.checked = false;
      }
      return self;
    };
    this.value = function(val){
      self.value = val;
      return this;
    };
    if (arguments[0]){
      var ran = Math.random().toString(36).slice(2);
      var label = document.createElement('label');
      elt.setAttribute('id', ran);
      label.htmlFor = ran;
      self.value(arguments[0]);
      label.appendChild(document.createTextNode(arguments[0]));
      addElement(label, this);
    }
    if (arguments[1]){
      elt.checked = true;
    }
    return self;
  };

  /**
   * Creates a dropdown menu &lt;select&gt;&lt;/select&gt; element in the DOM.
   * @method createSelect
   * @param {boolean} [multiple] [true if dropdown should support multiple selections]
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div><code>
   * var sel;
   *
   * function setup() {
   *   textAlign(CENTER);
   *   background(200);
   *   sel = createSelect();
   *   sel.position(10, 10);
   *   sel.option('pear');
   *   sel.option('kiwi');
   *   sel.option('grape');
   *   sel.changed(mySelectEvent);
   * }
   *
   * function mySelectEvent() {
   *   var item = sel.value();
   *   background(200);
   *   text("it's a "+item+"!", 50, 50);
   * }
   * </code></div>
   */
  p5.prototype.createSelect = function(mult) {
    var elt = document.createElement('select');
    if (mult){
      elt.setAttribute('multiple', 'true');
    }
    var self = addElement(elt, this);
    self.option = function(name, value){
      var opt = document.createElement('option');
      opt.innerHTML = name;
      if (arguments.length > 1)
        opt.value = value;
      else
        opt.value = name;
      elt.appendChild(opt);
    };
    self.selected = function(value){
      var arr = [];
      if (arguments.length > 0){
        for (var i = 0; i < this.elt.length; i++){
          if (value.toString() === this.elt[i].value){
            this.elt.selectedIndex = i;
          }
        }
        return this;
      }else{
        if (mult){
          for (var i = 0; i < this.elt.selectedOptions.length; i++){
            arr.push(this.elt.selectedOptions[i].value);
          }
          return arr;
        }else{
          return this.elt.value;
        }
      }
    };
    return self;
  };

  /**
   * Creates a radio button &lt;input&gt;&lt;/input&gt; element in the DOM.
   *
   * @method createRadio
   * @param  {String} [divId] the id and name of the created div and input field respectively 
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   */
  p5.prototype.createRadio = function() {
    var radios = document.querySelectorAll("input[type=radio]");
    var count = 0;
    if(radios.length > 1){
      console.log(radios,radios[0].name);
      var length = radios.length;
      var prev=radios[0].name;
      var current = radios[1].name;
      count=1;
      for(var i = 1; i < length; i++ ){
        current = radios[i].name;
        if(prev != current){
          count++;
        }
        prev = current;
      }
    }
    else if (radios.length == 1){
      count = 1;
    }
    var elt = document.createElement('div');
    var self = addElement(elt, this);
    var times = -1;
    self.option = function(name, value){
      var opt = document.createElement('input');
      opt.type = 'radio';
      opt.innerHTML = name;
      if (arguments.length > 1)
        opt.value = value;
      else
        opt.value = name;
      opt.setAttribute('name',"defaultradio"+count);
      elt.appendChild(opt);
      if (name){
        times++;
        var ran = Math.random().toString(36).slice(2);
        var label = document.createElement('label');
        opt.setAttribute('id', "defaultradio"+count+"-"+times);
        label.htmlFor = "defaultradio"+count+"-"+times;
        label.appendChild(document.createTextNode(name));
        elt.appendChild(label);
      }
      return opt;
    };
    self.selected = function(){
      var length = this.elt.childNodes.length;
      if(arguments[0]) {
        for (var i = 0; i < length; i+=2){
          if(this.elt.childNodes[i].value == arguments[0])
            this.elt.childNodes[i].checked = true;
        }
        return this;
      } else {
        for (var i = 0; i < length; i+=2){
          if(this.elt.childNodes[i].checked == true)
            return this.elt.childNodes[i].value;
        }
      }
    };
    self.value = function(){
      var length = this.elt.childNodes.length;
      if(arguments[0]) {
        for (var i = 0; i < length; i+=2){
          if(this.elt.childNodes[i].value == arguments[0])
            this.elt.childNodes[i].checked = true;
        }
        return this;
      } else {
        for (var i = 0; i < length; i+=2){
          if(this.elt.childNodes[i].checked == true)
            return this.elt.childNodes[i].value;
        }
        return "";
      }
    };
    return self
  };
  
  /**
   * Creates an &lt;input&gt;&lt;/input&gt; element in the DOM for text input.
   * Use .size() to set the display length of the box.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createInput
   * @param  {Number} [value] default value of the input box
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * function setup(){
   *   var inp = createInput('');
   *   inp.input(myInputEvent);
   * }
   *
   * function myInputEvent(){
   *   console.log('you are typing: ', this.value());
   * }
   *
   * </code></div>
   */
  p5.prototype.createInput = function(value) {
    var elt = document.createElement('input');
    elt.type = 'text';
    if (value) elt.value = value;
    return addElement(elt, this);
  };

  /**
   * Creates an &lt;input&gt;&lt;/input&gt; element in the DOM of type 'file'.
   * This allows users to select local files for use in a sketch.
   *
   * @method createFileInput
   * @param  {Function} [callback] callback function for when a file loaded
   * @param  {String} [multiple] optional to allow multiple files selected
   * @return {Object/p5.Element} pointer to p5.Element holding created DOM element
   */
  p5.prototype.createFileInput = function(callback, multiple) {

    // Is the file stuff supported?
    if (window.File && window.FileReader && window.FileList && window.Blob) {
      // Yup, we're ok and make an input file selector
      var elt = document.createElement('input');
      elt.type = 'file';

      // If we get a second argument that evaluates to true
      // then we are looking for multiple files
      if (multiple) {
        // Anything gets the job done
        elt.multiple = 'multiple';
      }

      // Function to handle when a file is selected
      // We're simplifying life and assuming that we always
      // want to load every selected file
      function handleFileSelect(evt) {
        // These are the files
        var files = evt.target.files;
        // Load each one and trigger a callback
        for (var i = 0; i < files.length; i++) {
          var f = files[i];
          var reader = new FileReader();
          function makeLoader(theFile) {
            // Making a p5.File object
            var p5file = new p5.File(theFile);
            return function(e) {
              p5file.data = e.target.result;
              callback(p5file);
            };
          };
          reader.onload = makeLoader(f);

          // Text or data?
          // This should likely be improved
          if (f.type.indexOf('text') > -1) {
            reader.readAsText(f);
          } else {
            reader.readAsDataURL(f);
          }
        }
      }
      
      // Now let's handle when a file was selected
      elt.addEventListener('change', handleFileSelect, false);
      return addElement(elt, this);
    } else {
      console.log('The File APIs are not fully supported in this browser. Cannot create element.');
    }
  };


  /** VIDEO STUFF **/

  function createMedia(pInst, type, src, callback) {
    var elt = document.createElement(type);
    if (typeof src === 'string') {
      src = [src];
    }
    for (var i=0; i<src.length; i++) {
      var source = document.createElement('source');
      source.src = src[i];
      elt.appendChild(source);
    }
    if (typeof callback !== 'undefined') {
      var callbackHandler = function() {
        callback();
        elt.removeEventListener('canplaythrough', callbackHandler);
      }
      elt.addEventListener('canplaythrough', callbackHandler);
    }

    var c = addElement(elt, pInst, true);
    c.loadedmetadata = false;
    // set width and height onload metadata
    elt.addEventListener('loadedmetadata', function() {
      c.width = elt.videoWidth;
      c.height = elt.videoHeight;
      c.loadedmetadata = true;
    });

    return c;
  }
  /**
   * Creates an HTML5 &lt;video&gt; element in the DOM for simple playback
   * of audio/video. Shown by default, can be hidden with .hide()
   * and drawn into canvas using video(). Appends to the container
   * node if one is specified, otherwise appends to body. The first parameter
   * can be either a single string path to a video file, or an array of string
   * paths to different formats of the same video. This is useful for ensuring
   * that your video can play across different browsers, as each supports
   * different formats. See <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats">this
   * page</a> for further information about supported formats.
   *
   * @method createVideo
   * @param  {String|Array} src  path to a video file, or array of paths for
   *                             supporting different browsers
   * @param  {Object} [callback] callback function to be called upon
   *                             'canplaythrough' event fire, that is, when the
   *                             browser can play the media, and estimates that
   *                             enough data has been loaded to play the media
   *                             up to its end without having to stop for
   *                             further buffering of content
   * @return {Object/p5.Element} pointer to video p5.Element
   */
  p5.prototype.createVideo = function(src, callback) {
    return createMedia(this, 'video', src, callback);
  };

  /** AUDIO STUFF **/

  /**
   * Creates a hidden HTML5 &lt;audio&gt; element in the DOM for simple audio
   * playback. Appends to the container node if one is specified,
   * otherwise appends to body. The first parameter
   * can be either a single string path to a audio file, or an array of string
   * paths to different formats of the same audio. This is useful for ensuring
   * that your audio can play across different browsers, as each supports
   * different formats. See <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats">this
   * page for further information about supported formats.
   *
   * @method createAudio
   * @param  {String|Array} src  path to an audio file, or array of paths for
   *                             supporting different browsers
   * @param  {Object} [callback] callback function to be called upon
   *                             'canplaythrough' event fire, that is, when the
   *                             browser can play the media, and estimates that
   *                             enough data has been loaded to play the media
   *                             up to its end without having to stop for
   *                             further buffering of content
   * @return {Object/p5.Element} pointer to audio p5.Element
   */
  p5.prototype.createAudio = function(src, callback) {
    return createMedia(this, 'audio', src, callback);
  };


  /** CAMERA STUFF **/

  p5.prototype.VIDEO = 'video';
  p5.prototype.AUDIO = 'audio';

  navigator.getUserMedia  = navigator.getUserMedia ||
                            navigator.webkitGetUserMedia ||
                            navigator.mozGetUserMedia ||
                            navigator.msGetUserMedia;

  /**
   * Creates a new &lt;video&gt; element that contains the audio/video feed
   * from a webcam. This can be drawn onto the canvas using video(). More
   * specific properties of the stream can be passing in a Constraints object.
   * See the
   * <a href="http://w3c.github.io/mediacapture-main/getusermedia.html">W3C
   * spec</a> for possible properties. Note that not all of these are supported
   * by all browsers.
   *
   * @method createCapture
   * @param  {String|Constant|Object}   type type of capture, either VIDEO or
   *                                    AUDIO if none specified, default both,
   *                                    or a Constraints boject
   * @param  {Function}                 callback function to be called once
   *                                    stream has loaded
   * @return {Object/p5.Element} capture video p5.Element
   * @example
   * <div class='norender'><code>
   * var capture;
   *
   * function setup() {
   *   createCanvas(480, 120);
   *   capture = createCapture(VIDEO);
   * }
   *
   * function draw() {
   *   image(capture, 0, 0, width, width*capture.height/capture.width);
   *   filter(INVERT);
   * }
   * </code></div>
   * <div class='norender'><code>
   * function setup() {
   *   createCanvas(480, 120);
   *   var constraints = {
   *     video: {
   *       mandatory: {
   *         minWidth: 1280,
   *         minHeight: 720
   *       },
   *       optional: [
   *         { maxFrameRate: 10 }
   *       ]
   *     },
   *     audio: true
   *   };
   *   createCapture(constraints, function(stream) {
   *     console.log(stream);
   *   });
   * }
   * </code></div>
   */
  p5.prototype.createCapture = function() {
    var useVideo = true;
    var useAudio = true;
    var constraints;
    var cb;
    for (var i=0; i<arguments.length; i++) {
      if (arguments[i] === p5.prototype.VIDEO) {
        useAudio = false;
      } else if (arguments[i] === p5.prototype.AUDIO) {
        useVideo = false;
      } else if (typeof arguments[i] === 'object') {
        constraints = arguments[i];
      } else if (typeof arguments[i] === 'function') {
        cb = arguments[i];
      }
    }

    if (navigator.getUserMedia) {
      var elt = document.createElement('video');

      if (!constraints) {
        constraints = {video: useVideo, audio: useAudio};
      }

      navigator.getUserMedia(constraints, function(stream) {
        elt.src = window.URL.createObjectURL(stream);
        elt.onloadedmetadata = function(e) {
          elt.play();
          if (cb) {
            cb(stream);
          }
        };
      }, function(e) { console.log(e); });
    } else {
      throw 'getUserMedia not supported in this browser';
    }
    var c = addElement(elt, this, true);
    c.loadedmetadata = false;
    // set width and height onload metadata
    elt.addEventListener('loadedmetadata', function() {
      c.width = elt.videoWidth;
      c.height = elt.videoHeight;
      c.loadedmetadata = true;
    });
    return c;
  };

  /**
   * Creates element with given tag in the DOM with given content.
   * Appends to the container node if one is specified, otherwise
   * appends to body.
   *
   * @method createElement
   * @param  {String} tag tag for the new element
   * @param  {String} [content] html content to be inserted into the element
   * @return {Object/p5.Element} pointer to p5.Element holding created node
   * @example
   * <div class='norender'><code>
   * var h2 = createElement('h2','im an h2 p5.element!');
   * </code></div>
   */
  p5.prototype.createElement = function(tag, content) {
    var elt = document.createElement(tag);
    if (typeof content !== 'undefined') {
      elt.innerHTML = content;
    }
    return addElement(elt, this);
  };


// =============================================================================
//                         p5.Element additions
// =============================================================================
  /**
   *
   * Adds specified class to the element.
   *
   * @for p5.Element
   * @method addClass
   * @param  {String} class name of class to add
   * @return {Object/p5.Element}
   * @example
   * <div class='norender'><code>
   * var div = createDiv('div');
   * div.addClass('myClass');
   * </code></div>
   */
  p5.Element.prototype.addClass = function(c) {
    if (this.elt.className) {
      // PEND don't add class more than once
      //var regex = new RegExp('[^a-zA-Z\d:]?'+c+'[^a-zA-Z\d:]?');
      //if (this.elt.className.search(/[^a-zA-Z\d:]?hi[^a-zA-Z\d:]?/) === -1) {
      this.elt.className = this.elt.className+' '+c;
      //}
    } else {
      this.elt.className = c;
    }
    return this;
  }

  /**
   *
   * Removes specified class from the element.
   *
   * @method removeClass
   * @param  {String} class name of class to remove
   * @return {Object/p5.Element}
   */
  p5.Element.prototype.removeClass = function(c) {
    var regex = new RegExp('(?:^|\\s)'+c+'(?!\\S)');
    this.elt.className = this.elt.className.replace(regex, '');
    this.elt.className = this.elt.className.replace(/^\s+|\s+$/g, ""); //prettify (optional)
    return this;
  }

  /**
   *
   * Attaches the element  as a child to the parent specified.
   * Accepts either a string ID, DOM node, or p5.Element
   *
   * @method child
   * @param  {String|Object/p5.Element} child the ID, DOM node, or p5.Element
   *                         to add to the current element
   * @return {p5.Element}
   * @example
   * <div class='norender'><code>
   * var div0 = createDiv('this is the parent');
   * var div1 = createDiv('this is the child');
   * div0.child(div1); // use p5.Element
   * </code></div>
   * <div class='norender'><code>
   * var div0 = createDiv('this is the parent');
   * var div1 = createDiv('this is the child');
   * div1.id('apples');
   * div0.child('apples'); // use id
   * </code></div>
   * <div class='norender'><code>
   * var div0 = createDiv('this is the parent');
   * var elt = document.getElementById('myChildDiv');
   * div0.child(elt); // use element from page
   * </code></div>
   */
  p5.Element.prototype.child = function(c) {
    if (typeof c === 'string') {
      if (c[0] === '#') {
        c = c.substring(1);
      }
      c = document.getElementById(c);
    } else if (c instanceof p5.Element) {
      c = c.elt;
    }
    this.elt.appendChild(c);
    return this;
  };

  /**
   * Centers a p5 Element either vertically, horizontally,
   * or both, relative to its parent or according to
   * the body if the Element has no parent. If no argument is passed
   * the Element is aligned both vertically and horizontally.
   *
   * @param  {String} align       passing 'vertical', 'horizontal' aligns element accordingly
   * @return {Object/p5.Element} pointer to p5.Element
   * @example
   * <div><code>
   * function setup() {
   *   var div = createDiv('').size(10,10);
   *   div.style('background-color','orange');
   *   div.center();
   *
   * }
   * </code></div>
   */
  p5.Element.prototype.center = function(align) {
    var style = this.elt.style.display;
    var hidden = this.elt.style.display === 'none';
    var parentHidden = this.parent().style.display === 'none';
    var pos = { x : this.elt.offsetLeft, y : this.elt.offsetTop };

    if (hidden) this.show();

    this.elt.style.display = 'block';
    this.position(0,0);

    if (parentHidden) this.parent().style.display = 'block';

    var wOffset = Math.abs(this.parent().offsetWidth - this.elt.offsetWidth);
    var hOffset = Math.abs(this.parent().offsetHeight - this.elt.offsetHeight);
    var y = pos.y;
    var x = pos.x;

    if (align === 'both' || align === undefined){
      this.position(wOffset/2, hOffset/2);
    }else if (align === 'horizontal'){
      this.position(wOffset/2, y);
    }else if (align === 'vertical'){
      this.position(x, hOffset/2);
    }

    this.style('display', style);

    if (hidden) this.hide();

    if (parentHidden) this.parent().style.display = 'none';

    return this;
  };

  /**
   *
   * If an argument is given, sets the inner HTML of the element,
   * replacing any existing html. If no arguments are given, returns
   * the inner HTML of the element.
   *
   * @for p5.Element
   * @method html
   * @param  {String} [html] the HTML to be placed inside the element
   * @return {Object/p5.Element|String}
   * @example
   * <div class='norender'><code>
   * var div = createDiv('').size(100,100);
   * div.style('background-color','orange');
   * div.html('hi');
   * </code></div>
   */
  p5.Element.prototype.html = function(html) {
    if (typeof html !== 'undefined') {
      this.elt.innerHTML = html;
      return this;
    } else {
      return this.elt.innerHTML;
    }
  };

  /**
   *
   * Sets the position of the element relative to (0, 0) of the
   * window. Essentially, sets position:absolute and left and top
   * properties of style. If no arguments given returns the x and y position
   * of the element in an object.
   *
   * @method position
   * @param  {Number} [x] x-position relative to upper left of window
   * @param  {Number} [y] y-position relative to upper left of window
   * @return {Object/p5.Element}
   * @example
   * <div><code class='norender'>
   * function setup() {
   *   var cnv = createCanvas(100, 100);
   *   // positions canvas 50px to the right and 100px
   *   // below upper left corner of the window
   *   cnv.position(50, 100);
   * }
   * </code></div>
   */
  p5.Element.prototype.position = function() {
    if (arguments.length === 0){
      return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
    }else{
      this.elt.style.position = 'absolute';
      this.elt.style.left = arguments[0]+'px';
      this.elt.style.top = arguments[1]+'px';
      this.x = arguments[0];
      this.y = arguments[1];
      return this;
    }
  };

  /**
   * Translates an element with css transforms in either 2d (if 2 arguments given)
   * or 3d (if 3 arguments given) space.
   * @method  translate
   * @param  {Number} x x-position in px
   * @param  {Number} y y-position in px
   * @param  {Number} [z] z-position in px
   * @param  {Number} [perspective] sets the perspective of the parent element in px,
   * default value set to 1000px
   * @return {Object/p5.Element}
   * @example
   * <div ><code class='norender'>
   * function setup() {
   *   var cnv = createCanvas(100,100);
   *   //translates canvas 50px down
   *   cnv.translate(0,50);
   * }
   * </code></div>
   */
  p5.Element.prototype.translate = function(){
    this.elt.style.position = 'absolute';
    if (arguments.length === 2){
      var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
      style = style.replace(/translate[X-Z]?\(.*\)/g, '');
      this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
      this.elt.style.transform += style;
    }else if (arguments.length === 3){
      var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
      style = style.replace(/translate[X-Z]?\(.*\)/g, '');
      this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
      this.elt.style.transform += style;
      this.elt.parentElement.style.perspective = '1000px';
    }else if (arguments.length === 4){
      var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
      style = style.replace(/translate[X-Z]?\(.*\)/g, '');
      this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
      this.elt.style.transform += style;
      this.elt.parentElement.style.perspective = arguments[3]+'px';
    }
      return this;
  };

  /**
   * Rotates an element with css transforms in either 2d (if 2 arguments given)
   * or 3d (if 3 arguments given) space.
   * @method  rotate
   * @param  {Number} x amount of degrees to rotate the element along the x-axis in deg
   * @param  {Number} [y] amount of degrees to rotate the element along the y-axis in deg
   * @param  {Number} [z] amount of degrees to rotate the element along the z-axis in deg
   * @return {Object/p5.Element}
   * @example
   * <div><code>
   * var x = 0,
   *     y = 0,
   *     z = 0;
   *
   * function draw(){
   *   x+=.5 % 360;
   *   y+=.5 % 360;
   *   z+=.5 % 360;
   *   //rotates p5.js logo .5 degrees on every axis each frame.
   *   select('canvas').rotate(x,y,z);
   * }
   * </code></div>
   */
  p5.Element.prototype.rotate = function(){
    if (arguments.length === 1){
      var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
      style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
      this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
      this.elt.style.transform += style;
    }else if (arguments.length === 2){
      var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
      style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
      this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
      this.elt.style.transform += style;
    }else if (arguments.length === 3){
      var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
      style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
      this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
      this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
      this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
      this.elt.style.transform += style;
    }
      return this;
  };

  /**
   * Sets the given style (css) property (1st arg) of the element with the
   * given value (2nd arg). If a single argument is given, .style()
   * returns the value of the given property; however, if the single argument
   * is given in css syntax ('text-align:center'), .style() sets the css
   * appropriatly. .style() also handles 2d and 3d css transforms. If
   * the 1st arg is 'rotate', 'translate', or 'position', the following arguments
   * accept Numbers as values. ('translate', 10, 100, 50);
   *
   * @method style
   * @param  {String} property   property to be set
   * @param  {String|Number|p5.Color} [value]   value to assign to property
   * @param  {String|Number} [value]   value to assign to property (rotate/translate)
   * @param  {String|Number} [value]   value to assign to property (rotate/translate)
   * @param  {String|Number} [value]   value to assign to property (translate)
   * @return {String|Object/p5.Element} value of property, if no value is specified
   * or p5.Element
   * @example
   * <div><code class="norender">
   * var myDiv = createDiv("I like pandas.");
   * myDiv.style("font-size", "18px");
   * myDiv.style("color", "#ff0000");
   * var col = color(25,23,200,50);
   * createButton.style("background-color", col);
   * </code></div>
   */
  p5.Element.prototype.style = function(prop, val) {
    var self = this;

    if (val instanceof p5.Color)
      val = 'rgba(' + val.levels[0] + ',' + val.levels[1] + ',' + val.levels[2] + ',' + val.levels[3]/255 + ')'

    if (typeof val === 'undefined') {
      if (prop.indexOf(':') === -1) {
        var styles = window.getComputedStyle(self.elt);
        var style = styles.getPropertyValue(prop);
        return style;
      } else {
        var attrs = prop.split(';');
        for (var i = 0; i < attrs.length; i++) {
          var parts = attrs[i].split(':');
          if (parts[0] && parts[1]) {
            this.elt.style[parts[0].trim()] = parts[1].trim();
          }
        }
      }
    } else {
      if (prop === 'rotate'){
        if (arguments.length === 2) {
          var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
          style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
          this.elt.style.transform = 'rotate(' + arguments[0] + 'deg)';
          this.elt.style.transform += style;
        } else if (arguments.length === 3) {
          var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
          style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
          this.elt.style.transform = 'rotate(' + arguments[0] + 'deg, ' + arguments[1] + 'deg)';
          this.elt.style.transform += style;
        } else if (arguments.length === 4) {
          var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
          style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
          this.elt.style.transform = 'rotateX(' + arguments[0] + 'deg)';
          this.elt.style.transform += 'rotateY(' + arguments[1] + 'deg)';
          this.elt.style.transform += 'rotateZ(' + arguments[2] + 'deg)';
          this.elt.style.transform += style;
        }
      } else if (prop === 'translate') {
        if (arguments.length === 3) {
          var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
          style = style.replace(/translate[X-Z]?\(.*\)/g, '');
          this.elt.style.transform = 'translate(' + arguments[0] + 'px, ' + arguments[1] + 'px)';
          this.elt.style.transform += style;
        } else if (arguments.length === 4) {
          var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
          style = style.replace(/translate[X-Z]?\(.*\)/g, '');
          this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
          this.elt.style.transform += style;
          this.elt.parentElement.style.perspective = '1000px';
        } else if (arguments.length === 5) {
          var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
          style = style.replace(/translate[X-Z]?\(.*\)/g, '');
          this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
          this.elt.style.transform += style;
          this.elt.parentElement.style.perspective = arguments[3] + 'px';
        }
      } else if (prop === 'position') {
        this.elt.style.left = arguments[1] + 'px';
        this.elt.style.top = arguments[2] + 'px';
        this.x = arguments[1];
        this.y = arguments[2];
      } else {
        this.elt.style[prop] = val;
        if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top') {
          var numVal = val.replace(/\D+/g, '');
          this[prop] = parseInt(numVal, 10);
        }
      }
    }
    return this;
  };


  /**
   *
   * Adds a new attribute or changes the value of an existing attribute
   * on the specified element. If no value is specified, returns the
   * value of the given attribute, or null if attribute is not set.
   *
   * @method attribute
   * @param  {String} attr       attribute to set
   * @param  {String} [value]    value to assign to attribute
   * @return {String|Object/p5.Element} value of attribute, if no value is
   *                             specified or p5.Element
   * @example
   * <div class="norender"><code>
   * var myDiv = createDiv("I like pandas.");
   *myDiv.attribute("align", "center");
   * </code></div>
   */
  p5.Element.prototype.attribute = function(attr, value) {
    if (typeof value === 'undefined') {
      return this.elt.getAttribute(attr);
    } else {
      this.elt.setAttribute(attr, value);
      return this;
    }
  };


  /**
   * Either returns the value of the element if no arguments
   * given, or sets the value of the element.
   *
   * @method value
   * @param  {String|Number}     [value]
   * @return {String|Object/p5.Element} value of element if no value is specified or p5.Element
   */
  p5.Element.prototype.value = function() {
    if (arguments.length > 0) {
      this.elt.value = arguments[0];
      return this;
    } else {
      if (this.elt.type === 'range') {
        return parseFloat(this.elt.value);
      }
      else return this.elt.value;
    }
  };

  /**
   *
   * Shows the current element. Essentially, setting display:block for the style.
   *
   * @method show
   * @return {Object/p5.Element}
   */
  p5.Element.prototype.show = function() {
    this.elt.style.display = 'block';
    return this;
  };

  /**
   * Hides the current element. Essentially, setting display:none for the style.
   *
   * @method hide
   * @return {Object/p5.Element}
   */
  p5.Element.prototype.hide = function() {
    this.elt.style.display = 'none';
    return this;
  };

  /**
   *
   * Sets the width and height of the element. AUTO can be used to
   * only adjust one dimension. If no arguments given returns the width and height
   * of the element in an object.
   *
   * @method size
   * @param  {Number} [w] width of the element
   * @param  {Number} [h] height of the element
   * @return {Object/p5.Element}
   */
  p5.Element.prototype.size = function(w, h) {
    if (arguments.length === 0){
      return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
    }else{
      var aW = w;
      var aH = h;
      var AUTO = p5.prototype.AUTO;
      if (aW !== AUTO || aH !== AUTO) {
        if (aW === AUTO) {
          aW = h * this.width / this.height;
        } else if (aH === AUTO) {
          aH = w * this.height / this.width;
        }
        // set diff for cnv vs normal div
        if (this.elt instanceof HTMLCanvasElement) {
          var j = {};
          var k  = this.elt.getContext('2d');
          for (var prop in k) {
            j[prop] = k[prop];
          }
          this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
          this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
          this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
          this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
          for (var prop in j) {
            this.elt.getContext('2d')[prop] = j[prop];
          }
        } else {
          this.elt.style.width = aW+'px';
          this.elt.style.height = aH+'px';
          this.elt.width = aW;
          this.elt.height = aH;
          this.width = aW;
          this.height = aH;
        }

        this.width = this.elt.offsetWidth;
        this.height = this.elt.offsetHeight;

        if (this._pInst) { // main canvas associated with p5 instance
          if (this._pInst._curElement.elt === this.elt) {
            this._pInst._setProperty('width', this.elt.offsetWidth);
            this._pInst._setProperty('height', this.elt.offsetHeight);
          }
        }
      }
      return this;
    }
  };

  /**
   * Removes the element and deregisters all listeners.
   * @method remove
   * @example
   * <div class='norender'><code>
   * var myDiv = createDiv('this is some text');
   * myDiv.remove();
   * </code></div>
   */
  p5.Element.prototype.remove = function() {
    // deregister events
    for (var ev in this._events) {
      this.elt.removeEventListener(ev, this._events[ev]);
    }
    if (this.elt.parentNode) {
      this.elt.parentNode.removeChild(this.elt);
    }
    delete(this);
  };



// =============================================================================
//                         p5.MediaElement additions
// =============================================================================


  /**
   * Extends p5.Element to handle audio and video. In addition to the methods
   * of p5.Element, it also contains methods for controlling media. It is not
   * called directly, but p5.MediaElements are created by calling createVideo,
   * createAudio, and createCapture.
   *
   * @class p5.MediaElement
   * @constructor
   * @param {String} elt DOM node that is wrapped
   * @param {Object} [pInst] pointer to p5 instance
   */
  p5.MediaElement = function(elt, pInst) {
    p5.Element.call(this, elt, pInst);


    this._prevTime = 0;
    this._cueIDCounter = 0;
    this._cues = [];
    this._pixelDensity = 1;

  };
  p5.MediaElement.prototype = Object.create(p5.Element.prototype);




  /**
   * Play an HTML5 media element.
   *
   * @method play
   * @return {Object/p5.Element}
   */
  p5.MediaElement.prototype.play = function() {
    if (this.elt.currentTime === this.elt.duration) {
      this.elt.currentTime = 0;
    }

    if (this.elt.readyState > 1) {
      this.elt.play();
    } else {
      // in Chrome, playback cannot resume after being stopped and must reload
      this.elt.load();
      this.elt.play();
    }
    return this;
  };

  /**
   * Stops an HTML5 media element (sets current time to zero).
   *
   * @method stop
   * @return {Object/p5.Element}
   */
  p5.MediaElement.prototype.stop = function() {
    this.elt.pause();
    this.elt.currentTime = 0;
    return this;
  };

  /**
   * Pauses an HTML5 media element.
   *
   * @method pause
   * @return {Object/p5.Element}
   */
  p5.MediaElement.prototype.pause = function() {
    this.elt.pause();
    return this;
  };

  /**
   * Set 'loop' to true for an HTML5 media element, and starts playing.
   *
   * @method loop
   * @return {Object/p5.Element}
   */
  p5.MediaElement.prototype.loop = function() {
    this.elt.setAttribute('loop', true);
    this.play();
    return this;
  };
  /**
   * Set 'loop' to false for an HTML5 media element. Element will stop
   * when it reaches the end.
   *
   * @method noLoop
   * @return {Object/p5.Element}
   */
  p5.MediaElement.prototype.noLoop = function() {
    this.elt.setAttribute('loop', false);
    return this;
  };


  /**
   * Set HTML5 media element to autoplay or not.
   *
   * @method autoplay
   * @param {Boolean} autoplay whether the element should autoplay
   * @return {Object/p5.Element}
   */
  p5.MediaElement.prototype.autoplay = function(val) {
    this.elt.setAttribute('autoplay', val);
    return this;
  };

  /**
   * Sets volume for this HTML5 media element. If no argument is given,
   * returns the current volume.
   *
   * @param {Number}            [val] volume between 0.0 and 1.0
   * @return {Number|p5.MediaElement} current volume or p5.MediaElement
   * @method volume
   */
  p5.MediaElement.prototype.volume = function(val) {
    if (typeof val === 'undefined') {
      return this.elt.volume;
    } else {
      this.elt.volume = val;
    }
  };

  /**
   * If no arguments are given, returns the current time of the element.
   * If an argument is given the current time of the element is set to it.
   *
   * @method time
   * @param {Number} [time] time to jump to (in seconds)
   * @return {Number|Object/p5.MediaElement} current time (in seconds)
   *                                  or p5.MediaElement
   */
  p5.MediaElement.prototype.time = function(val) {
    if (typeof val === 'undefined') {
      return this.elt.currentTime;
    } else {
      this.elt.currentTime = val;
    }
  };

  /**
   * Returns the duration of the HTML5 media element.
   *
   * @method duration
   * @return {Number} duration
   */
  p5.MediaElement.prototype.duration = function() {
    return this.elt.duration;
  };
  p5.MediaElement.prototype.pixels = [];
  p5.MediaElement.prototype.loadPixels = function() {
    if (this.loadedmetadata) { // wait for metadata for w/h
      if (!this.canvas) {
        this.canvas = document.createElement('canvas');
        this.drawingContext = this.canvas.getContext('2d');
      }
      if (this.canvas.width !== this.elt.width) {
        this.canvas.width = this.elt.width;
        this.canvas.height = this.elt.height;
        this.width = this.canvas.width;
        this.height = this.canvas.height;
      }
      this.drawingContext.drawImage(this.elt, 0, 0, this.canvas.width, this.canvas.height);
      p5.Renderer2D.prototype.loadPixels.call(this);
    }
    return this;
  }
  p5.MediaElement.prototype.updatePixels =  function(x, y, w, h){
    if (this.loadedmetadata) { // wait for metadata
      p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
    }
    return this;
  }
  p5.MediaElement.prototype.get = function(x, y, w, h){
    if (this.loadedmetadata) { // wait for metadata
      return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
    } else return [0, 0, 0, 255];
  };
  p5.MediaElement.prototype.set = function(x, y, imgOrCol){
    if (this.loadedmetadata) { // wait for metadata
      p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
    }
  };

  /*** CONNECT TO WEB AUDIO API / p5.sound.js ***/

  /**
   *  Send the audio output of this element to a specified audioNode or
   *  p5.sound object. If no element is provided, connects to p5's master
   *  output. That connection is established when this method is first called.
   *  All connections are removed by the .disconnect() method.
   *
   *  This method is meant to be used with the p5.sound.js addon library.
   *
   *  @method  connect
   *  @param  {AudioNode|p5.sound object} audioNode AudioNode from the Web Audio API,
   *  or an object from the p5.sound library
   */
  p5.MediaElement.prototype.connect = function(obj) {
    var audioContext, masterOutput;

    // if p5.sound exists, same audio context
    if (typeof p5.prototype.getAudioContext === 'function') {
      audioContext = p5.prototype.getAudioContext();
      masterOutput = p5.soundOut.input;
    } else {
      try {
        audioContext = obj.context;
        masterOutput = audioContext.destination
      } catch(e) {
        throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
      }
    }

    // create a Web Audio MediaElementAudioSourceNode if none already exists
    if (!this.audioSourceNode) {
      this.audioSourceNode = audioContext.createMediaElementSource(this.elt);

      // connect to master output when this method is first called
      this.audioSourceNode.connect(masterOutput);
    }

    // connect to object if provided
    if (obj) {
      if (obj.input) {
        this.audioSourceNode.connect(obj.input);
      } else {
        this.audioSourceNode.connect(obj);
      }
    }

    // otherwise connect to master output of p5.sound / AudioContext
    else {
      this.audioSourceNode.connect(masterOutput);
    }

  };

  /**
   *  Disconnect all Web Audio routing, including to master output.
   *  This is useful if you want to re-route the output through
   *  audio effects, for example.
   *
   *  @method  disconnect
   */
  p5.MediaElement.prototype.disconnect = function() {
    if (this.audioSourceNode) {
      this.audioSourceNode.disconnect();
    } else {
      throw 'nothing to disconnect';
    }
  };


  /*** SHOW / HIDE CONTROLS ***/

  /**
   *  Show the default MediaElement controls, as determined by the web browser.
   *
   *  @method  showControls
   */
  p5.MediaElement.prototype.showControls = function() {
    // must set style for the element to show on the page
    this.elt.style['text-align'] = 'inherit';
    this.elt.controls = true;
  };

  /**
   *  Hide the default mediaElement controls.
   *
   *  @method hideControls
   */
  p5.MediaElement.prototype.hideControls = function() {
    this.elt.controls = false;
  };


  /*** SCHEDULE EVENTS ***/

  /**
   *  Schedule events to trigger every time a MediaElement
   *  (audio/video) reaches a playback cue point.
   *
   *  Accepts a callback function, a time (in seconds) at which to trigger
   *  the callback, and an optional parameter for the callback.
   *
   *  Time will be passed as the first parameter to the callback function,
   *  and param will be the second parameter.
   *
   *
   *  @method  addCue
   *  @param {Number}   time     Time in seconds, relative to this media
   *                             element's playback. For example, to trigger
   *                             an event every time playback reaches two
   *                             seconds, pass in the number 2. This will be
   *                             passed as the first parameter to
   *                             the callback function.
   *  @param {Function} callback Name of a function that will be
   *                             called at the given time. The callback will
   *                             receive time and (optionally) param as its
   *                             two parameters.
   *  @param {Object} [value]    An object to be passed as the
   *                             second parameter to the
   *                             callback function.
   *  @return {Number} id ID of this cue,
   *                      useful for removeCue(id)
   *  @example
   *  <div><code>
   *  function setup() {
   *    background(255,255,255);
   *
   *    audioEl = createAudio('assets/beat.mp3');
   *    audioEl.showControls();
   *
   *    // schedule three calls to changeBackground
   *    audioEl.addCue(0.5, changeBackground, color(255,0,0) );
   *    audioEl.addCue(1.0, changeBackground, color(0,255,0) );
   *    audioEl.addCue(2.5, changeBackground, color(0,0,255) );
   *    audioEl.addCue(3.0, changeBackground, color(0,255,255) );
   *    audioEl.addCue(4.2, changeBackground, color(255,255,0) );
   *    audioEl.addCue(5.0, changeBackground, color(255,255,0) );
   *  }
   *
   *  function changeBackground(val) {
   *    background(val);
   *  }
   *  </code></div>
   */
  p5.MediaElement.prototype.addCue = function(time, callback, val) {
    var id = this._cueIDCounter++;

    var cue = new Cue(callback, time, id, val);
    this._cues.push(cue);

    if (!this.elt.ontimeupdate) {
      this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
    }

    return id;
  };

  /**
   *  Remove a callback based on its ID. The ID is returned by the
   *  addCue method.
   *
   *  @method removeCue
   *  @param  {Number} id ID of the cue, as returned by addCue
   */
  p5.MediaElement.prototype.removeCue = function(id) {
    for (var i = 0; i < this._cues.length; i++) {
      var cue = this._cues[i];
      if (cue.id === id) {
        this.cues.splice(i, 1);
      }
    }

    if (this._cues.length === 0) {
      this.elt.ontimeupdate = null
    }
  };

  /**
   *  Remove all of the callbacks that had originally been scheduled
   *  via the addCue method.
   *
   *  @method  clearCues
   */
  p5.MediaElement.prototype.clearCues = function() {
    this._cues = [];
    this.elt.ontimeupdate = null;
  };

  // private method that checks for cues to be fired if events
  // have been scheduled using addCue(callback, time).
  p5.MediaElement.prototype._onTimeUpdate = function() {
    var playbackTime = this.time();

    for (var i = 0 ; i < this._cues.length; i++) {
      var callbackTime = this._cues[i].time;
      var val = this._cues[i].val;


      if (this._prevTime < callbackTime && callbackTime <= playbackTime) {

        // pass the scheduled callbackTime as parameter to the callback
        this._cues[i].callback(val);
      }

    }

    this._prevTime = playbackTime;
  };


  // Cue inspired by JavaScript setTimeout, and the
  // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
  var Cue = function(callback, time, id, val) {
    this.callback = callback;
    this.time = time;
    this.id = id;
    this.val = val;
  };

// =============================================================================
//                         p5.File
// =============================================================================


  /**
   * Base class for a file
   * Using this for createFileInput
   *
   * @class p5.File
   * @constructor
   * @param {File} file File that is wrapped
   * @param {Object} [pInst] pointer to p5 instance
   */
  p5.File = function(file, pInst) {
    /**
     * Underlying File object. All normal File methods can be called on this.
     *
     * @property file
     */
    this.file = file;

    this._pInst = pInst;

    // Splitting out the file type into two components
    // This makes determining if image or text etc simpler
    var typeList = file.type.split('/');
    /**
     * File type (image, text, etc.)
     *
     * @property type
     */
    this.type = typeList[0];
    /**
     * File subtype (usually the file extension jpg, png, xml, etc.)
     *
     * @property subtype
     */
    this.subtype = typeList[1];
    /**
     * File name
     *
     * @property name
     */
    this.name = file.name;
    /**
     * File size
     *
     * @property size
     */
    this.size = file.size;

    // Data not loaded yet
    this.data = undefined;
  };

}));


================================================
FILE: p5-ableton/libraries/p5.js
================================================
/*! p5.js v0.4.19 November 11, 2015 */
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.p5 = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){

},{}],2:[function(_dereq_,module,exports){
// Run-time checking of preconditions.

'use strict';

// Precondition function that checks if the given predicate is true.
// If not, it will throw an error.
exports.argument = function(predicate, message) {
    if (!predicate) {
        throw new Error(message);
    }
};

// Precondition function that checks if the given assertion is true.
// If not, it will throw an error.
exports.assert = exports.argument;

},{}],3:[function(_dereq_,module,exports){
// Drawing utility functions.

'use strict';

// Draw a line on the given context from point `x1,y1` to point `x2,y2`.
function line(ctx, x1, y1, x2, y2) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
}

exports.line = line;

},{}],4:[function(_dereq_,module,exports){
// Glyph encoding

'use strict';

var cffStandardStrings = [
    '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright',
    'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two',
    'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater',
    'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
    'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
    'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
    'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling',
    'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft',
    'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph',
    'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand',
    'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring',
    'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE',
    'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
    'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn',
    'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
    'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex',
    'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
    'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute',
    'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute',
    'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute',
    'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave',
    'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior',
    'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff', 'onedotenleader',
    'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle',
    'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior',
    'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
    'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl',
    'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall',
    'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall',
    'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
    'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall',
    'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall',
    'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall',
    'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds',
    'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
    'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior',
    'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior',
    'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall',
    'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall',
    'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall',
    'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall',
    'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000',
    '001.001', '001.002', '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'];

var cffStandardEncoding = [
    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright',
    'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two',
    'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater',
    'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
    'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
    'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
    'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle',
    'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger',
    'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright',
    'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde',
    'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron',
    'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '',
    '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '',
    'lslash', 'oslash', 'oe', 'germandbls'];

var cffExpertEncoding = [
    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior',
    'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader',
    'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
    'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',
    'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior',
    'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',
    'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl',
    'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall',
    'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall',
    'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
    'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
    'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior',
    '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',
    'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '',
    '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
    'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',
    'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior',
    'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
    'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall',
    'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
    'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall',
    'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
    'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'];

var standardNames = [
    '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
    'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash',
    'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
    'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
    'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
    'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
    'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave',
    'acircumflex', 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
    'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis',
    'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section',
    'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', 'dieresis', 'notequal',
    'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation',
    'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', 'questiondown',
    'exclamdown', 'logicalnot', 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', 'guillemotright',
    'ellipsis', 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft',
    'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
    'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase',
    'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute',
    'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex',
    'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut',
    'ogonek', 'caron', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', 'Eth', 'eth',
    'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', 'onesuperior', 'twosuperior', 'threesuperior',
    'onehalf', 'onequarter', 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', 'scedilla',
    'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];

// This is the encoding used for fonts created from scratch.
// It loops through all glyphs and finds the appropriate unicode value.
// Since it's linear time, other encodings will be faster.
function DefaultEncoding(font) {
    this.font = font;
}

DefaultEncoding.prototype.charToGlyphIndex = function(c) {
    var code = c.charCodeAt(0);
    var glyphs = this.font.glyphs;
    if (glyphs) {
        for (var i = 0; i < glyphs.length; i += 1) {
            var glyph = glyphs.get(i);
            for (var j = 0; j < glyph.unicodes.length; j += 1) {
                if (glyph.unicodes[j] === code) {
                    return i;
                }
            }
        }
    } else {
        return null;
    }
};

function CmapEncoding(cmap) {
    this.cmap = cmap;
}

CmapEncoding.prototype.charToGlyphIndex = function(c) {
    return this.cmap.glyphIndexMap[c.charCodeAt(0)] || 0;
};

function CffEncoding(encoding, charset) {
    this.encoding = encoding;
    this.charset = charset;
}

CffEncoding.prototype.charToGlyphIndex = function(s) {
    var code = s.charCodeAt(0);
    var charName = this.encoding[code];
    return this.charset.indexOf(charName);
};

function GlyphNames(post) {
    var i;
    switch (post.version) {
    case 1:
        this.names = exports.standardNames.slice();
        break;
    case 2:
        this.names = new Array(post.numberOfGlyphs);
        for (i = 0; i < post.numberOfGlyphs; i++) {
            if (post.glyphNameIndex[i] < exports.standardNames.length) {
                this.names[i] = exports.standardNames[post.glyphNameIndex[i]];
            } else {
                this.names[i] = post.names[post.glyphNameIndex[i] - exports.standardNames.length];
            }
        }

        break;
    case 2.5:
        this.names = new Array(post.numberOfGlyphs);
        for (i = 0; i < post.numberOfGlyphs; i++) {
            this.names[i] = exports.standardNames[i + post.glyphNameIndex[i]];
        }

        break;
    case 3:
        this.names = [];
        break;
    }
}

GlyphNames.prototype.nameToGlyphIndex = function(name) {
    return this.names.indexOf(name);
};

GlyphNames.prototype.glyphIndexToName = function(gid) {
    return this.names[gid];
};

function addGlyphNames(font) {
    var glyph;
    var glyphIndexMap = font.tables.cmap.glyphIndexMap;
    var charCodes = Object.keys(glyphIndexMap);

    for (var i = 0; i < charCodes.length; i += 1) {
        var c = charCodes[i];
        var glyphIndex = glyphIndexMap[c];
        glyph = font.glyphs.get(glyphIndex);
        glyph.addUnicode(parseInt(c));
    }

    for (i = 0; i < font.glyphs.length; i += 1) {
        glyph = font.glyphs.get(i);
        if (font.cffEncoding) {
            glyph.name = font.cffEncoding.charset[i];
        } else {
            glyph.name = font.glyphNames.glyphIndexToName(i);
        }
    }
}

exports.cffStandardStrings = cffStandardStrings;
exports.cffStandardEncoding = cffStandardEncoding;
exports.cffExpertEncoding = cffExpertEncoding;
exports.standardNames = standardNames;
exports.DefaultEncoding = DefaultEncoding;
exports.CmapEncoding = CmapEncoding;
exports.CffEncoding = CffEncoding;
exports.GlyphNames = GlyphNames;
exports.addGlyphNames = addGlyphNames;

},{}],5:[function(_dereq_,module,exports){
// The Font object

'use strict';

var path = _dereq_('./path');
var sfnt = _dereq_('./tables/sfnt');
var encoding = _dereq_('./encoding');
var glyphset = _dereq_('./glyphset');

// A Font represents a loaded OpenType font file.
// It contains a set of glyphs and methods to draw text on a drawing context,
// or to get a path representing the text.
function Font(options) {
    options = options || {};

    // OS X will complain if the names are empty, so we put a single space everywhere by default.
    this.familyName = options.familyName || ' ';
    this.styleName = options.styleName || ' ';
    this.designer = options.designer || ' ';
    this.designerURL = options.designerURL || ' ';
    this.manufacturer = options.manufacturer || ' ';
    this.manufacturerURL = options.manufacturerURL || ' ';
    this.license = options.license || ' ';
    this.licenseURL = options.licenseURL || ' ';
    this.version = options.version || 'Version 0.1';
    this.description = options.description || ' ';
    this.copyright = options.copyright || ' ';
    this.trademark = options.trademark || ' ';
    this.unitsPerEm = options.unitsPerEm || 1000;
    this.ascender = options.ascender;
    this.descender = options.descender;
    this.supported = true;
    this.glyphs = new glyphset.GlyphSet(this, options.glyphs || []);
    this.encoding = new encoding.DefaultEncoding(this);
    this.tables = {};
}

// Check if the font has a glyph for the given character.
Font.prototype.hasChar = function(c) {
    return this.encoding.charToGlyphIndex(c) !== null;
};

// Convert the given character to a single glyph index.
// Note that this function assumes that there is a one-to-one mapping between
// the given character and a glyph; for complex scripts this might not be the case.
Font.prototype.charToGlyphIndex = function(s) {
    return this.encoding.charToGlyphIndex(s);
};

// Convert the given character to a single Glyph object.
// Note that this function assumes that there is a one-to-one mapping between
// the given character and a glyph; for complex scripts this might not be the case.
Font.prototype.charToGlyph = function(c) {
    var glyphIndex = this.charToGlyphIndex(c);
    var glyph = this.glyphs.get(glyphIndex);
    if (!glyph) {
        // .notdef
        glyph = this.glyphs.get(0);
    }

    return glyph;
};

// Convert the given text to a list of Glyph objects.
// Note that there is no strict one-to-one mapping between characters and
// glyphs, so the list of returned glyphs can be larger or smaller than the
// length of the given string.
Font.prototype.stringToGlyphs = function(s) {
    var glyphs = [];
    for (var i = 0; i < s.length; i += 1) {
        var c = s[i];
        glyphs.push(this.charToGlyph(c));
    }

    return glyphs;
};

Font.prototype.nameToGlyphIndex = function(name) {
    return this.glyphNames.nameToGlyphIndex(name);
};

Font.prototype.nameToGlyph = function(name) {
    var glyphIndex = this.nametoGlyphIndex(name);
    var glyph = this.glyphs.get(glyphIndex);
    if (!glyph) {
        // .notdef
        glyph = this.glyphs.get(0);
    }

    return glyph;
};

Font.prototype.glyphIndexToName = function(gid) {
    if (!this.glyphNames.glyphIndexToName) {
        return '';
    }

    return this.glyphNames.glyphIndexToName(gid);
};

// Retrieve the value of the kerning pair between the left glyph (or its index)
// and the right glyph (or its index). If no kerning pair is found, return 0.
// The kerning value gets added to the advance width when calculating the spacing
// between glyphs.
Font.prototype.getKerningValue = function(leftGlyph, rightGlyph) {
    leftGlyph = leftGlyph.index || leftGlyph;
    rightGlyph = rightGlyph.index || rightGlyph;
    var gposKerning = this.getGposKerningValue;
    return gposKerning ? gposKerning(leftGlyph, rightGlyph) :
        (this.kerningPairs[leftGlyph + ',' + rightGlyph] || 0);
};

// Helper function that invokes the given callback for each glyph in the given text.
// The callback gets `(glyph, x, y, fontSize, options)`.
Font.prototype.forEachGlyph = function(text, x, y, fontSize, options, callback) {
    if (!this.supported) {
        return;
    }

    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 72;
    options = options || {};
    var kerning = options.kerning === undefined ? true : options.kerning;
    var fontScale = 1 / this.unitsPerEm * fontSize;
    var glyphs = this.stringToGlyphs(text);
    for (var i = 0; i < glyphs.length; i += 1) {
        var glyph = glyphs[i];
        callback(glyph, x, y, fontSize, options);
        if (glyph.advanceWidth) {
            x += glyph.advanceWidth * fontScale;
        }

        if (kerning && i < glyphs.length - 1) {
            var kerningValue = this.getKerningValue(glyph, glyphs[i + 1]);
            x += kerningValue * fontScale;
        }
    }
};

// Create a Path object that represents the given text.
//
// text - The text to create.
// x - Horizontal position of the beginning of the text. (default: 0)
// y - Vertical position of the *baseline* of the text. (default: 0)
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72)
// Options is an optional object that contains:
// - kerning - Whether to take kerning information into account. (default: true)
//
// Returns a Path object.
Font.prototype.getPath = function(text, x, y, fontSize, options) {
    var fullPath = new path.Path();
    this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) {
        var glyphPath = glyph.getPath(gX, gY, gFontSize);
        fullPath.extend(glyphPath);
    });

    return fullPath;
};

// Draw the text on the given drawing context.
//
// ctx - A 2D drawing context, like Canvas.
// text - The text to create.
// x - Horizontal position of the beginning of the text. (default: 0)
// y - Vertical position of the *baseline* of the text. (default: 0)
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72)
// Options is an optional object that contains:
// - kerning - Whether to take kerning information into account. (default: true)
Font.prototype.draw = function(ctx, text, x, y, fontSize, options) {
    this.getPath(text, x, y, fontSize, options).draw(ctx);
};

// Draw the points of all glyphs in the text.
// On-curve points will be drawn in blue, off-curve points will be drawn in red.
//
// ctx - A 2D drawing context, like Canvas.
// text - The text to create.
// x - Horizontal position of the beginning of the text. (default: 0)
// y - Vertical position of the *baseline* of the text. (default: 0)
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72)
// Options is an optional object that contains:
// - kerning - Whether to take kerning information into account. (default: true)
Font.prototype.drawPoints = function(ctx, text, x, y, fontSize, options) {
    this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) {
        glyph.drawPoints(ctx, gX, gY, gFontSize);
    });
};

// Draw lines indicating important font measurements for all glyphs in the text.
// Black lines indicate the origin of the coordinate system (point 0,0).
// Blue lines indicate the glyph bounding box.
// Green line indicates the advance width of the glyph.
//
// ctx - A 2D drawing context, like Canvas.
// text - The text to create.
// x - Horizontal position of the beginning of the text. (default: 0)
// y - Vertical position of the *baseline* of the text. (default: 0)
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72)
// Options is an optional object that contains:
// - kerning - Whether to take kerning information into account. (default: true)
Font.prototype.drawMetrics = function(ctx, text, x, y, fontSize, options) {
    this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) {
        glyph.drawMetrics(ctx, gX, gY, gFontSize);
    });
};

// Validate
Font.prototype.validate = function() {
    var warnings = [];
    var _this = this;

    function assert(predicate, message) {
        if (!predicate) {
            warnings.push(message);
        }
    }

    function assertStringAttribute(attrName) {
        assert(_this[attrName] && _this[attrName].trim().length > 0, 'No ' + attrName + ' specified.');
    }

    // Identification information
    assertStringAttribute('familyName');
    assertStringAttribute('weightName');
    assertStringAttribute('manufacturer');
    assertStringAttribute('copyright');
    assertStringAttribute('version');

    // Dimension information
    assert(this.unitsPerEm > 0, 'No unitsPerEm specified.');
};

// Convert the font object to a SFNT data structure.
// This structure contains all the necessary tables and metadata to create a binary OTF file.
Font.prototype.toTables = function() {
    return sfnt.fontToTable(this);
};

Font.prototype.toBuffer = function() {
    var sfntTable = this.toTables();
    var bytes = sfntTable.encode();
    var buffer = new ArrayBuffer(bytes.length);
    var intArray = new Uint8Array(buffer);
    for (var i = 0; i < bytes.length; i++) {
        intArray[i] = bytes[i];
    }

    return buffer;
};

// Initiate a download of the OpenType font.
Font.prototype.download = function() {
    var fileName = this.familyName.replace(/\s/g, '') + '-' + this.styleName + '.otf';
    var buffer = this.toBuffer();

    window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
    window.requestFileSystem(window.TEMPORARY, buffer.byteLength, function(fs) {
        fs.root.getFile(fileName, {create: true}, function(fileEntry) {
            fileEntry.createWriter(function(writer) {
                var dataView = new DataView(buffer);
                var blob = new Blob([dataView], {type: 'font/opentype'});
                writer.write(blob);

                writer.addEventListener('writeend', function() {
                    // Navigating to the file will download it.
                    location.href = fileEntry.toURL();
                }, false);
            });
        });
    },

    function(err) {
        throw err;
    });
};

exports.Font = Font;

},{"./encoding":4,"./glyphset":7,"./path":10,"./tables/sfnt":25}],6:[function(_dereq_,module,exports){
// The Glyph object

'use strict';

var check = _dereq_('./check');
var draw = _dereq_('./draw');
var path = _dereq_('./path');

function getPathDefinition(glyph, path) {
    var _path = path || { commands: [] };
    return {
        configurable: true,

        get: function() {
            if (typeof _path === 'function') {
                _path = _path();
            }

            return _path;
        },

        set: function(p) {
            _path = p;
        }
    };
}

// A Glyph is an individual mark that often corresponds to a character.
// Some glyphs, such as ligatures, are a combination of many characters.
// Glyphs are the basic building blocks of a font.
//
// The `Glyph` class contains utility methods for drawing the path and its points.
function Glyph(options) {
    // By putting all the code on a prototype function (which is only declared once)
    // we reduce the memory requirements for larger fonts by some 2%
    this.bindConstructorValues(options);
}

Glyph.prototype.bindConstructorValues = function(options) {
    this.index = options.index || 0;

    // These three values cannnot be deferred for memory optimization:
    this.name = options.name || null;
    this.unicode = options.unicode || undefined;
    this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : [];

    // But by binding these values only when necessary, we reduce can
    // the memory requirements by almost 3% for larger fonts.
    if (options.xMin) {
        this.xMin = options.xMin;
    }

    if (options.yMin) {
        this.yMin = options.yMin;
    }

    if (options.xMax) {
        this.xMax = options.xMax;
    }

    if (options.yMax) {
        this.yMax = options.yMax;
    }

    if (options.advanceWidth) {
        this.advanceWidth = options.advanceWidth;
    }

    // The path for a glyph is the most memory intensive, and is bound as a value
    // with a getter/setter to ensure we actually do path parsing only once the
    // path is actually needed by anything.
    Object.defineProperty(this, 'path', getPathDefinition(this, options.path));
};

Glyph.prototype.addUnicode = function(unicode) {
    if (this.unicodes.length === 0) {
        this.unicode = unicode;
    }

    this.unicodes.push(unicode);
};

// Convert the glyph to a Path we can draw on a drawing context.
//
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.getPath = function(x, y, fontSize) {
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 72;
    var scale = 1 / this.path.unitsPerEm * fontSize;
    var p = new path.Path();
    var commands = this.path.commands;
    for (var i = 0; i < commands.length; i += 1) {
        var cmd = commands[i];
        if (cmd.type === 'M') {
            p.moveTo(x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'L') {
            p.lineTo(x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'Q') {
            p.quadraticCurveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale),
                               x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'C') {
            p.curveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale),
                      x + (cmd.x2 * scale), y + (-cmd.y2 * scale),
                      x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'Z') {
            p.closePath();
        }
    }

    return p;
};

// Split the glyph into contours.
// This function is here for backwards compatibility, and to
// provide raw access to the TrueType glyph outlines.
Glyph.prototype.getContours = function() {
    if (this.points === undefined) {
        return [];
    }

    var contours = [];
    var currentContour = [];
    for (var i = 0; i < this.points.length; i += 1) {
        var pt = this.points[i];
        currentContour.push(pt);
        if (pt.lastPointOfContour) {
            contours.push(currentContour);
            currentContour = [];
        }
    }

    check.argument(currentContour.length === 0, 'There are still points left in the current contour.');
    return contours;
};

// Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph.
Glyph.prototype.getMetrics = function() {
    var commands = this.path.commands;
    var xCoords = [];
    var yCoords = [];
    for (var i = 0; i < commands.length; i += 1) {
        var cmd = commands[i];
        if (cmd.type !== 'Z') {
            xCoords.push(cmd.x);
            yCoords.push(cmd.y);
        }

        if (cmd.type === 'Q' || cmd.type === 'C') {
            xCoords.push(cmd.x1);
            yCoords.push(cmd.y1);
        }

        if (cmd.type === 'C') {
            xCoords.push(cmd.x2);
            yCoords.push(cmd.y2);
        }
    }

    var metrics = {
        xMin: Math.min.apply(null, xCoords),
        yMin: Math.min.apply(null, yCoords),
        xMax: Math.max.apply(null, xCoords),
        yMax: Math.max.apply(null, yCoords),
        leftSideBearing: 0
    };
    metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin);
    return metrics;
};

// Draw the glyph on the given context.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.draw = function(ctx, x, y, fontSize) {
    this.getPath(x, y, fontSize).draw(ctx);
};

// Draw the points of the glyph.
// On-curve points will be drawn in blue, off-curve points will be drawn in red.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.drawPoints = function(ctx, x, y, fontSize) {

    function drawCircles(l, x, y, scale) {
        var PI_SQ = Math.PI * 2;
        ctx.beginPath();
        for (var j = 0; j < l.length; j += 1) {
            ctx.moveTo(x + (l[j].x * scale), y + (l[j].y * scale));
            ctx.arc(x + (l[j].x * scale), y + (l[j].y * scale), 2, 0, PI_SQ, false);
        }

        ctx.closePath();
        ctx.fill();
    }

    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    var scale = 1 / this.path.unitsPerEm * fontSize;

    var blueCircles = [];
    var redCircles = [];
    var path = this.path;
    for (var i = 0; i < path.commands.length; i += 1) {
        var cmd = path.commands[i];
        if (cmd.x !== undefined) {
            blueCircles.push({x: cmd.x, y: -cmd.y});
        }

        if (cmd.x1 !== undefined) {
            redCircles.push({x: cmd.x1, y: -cmd.y1});
        }

        if (cmd.x2 !== undefined) {
            redCircles.push({x: cmd.x2, y: -cmd.y2});
        }
    }

    ctx.fillStyle = 'blue';
    drawCircles(blueCircles, x, y, scale);
    ctx.fillStyle = 'red';
    drawCircles(redCircles, x, y, scale);
};

// Draw lines indicating important font measurements.
// Black lines indicate the origin of the coordinate system (point 0,0).
// Blue lines indicate the glyph bounding box.
// Green line indicates the advance width of the glyph.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) {
    var scale;
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    scale = 1 / this.path.unitsPerEm * fontSize;
    ctx.lineWidth = 1;

    // Draw the origin
    ctx.strokeStyle = 'black';
    draw.line(ctx, x, -10000, x, 10000);
    draw.line(ctx, -10000, y, 10000, y);

    // This code is here due to memory optimization: by not using
    // defaults in the constructor, we save a notable amount of memory.
    var xMin = this.xMin || 0;
    var yMin = this.yMin || 0;
    var xMax = this.xMax || 0;
    var yMax = this.yMax || 0;
    var advanceWidth = this.advanceWidth || 0;

    // Draw the glyph box
    ctx.strokeStyle = 'blue';
    draw.line(ctx, x + (xMin * scale), -10000, x + (xMin * scale), 10000);
    draw.line(ctx, x + (xMax * scale), -10000, x + (xMax * scale), 10000);
    draw.line(ctx, -10000, y + (-yMin * scale), 10000, y + (-yMin * scale));
    draw.line(ctx, -10000, y + (-yMax * scale), 10000, y + (-yMax * scale));

    // Draw the advance width
    ctx.strokeStyle = 'green';
    draw.line(ctx, x + (advanceWidth * scale), -10000, x + (advanceWidth * scale), 10000);
};

exports.Glyph = Glyph;

},{"./check":2,"./draw":3,"./path":10}],7:[function(_dereq_,module,exports){
// The GlyphSet object

'use strict';

var _glyph = _dereq_('./glyph');

// A GlyphSet represents all glyphs available in the font, but modelled using
// a deferred glyph loader, for retrieving glyphs only once they are absolutely
// necessary, to keep the memory footprint down.
function GlyphSet(font, glyphs) {
    this.font = font;
    this.glyphs = {};
    if (Array.isArray(glyphs)) {
        for (var i = 0; i < glyphs.length; i++) {
            this.glyphs[i] = glyphs[i];
        }
    }

    this.length = (glyphs && glyphs.length) || 0;
}

GlyphSet.prototype.get = function(index) {
    if (typeof this.glyphs[index] === 'function') {
        this.glyphs[index] = this.glyphs[index]();
    }

    return this.glyphs[index];
};

GlyphSet.prototype.push = function(index, loader) {
    this.glyphs[index] = loader;
    this.length++;
};

function glyphLoader(font, index) {
    return new _glyph.Glyph({index: index, font: font});
}

/**
 * Generate a stub glyph that can be filled with all metadata *except*
 * the "points" and "path" properties, which must be loaded only once
 * the glyph's path is actually requested for text shaping.
 */

function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPath) {
    return function() {
        var glyph = new _glyph.Glyph({index: index, font: font});

        glyph.path = function() {
            parseGlyph(glyph, data, position);
            var path = buildPath(font.glyphs, glyph);
            path.unitsPerEm = font.unitsPerEm;
            return path;
        };

        return glyph;
    };
}

function cffGlyphLoader(font, index, parseCFFCharstring, charstring) {
    return function() {
        var glyph = new _glyph.Glyph({index: index, font: font});

        glyph.path = function() {
            var path = parseCFFCharstring(font, glyph, charstring);
            path.unitsPerEm = font.unitsPerEm;
            return path;
        };

        return glyph;
    };
}

exports.GlyphSet = GlyphSet;
exports.glyphLoader = glyphLoader;
exports.ttfGlyphLoader = ttfGlyphLoader;
exports.cffGlyphLoader = cffGlyphLoader;

},{"./glyph":6}],8:[function(_dereq_,module,exports){
// opentype.js
// https://github.com/nodebox/opentype.js
// (c) 2015 Frederik De Bleser
// opentype.js may be freely distributed under the MIT license.

/* global ArrayBuffer, DataView, Uint8Array, XMLHttpRequest  */

'use strict';

var encoding = _dereq_('./encoding');
var _font = _dereq_('./font');
var glyph = _dereq_('./glyph');
var parse = _dereq_('./parse');
var path = _dereq_('./path');

var cmap = _dereq_('./tables/cmap');
var cff = _dereq_('./tables/cff');
var glyf = _dereq_('./tables/glyf');
var gpos = _dereq_('./tables/gpos');
var head = _dereq_('./tables/head');
var hhea = _dereq_('./tables/hhea');
var hmtx = _dereq_('./tables/hmtx');
var kern = _dereq_('./tables/kern');
var loca = _dereq_('./tables/loca');
var maxp = _dereq_('./tables/maxp');
var _name = _dereq_('./tables/name');
var os2 = _dereq_('./tables/os2');
var post = _dereq_('./tables/post');

// File loaders /////////////////////////////////////////////////////////

// Convert a Node.js Buffer to an ArrayBuffer
function toArrayBuffer(buffer) {
    var arrayBuffer = new ArrayBuffer(buffer.length);
    var data = new Uint8Array(arrayBuffer);
    for (var i = 0; i < buffer.length; i += 1) {
        data[i] = buffer[i];
    }

    return arrayBuffer;
}

function loadFromFile(path, callback) {
    var fs = _dereq_('fs');
    fs.readFile(path, function(err, buffer) {
        if (err) {
            return callback(err.message);
        }

        callback(null, toArrayBuffer(buffer));
    });
}

function loadFromUrl(url, callback) {
    var request = new XMLHttpRequest();
    request.open('get', url, true);
    request.responseType = 'arraybuffer';
    request.onload = function() {
        if (request.status !== 200) {
            return callback('Font could not be loaded: ' + request.statusText);
        }

        return callback(null, request.response);
    };

    request.send();
}

// Public API ///////////////////////////////////////////////////////////

// Parse the OpenType file data (as an ArrayBuffer) and return a Font object.
// If the file could not be parsed (most likely because it contains Postscript outlines)
// we return an empty Font object with the `supported` flag set to `false`.
function parseBuffer(buffer) {
    var indexToLocFormat;
    var hmtxOffset;
    var glyfOffset;
    var locaOffset;
    var cffOffset;
    var kernOffset;
    var gposOffset;

    // OpenType fonts use big endian byte ordering.
    // We can't rely on typed array view types, because they operate with the endianness of the host computer.
    // Instead we use DataViews where we can specify endianness.

    var font = new _font.Font();
    var data = new DataView(buffer, 0);

    var version = parse.getFixed(data, 0);
    if (version === 1.0) {
        font.outlinesFormat = 'truetype';
    } else {
        version = parse.getTag(data, 0);
        if (version === 'OTTO') {
            font.outlinesFormat = 'cff';
        } else {
            throw new Error('Unsupported OpenType version ' + version);
        }
    }

    var numTables = parse.getUShort(data, 4);

    // Offset into the table records.
    var p = 12;
    for (var i = 0; i < numTables; i += 1) {
        var tag = parse.getTag(data, p);
        var offset = parse.getULong(data, p + 8);
        switch (tag) {
        case 'cmap':
            font.tables.cmap = cmap.parse(data, offset);
            font.encoding = new encoding.CmapEncoding(font.tables.cmap);
            if (!font.encoding) {
                font.supported = false;
            }

            break;
        case 'head':
            font.tables.head = head.parse(data, offset);
            font.unitsPerEm = font.tables.head.unitsPerEm;
            indexToLocFormat = font.tables.head.indexToLocFormat;
            break;
        case 'hhea':
            font.tables.hhea = hhea.parse(data, offset);
            font.ascender = font.tables.hhea.ascender;
            font.descender = font.tables.hhea.descender;
            font.numberOfHMetrics = font.tables.hhea.numberOfHMetrics;
            break;
        case 'hmtx':
            hmtxOffset = offset;
            break;
        case 'maxp':
            font.tables.maxp = maxp.parse(data, offset);
            font.numGlyphs = font.tables.maxp.numGlyphs;
            break;
        case 'name':
            font.tables.name = _name.parse(data, offset);
            font.familyName = font.tables.name.fontFamily;
            font.styleName = font.tables.name.fontSubfamily;
            break;
        case 'OS/2':
            font.tables.os2 = os2.parse(data, offset);
            break;
        case 'post':
            font.tables.post = post.parse(data, offset);
            font.glyphNames = new encoding.GlyphNames(font.tables.post);
            break;
        case 'glyf':
            glyfOffset = offset;
            break;
        case 'loca':
            locaOffset = offset;
            break;
        case 'CFF ':
            cffOffset = offset;
            break;
        case 'kern':
            kernOffset = offset;
            break;
        case 'GPOS':
            gposOffset = offset;
            break;
        }
        p += 16;
    }

    if (glyfOffset && locaOffset) {
        var shortVersion = indexToLocFormat === 0;
        var locaTable = loca.parse(data, locaOffset, font.numGlyphs, shortVersion);
        font.glyphs = glyf.parse(data, glyfOffset, locaTable, font);
        hmtx.parse(data, hmtxOffset, font.numberOfHMetrics, font.numGlyphs, font.glyphs);
        encoding.addGlyphNames(font);
    } else if (cffOffset) {
        cff.parse(data, cffOffset, font);
        encoding.addGlyphNames(font);
    } else {
        font.supported = false;
    }

    if (font.supported) {
        if (kernOffset) {
            font.kerningPairs = kern.parse(data, kernOffset);
        } else {
            font.kerningPairs = {};
        }

        if (gposOffset) {
            gpos.parse(data, gposOffset, font);
        }
    }

    return font;
}

// Asynchronously load the font from a URL or a filesystem. When done, call the callback
// with two arguments `(err, font)`. The `err` will be null on success,
// the `font` is a Font object.
//
// We use the node.js callback convention so that
// opentype.js can integrate with frameworks like async.js.
function load(url, callback) {
    var isNode = typeof window === 'undefined';
    var loadFn = isNode ? loadFromFile : loadFromUrl;
    loadFn(url, function(err, arrayBuffer) {
        if (err) {
            return callback(err);
        }

        var font = parseBuffer(arrayBuffer);
        if (!font.supported) {
            return callback('Font is not supported (is this a Postscript font?)');
        }

        return callback(null, font);
    });
}

exports._parse = parse;
exports.Font = _font.Font;
exports.Glyph = glyph.Glyph;
exports.Path = path.Path;
exports.parse = parseBuffer;
exports.load = load;

},{"./encoding":4,"./font":5,"./glyph":6,"./parse":9,"./path":10,"./tables/cff":12,"./tables/cmap":13,"./tables/glyf":14,"./tables/gpos":15,"./tables/head":16,"./tables/hhea":17,"./tables/hmtx":18,"./tables/kern":19,"./tables/loca":20,"./tables/maxp":21,"./tables/name":22,"./tables/os2":23,"./tables/post":24,"fs":1}],9:[function(_dereq_,module,exports){
// Parsing utility functions

'use strict';

// Retrieve an unsigned byte from the DataView.
exports.getByte = function getByte(dataView, offset) {
    return dataView.getUint8(offset);
};

exports.getCard8 = exports.getByte;

// Retrieve an unsigned 16-bit short from the DataView.
// The value is stored in big endian.
exports.getUShort = function(dataView, offset) {
    return dataView.getUint16(offset, false);
};

exports.getCard16 = exports.getUShort;

// Retrieve a signed 16-bit short from the DataView.
// The value is stored in big endian.
exports.getShort = function(dataView, offset) {
    return dataView.getInt16(offset, false);
};

// Retrieve an unsigned 32-bit long from the DataView.
// The value is stored in big endian.
exports.getULong = function(dataView, offset) {
    return dataView.getUint32(offset, false);
};

// Retrieve a 32-bit signed fixed-point number (16.16) from the DataView.
// The value is stored in big endian.
exports.getFixed = function(dataView, offset) {
    var decimal = dataView.getInt16(offset, false);
    var fraction = dataView.getUint16(offset + 2, false);
    return decimal + fraction / 65535;
};

// Retrieve a 4-character tag from the DataView.
// Tags are used to identify tables.
exports.getTag = function(dataView, offset) {
    var tag = '';
    for (var i = offset; i < offset + 4; i += 1) {
        tag += String.fromCharCode(dataView.getInt8(i));
    }

    return tag;
};

// Retrieve an offset from the DataView.
// Offsets are 1 to 4 bytes in length, depending on the offSize argument.
exports.getOffset = function(dataView, offset, offSize) {
    var v = 0;
    for (var i = 0; i < offSize; i += 1) {
        v <<= 8;
        v += dataView.getUint8(offset + i);
    }

    return v;
};

// Retrieve a number of bytes from start offset to the end offset from the DataView.
exports.getBytes = function(dataView, startOffset, endOffset) {
    var bytes = [];
    for (var i = startOffset; i < endOffset; i += 1) {
        bytes.push(dataView.getUint8(i));
    }

    return bytes;
};

// Convert the list of bytes to a string.
exports.bytesToString = function(bytes) {
    var s = '';
    for (var i = 0; i < bytes.length; i += 1) {
        s += String.fromCharCode(bytes[i]);
    }

    return s;
};

var typeOffsets = {
    byte: 1,
    uShort: 2,
    short: 2,
    uLong: 4,
    fixed: 4,
    longDateTime: 8,
    tag: 4
};

// A stateful parser that changes the offset whenever a value is retrieved.
// The data is a DataView.
function Parser(data, offset) {
    this.data = data;
    this.offset = offset;
    this.relativeOffset = 0;
}

Parser.prototype.parseByte = function() {
    var v = this.data.getUint8(this.offset + this.relativeOffset);
    this.relativeOffset += 1;
    return v;
};

Parser.prototype.parseChar = function() {
    var v = this.data.getInt8(this.offset + this.relativeOffset);
    this.relativeOffset += 1;
    return v;
};

Parser.prototype.parseCard8 = Parser.prototype.parseByte;

Parser.prototype.parseUShort = function() {
    var v = this.data.getUint16(this.offset + this.relativeOffset);
    this.relativeOffset += 2;
    return v;
};

Parser.prototype.parseCard16 = Parser.prototype.parseUShort;
Parser.prototype.parseSID = Parser.prototype.parseUShort;
Parser.prototype.parseOffset16 = Parser.prototype.parseUShort;

Parser.prototype.parseShort = function() {
    var v = this.data.getInt16(this.offset + this.relativeOffset);
    this.relativeOffset += 2;
    return v;
};

Parser.prototype.parseF2Dot14 = function() {
    var v = this.data.getInt16(this.offset + this.relativeOffset) / 16384;
    this.relativeOffset += 2;
    return v;
};

Parser.prototype.parseULong = function() {
    var v = exports.getULong(this.data, this.offset + this.relativeOffset);
    this.relativeOffset += 4;
    return v;
};

Parser.prototype.parseFixed = function() {
    var v = exports.getFixed(this.data, this.offset + this.relativeOffset);
    this.relativeOffset += 4;
    return v;
};

Parser.prototype.parseOffset16List =
Parser.prototype.parseUShortList = function(count) {
    var offsets = new Array(count);
    var dataView = this.data;
    var offset = this.offset + this.relativeOffset;
    for (var i = 0; i < count; i++) {
        offsets[i] = exports.getUShort(dataView, offset);
        offset += 2;
    }

    this.relativeOffset += count * 2;
    return offsets;
};

Parser.prototype.parseString = function(length) {
    var dataView = this.data;
    var offset = this.offset + this.relativeOffset;
    var string = '';
    this.relativeOffset += length;
    for (var i = 0; i < length; i++) {
        string += String.fromCharCode(dataView.getUint8(offset + i));
    }

    return string;
};

Parser.prototype.parseTag = function() {
    return this.parseString(4);
};

// LONGDATETIME is a 64-bit integer.
// JavaScript and unix timestamps traditionally use 32 bits, so we
// only take the last 32 bits.
Parser.prototype.parseLongDateTime = function() {
    var v = exports.getULong(this.data, this.offset + this.relativeOffset + 4);
    this.relativeOffset += 8;
    return v;
};

Parser.prototype.parseFixed = function() {
    var v = exports.getULong(this.data, this.offset + this.relativeOffset);
    this.relativeOffset += 4;
    return v / 65536;
};

Parser.prototype.parseVersion = function() {
    var major = exports.getUShort(this.data, this.offset + this.relativeOffset);

    // How to interpret the minor version is very vague in the spec. 0x5000 is 5, 0x1000 is 1
    // This returns the correct number if minor = 0xN000 where N is 0-9
    var minor = exports.getUShort(this.data, this.offset + this.relativeOffset + 2);
    this.relativeOffset += 4;
    return major + minor / 0x1000 / 10;
};

Parser.prototype.skip = function(type, amount) {
    if (amount === undefined) {
        amount = 1;
    }

    this.relativeOffset += typeOffsets[type] * amount;
};

exports.Parser = Parser;

},{}],10:[function(_dereq_,module,exports){
// Geometric objects

'use strict';

// A bézier path containing a set of path commands similar to a SVG path.
// Paths can be drawn on a context using `draw`.
function Path() {
    this.commands = [];
    this.fill = 'black';
    this.stroke = null;
    this.strokeWidth = 1;
}

Path.prototype.moveTo = function(x, y) {
    this.commands.push({
        type: 'M',
        x: x,
        y: y
    });
};

Path.prototype.lineTo = function(x, y) {
    this.commands.push({
        type: 'L',
        x: x,
        y: y
    });
};

Path.prototype.curveTo = Path.prototype.bezierCurveTo = function(x1, y1, x2, y2, x, y) {
    this.commands.push({
        type: 'C',
        x1: x1,
        y1: y1,
        x2: x2,
        y2: y2,
        x: x,
        y: y
    });
};

Path.prototype.quadTo = Path.prototype.quadraticCurveTo = function(x1, y1, x, y) {
    this.commands.push({
        type: 'Q',
        x1: x1,
        y1: y1,
        x: x,
        y: y
    });
};

Path.prototype.close = Path.prototype.closePath = function() {
    this.commands.push({
        type: 'Z'
    });
};

// Add the given path or list of commands to the commands of this path.
Path.prototype.extend = function(pathOrCommands) {
    if (pathOrCommands.commands) {
        pathOrCommands = pathOrCommands.commands;
    }

    Array.prototype.push.apply(this.commands, pathOrCommands);
};

// Draw the path to a 2D context.
Path.prototype.draw = function(ctx) {
    ctx.beginPath();
    for (var i = 0; i < this.commands.length; i += 1) {
        var cmd = this.commands[i];
        if (cmd.type === 'M') {
            ctx.moveTo(cmd.x, cmd.y);
        } else if (cmd.type === 'L') {
            ctx.lineTo(cmd.x, cmd.y);
        } else if (cmd.type === 'C') {
            ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y);
        } else if (cmd.type === 'Q') {
            ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y);
        } else if (cmd.type === 'Z') {
            ctx.closePath();
        }
    }

    if (this.fill) {
        ctx.fillStyle = this.fill;
        ctx.fill();
    }

    if (this.stroke) {
        ctx.strokeStyle = this.stroke;
        ctx.lineWidth = this.strokeWidth;
        ctx.stroke();
    }
};

// Convert the Path to a string of path data instructions
// See http://www.w3.org/TR/SVG/paths.html#PathData
// Parameters:
// - decimalPlaces: The amount of decimal places for floating-point values (default: 2)
Path.prototype.toPathData = function(decimalPlaces) {
    decimalPlaces = decimalPlaces !== undefined ? decimalPlaces : 2;

    function floatToString(v) {
        if (Math.round(v) === v) {
            return '' + Math.round(v);
        } else {
            return v.toFixed(decimalPlaces);
        }
    }

    function packValues() {
        var s = '';
        for (var i = 0; i < arguments.length; i += 1) {
            var v = arguments[i];
            if (v >= 0 && i > 0) {
                s += ' ';
            }

            s += floatToString(v);
        }

        return s;
    }

    var d = '';
    for (var i = 0; i < this.commands.length; i += 1) {
        var cmd = this.commands[i];
        if (cmd.type === 'M') {
            d += 'M' + packValues(cmd.x, cmd.y);
        } else if (cmd.type === 'L') {
            d += 'L' + packValues(cmd.x, cmd.y);
        } else if (cmd.type === 'C') {
            d += 'C' + packValues(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y);
        } else if (cmd.type === 'Q') {
            d += 'Q' + packValues(cmd.x1, cmd.y1, cmd.x, cmd.y);
        } else if (cmd.type === 'Z') {
            d += 'Z';
        }
    }

    return d;
};

// Convert the path to a SVG <path> element, as a string.
// Parameters:
// - decimalPlaces: The amount of decimal places for floating-point values (default: 2)
Path.prototype.toSVG = function(decimalPlaces) {
    var svg = '<path d="';
    svg += this.toPathData(decimalPlaces);
    svg += '"';
    if (this.fill & this.fill !== 'black') {
        if (this.fill === null) {
            svg += ' fill="none"';
        } else {
            svg += ' fill="' + this.fill + '"';
        }
    }

    if (this.stroke) {
        svg += ' stroke="' + this.stroke + '" stroke-width="' + this.strokeWidth + '"';
    }

    svg += '/>';
    return svg;
};

exports.Path = Path;

},{}],11:[function(_dereq_,module,exports){
// Table metadata

'use strict';

var check = _dereq_('./check');
var encode = _dereq_('./types').encode;
var sizeOf = _dereq_('./types').sizeOf;

function Table(tableName, fields, options) {
    var i;
    for (i = 0; i < fields.length; i += 1) {
        var field = fields[i];
        this[field.name] = field.value;
    }

    this.tableName = tableName;
    this.fields = fields;
    if (options) {
        var optionKeys = Object.keys(options);
        for (i = 0; i < optionKeys.length; i += 1) {
            var k = optionKeys[i];
            var v = options[k];
            if (this[k] !== undefined) {
                this[k] = v;
            }
        }
    }
}

Table.prototype.sizeOf = function() {
    var v = 0;
    for (var i = 0; i < this.fields.length; i += 1) {
        var field = this.fields[i];
        var value = this[field.name];
        if (value === undefined) {
            value = field.value;
        }

        if (typeof value.sizeOf === 'function') {
            v += value.sizeOf();
        } else {
            var sizeOfFunction = sizeOf[field.type];
            check.assert(typeof sizeOfFunction === 'function', 'Could not find sizeOf function for field' + field.name);
            v += sizeOfFunction(value);
        }
    }

    return v;
};

Table.prototype.encode = function() {
    return encode.TABLE(this);
};

exports.Table = Table;

},{"./check":2,"./types":26}],12:[function(_dereq_,module,exports){
// The `CFF` table contains the glyph outlines in PostScript format.
// https://www.microsoft.com/typography/OTSPEC/cff.htm
// http://download.microsoft.com/download/8/0/1/801a191c-029d-4af3-9642-555f6fe514ee/cff.pdf
// http://download.microsoft.com/download/8/0/1/801a191c-029d-4af3-9642-555f6fe514ee/type2.pdf

'use strict';

var encoding = _dereq_('../encoding');
var glyphset = _dereq_('../glyphset');
var parse = _dereq_('../parse');
var path = _dereq_('../path');
var table = _dereq_('../table');

// Custom equals function that can also check lists.
function equals(a, b) {
    if (a === b) {
        return true;
    } else if (Array.isArray(a) && Array.isArray(b)) {
        if (a.length !== b.length) {
            return false;
        }

        for (var i = 0; i < a.length; i += 1) {
            if (!equals(a[i], b[i])) {
                return false;
            }
        }

        return true;
    } else {
        return false;
    }
}

// Parse a `CFF` INDEX array.
// An index array consists of a list of offsets, then a list of objects at those offsets.
function parseCFFIndex(data, start, conversionFn) {
    //var i, objectOffset, endOffset;
    var offsets = [];
    var objects = [];
    var count = parse.getCard16(data, start);
    var i;
    var objectOffset;
    var endOffset;
    if (count !== 0) {
        var offsetSize = parse.getByte(data, start + 2);
        objectOffset = start + ((count + 1) * offsetSize) + 2;
        var pos = start + 3;
        for (i = 0; i < count + 1; i += 1) {
            offsets.push(parse.getOffset(data, pos, offsetSize));
            pos += offsetSize;
        }

        // The total size of the index array is 4 header bytes + the value of the last offset.
        endOffset = objectOffset + offsets[count];
    } else {
        endOffset = start + 2;
    }

    for (i = 0; i < offsets.length - 1; i += 1) {
        var value = parse.getBytes(data, objectOffset + offsets[i], objectOffset + offsets[i + 1]);
        if (conversionFn) {
            value = conversionFn(value);
        }

        objects.push(value);
    }

    return {objects: objects, startOffset: start, endOffset: endOffset};
}

// Parse a `CFF` DICT real value.
function parseFloatOperand(parser) {
    var s = '';
    var eof = 15;
    var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-'];
    while (true) {
        var b = parser.parseByte();
        var n1 = b >> 4;
        var n2 = b & 15;

        if (n1 === eof) {
            break;
        }

        s += lookup[n1];

        if (n2 === eof) {
            break;
        }

        s += lookup[n2];
    }

    return parseFloat(s);
}

// Parse a `CFF` DICT operand.
function parseOperand(parser, b0) {
    var b1;
    var b2;
    var b3;
    var b4;
    if (b0 === 28) {
        b1 = parser.parseByte();
        b2 = parser.parseByte();
        return b1 << 8 | b2;
    }

    if (b0 === 29) {
        b1 = parser.parseByte();
        b2 = parser.parseByte();
        b3 = parser.parseByte();
        b4 = parser.parseByte();
        return b1 << 24 | b2 << 16 | b3 << 8 | b4;
    }

    if (b0 === 30) {
        return parseFloatOperand(parser);
    }

    if (b0 >= 32 && b0 <= 246) {
        return b0 - 139;
    }

    if (b0 >= 247 && b0 <= 250) {
        b1 = parser.parseByte();
        return (b0 - 247) * 256 + b1 + 108;
    }

    if (b0 >= 251 && b0 <= 254) {
        b1 = parser.parseByte();
        return -(b0 - 251) * 256 - b1 - 108;
    }

    throw new Error('Invalid b0 ' + b0);
}

// Convert the entries returned by `parseDict` to a proper dictionary.
// If a value is a list of one, it is unpacked.
function entriesToObject(entries) {
    var o = {};
    for (var i = 0; i < entries.length; i += 1) {
        var key = entries[i][0];
        var values = entries[i][1];
        var value;
        if (values.length === 1) {
            value = values[0];
        } else {
            value = values;
        }

        if (o.hasOwnProperty(key)) {
            throw new Error('Object ' + o + ' already has key ' + key);
        }

        o[key] = value;
    }

    return o;
}

// Parse a `CFF` DICT object.
// A dictionary contains key-value pairs in a compact tokenized format.
function parseCFFDict(data, start, size) {
    start = start !== undefined ? start : 0;
    var parser = new parse.Parser(data, start);
    var entries = [];
    var operands = [];
    size = size !== undefined ? size : data.length;

    while (parser.relativeOffset < size) {
        var op = parser.parseByte();

        // The first byte for each dict item distinguishes between operator (key) and operand (value).
        // Values <= 21 are operators.
        if (op <= 21) {
            // Two-byte operators have an initial escape byte of 12.
            if (op === 12) {
                op = 1200 + parser.parseByte();
            }

            entries.push([op, operands]);
            operands = [];
        } else {
            // Since the operands (values) come before the operators (keys), we store all operands in a list
            // until we encounter an operator.
            operands.push(parseOperand(parser, op));
        }
    }

    return entriesToObject(entries);
}

// Given a String Index (SID), return the value of the string.
// Strings below index 392 are standard CFF strings and are not encoded in the font.
function getCFFString(strings, index) {
    if (index <= 390) {
        index = encoding.cffStandardStrings[index];
    } else {
        index = strings[index - 391];
    }

    return index;
}

// Interpret a dictionary and return a new dictionary with readable keys and values for missing entries.
// This function takes `meta` which is a list of objects containing `operand`, `name` and `default`.
function interpretDict(dict, meta, strings) {
    var newDict = {};

    // Because we also want to include missing values, we start out from the meta list
    // and lookup values in the dict.
    for (var i = 0; i < meta.length; i += 1) {
        var m = meta[i];
        var value = dict[m.op];
        if (value === undefined) {
            value = m.value !== undefined ? m.value : null;
        }

        if (m.type === 'SID') {
            value = getCFFString(strings, value);
        }

        newDict[m.name] = value;
    }

    return newDict;
}

// Parse the CFF header.
function parseCFFHeader(data, start) {
    var header = {};
    header.formatMajor = parse.getCard8(data, start);
    header.formatMinor = parse.getCard8(data, start + 1);
    header.size = parse.getCard8(data, start + 2);
    header.offsetSize = parse.getCard8(data, start + 3);
    header.startOffset = start;
    header.endOffset = start + 4;
    return header;
}

var TOP_DICT_META = [
    {name: 'version', op: 0, type: 'SID'},
    {name: 'notice', op: 1, type: 'SID'},
    {name: 'copyright', op: 1200, type: 'SID'},
    {name: 'fullName', op: 2, type: 'SID'},
    {name: 'familyName', op: 3, type: 'SID'},
    {name: 'weight', op: 4, type: 'SID'},
    {name: 'isFixedPitch', op: 1201, type: 'number', value: 0},
    {name: 'italicAngle', op: 1202, type: 'number', value: 0},
    {name: 'underlinePosition', op: 1203, type: 'number', value: -100},
    {name: 'underlineThickness', op: 1204, type: 'number', value: 50},
    {name: 'paintType', op: 1205, type: 'number', value: 0},
    {name: 'charstringType', op: 1206, type: 'number', value: 2},
    {name: 'fontMatrix', op: 1207, type: ['real', 'real', 'real', 'real', 'real', 'real'], value: [0.001, 0, 0, 0.001, 0, 0]},
    {name: 'uniqueId', op: 13, type: 'number'},
    {name: 'fontBBox', op: 5, type: ['number', 'number', 'number', 'number'], value: [0, 0, 0, 0]},
    {name: 'strokeWidth', op: 1208, type: 'number', value: 0},
    {name: 'xuid', op: 14, type: [], value: null},
    {name: 'charset', op: 15, type: 'offset', value: 0},
    {name: 'encoding', op: 16, type: 'offset', value: 0},
    {name: 'charStrings', op: 17, type: 'offset', value: 0},
    {name: 'private', op: 18, type: ['number', 'offset'], value: [0, 0]}
];

var PRIVATE_DICT_META = [
    {name: 'subrs', op: 19, type: 'offset', value: 0},
    {name: 'defaultWidthX', op: 20, type: 'number', value: 0},
    {name: 'nominalWidthX', op: 21, type: 'number', value: 0}
];

// Parse the CFF top dictionary. A CFF table can contain multiple fonts, each with their own top dictionary.
// The top dictionary contains the essential metadata for the font, together with the private dictionary.
function parseCFFTopDict(data, strings) {
    var dict = parseCFFDict(data, 0, data.byteLength);
    return interpretDict(dict, TOP_DICT_META, strings);
}

// Parse the CFF private dictionary. We don't fully parse out all the values, only the ones we need.
function parseCFFPrivateDict(data, start, size, strings) {
    var dict = parseCFFDict(data, start, size);
    return interpretDict(dict, PRIVATE_DICT_META, strings);
}

// Parse the CFF charset table, which contains internal names for all the glyphs.
// This function will return a list of glyph names.
// See Adobe TN #5176 chapter 13, "Charsets".
function parseCFFCharset(data, start, nGlyphs, strings) {
    var i;
    var sid;
    var count;
    var parser = new parse.Parser(data, start);

    // The .notdef glyph is not included, so subtract 1.
    nGlyphs -= 1;
    var charset = ['.notdef'];

    var format = parser.parseCard8();
    if (format === 0) {
        for (i = 0; i < nGlyphs; i += 1) {
            sid = parser.parseSID();
            charset.push(getCFFString(strings, sid));
        }
    } else if (format === 1) {
        while (charset.length <= nGlyphs) {
            sid = parser.parseSID();
            count = parser.parseCard8();
            for (i = 0; i <= count; i += 1) {
                charset.push(getCFFString(strings, sid));
                sid += 1;
            }
        }
    } else if (format === 2) {
        while (charset.length <= nGlyphs) {
            sid = parser.parseSID();
            count = parser.parseCard16();
            for (i = 0; i <= count; i += 1) {
                charset.push(getCFFString(strings, sid));
                sid += 1;
            }
        }
    } else {
        throw new Error('Unknown charset format ' + format);
    }

    return charset;
}

// Parse the CFF encoding data. Only one encoding can be specified per font.
// See Adobe TN #5176 chapter 12, "Encodings".
function parseCFFEncoding(data, start, charset) {
    var i;
    var code;
    var enc = {};
    var parser = new parse.Parser(data, start);
    var format = parser.parseCard8();
    if (format === 0) {
        var nCodes = parser.parseCard8();
        for (i = 0; i < nCodes; i += 1) {
            code = parser.parseCard8();
            enc[code] = i;
        }
    } else if (format === 1) {
        var nRanges = parser.parseCard8();
        code = 1;
        for (i = 0; i < nRanges; i += 1) {
            var first = parser.parseCard8();
            var nLeft = parser.parseCard8();
            for (var j = first; j <= first + nLeft; j += 1) {
                enc[j] = code;
                code += 1;
            }
        }
    } else {
        throw new Error('Unknown encoding format ' + format);
    }

    return new encoding.CffEncoding(enc, charset);
}

// Take in charstring code and return a Glyph object.
// The encoding is described in the Type 2 Charstring Format
// https://www.microsoft.com/typography/OTSPEC/charstr2.htm
function parseCFFCharstring(font, glyph, code) {
    var c1x;
    var c1y;
    var c2x;
    var c2y;
    var p = new path.Path();
    var stack = [];
    var nStems = 0;
    var haveWidth = false;
    var width = font.defaultWidthX;
    var open = false;
    var x = 0;
    var y = 0;

    function newContour(x, y) {
        if (open) {
            p.closePath();
        }

        p.moveTo(x, y);
        open = true;
    }

    function parseStems() {
        var hasWidthArg;

        // The number of stem operators on the stack is always even.
        // If the value is uneven, that means a width is specified.
        hasWidthArg = stack.length % 2 !== 0;
        if (hasWidthArg && !haveWidth) {
            width = stack.shift() + font.nominalWidthX;
        }

        nStems += stack.length >> 1;
        stack.length = 0;
        haveWidth = true;
    }

    function parse(code) {
        var b1;
        var b2;
        var b3;
        var b4;
        var codeIndex;
        var subrCode;
        var jpx;
        var jpy;
        var c3x;
        var c3y;
        var c4x;
        var c4y;

        var i = 0;
        while (i < code.length) {
            var v = code[i];
            i += 1;
            switch (v) {
            case 1: // hstem
                parseStems();
                break;
            case 3: // vstem
                parseStems();
                break;
            case 4: // vmoveto
                if (stack.length > 1 && !haveWidth) {
                    width = stack.shift() + font.nominalWidthX;
                    haveWidth = true;
                }

                y += stack.pop();
                newContour(x, y);
                break;
            case 5: // rlineto
                while (stack.length > 0) {
                    x += stack.shift();
                    y += stack.shift();
                    p.lineTo(x, y);
                }

                break;
            case 6: // hlineto
                while (stack.length > 0) {
                    x += stack.shift();
                    p.lineTo(x, y);
                    if (stack.length === 0) {
                        break;
                    }

                    y += stack.shift();
                    p.lineTo(x, y);
                }

                break;
            case 7: // vlineto
                while (stack.length > 0) {
                    y += stack.shift();
                    p.lineTo(x, y);
                    if (stack.length === 0) {
                        break;
                    }

                    x += stack.shift();
                    p.lineTo(x, y);
                }

                break;
            case 8: // rrcurveto
                while (stack.length > 0) {
                    c1x = x + stack.shift();
                    c1y = y + stack.shift();
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    x = c2x + stack.shift();
                    y = c2y + stack.shift();
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                }

                break;
            case 10: // callsubr
                codeIndex = stack.pop() + font.subrsBias;
                subrCode = font.subrs[codeIndex];
                if (subrCode) {
                    parse(subrCode);
                }

                break;
            case 11: // return
                return;
            case 12: // flex operators
                v = code[i];
                i += 1;
                switch (v) {
                case 35: // flex
                    // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |-
                    c1x = x   + stack.shift();    // dx1
                    c1y = y   + stack.shift();    // dy1
                    c2x = c1x + stack.shift();    // dx2
                    c2y = c1y + stack.shift();    // dy2
                    jpx = c2x + stack.shift();    // dx3
                    jpy = c2y + stack.shift();    // dy3
                    c3x = jpx + stack.shift();    // dx4
                    c3y = jpy + stack.shift();    // dy4
                    c4x = c3x + stack.shift();    // dx5
                    c4y = c3y + stack.shift();    // dy5
                    x = c4x + stack.shift();      // dx6
                    y = c4y + stack.shift();      // dy6
                    stack.shift();                // flex depth
                    p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
                    p.curveTo(c3x, c3y, c4x, c4y, x, y);
                    break;
                case 34: // hflex
                    // |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |-
                    c1x = x   + stack.shift();    // dx1
                    c1y = y;                      // dy1
                    c2x = c1x + stack.shift();    // dx2
                    c2y = c1y + stack.shift();    // dy2
                    jpx = c2x + stack.shift();    // dx3
                    jpy = c2y;                    // dy3
                    c3x = jpx + stack.shift();    // dx4
                    c3y = c2y;                    // dy4
                    c4x = c3x + stack.shift();    // dx5
                    c4y = y;                      // dy5
                    x = c4x + stack.shift();      // dx6
                    p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
                    p.curveTo(c3x, c3y, c4x, c4y, x, y);
                    break;
                case 36: // hflex1
                    // |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |-
                    c1x = x   + stack.shift();    // dx1
                    c1y = y   + stack.shift();    // dy1
                    c2x = c1x + stack.shift();    // dx2
                    c2y = c1y + stack.shift();    // dy2
                    jpx = c2x + stack.shift();    // dx3
                    jpy = c2y;                    // dy3
                    c3x = jpx + stack.shift();    // dx4
                    c3y = c2y;                    // dy4
                    c4x = c3x + stack.shift();    // dx5
                    c4y = c3y + stack.shift();    // dy5
                    x = c4x + stack.shift();      // dx6
                    p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
                    p.curveTo(c3x, c3y, c4x, c4y, x, y);
                    break;
                case 37: // flex1
                    // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |-
                    c1x = x   + stack.shift();    // dx1
                    c1y = y   + stack.shift();    // dy1
                    c2x = c1x + stack.shift();    // dx2
                    c2y = c1y + stack.shift();    // dy2
                    jpx = c2x + stack.shift();    // dx3
                    jpy = c2y + stack.shift();    // dy3
                    c3x = jpx + stack.shift();    // dx4
                    c3y = jpy + stack.shift();    // dy4
                    c4x = c3x + stack.shift();    // dx5
                    c4y = c3y + stack.shift();    // dy5
                    if (Math.abs(c4x - x) > Math.abs(c4y - y)) {
                        x = c4x + stack.shift();
                    } else {
                        y = c4y + stack.shift();
                    }

                    p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
                    p.curveTo(c3x, c3y, c4x, c4y, x, y);
                    break;
                default:
                    console.log('Glyph ' + glyph.index + ': unknown operator ' + 1200 + v);
                    stack.length = 0;
                }
                break;
            case 14: // endchar
                if (stack.length > 0 && !haveWidth) {
                    width = stack.shift() + font.nominalWidthX;
                    haveWidth = true;
                }

                if (open) {
                    p.closePath();
                    open = false;
                }

                break;
            case 18: // hstemhm
                parseStems();
                break;
            case 19: // hintmask
            case 20: // cntrmask
                parseStems();
                i += (nStems + 7) >> 3;
                break;
            case 21: // rmoveto
                if (stack.length > 2 && !haveWidth) {
                    width = stack.shift() + font.nominalWidthX;
                    haveWidth = true;
                }

                y += stack.pop();
                x += stack.pop();
                newContour(x, y);
                break;
            case 22: // hmoveto
                if (stack.length > 1 && !haveWidth) {
                    width = stack.shift() + font.nominalWidthX;
                    haveWidth = true;
                }

                x += stack.pop();
                newContour(x, y);
                break;
            case 23: // vstemhm
                parseStems();
                break;
            case 24: // rcurveline
                while (stack.length > 2) {
                    c1x = x + stack.shift();
                    c1y = y + stack.shift();
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    x = c2x + stack.shift();
                    y = c2y + stack.shift();
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                }

                x += stack.shift();
                y += stack.shift();
                p.lineTo(x, y);
                break;
            case 25: // rlinecurve
                while (stack.length > 6) {
                    x += stack.shift();
                    y += stack.shift();
                    p.lineTo(x, y);
                }

                c1x = x + stack.shift();
                c1y = y + stack.shift();
                c2x = c1x + stack.shift();
                c2y = c1y + stack.shift();
                x = c2x + stack.shift();
                y = c2y + stack.shift();
                p.curveTo(c1x, c1y, c2x, c2y, x, y);
                break;
            case 26: // vvcurveto
                if (stack.length % 2) {
                    x += stack.shift();
                }

                while (stack.length > 0) {
                    c1x = x;
                    c1y = y + stack.shift();
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    x = c2x;
                    y = c2y + stack.shift();
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                }

                break;
            case 27: // hhcurveto
                if (stack.length % 2) {
                    y += stack.shift();
                }

                while (stack.length > 0) {
                    c1x = x + stack.shift();
                    c1y = y;
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    x = c2x + stack.shift();
                    y = c2y;
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                }

                break;
            case 28: // shortint
                b1 = code[i];
                b2 = code[i + 1];
                stack.push(((b1 << 24) | (b2 << 16)) >> 16);
                i += 2;
                break;
            case 29: // callgsubr
                codeIndex = stack.pop() + font.gsubrsBias;
                subrCode = font.gsubrs[codeIndex];
                if (subrCode) {
                    parse(subrCode);
                }

                break;
            case 30: // vhcurveto
                while (stack.length > 0) {
                    c1x = x;
                    c1y = y + stack.shift();
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    x = c2x + stack.shift();
                    y = c2y + (stack.length === 1 ? stack.shift() : 0);
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                    if (stack.length === 0) {
                        break;
                    }

                    c1x = x + stack.shift();
                    c1y = y;
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    y = c2y + stack.shift();
                    x = c2x + (stack.length === 1 ? stack.shift() : 0);
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                }

                break;
            case 31: // hvcurveto
                while (stack.length > 0) {
                    c1x = x + stack.shift();
                    c1y = y;
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    y = c2y + stack.shift();
                    x = c2x + (stack.length === 1 ? stack.shift() : 0);
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                    if (stack.length === 0) {
                        break;
                    }

                    c1x = x;
                    c1y = y + stack.shift();
                    c2x = c1x + stack.shift();
                    c2y = c1y + stack.shift();
                    x = c2x + stack.shift();
                    y = c2y + (stack.length === 1 ? stack.shift() : 0);
                    p.curveTo(c1x, c1y, c2x, c2y, x, y);
                }

                break;
            default:
                if (v < 32) {
                    console.log('Glyph ' + glyph.index + ': unknown operator ' + v);
                } else if (v < 247) {
                    stack.push(v - 139);
                } else if (v < 251) {
                    b1 = code[i];
                    i += 1;
                    stack.push((v - 247) * 256 + b1 + 108);
                } else if (v < 255) {
                    b1 = code[i];
                    i += 1;
                    stack.push(-(v - 251) * 256 - b1 - 108);
                } else {
                    b1 = code[i];
                    b2 = code[i + 1];
                    b3 = code[i + 2];
                    b4 = code[i + 3];
                    i += 4;
                    stack.push(((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65536);
                }
            }
        }
    }

    parse(code);

    glyph.advanceWidth = width;
    return p;
}

// Subroutines are encoded using the negative half of the number space.
// See type 2 chapter 4.7 "Subroutine operators".
function calcCFFSubroutineBias(subrs) {
    var bias;
    if (subrs.length < 1240) {
        bias = 107;
    } else if (subrs.length < 33900) {
        bias = 1131;
    } else {
        bias = 32768;
    }

    return bias;
}

// Parse the `CFF` table, which contains the glyph outlines in PostScript format.
function parseCFFTable(data, start, font) {
    font.tables.cff = {};
    var header = parseCFFHeader(data, start);
    var nameIndex = parseCFFIndex(data, header.endOffset, parse.bytesToString);
    var topDictIndex = parseCFFIndex(data, nameIndex.endOffset);
    var stringIndex = parseCFFIndex(data, topDictIndex.endOffset, parse.bytesToString);
    var globalSubrIndex = parseCFFIndex(data, stringIndex.endOffset);
    font.gsubrs = globalSubrIndex.objects;
    font.gsubrsBias = calcCFFSubroutineBias(font.gsubrs);

    var topDictData = new DataView(new Uint8Array(topDictIndex.objects[0]).buffer);
    var topDict = parseCFFTopDict(topDictData, stringIndex.objects);
    font.tables.cff.topDict = topDict;

    var privateDictOffset = start + topDict['private'][1];
    var privateDict = parseCFFPrivateDict(data, privateDictOffset, topDict['private'][0], stringIndex.objects);
    font.defaultWidthX = privateDict.defaultWidthX;
    font.nominalWidthX = privateDict.nominalWidthX;

    if (privateDict.subrs !== 0) {
        var subrOffset = privateDictOffset + privateDict.subrs;
        var subrIndex = parseCFFIndex(data, subrOffset);
        font.subrs = subrIndex.objects;
        font.subrsBias = calcCFFSubroutineBias(font.subrs);
    } else {
        font.subrs = [];
        font.subrsBias = 0;
    }

    // Offsets in the top dict are relative to the beginning of the CFF data, so add the CFF start offset.
    var charStringsIndex = parseCFFIndex(data, start + topDict.charStrings);
    font.nGlyphs = charStringsIndex.objects.length;

    var charset = parseCFFCharset(data, start + topDict.charset, font.nGlyphs, stringIndex.objects);
    if (topDict.encoding === 0) { // Standard encoding
        font.cffEncoding = new encoding.CffEncoding(encoding.cffStandardEncoding, charset);
    } else if (topDict.encoding === 1) { // Expert encoding
        font.cffEncoding = new encoding.CffEncoding(encoding.cffExpertEncoding, charset);
    } else {
        font.cffEncoding = parseCFFEncoding(data, start + topDict.encoding, charset);
    }

    // Prefer the CMAP encoding to the CFF encoding.
    font.encoding = font.encoding || font.cffEncoding;

    font.glyphs = new glyphset.GlyphSet(font);
    for (var i = 0; i < font.nGlyphs; i += 1) {
        var charString = charStringsIndex.objects[i];
        font.glyphs.push(i, glyphset.cffGlyphLoader(font, i, parseCFFCharstring, charString));
    }
}

// Convert a string to a String ID (SID).
// The list of strings is modified in place.
function encodeString(s, strings) {
    var sid;

    // Is the string in the CFF standard strings?
    var i = encoding.cffStandardStrings.indexOf(s);
    if (i >= 0) {
        sid = i;
    }

    // Is the string already in the string index?
    i = strings.indexOf(s);
    if (i >= 0) {
        sid = i + encoding.cffStandardStrings.length;
    } else {
        sid = encoding.cffStandardStrings.length + strings.length;
        strings.push(s);
    }

    return sid;
}

function makeHeader() {
    return new table.Table('Header', [
        {name: 'major', type: 'Card8', value: 1},
        {name: 'minor', type: 'Card8', value: 0},
        {name: 'hdrSize', type: 'Card8', value: 4},
        {name: 'major', type: 'Card8', value: 1}
    ]);
}

function makeNameIndex(fontNames) {
    var t = new table.Table('Name INDEX', [
        {name: 'names', type: 'INDEX', value: []}
    ]);
    t.names = [];
    for (var i = 0; i < fontNames.length; i += 1) {
        t.names.push({name: 'name_' + i, type: 'NAME', value: fontNames[i]});
    }

    return t;
}

// Given a dictionary's metadata, create a DICT structure.
function makeDict(meta, attrs, strings) {
    var m = {};
    for (var i = 0; i < meta.length; i += 1) {
        var entry = meta[i];
        var value = attrs[entry.name];
        if (value !== undefined && !equals(value, entry.value)) {
            if (entry.type === 'SID') {
                value = encodeString(value, strings);
            }

            m[entry.op] = {name: entry.name, type: entry.type, value: value};
        }
    }

    return m;
}

// The Top DICT houses the global font attributes.
function makeTopDict(attrs, strings) {
    var t = new table.Table('Top DICT', [
        {name: 'dict', type: 'DICT', value: {}}
    ]);
    t.dict = makeDict(TOP_DICT_META, attrs, strings);
    return t;
}

function makeTopDictIndex(topDict) {
    var t = new table.Table('Top DICT INDEX', [
        {name: 'topDicts', type: 'INDEX', value: []}
    ]);
    t.topDicts = [{name: 'topDict_0', type: 'TABLE', value: topDict}];
    return t;
}

function makeStringIndex(strings) {
    var t = new table.Table('String INDEX', [
        {name: 'strings', type: 'INDEX', value: []}
    ]);
    t.strings = [];
    for (var i = 0; i < strings.length; i += 1) {
        t.strings.push({name: 'string_' + i, type: 'STRING', value: strings[i]});
    }

    return t;
}

function makeGlobalSubrIndex() {
    // Currently we don't use subroutines.
    return new table.Table('Global Subr INDEX', [
        {name: 'subrs', type: 'INDEX', value: []}
    ]);
}

function makeCharsets(glyphNames, strings) {
    var t = new table.Table('Charsets', [
        {name: 'format', type: 'Card8', value: 0}
    ]);
    for (var i = 0; i < glyphNames.length; i += 1) {
        var glyphName = glyphNames[i];
        var glyphSID = encodeString(glyphName, strings);
        t.fields.push({name: 'glyph_' + i, type: 'SID', value: glyphSID});
    }

    return t;
}

function glyphToOps(glyph) {
    var ops = [];
    var path = glyph.path;
    ops.push({name: 'width', type: 'NUMBER', value: glyph.advanceWidth});
    var x = 0;
    var y = 0;
    for (var i = 0; i < path.commands.length; i += 1) {
        var dx;
        var dy;
        var cmd = path.commands[i];
        if (cmd.type === 'Q') {
            // CFF only supports bézier curves, so convert the quad to a bézier.
            var _13 = 1 / 3;
            var _23 = 2 / 3;

            // We're going to create a new command so we don't change the original path.
            cmd = {
                type: 'C',
                x: cmd.x,
                y: cmd.y,
                x1: _13 * x + _23 * cmd.x1,
                y1: _13 * y + _23 * cmd.y1,
                x2: _13 * cmd.x + _23 * cmd.x1,
                y2: _13 * cmd.y + _23 * cmd.y1
            };
        }

        if (cmd.type === 'M') {
            dx = Math.round(cmd.x - x);
            dy = Math.round(cmd.y - y);
            ops.push({name: 'dx', type: 'NUMBER', value: dx});
            ops.push({name: 'dy', type: 'NUMBER', value: dy});
            ops.push({name: 'rmoveto', type: 'OP', value: 21});
            x = Math.round(cmd.x);
            y = Math.round(cmd.y);
        } else if (cmd.type === 'L') {
            dx = Math.round(cmd.x - x);
            dy = Math.round(cmd.y - y);
            ops.push({name: 'dx', type: 'NUMBER', value: dx});
            ops.push({name: 'dy', type: 'NUMBER', value: dy});
            ops.push({name: 'rlineto', type: 'OP', value: 5});
            x = Math.round(cmd.x);
            y = Math.round(cmd.y);
        } else if (cmd.type === 'C') {
            var dx1 = Math.round(cmd.x1 - x);
            var dy1 = Math.round(cmd.y1 - y);
            var dx2 = Math.round(cmd.x2 - cmd.x1);
            var dy2 = Math.round(cmd.y2 - cmd.y1);
            dx = Math.round(cmd.x - cmd.x2);
            dy = Math.round(cmd.y - cmd.y2);
            ops.push({name: 'dx1', type: 'NUMBER', value: dx1});
            ops.push({name: 'dy1', type: 'NUMBER', value: dy1});
            ops.push({name: 'dx2', type: 'NUMBER', value: dx2});
            ops.push({name: 'dy2', type: 'NUMBER', value: dy2});
            ops.push({name: 'dx', type: 'NUMBER', value: dx});
            ops.push({name: 'dy', type: 'NUMBER', value: dy});
            ops.push({name: 'rrcurveto', type: 'OP', value: 8});
            x = Math.round(cmd.x);
            y = Math.round(cmd.y);
        }

        // Contours are closed automatically.

    }

    ops.push({name: 'endchar', type: 'OP', value: 14});
    return ops;
}

function makeCharStringsIndex(glyphs) {
    var t = new table.Table('CharStrings INDEX', [
        {name: 'charStrings', type: 'INDEX', value: []}
    ]);

    for (var i = 0; i < glyphs.length; i += 1) {
        var glyph = glyphs.get(i);
        var ops = glyphToOps(glyph);
        t.charStrings.push({name: glyph.name, type: 'CHARSTRING', value: ops});
    }

    return t;
}

function makePrivateDict(attrs, strings) {
    var t = new table.Table('Private DICT', [
        {name: 'dict', type: 'DICT', value: {}}
    ]);
    t.dict = makeDict(PRIVATE_DICT_META, attrs, strings);
    return t;
}

function makePrivateDictIndex(privateDict) {
    var t = new table.Table('Private DICT INDEX', [
        {name: 'privateDicts', type: 'INDEX', value: []}
    ]);
    t.privateDicts = [{name: 'privateDict_0', type: 'TABLE', value: privateDict}];
    return t;
}

function makeCFFTable(glyphs, options) {
    var t = new table.Table('CFF ', [
        {name: 'header', type: 'TABLE'},
        {name: 'nameIndex', type: 'TABLE'},
        {name: 'topDictIndex', type: 'TABLE'},
        {name: 'stringIndex', type: 'TABLE'},
        {name: 'globalSubrIndex', type: 'TABLE'},
        {name: 'charsets', type: 'TABLE'},
        {name: 'charStringsIndex', type: 'TABLE'},
        {name: 'privateDictIndex', type: 'TABLE'}
    ]);

    var fontScale = 1 / options.unitsPerEm;
    // We use non-zero values for the offsets so that the DICT encodes them.
    // This is important because the size of the Top DICT plays a role in offset calculation,
    // and the size shouldn't change after we've written correct offsets.
    var attrs = {
        version: options.version,
        fullName: options.fullName,
        familyName: options.familyName,
        weight: options.weightName,
        fontMatrix: [fontScale, 0, 0, fontScale, 0, 0],
        charset: 999,
        encoding: 0,
        charStrings: 999,
        private: [0, 999]
    };

    var privateAttrs = {};

    var glyphNames = [];
    var glyph;

    // Skip first glyph (.notdef)
    for (var i = 1; i < glyphs.length; i += 1) {
        glyph = glyphs.get(i);
        glyphNames.push(glyph.name);
    }

    var strings = [];

    t.header = makeHeader();
    t.nameIndex = makeNameIndex([options.postScriptName]);
    var topDict = makeTopDict(attrs, strings);
    t.topDictIndex = makeTopDictIndex(topDict);
    t.globalSubrIndex = makeGlobalSubrIndex();
    t.charsets = makeCharsets(glyphNames, strings);
    t.charStringsIndex = makeCharStringsIndex(glyphs);
    var privateDict = makePrivateDict(privateAttrs, strings);
    t.privateDictIndex = makePrivateDictIndex(privateDict);

    // Needs to come at the end, to encode all custom strings used in the font.
    t.stringIndex = makeStringIndex(strings);

    var startOffset = t.header.sizeOf() +
        t.nameIndex.sizeOf() +
        t.topDictIndex.sizeOf() +
        t.stringIndex.sizeOf() +
        t.globalSubrIndex.sizeOf();
    attrs.charset = startOffset;

    // We use the CFF standard encoding; proper encoding will be handled in cmap.
    attrs.encoding = 0;
    attrs.charStrings = attrs.charset + t.charsets.sizeOf();
    attrs.private[1] = attrs.charStrings + t.charStringsIndex.sizeOf();

    // Recreate the Top DICT INDEX with the correct offsets.
    topDict = makeTopDict(attrs, strings);
    t.topDictIndex = makeTopDictIndex(topDict);

    return t;
}

exports.parse = parseCFFTable;
exports.make = makeCFFTable;

},{"../encoding":4,"../glyphset":7,"../parse":9,"../path":10,"../table":11}],13:[function(_dereq_,module,exports){
// The `cmap` table stores the mappings from characters to glyphs.
// https://www.microsoft.com/typography/OTSPEC/cmap.htm

'use strict';

var check = _dereq_('../check');
var parse = _dereq_('../parse');
var table = _dereq_('../table');

// Parse the `cmap` table. This table stores the mappings from characters to glyphs.
// There are many available formats, but we only support the Windows format 4.
// This function returns a `CmapEncoding` object or null if no supported format could be found.
function parseCmapTable(data, start) {
    var i;
    var cmap = {};
    cmap.version = parse.getUShort(data, start);
    check.argument(cmap.version === 0, 'cmap table version should be 0.');

    // The cmap table can contain many sub-tables, each with their own format.
    // We're only interested in a "platform 3" table. This is a Windows format.
    cmap.numTables = parse.getUShort(data, start + 2);
    var offset = -1;
    for (i = 0; i < cmap.numTables; i += 1) {
        var platformId = parse.getUShort(data, start + 4 + (i * 8));
        var encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2);
        if (platformId === 3 && (encodingId === 1 || encodingId === 0)) {
            offset = parse.getULong(data, start + 4 + (i * 8) + 4);
            break;
        }
    }

    if (offset === -1) {
        // There is no cmap table in the font that we support, so return null.
        // This font will be marked as unsupported.
        return null;
    }

    var p = new parse.Parser(data, start + offset);
    cmap.format = p.parseUShort();
    check.argument(cmap.format === 4, 'Only format 4 cmap tables are supported.');

    // Length in bytes of the sub-tables.
    cmap.length = p.parseUShort();
    cmap.language = p.parseUShort();

    // segCount is stored x 2.
    var segCount;
    cmap.segCount = segCount = p.parseUShort() >> 1;

    // Skip searchRange, entrySelector, rangeShift.
    p.skip('uShort', 3);

    // The "unrolled" mapping from character codes to glyph indices.
    cmap.glyphIndexMap = {};

    var endCountParser = new parse.Parser(data, start + offset + 14);
    var startCountParser = new parse.Parser(data, start + offset + 16 + segCount * 2);
    var idDeltaParser = new parse.Parser(data, start + offset + 16 + segCount * 4);
    var idRangeOffsetParser = new parse.Parser(data, start + offset + 16 + segCount * 6);
    var glyphIndexOffset = start + offset + 16 + segCount * 8;
    for (i = 0; i < segCount - 1; i += 1) {
        var glyphIndex;
        var endCount = endCountParser.parseUShort();
        var startCount = startCountParser.parseUShort();
        var idDelta = idDeltaParser.parseShort();
        var idRangeOffset = idRangeOffsetParser.parseUShort();
        for (var c = startCount; c <= endCount; c += 1) {
            if (idRangeOffset !== 0) {
                // The idRangeOffset is relative to the current position in the idRangeOffset array.
                // Take the current offset in the idRangeOffset array.
                glyphIndexOffset = (idRangeOffsetParser.offset + idRangeOffsetParser.relativeOffset - 2);

                // Add the value of the idRangeOffset, which will move us into the glyphIndex array.
                glyphIndexOffset += idRangeOffset;

                // Then add the character index of the current segment, multiplied by 2 for USHORTs.
                glyphIndexOffset += (c - startCount) * 2;
                glyphIndex = parse.getUShort(data, glyphIndexOffset);
                if (glyphIndex !== 0) {
                    glyphIndex = (glyphIndex + idDelta) & 0xFFFF;
                }
            } else {
                glyphIndex = (c + idDelta) & 0xFFFF;
            }

            cmap.glyphIndexMap[c] = glyphIndex;
        }
    }

    return cmap;
}

function addSegment(t, code, glyphIndex) {
    t.segments.push({
        end: code,
        start: code,
        delta: -(code - glyphIndex),
        offset: 0
    });
}

function addTerminatorSegment(t) {
    t.segments.push({
        end: 0xFFFF,
        start: 0xFFFF,
        delta: 1,
        offset: 0
    });
}

function makeCmapTable(glyphs) {
    var i;
    var t = new table.Table('cmap', [
        {name: 'version', type: 'USHORT', value: 0},
        {name: 'numTables', type: 'USHORT', value: 1},
        {name: 'platformID', type: 'USHORT', value: 3},
        {name: 'encodingID', type: 'USHORT', value: 1},
        {name: 'offset', type: 'ULONG', value: 12},
        {name: 'format', type: 'USHORT', value: 4},
        {name: 'length', type: 'USHORT', value: 0},
        {name: 'language', type: 'USHORT', value: 0},
        {name: 'segCountX2', type: 'USHORT', value: 0},
        {name: 'searchRange', type: 'USHORT', value: 0},
        {name: 'entrySelector', type: 'USHORT', value: 0},
        {name: 'rangeShift', type: 'USHORT', value: 0}
    ]);

    t.segments = [];
    for (i = 0; i < glyphs.length; i += 1) {
        var glyph = glyphs.get(i);
        for (var j = 0; j < glyph.unicodes.length; j += 1) {
            addSegment(t, glyph.unicodes[j], i);
        }

        t.segments = t.segments.sort(function(a, b) {
            return a.start - b.start;
        });
    }

    addTerminatorSegment(t);

    var segCount;
    segCount = t.segments.length;
    t.segCountX2 = segCount * 2;
    t.searchRange = Math.pow(2, Math.floor(Math.log(segCount) / Math.log(2))) * 2;
    t.entrySelector = Math.log(t.searchRange / 2) / Math.log(2);
    t.rangeShift = t.segCountX2 - t.searchRange;

    // Set up parallel segment arrays.
    var endCounts = [];
    var startCounts = [];
    var idDeltas = [];
    var idRangeOffsets = [];
    var glyphIds = [];

    for (i = 0; i < segCount; i += 1) {
        var segment = t.segments[i];
        endCounts = endCounts.concat({name: 'end_' + i, type: 'USHORT', value: segment.end});
        startCounts = startCounts.concat({name: 'start_' + i, type: 'USHORT', value: segment.start});
        idDeltas = idDeltas.concat({name: 'idDelta_' + i, type: 'SHORT', value: segment.delta});
        idRangeOffsets = idRangeOffsets.concat({name: 'idRangeOffset_' + i, type: 'USHORT', value: segment.offset});
        if (segment.glyphId !== undefined) {
            glyphIds = glyphIds.concat({name: 'glyph_' + i, type: 'USHORT', value: segment.glyphId});
        }
    }

    t.fields = t.fields.concat(endCounts);
    t.fields.push({name: 'reservedPad', type: 'USHORT', value: 0});
    t.fields = t.fields.concat(startCounts);
    t.fields = t.fields.concat(idDeltas);
    t.fields = t.fields.concat(idRangeOffsets);
    t.fields = t.fields.concat(glyphIds);

    t.length = 14 + // Subtable header
        endCounts.length * 2 +
        2 + // reservedPad
        startCounts.length * 2 +
        idDeltas.length * 2 +
        idRangeOffsets.length * 2 +
        glyphIds.length * 2;

    return t;
}

exports.parse = parseCmapTable;
exports.make = makeCmapTable;

},{"../check":2,"../parse":9,"../table":11}],14:[function(_dereq_,module,exports){
// The `glyf` table describes the glyphs in TrueType outline format.
// http://www.microsoft.com/typography/otspec/glyf.htm

'use strict';

var check = _dereq_('../check');
var glyphset = _dereq_('../glyphset');
var parse = _dereq_('../parse');
var path = _dereq_('../path');

// Parse the coordinate data for a glyph.
function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask, sameBitMask) {
    var v;
    if ((flag & shortVectorBitMask) > 0) {
        // The coordinate is 1 byte long.
        v = p.parseByte();
        // The `same` bit is re-used for short values to signify the sign of the value.
        if ((flag & sameBitMask) === 0) {
            v = -v;
        }

        v = previousValue + v;
    } else {
        //  The coordinate is 2 bytes long.
        // If the `same` bit is set, the coordinate is the same as the previous coordinate.
        if ((flag & sameBitMask) > 0) {
            v = previousValue;
        } else {
            // Parse the coordinate as a signed 16-bit delta value.
            v = previousValue + p.parseShort();
        }
    }

    return v;
}

// Parse a TrueType glyph.
function parseGlyph(glyph, data, start) {
    var p = new parse.Parser(data, start);
    glyph.numberOfContours = p.parseShort();
    glyph.xMin = p.parseShort();
    glyph.yMin = p.parseShort();
    glyph.xMax = p.parseShort();
    glyph.yMax = p.parseShort();
    var flags;
    var flag;
    if (glyph.numberOfContours > 0) {
        var i;
        // This glyph is not a composite.
        var endPointIndices = glyph.endPointIndices = [];
        for (i = 0; i < glyph.numberOfContours; i += 1) {
            endPointIndices.push(p.parseUShort());
        }

        glyph.instructionLength = p.parseUShort();
        glyph.instructions = [];
        for (i = 0; i < glyph.instructionLength; i += 1) {
            glyph.instructions.push(p.parseByte());
        }

        var numberOfCoordinates = endPointIndices[endPointIndices.length - 1] + 1;
        flags = [];
        for (i = 0; i < numberOfCoordinates; i += 1) {
            flag = p.parseByte();
            flags.push(flag);
            // If bit 3 is set, we repeat this flag n times, where n is the next byte.
            if ((flag & 8) > 0) {
                var repeatCount = p.parseByte();
                for (var j = 0; j < repeatCount; j += 1) {
                    flags.push(flag);
                    i += 1;
                }
            }
        }

        check.argument(flags.length === numberOfCoordinates, 'Bad flags.');

        if (endPointIndices.length > 0) {
            var points = [];
            var point;
            // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0.
            if (numberOfCoordinates > 0) {
                for (i = 0; i < numberOfCoordinates; i += 1) {
                    flag = flags[i];
                    point = {};
                    point.onCurve = !!(flag & 1);
                    point.lastPointOfContour = endPointIndices.indexOf(i) >= 0;
                    points.push(point);
                }

                var px = 0;
                for (i = 0; i < numberOfCoordinates; i += 1) {
                    flag = flags[i];
                    point = points[i];
                    point.x = parseGlyphCoordinate(p, flag, px, 2, 16);
                    px = point.x;
                }

                var py = 0;
                for (i = 0; i < numberOfCoordinates; i += 1) {
                    flag = flags[i];
                    point = points[i];
                    point.y = parseGlyphCoordinate(p, flag, py, 4, 32);
                    py = point.y;
                }
            }

            glyph.points = points;
        } else {
            glyph.points = [];
        }
    } else if (glyph.numberOfContours === 0) {
        glyph.points = [];
    } else {
        glyph.isComposite = true;
        glyph.points = [];
        glyph.components = [];
        var moreComponents = true;
        while (moreComponents) {
            flags = p.parseUShort();
            var component = {
                glyphIndex: p.parseUShort(),
                xScale: 1,
                scale01: 0,
                scale10: 0,
                yScale: 1,
                dx: 0,
                dy: 0
            };
            if ((flags & 1) > 0) {
                // The arguments are words
                component.dx = p.parseShort();
                component.dy = p.parseShort();
            } else {
                // The arguments are bytes
                component.dx = p.parseChar();
                component.dy = p.parseChar();
            }

            if ((flags & 8) > 0) {
                // We have a scale
                component.xScale = component.yScale = p.parseF2Dot14();
            } else if ((flags & 64) > 0) {
                // We have an X / Y scale
                component.xScale = p.parseF2Dot14();
                component.yScale = p.parseF2Dot14();
            } else if ((flags & 128) > 0) {
                // We have a 2x2 transformation
                component.xScale = p.parseF2Dot14();
                component.scale01 = p.parseF2Dot14();
                component.scale10 = p.parseF2Dot14();
                component.yScale = p.parseF2Dot14();
            }

            glyph.components.push(component);
            moreComponents = !!(flags & 32);
        }
    }
}

// Transform an array of points and return a new array.
function transformPoints(points, transform) {
    var newPoints = [];
    for (var i = 0; i < points.length; i += 1) {
        var pt = points[i];
        var newPt = {
            x: transform.xScale * pt.x + transform.scale01 * pt.y + transform.dx,
            y: transform.scale10 * pt.x + transform.yScale * pt.y + transform.dy,
            onCurve: pt.onCurve,
            lastPointOfContour: pt.lastPointOfContour
        };
        newPoints.push(newPt);
    }

    return newPoints;
}

function getContours(points) {
    var contours = [];
    var currentContour = [];
    for (var i = 0; i < points.length; i += 1) {
        var pt = points[i];
        currentContour.push(pt);
        if (pt.lastPointOfContour) {
            contours.push(currentContour);
            currentContour = [];
        }
    }

    check.argument(currentContour.length === 0, 'There are still points left in the current contour.');
    return contours;
}

// Convert the TrueType glyph outline to a Path.
function getPath(points) {
    var p = new path.Path();
    if (!points) {
        return p;
    }

    var contours = getContours(points);
    for (var i = 0; i < contours.length; i += 1) {
        var contour = contours[i];
        var firstPt = contour[0];
        var lastPt = contour[contour.length - 1];
        var curvePt;
        var realFirstPoint;
        if (firstPt.onCurve) {
            curvePt = null;
            // The first point will be consumed by the moveTo command,
            // so skip it in the loop.
            realFirstPoint = true;
        } else {
            if (lastPt.onCurve) {
                // If the first point is off-curve and the last point is on-curve,
                // start at the last point.
                firstPt = lastPt;
            } else {
                // If both first and last points are off-curve, start at their middle.
                firstPt = { x: (firstPt.x + lastPt.x) / 2, y: (firstPt.y + lastPt.y) / 2 };
            }

            curvePt = firstPt;
            // The first point is synthesized, so don't skip the real first point.
            realFirstPoint = false;
        }

        p.moveTo(firstPt.x, firstPt.y);

        for (var j = realFirstPoint ? 1 : 0; j < contour.length; j += 1) {
            var pt = contour[j];
            var prevPt = j === 0 ? firstPt : contour[j - 1];
            if (prevPt.onCurve && pt.onCurve) {
                // This is a straight line.
                p.lineTo(pt.x, pt.y);
            } else if (prevPt.onCurve && !pt.onCurve) {
                curvePt = pt;
            } else if (!prevPt.onCurve && !pt.onCurve) {
                var midPt = { x: (prevPt.x + pt.x) / 2, y: (prevPt.y + pt.y) / 2 };
                p.quadraticCurveTo(prevPt.x, prevPt.y, midPt.x, midPt.y);
                curvePt = pt;
            } else if (!prevPt.onCurve && pt.onCurve) {
                // Previous point off-curve, this point on-curve.
                p.quadraticCurveTo(curvePt.x, curvePt.y, pt.x, pt.y);
                curvePt = null;
            } else {
                throw new Error('Invalid state.');
            }
        }

        if (firstPt !== lastPt) {
            // Connect the last and first points
            if (curvePt) {
                p.quadraticCurveTo(curvePt.x, curvePt.y, firstPt.x, firstPt.y);
            } else {
                p.lineTo(firstPt.x, firstPt.y);
            }
        }
    }

    p.closePath();
    return p;
}

function buildPath(glyphs, glyph) {
    if (glyph.isComposite) {
        for (var j = 0; j < glyph.components.length; j += 1) {
            var component = glyph.components[j];
            var componentGlyph = glyphs.get(component.glyphIndex);
            if (componentGlyph.points) {
                var transformedPoints = transformPoints(componentGlyph.points, component);
                glyph.points = glyph.points.concat(transformedPoints);
            }
        }
    }

    return getPath(glyph.points);
}

// Parse all the glyphs according to the offsets from the `loca` table.
function parseGlyfTable(data, start, loca, font) {
    var glyphs = new glyphset.GlyphSet(font);
    var i;

    // The last element of the loca table is invalid.
    for (i = 0; i < loca.length - 1; i += 1) {
        var offset = loca[i];
        var nextOffset = loca[i + 1];
        if (offset !== nextOffset) {
            glyphs.push(i, glyphset.ttfGlyphLoader(font, i, parseGlyph, data, start + offset, buildPath));
        } else {
            glyphs.push(i, glyphset.glyphLoader(font, i));
        }
    }

    return glyphs;
}

exports.parse = parseGlyfTable;

},{"../check":2,"../glyphset":7,"../parse":9,"../path":10}],15:[function(_dereq_,module,exports){
// The `GPOS` table contains kerning pairs, among other things.
// https://www.microsoft.com/typography/OTSPEC/gpos.htm

'use strict';

var check = _dereq_('../check');
var parse = _dereq_('../parse');

// Parse ScriptList and FeatureList tables of GPOS, GSUB, GDEF, BASE, JSTF tables.
// These lists are unused by now, this function is just the basis for a real parsing.
function parseTaggedListTable(data, start) {
    var p = new parse.Parser(data, start);
    var n = p.parseUShort();
    var list = [];
    for (var i = 0; i < n; i++) {
        list[p.parseTag()] = { offset: p.parseUShort() };
    }

    return list;
}

// Parse a coverage table in a GSUB, GPOS or GDEF table.
// Format 1 is a simple list of glyph ids,
// Format 2 is a list of ranges. It is expanded in a list of glyphs, maybe not the best idea.
function parseCoverageTable(data, start) {
    var p = new parse.Parser(data, start);
    var format = p.parseUShort();
    var count =  p.parseUShort();
    if (format === 1) {
        return p.parseUShortList(count);
    }
    else if (format === 2) {
        var coverage = [];
        for (; count--;) {
            var begin = p.parseUShort();
            var end = p.parseUShort();
            var index = p.parseUShort();
            for (var i = begin; i <= end; i++) {
                coverage[index++] = i;
            }
        }

        return coverage;
    }
}

// Parse a Class Definition Table in a GSUB, GPOS or GDEF table.
// Returns a function that gets a class value from a glyph ID.
function parseClassDefTable(data, start) {
    var p = new parse.Parser(data, start);
    var format = p.parseUShort();
    if (format === 1) {
        // Format 1 specifies a range of consecutive glyph indices, one class per glyph ID.
        var startGlyph = p.parseUShort();
        var glyphCount = p.parseUShort();
        var classes = p.parseUShortList(glyphCount);
        return function(glyphID) {
            return classes[glyphID - startGlyph] || 0;
        };
    }
    else if (format === 2) {
        // Format 2 defines multiple groups of glyph indices that belong to the same class.
        var rangeCount = p.parseUShort();
        var startGlyphs = [];
        var endGlyphs = [];
        var classValues = [];
        for (var i = 0; i < rangeCount; i++) {
            startGlyphs[i] = p.parseUShort();
            endGlyphs[i] = p.parseUShort();
            classValues[i] = p.parseUShort();
        }

        return function(glyphID) {
            var l = 0;
            var r = startGlyphs.length - 1;
            while (l < r) {
                var c = (l + r + 1) >> 1;
                if (glyphID < startGlyphs[c]) {
                    r = c - 1;
                } else {
                    l = c;
                }
            }

            if (startGlyphs[l] <= glyphID && glyphID <= endGlyphs[l]) {
                return classValues[l] || 0;
            }

            return 0;
        };
    }
}

// Parse a pair adjustment positioning subtable, format 1 or format 2
// The subtable is returned in the form of a lookup function.
function parsePairPosSubTable(data, start) {
    var p = new parse.Parser(data, start);
    // This part is common to format 1 and format 2 subtables
    var format = p.parseUShort();
    var coverageOffset = p.parseUShort();
    var coverage = parseCoverageTable(data, start + coverageOffset);
    // valueFormat 4: XAdvance only, 1: XPlacement only, 0: no ValueRecord for second glyph
    // Only valueFormat1=4 and valueFormat2=0 is supported.
    var valueFormat1 = p.parseUShort();
    var valueFormat2 = p.parseUShort();
    var value1;
    var value2;
    if (valueFormat1 !== 4 || valueFormat2 !== 0) return;
    var sharedPairSets = {};
    if (format === 1) {
        // Pair Positioning Adjustment: Format 1
        var pairSetCount = p.parseUShort();
        var pairSet = [];
        // Array of offsets to PairSet tables-from beginning of PairPos subtable-ordered by Coverage Index
        var pairSetOffsets = p.parseOffset16List(pairSetCount);
        for (var firstGlyph = 0; firstGlyph < pairSetCount; firstGlyph++) {
            var pairSetOffset = pairSetOffsets[firstGlyph];
            var sharedPairSet = sharedPairSets[pairSetOffset];
            if (!sharedPairSet) {
                // Parse a pairset table in a pair adjustment subtable format 1
                sharedPairSet = {};
                p.relativeOffset = pairSetOffset;
                var pairValueCount = p.parseUShort();
                for (; pairValueCount--;) {
                    var secondGlyph = p.parseUShort();
                    if (valueFormat1) value1 = p.parseShort();
                    if (valueFormat2) value2 = p.parseShort();
                    // We only support valueFormat1 = 4 and valueFormat2 = 0,
                    // so value1 is the XAdvance and value2 is empty.
                    sharedPairSet[secondGlyph] = value1;
                }
            }

            pairSet[coverage[firstGlyph]] = sharedPairSet;
        }

        return function(leftGlyph, rightGlyph) {
            var pairs = pairSet[leftGlyph];
            if (pairs) return pairs[rightGlyph];
        };
    }
    else if (format === 2) {
        // Pair Positioning Adjustment: Format 2
        var classDef1Offset = p.parseUShort();
        var classDef2Offset = p.parseUShort();
        var class1Count = p.parseUShort();
        var class2Count = p.parseUShort();
        var getClass1 = parseClassDefTable(data, start + classDef1Offset);
        var getClass2 = parseClassDefTable(data, start + classDef2Offset);

        // Parse kerning values by class pair.
        var kerningMatrix = [];
        for (var i = 0; i < class1Count; i++) {
            var kerningRow = kerningMatrix[i] = [];
            for (var j = 0; j < class2Count; j++) {
                if (valueFormat1) value1 = p.parseShort();
                if (valueFormat2) value2 = p.parseShort();
                // We only support valueFormat1 = 4 and valueFormat2 = 0,
                // so value1 is the XAdvance and value2 is empty.
                kerningRow[j] = value1;
            }
        }

        // Convert coverage list to a hash
        var covered = {};
        for (i = 0; i < coverage.length; i++) covered[coverage[i]] = 1;

        // Get the kerning value for a specific glyph pair.
        return function(leftGlyph, rightGlyph) {
            if (!covered[leftGlyph]) return;
            var class1 = getClass1(leftGlyph);
            var class2 = getClass2(rightGlyph);
            var kerningRow = kerningMatrix[class1];

            if (kerningRow) {
                return kerningRow[class2];
            }
        };
    }
}

// Parse a LookupTable (present in of GPOS, GSUB, GDEF, BASE, JSTF tables).
function parseLookupTable(data, start) {
    var p = new parse.Parser(data, start);
    var lookupType = p.parseUShort();
    var lookupFlag = p.parseUShort();
    var useMarkFilteringSet = lookupFlag & 0x10;
    var subTableCount = p.parseUShort();
    var subTableOffsets = p.parseOffset16List(subTableCount);
    var table = {
        lookupType: lookupType,
        lookupFlag: lookupFlag,
        markFilteringSet: useMarkFilteringSet ? p.parseUShort() : -1
    };
    // LookupType 2, Pair adjustment
    if (lookupType === 2) {
        var subtables = [];
        for (var i = 0; i < subTableCount; i++) {
            subtables.push(parsePairPosSubTable(data, start + subTableOffsets[i]));
        }
        // Return a function which finds the kerning values in the subtables.
        table.getKerningValue = function(leftGlyph, rightGlyph) {
            for (var i = subtables.length; i--;) {
                var value = subtables[i](leftGlyph, rightGlyph);
                if (value !== undefined) return value;
            }

            return 0;
        };
    }

    return table;
}

// Parse the `GPOS` table which contains, among other things, kerning pairs.
// https://www.microsoft.com/typography/OTSPEC/gpos.htm
function parseGposTable(data, start, font) {
    var p = new parse.Parser(data, start);
    var tableVersion = p.parseFixed();
    check.argument(tableVersion === 1, 'Unsupported GPOS table version.');

    // ScriptList and FeatureList - ignored for now
    parseTaggedListTable(data, start + p.parseUShort());
    // 'kern' is the feature we are looking for.
    parseTaggedListTable(data, start + p.parseUShort());

    // LookupList
    var lookupListOffset = p.parseUShort();
    p.relativeOffset = lookupListOffset;
    var lookupCount = p.parseUShort();
    var lookupTableOffsets = p.parseOffset16List(lookupCount);
    var lookupListAbsoluteOffset = start + lookupListOffset;
    for (var i = 0; i < lookupCount; i++) {
        var table = parseLookupTable(data, lookupListAbsoluteOffset + lookupTableOffsets[i]);
        if (table.lookupType === 2 && !font.getGposKerningValue) font.getGposKerningValue = table.getKerningValue;
    }
}

exports.parse = parseGposTable;

},{"../check":2,"../parse":9}],16:[function(_dereq_,module,exports){
// The `head` table contains global information about the font.
// https://www.microsoft.com/typography/OTSPEC/head.htm

'use strict';

var check = _dereq_('../check');
var parse = _dereq_('../parse');
var table = _dereq_('../table');

// Parse the header `head` table
function parseHeadTable(data, start) {
    var head = {};
    var p = new parse.Parser(data, start);
    head.version = p.parseVersion();
    head.fontRevision = Math.round(p.parseFixed() * 1000) / 1000;
    head.checkSumAdjustment = p.parseULong();
    head.magicNumber = p.parseULong();
    check.argument(head.magicNumber === 0x5F0F3CF5, 'Font header has wrong magic number.');
    head.flags = p.parseUShort();
    head.unitsPerEm = p.parseUShort();
    head.created = p.parseLongDateTime();
    head.modified = p.parseLongDateTime();
    head.xMin = p.parseShort();
    head.yMin = p.parseShort();
    head.xMax = p.parseShort();
    head.yMax = p.parseShort();
    head.macStyle = p.parseUShort();
    head.lowestRecPPEM = p.parseUShort();
    head.fontDirectionHint = p.parseShort();
    head.indexToLocFormat = p.parseShort();     // 50
    head.glyphDataFormat = p.parseShort();
    return head;
}

function makeHeadTable(options) {
    return new table.Table('head', [
        {name: 'version', type: 'FIXED', value: 0x00010000},
        {name: 'fontRevision', type: 'FIXED', value: 0x00010000},
        {name: 'checkSumAdjustment', type: 'ULONG', value: 0},
        {name: 'magicNumber', type: 'ULONG', value: 0x5F0F3CF5},
        {name: 'flags', type: 'USHORT', value: 0},
        {name: 'unitsPerEm', type: 'USHORT', value: 1000},
        {name: 'created', type: 'LONGDATETIME', value: 0},
        {name: 'modified', type: 'LONGDATETIME', value: 0},
        {name: 'xMin', type: 'SHORT', value: 0},
        {name: 'yMin', type: 'SHORT', value: 0},
        {name: 'xMax', type: 'SHORT', value: 0},
        {name: 'yMax', type: 'SHORT', value: 0},
        {name: 'macStyle', type: 'USHORT', value: 0},
        {name: 'lowestRecPPEM', type: 'USHORT', value: 0},
        {name: 'fontDirectionHint', type: 'SHORT', value: 2},
        {name: 'indexToLocFormat', type: 'SHORT', value: 0},
        {name: 'glyphDataFormat', type: 'SHORT', value: 0}
    ], options);
}

exports.parse = parseHeadTable;
exports.make = makeHeadTable;

},{"../check":2,"../parse":9,"../table":11}],17:[function(_dereq_,module,exports){
// The `hhea` table contains information for horizontal layout.
// https://www.microsoft.com/typography/OTSPEC/hhea.htm

'use strict';

var parse = _dereq_('../parse');
var table = _dereq_('../table');

// Parse the horizontal header `hhea` table
function parseHheaTable(data, start) {
    var hhea = {};
    var p = new parse.Parser(data, start);
    hhea.version = p.parseVersion();
    hhea.ascender = p.parseShort();
    hhea.descender = p.parseShort();
    hhea.lineGap = p.parseShort();
    hhea.advanceWidthMax = p.parseUShort();
    hhea.minLeftSideBearing = p.parseShort();
    hhea.minRightSideBearing = p.parseShort();
    hhea.xMaxExtent = p.parseShort();
    hhea.caretSlopeRise = p.parseShort();
    hhea.caretSlopeRun = p.parseShort();
    hhea.caretOffset = p.parseShort();
    p.relativeOffset += 8;
    hhea.metricDataFormat = p.parseShort();
    hhea.numberOfHMetrics = p.parseUShort();
    return hhea;
}

function makeHheaTable(options) {
    return new table.Table('hhea', [
        {name: 'version', type: 'FIXED', value: 0x00010000},
        {name: 'ascender', type: 'FWORD', value: 0},
        {name: 'descender', type: 'FWORD', value: 0},
        {name: 'lineGap', type: 'FWORD', value: 0},
        {name: 'advanceWidthMax', type: 'UFWORD', value: 0},
        {name: 'minLeftSideBearing', type: 'FWORD', value: 0},
        {name: 'minRightSideBearing', type: 'FWORD', value: 0},
        {name: 'xMaxExtent', type: 'FWORD', value: 0},
        {name: 'caretSlopeRise', type: 'SHORT', value: 1},
        {name: 'caretSlopeRun', type: 'SHORT', value: 0},
        {name: 'caretOffset', type: 'SHORT', value: 0},
        {name: 'reserved1', type: 'SHORT', value: 0},
        {name: 'reserved2', type: 'SHORT', value: 0},
        {name: 'reserved3', type: 'SHORT', value: 0},
        {name: 'reserved4', type: 'SHORT', value: 0},
        {name: 'metricDataFormat', type: 'SHORT', value: 0},
        {name: 'numberOfHMetrics', type: 'USHORT', value: 0}
    ], options);
}

exports.parse = parseHheaTable;
exports.make = makeHheaTable;

},{"../parse":9,"../table":11}],18:[function(_dereq_,module,exports){
// The `hmtx` table contains the horizontal metrics for all glyphs.
// https://www.microsoft.com/typography/OTSPEC/hmtx.htm

'use strict';

var parse = _dereq_('../parse');
var table = _dereq_('../table');

// Parse the `hmtx` table, which contains the horizontal metrics for all glyphs.
// This function augments the glyph array, adding the advanceWidth and leftSideBearing to each glyph.
function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) {
    var advan
Download .txt
gitextract_v0gih5tc/

├── .gitignore
├── Applications.md
├── README.md
├── bridge.js
├── p5-ableton/
│   ├── basic-percussion/
│   │   ├── Ableton Project Info/
│   │   │   └── Project8_1.cfg
│   │   ├── Icon
│   │   ├── basic-percussion.als
│   │   └── receive-osc.amxd
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-basic/
│   ├── ProcessingOSC/
│   │   └── ProcessingOSC.pde
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-faceOsc/
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-faceOsc-flocking/
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
├── p5-kinect/
│   ├── index.html
│   ├── libraries/
│   │   ├── p5.dom.js
│   │   ├── p5.js
│   │   ├── p5.sound.js
│   │   └── socket.io.js
│   └── sketch.js
└── package.json
Download .txt
SYMBOL INDEX (835 symbols across 20 files)

FILE: p5-ableton/libraries/p5.dom.js
  function getContainer (line 158) | function getContainer(p) {
  function wrapElement (line 174) | function wrapElement(elt) {
  function addElement (line 224) | function addElement(elt, pInst, media) {
  function handleFileSelect (line 706) | function handleFileSelect(evt) {
  function createMedia (line 744) | function createMedia(pInst, type, src, callback) {

FILE: p5-ableton/libraries/p5.js
  function s (line 2) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
  function line (line 27) | function line(ctx, x1, y1, x2, y2) {
  function DefaultEncoding (line 163) | function DefaultEncoding(font) {
  function CmapEncoding (line 184) | function CmapEncoding(cmap) {
  function CffEncoding (line 192) | function CffEncoding(encoding, charset) {
  function GlyphNames (line 203) | function GlyphNames(post) {
  function addGlyphNames (line 241) | function addGlyphNames(font) {
  function Font (line 286) | function Font(options) {
  function assert (line 486) | function assert(predicate, message) {
  function assertStringAttribute (line 492) | function assertStringAttribute(attrName) {
  function getPathDefinition (line 562) | function getPathDefinition(glyph, path) {
  function Glyph (line 586) | function Glyph(options) {
  function drawCircles (line 745) | function drawCircles(l, x, y, scale) {
  function GlyphSet (line 840) | function GlyphSet(font, glyphs) {
  function glyphLoader (line 865) | function glyphLoader(font, index) {
  function ttfGlyphLoader (line 875) | function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPa...
  function cffGlyphLoader (line 890) | function cffGlyphLoader(font, index, parseCFFCharstring, charstring) {
  function toArrayBuffer (line 942) | function toArrayBuffer(buffer) {
  function loadFromFile (line 952) | function loadFromFile(path, callback) {
  function loadFromUrl (line 963) | function loadFromUrl(url, callback) {
  function parseBuffer (line 983) | function parseBuffer(buffer) {
  function load (line 1110) | function load(url, callback) {
  function Parser (line 1229) | function Parser(data, offset) {
  function Path (line 1355) | function Path() {
  function floatToString (line 1452) | function floatToString(v) {
  function packValues (line 1460) | function packValues() {
  function Table (line 1527) | function Table(tableName, fields, options) {
  function equals (line 1590) | function equals(a, b) {
  function parseCFFIndex (line 1612) | function parseCFFIndex(data, start, conversionFn) {
  function parseFloatOperand (line 1648) | function parseFloatOperand(parser) {
  function parseOperand (line 1674) | function parseOperand(parser, b0) {
  function entriesToObject (line 1716) | function entriesToObject(entries) {
  function parseCFFDict (line 1740) | function parseCFFDict(data, start, size) {
  function getCFFString (line 1772) | function getCFFString(strings, index) {
  function interpretDict (line 1784) | function interpretDict(dict, meta, strings) {
  function parseCFFHeader (line 1807) | function parseCFFHeader(data, start) {
  function parseCFFTopDict (line 1850) | function parseCFFTopDict(data, strings) {
  function parseCFFPrivateDict (line 1856) | function parseCFFPrivateDict(data, start, size, strings) {
  function parseCFFCharset (line 1864) | function parseCFFCharset(data, start, nGlyphs, strings) {
  function parseCFFEncoding (line 1907) | function parseCFFEncoding(data, start, charset) {
  function parseCFFCharstring (line 1940) | function parseCFFCharstring(font, glyph, code) {
  function calcCFFSubroutineBias (line 2345) | function calcCFFSubroutineBias(subrs) {
  function parseCFFTable (line 2359) | function parseCFFTable(data, start, font) {
  function encodeString (line 2413) | function encodeString(s, strings) {
  function makeHeader (line 2434) | function makeHeader() {
  function makeNameIndex (line 2443) | function makeNameIndex(fontNames) {
  function makeDict (line 2456) | function makeDict(meta, attrs, strings) {
  function makeTopDict (line 2474) | function makeTopDict(attrs, strings) {
  function makeTopDictIndex (line 2482) | function makeTopDictIndex(topDict) {
  function makeStringIndex (line 2490) | function makeStringIndex(strings) {
  function makeGlobalSubrIndex (line 2502) | function makeGlobalSubrIndex() {
  function makeCharsets (line 2509) | function makeCharsets(glyphNames, strings) {
  function glyphToOps (line 2522) | function glyphToOps(glyph) {
  function makeCharStringsIndex (line 2591) | function makeCharStringsIndex(glyphs) {
  function makePrivateDict (line 2605) | function makePrivateDict(attrs, strings) {
  function makePrivateDictIndex (line 2613) | function makePrivateDictIndex(privateDict) {
  function makeCFFTable (line 2621) | function makeCFFTable(glyphs, options) {
  function parseCmapTable (line 2710) | function parseCmapTable(data, start) {
  function addSegment (line 2790) | function addSegment(t, code, glyphIndex) {
  function addTerminatorSegment (line 2799) | function addTerminatorSegment(t) {
  function makeCmapTable (line 2808) | function makeCmapTable(glyphs) {
  function parseGlyphCoordinate (line 2897) | function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask...
  function parseGlyph (line 2923) | function parseGlyph(glyph, data, start) {
  function transformPoints (line 3047) | function transformPoints(points, transform) {
  function getContours (line 3063) | function getContours(points) {
  function getPath (line 3080) | function getPath(points) {
  function buildPath (line 3150) | function buildPath(glyphs, glyph) {
  function parseGlyfTable (line 3166) | function parseGlyfTable(data, start, loca, font) {
  function parseTaggedListTable (line 3197) | function parseTaggedListTable(data, start) {
  function parseCoverageTable (line 3211) | function parseCoverageTable(data, start) {
  function parseClassDefTable (line 3235) | function parseClassDefTable(data, start) {
  function parsePairPosSubTable (line 3282) | function parsePairPosSubTable(data, start) {
  function parseLookupTable (line 3369) | function parseLookupTable(data, start) {
  function parseGposTable (line 3403) | function parseGposTable(data, start, font) {
  function parseHeadTable (line 3438) | function parseHeadTable(data, start) {
  function makeHeadTable (line 3462) | function makeHeadTable(options) {
  function parseHheaTable (line 3497) | function parseHheaTable(data, start) {
  function makeHheaTable (line 3517) | function makeHheaTable(options) {
  function parseHmtxTable (line 3553) | function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) {
  function makeHmtxTable (line 3570) | function makeHmtxTable(glyphs) {
  function parseKernTable (line 3597) | function parseKernTable(data, start) {
  function parseLocaTable (line 3637) | function parseLocaTable(data, start, numGlyphs, shortVersion) {
  function parseMaxpTable (line 3669) | function parseMaxpTable(data, start) {
  function makeMaxpTable (line 3693) | function makeMaxpTable(numGlyphs) {
  function parseNameTable (line 3743) | function parseNameTable(data, start) {
  function makeNameRecord (line 3787) | function makeNameRecord(platformID, encodingID, languageID, nameID, leng...
  function addMacintoshNameRecord (line 3798) | function addMacintoshNameRecord(t, recordID, s, offset) {
  function addWindowsNameRecord (line 3807) | function addWindowsNameRecord(t, recordID, s, offset) {
  function makeNameTable (line 3816) | function makeNameTable(options) {
  function getUnicodeRange (line 3993) | function getUnicodeRange(unicode) {
  function parseOS2Table (line 4005) | function parseOS2Table(data, start) {
  function makeOS2Table (line 4058) | function makeOS2Table(options) {
  function parsePostTable (line 4125) | function parsePostTable(data, start) {
  function makePostTable (line 4170) | function makePostTable() {
  function log2 (line 4209) | function log2(v) {
  function computeCheckSum (line 4213) | function computeCheckSum(bytes) {
  function makeTableRecord (line 4230) | function makeTableRecord(tag, checkSum, offset, length) {
  function makeSfntTable (line 4239) | function makeSfntTable(tables) {
  function metricsForChar (line 4295) | function metricsForChar(font, chars, notFoundMetrics) {
  function average (line 4307) | function average(vs) {
  function fontToSfntTable (line 4318) | function fontToSfntTable(font) {
  function constant (line 4506) | function constant(v) {
  function succeed (line 4977) | function succeed(r) {
  function handleReadyState (line 4983) | function handleReadyState(r, success, error) {
  function setHeaders (line 4998) | function setHeaders(http, o) {
  function setCredentials (line 5014) | function setCredentials(http, o) {
  function generalCallback (line 5020) | function generalCallback(data) {
  function urlappend (line 5024) | function urlappend (url, s) {
  function handleJsonp (line 5028) | function handleJsonp(o, fn, err, url) {
  function getRequest (line 5088) | function getRequest(fn, err) {
  function Reqwest (line 5136) | function Reqwest(o, fn) {
  function setType (line 5143) | function setType(header) {
  function init (line 5151) | function init(o, fn) {
  function reqwest (line 5333) | function reqwest(o, fn) {
  function normalize (line 5338) | function normalize(s) {
  function serial (line 5342) | function serial(el, cb) {
  function eachFormElement (line 5384) | function eachFormElement() {
  function serializeQueryString (line 5403) | function serializeQueryString() {
  function serializeHash (line 5408) | function serializeHash() {
  function buildParams (line 5469) | function buildParams(prefix, obj, traditional, add) {
  function _isPowerOf2 (line 6764) | function _isPowerOf2 (value){
  function flatten (line 7171) | function flatten(arr){
  function turnVectorArrayIntoNumberArray (line 7184) | function turnVectorArrayIntoNumberArray(arr){
  function launchFullscreen (line 12821) | function launchFullscreen(element) {
  function exitFullscreen (line 12840) | function exitFullscreen() {
  function typeMatches (line 12979) | function typeMatches(defType, argType, arg) {
  function report (line 13006) | function report(message, func, color) {
  function friendlyWelcome (line 13154) | function friendlyWelcome() {
  function makeLoader (line 13658) | function makeLoader(theFile) {
  function attachListener (line 13723) | function attachListener(ev, fxn, ctx) {
  function calculateOffset (line 14011) | function calculateOffset(object) {
  function getMousePos (line 18115) | function getMousePos(canvas, evt) {
  function getTouchInfo (line 18569) | function getTouchInfo(canvas, e, i) {
  function buildBlurKernel (line 19225) | function buildBlurKernel(r) {
  function blurARGB (line 19261) | function blurARGB(canvas, radius) {
  function _sAssign (line 19775) | function _sAssign(sVal, iVal) {
  function makeObject (line 21730) | function makeObject(row, headers) {
  function escapeHelper (line 22285) | function escapeHelper(content) {
  function _checkFileExtension (line 22476) | function _checkFileExtension(filename, extension) {
  function destroyClickedElement (line 22518) | function destroyClickedElement(event) {
  function cacheKey (line 27104) | function cacheKey() {
  function doNf (line 27916) | function doNf() {
  function doNfc (line 27996) | function doNfc() {
  function addNfp (line 28066) | function addNfp() {
  function addNfs (line 28119) | function addNfs() {

FILE: p5-ableton/libraries/p5.sound.js
  function fixSetTarget (line 86) | function fixSetTarget(param) {
  function getPeaksAtThreshold (line 1808) | function getPeaksAtThreshold(data, threshold) {
  function countIntervalsBetweenNearbyPeaks (line 1824) | function countIntervalsBetweenNearbyPeaks(peaksObj) {
  function groupNeighborsByTempo (line 1860) | function groupNeighborsByTempo(intervalCounts, sampleRate) {
  function getPeaksAtTopTempo (line 1887) | function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) {
  function mapTempo (line 1914) | function mapTempo(theoreticalTempo) {
  function isUndef (line 2711) | function isUndef(val) {
  function TempConstructor (line 2972) | function TempConstructor() {
  function createDCOffset (line 4460) | function createDCOffset() {
  function playNextPart (line 6570) | function playNextPart(aScore) {
  function interleave (line 6846) | function interleave(leftChannel, rightChannel) {
  function writeUTFBytes (line 6857) | function writeUTFBytes(view, offset, string) {

FILE: p5-ableton/sketch.js
  function setup (line 15) | function setup() {
  function draw (line 27) | function draw() {
  function receiveOsc (line 52) | function receiveOsc(address, value) {
  function sendOsc (line 56) | function sendOsc(address, value) {
  function setupOsc (line 62) | function setupOsc(oscPortIn, oscPortOut) {

FILE: p5-basic/libraries/p5.dom.js
  function getContainer (line 158) | function getContainer(p) {
  function wrapElement (line 174) | function wrapElement(elt) {
  function addElement (line 224) | function addElement(elt, pInst, media) {
  function handleFileSelect (line 706) | function handleFileSelect(evt) {
  function createMedia (line 744) | function createMedia(pInst, type, src, callback) {

FILE: p5-basic/libraries/p5.js
  function s (line 2) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
  function line (line 27) | function line(ctx, x1, y1, x2, y2) {
  function DefaultEncoding (line 163) | function DefaultEncoding(font) {
  function CmapEncoding (line 184) | function CmapEncoding(cmap) {
  function CffEncoding (line 192) | function CffEncoding(encoding, charset) {
  function GlyphNames (line 203) | function GlyphNames(post) {
  function addGlyphNames (line 241) | function addGlyphNames(font) {
  function Font (line 286) | function Font(options) {
  function assert (line 486) | function assert(predicate, message) {
  function assertStringAttribute (line 492) | function assertStringAttribute(attrName) {
  function getPathDefinition (line 562) | function getPathDefinition(glyph, path) {
  function Glyph (line 586) | function Glyph(options) {
  function drawCircles (line 745) | function drawCircles(l, x, y, scale) {
  function GlyphSet (line 840) | function GlyphSet(font, glyphs) {
  function glyphLoader (line 865) | function glyphLoader(font, index) {
  function ttfGlyphLoader (line 875) | function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPa...
  function cffGlyphLoader (line 890) | function cffGlyphLoader(font, index, parseCFFCharstring, charstring) {
  function toArrayBuffer (line 942) | function toArrayBuffer(buffer) {
  function loadFromFile (line 952) | function loadFromFile(path, callback) {
  function loadFromUrl (line 963) | function loadFromUrl(url, callback) {
  function parseBuffer (line 983) | function parseBuffer(buffer) {
  function load (line 1110) | function load(url, callback) {
  function Parser (line 1229) | function Parser(data, offset) {
  function Path (line 1355) | function Path() {
  function floatToString (line 1452) | function floatToString(v) {
  function packValues (line 1460) | function packValues() {
  function Table (line 1527) | function Table(tableName, fields, options) {
  function equals (line 1590) | function equals(a, b) {
  function parseCFFIndex (line 1612) | function parseCFFIndex(data, start, conversionFn) {
  function parseFloatOperand (line 1648) | function parseFloatOperand(parser) {
  function parseOperand (line 1674) | function parseOperand(parser, b0) {
  function entriesToObject (line 1716) | function entriesToObject(entries) {
  function parseCFFDict (line 1740) | function parseCFFDict(data, start, size) {
  function getCFFString (line 1772) | function getCFFString(strings, index) {
  function interpretDict (line 1784) | function interpretDict(dict, meta, strings) {
  function parseCFFHeader (line 1807) | function parseCFFHeader(data, start) {
  function parseCFFTopDict (line 1850) | function parseCFFTopDict(data, strings) {
  function parseCFFPrivateDict (line 1856) | function parseCFFPrivateDict(data, start, size, strings) {
  function parseCFFCharset (line 1864) | function parseCFFCharset(data, start, nGlyphs, strings) {
  function parseCFFEncoding (line 1907) | function parseCFFEncoding(data, start, charset) {
  function parseCFFCharstring (line 1940) | function parseCFFCharstring(font, glyph, code) {
  function calcCFFSubroutineBias (line 2345) | function calcCFFSubroutineBias(subrs) {
  function parseCFFTable (line 2359) | function parseCFFTable(data, start, font) {
  function encodeString (line 2413) | function encodeString(s, strings) {
  function makeHeader (line 2434) | function makeHeader() {
  function makeNameIndex (line 2443) | function makeNameIndex(fontNames) {
  function makeDict (line 2456) | function makeDict(meta, attrs, strings) {
  function makeTopDict (line 2474) | function makeTopDict(attrs, strings) {
  function makeTopDictIndex (line 2482) | function makeTopDictIndex(topDict) {
  function makeStringIndex (line 2490) | function makeStringIndex(strings) {
  function makeGlobalSubrIndex (line 2502) | function makeGlobalSubrIndex() {
  function makeCharsets (line 2509) | function makeCharsets(glyphNames, strings) {
  function glyphToOps (line 2522) | function glyphToOps(glyph) {
  function makeCharStringsIndex (line 2591) | function makeCharStringsIndex(glyphs) {
  function makePrivateDict (line 2605) | function makePrivateDict(attrs, strings) {
  function makePrivateDictIndex (line 2613) | function makePrivateDictIndex(privateDict) {
  function makeCFFTable (line 2621) | function makeCFFTable(glyphs, options) {
  function parseCmapTable (line 2710) | function parseCmapTable(data, start) {
  function addSegment (line 2790) | function addSegment(t, code, glyphIndex) {
  function addTerminatorSegment (line 2799) | function addTerminatorSegment(t) {
  function makeCmapTable (line 2808) | function makeCmapTable(glyphs) {
  function parseGlyphCoordinate (line 2897) | function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask...
  function parseGlyph (line 2923) | function parseGlyph(glyph, data, start) {
  function transformPoints (line 3047) | function transformPoints(points, transform) {
  function getContours (line 3063) | function getContours(points) {
  function getPath (line 3080) | function getPath(points) {
  function buildPath (line 3150) | function buildPath(glyphs, glyph) {
  function parseGlyfTable (line 3166) | function parseGlyfTable(data, start, loca, font) {
  function parseTaggedListTable (line 3197) | function parseTaggedListTable(data, start) {
  function parseCoverageTable (line 3211) | function parseCoverageTable(data, start) {
  function parseClassDefTable (line 3235) | function parseClassDefTable(data, start) {
  function parsePairPosSubTable (line 3282) | function parsePairPosSubTable(data, start) {
  function parseLookupTable (line 3369) | function parseLookupTable(data, start) {
  function parseGposTable (line 3403) | function parseGposTable(data, start, font) {
  function parseHeadTable (line 3438) | function parseHeadTable(data, start) {
  function makeHeadTable (line 3462) | function makeHeadTable(options) {
  function parseHheaTable (line 3497) | function parseHheaTable(data, start) {
  function makeHheaTable (line 3517) | function makeHheaTable(options) {
  function parseHmtxTable (line 3553) | function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) {
  function makeHmtxTable (line 3570) | function makeHmtxTable(glyphs) {
  function parseKernTable (line 3597) | function parseKernTable(data, start) {
  function parseLocaTable (line 3637) | function parseLocaTable(data, start, numGlyphs, shortVersion) {
  function parseMaxpTable (line 3669) | function parseMaxpTable(data, start) {
  function makeMaxpTable (line 3693) | function makeMaxpTable(numGlyphs) {
  function parseNameTable (line 3743) | function parseNameTable(data, start) {
  function makeNameRecord (line 3787) | function makeNameRecord(platformID, encodingID, languageID, nameID, leng...
  function addMacintoshNameRecord (line 3798) | function addMacintoshNameRecord(t, recordID, s, offset) {
  function addWindowsNameRecord (line 3807) | function addWindowsNameRecord(t, recordID, s, offset) {
  function makeNameTable (line 3816) | function makeNameTable(options) {
  function getUnicodeRange (line 3993) | function getUnicodeRange(unicode) {
  function parseOS2Table (line 4005) | function parseOS2Table(data, start) {
  function makeOS2Table (line 4058) | function makeOS2Table(options) {
  function parsePostTable (line 4125) | function parsePostTable(data, start) {
  function makePostTable (line 4170) | function makePostTable() {
  function log2 (line 4209) | function log2(v) {
  function computeCheckSum (line 4213) | function computeCheckSum(bytes) {
  function makeTableRecord (line 4230) | function makeTableRecord(tag, checkSum, offset, length) {
  function makeSfntTable (line 4239) | function makeSfntTable(tables) {
  function metricsForChar (line 4295) | function metricsForChar(font, chars, notFoundMetrics) {
  function average (line 4307) | function average(vs) {
  function fontToSfntTable (line 4318) | function fontToSfntTable(font) {
  function constant (line 4506) | function constant(v) {
  function succeed (line 4977) | function succeed(r) {
  function handleReadyState (line 4983) | function handleReadyState(r, success, error) {
  function setHeaders (line 4998) | function setHeaders(http, o) {
  function setCredentials (line 5014) | function setCredentials(http, o) {
  function generalCallback (line 5020) | function generalCallback(data) {
  function urlappend (line 5024) | function urlappend (url, s) {
  function handleJsonp (line 5028) | function handleJsonp(o, fn, err, url) {
  function getRequest (line 5088) | function getRequest(fn, err) {
  function Reqwest (line 5136) | function Reqwest(o, fn) {
  function setType (line 5143) | function setType(header) {
  function init (line 5151) | function init(o, fn) {
  function reqwest (line 5333) | function reqwest(o, fn) {
  function normalize (line 5338) | function normalize(s) {
  function serial (line 5342) | function serial(el, cb) {
  function eachFormElement (line 5384) | function eachFormElement() {
  function serializeQueryString (line 5403) | function serializeQueryString() {
  function serializeHash (line 5408) | function serializeHash() {
  function buildParams (line 5469) | function buildParams(prefix, obj, traditional, add) {
  function _isPowerOf2 (line 6764) | function _isPowerOf2 (value){
  function flatten (line 7171) | function flatten(arr){
  function turnVectorArrayIntoNumberArray (line 7184) | function turnVectorArrayIntoNumberArray(arr){
  function launchFullscreen (line 12821) | function launchFullscreen(element) {
  function exitFullscreen (line 12840) | function exitFullscreen() {
  function typeMatches (line 12979) | function typeMatches(defType, argType, arg) {
  function report (line 13006) | function report(message, func, color) {
  function friendlyWelcome (line 13154) | function friendlyWelcome() {
  function makeLoader (line 13658) | function makeLoader(theFile) {
  function attachListener (line 13723) | function attachListener(ev, fxn, ctx) {
  function calculateOffset (line 14011) | function calculateOffset(object) {
  function getMousePos (line 18115) | function getMousePos(canvas, evt) {
  function getTouchInfo (line 18569) | function getTouchInfo(canvas, e, i) {
  function buildBlurKernel (line 19225) | function buildBlurKernel(r) {
  function blurARGB (line 19261) | function blurARGB(canvas, radius) {
  function _sAssign (line 19775) | function _sAssign(sVal, iVal) {
  function makeObject (line 21730) | function makeObject(row, headers) {
  function escapeHelper (line 22285) | function escapeHelper(content) {
  function _checkFileExtension (line 22476) | function _checkFileExtension(filename, extension) {
  function destroyClickedElement (line 22518) | function destroyClickedElement(event) {
  function cacheKey (line 27104) | function cacheKey() {
  function doNf (line 27916) | function doNf() {
  function doNfc (line 27996) | function doNfc() {
  function addNfp (line 28066) | function addNfp() {
  function addNfs (line 28119) | function addNfs() {

FILE: p5-basic/libraries/p5.sound.js
  function fixSetTarget (line 86) | function fixSetTarget(param) {
  function getPeaksAtThreshold (line 1808) | function getPeaksAtThreshold(data, threshold) {
  function countIntervalsBetweenNearbyPeaks (line 1824) | function countIntervalsBetweenNearbyPeaks(peaksObj) {
  function groupNeighborsByTempo (line 1860) | function groupNeighborsByTempo(intervalCounts, sampleRate) {
  function getPeaksAtTopTempo (line 1887) | function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) {
  function mapTempo (line 1914) | function mapTempo(theoreticalTempo) {
  function isUndef (line 2711) | function isUndef(val) {
  function TempConstructor (line 2972) | function TempConstructor() {
  function createDCOffset (line 4460) | function createDCOffset() {
  function playNextPart (line 6570) | function playNextPart(aScore) {
  function interleave (line 6846) | function interleave(leftChannel, rightChannel) {
  function writeUTFBytes (line 6857) | function writeUTFBytes(view, offset, string) {

FILE: p5-basic/sketch.js
  function setup (line 3) | function setup() {
  function draw (line 8) | function draw() {
  function receiveOsc (line 16) | function receiveOsc(address, value) {
  function sendOsc (line 25) | function sendOsc(address, value) {
  function setupOsc (line 29) | function setupOsc(oscPortIn, oscPortOut) {

FILE: p5-faceOsc-flocking/libraries/p5.dom.js
  function getContainer (line 158) | function getContainer(p) {
  function wrapElement (line 174) | function wrapElement(elt) {
  function addElement (line 224) | function addElement(elt, pInst, media) {
  function handleFileSelect (line 706) | function handleFileSelect(evt) {
  function createMedia (line 744) | function createMedia(pInst, type, src, callback) {

FILE: p5-faceOsc-flocking/libraries/p5.js
  function s (line 2) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
  function line (line 27) | function line(ctx, x1, y1, x2, y2) {
  function DefaultEncoding (line 163) | function DefaultEncoding(font) {
  function CmapEncoding (line 184) | function CmapEncoding(cmap) {
  function CffEncoding (line 192) | function CffEncoding(encoding, charset) {
  function GlyphNames (line 203) | function GlyphNames(post) {
  function addGlyphNames (line 241) | function addGlyphNames(font) {
  function Font (line 286) | function Font(options) {
  function assert (line 486) | function assert(predicate, message) {
  function assertStringAttribute (line 492) | function assertStringAttribute(attrName) {
  function getPathDefinition (line 562) | function getPathDefinition(glyph, path) {
  function Glyph (line 586) | function Glyph(options) {
  function drawCircles (line 745) | function drawCircles(l, x, y, scale) {
  function GlyphSet (line 840) | function GlyphSet(font, glyphs) {
  function glyphLoader (line 865) | function glyphLoader(font, index) {
  function ttfGlyphLoader (line 875) | function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPa...
  function cffGlyphLoader (line 890) | function cffGlyphLoader(font, index, parseCFFCharstring, charstring) {
  function toArrayBuffer (line 942) | function toArrayBuffer(buffer) {
  function loadFromFile (line 952) | function loadFromFile(path, callback) {
  function loadFromUrl (line 963) | function loadFromUrl(url, callback) {
  function parseBuffer (line 983) | function parseBuffer(buffer) {
  function load (line 1110) | function load(url, callback) {
  function Parser (line 1229) | function Parser(data, offset) {
  function Path (line 1355) | function Path() {
  function floatToString (line 1452) | function floatToString(v) {
  function packValues (line 1460) | function packValues() {
  function Table (line 1527) | function Table(tableName, fields, options) {
  function equals (line 1590) | function equals(a, b) {
  function parseCFFIndex (line 1612) | function parseCFFIndex(data, start, conversionFn) {
  function parseFloatOperand (line 1648) | function parseFloatOperand(parser) {
  function parseOperand (line 1674) | function parseOperand(parser, b0) {
  function entriesToObject (line 1716) | function entriesToObject(entries) {
  function parseCFFDict (line 1740) | function parseCFFDict(data, start, size) {
  function getCFFString (line 1772) | function getCFFString(strings, index) {
  function interpretDict (line 1784) | function interpretDict(dict, meta, strings) {
  function parseCFFHeader (line 1807) | function parseCFFHeader(data, start) {
  function parseCFFTopDict (line 1850) | function parseCFFTopDict(data, strings) {
  function parseCFFPrivateDict (line 1856) | function parseCFFPrivateDict(data, start, size, strings) {
  function parseCFFCharset (line 1864) | function parseCFFCharset(data, start, nGlyphs, strings) {
  function parseCFFEncoding (line 1907) | function parseCFFEncoding(data, start, charset) {
  function parseCFFCharstring (line 1940) | function parseCFFCharstring(font, glyph, code) {
  function calcCFFSubroutineBias (line 2345) | function calcCFFSubroutineBias(subrs) {
  function parseCFFTable (line 2359) | function parseCFFTable(data, start, font) {
  function encodeString (line 2413) | function encodeString(s, strings) {
  function makeHeader (line 2434) | function makeHeader() {
  function makeNameIndex (line 2443) | function makeNameIndex(fontNames) {
  function makeDict (line 2456) | function makeDict(meta, attrs, strings) {
  function makeTopDict (line 2474) | function makeTopDict(attrs, strings) {
  function makeTopDictIndex (line 2482) | function makeTopDictIndex(topDict) {
  function makeStringIndex (line 2490) | function makeStringIndex(strings) {
  function makeGlobalSubrIndex (line 2502) | function makeGlobalSubrIndex() {
  function makeCharsets (line 2509) | function makeCharsets(glyphNames, strings) {
  function glyphToOps (line 2522) | function glyphToOps(glyph) {
  function makeCharStringsIndex (line 2591) | function makeCharStringsIndex(glyphs) {
  function makePrivateDict (line 2605) | function makePrivateDict(attrs, strings) {
  function makePrivateDictIndex (line 2613) | function makePrivateDictIndex(privateDict) {
  function makeCFFTable (line 2621) | function makeCFFTable(glyphs, options) {
  function parseCmapTable (line 2710) | function parseCmapTable(data, start) {
  function addSegment (line 2790) | function addSegment(t, code, glyphIndex) {
  function addTerminatorSegment (line 2799) | function addTerminatorSegment(t) {
  function makeCmapTable (line 2808) | function makeCmapTable(glyphs) {
  function parseGlyphCoordinate (line 2897) | function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask...
  function parseGlyph (line 2923) | function parseGlyph(glyph, data, start) {
  function transformPoints (line 3047) | function transformPoints(points, transform) {
  function getContours (line 3063) | function getContours(points) {
  function getPath (line 3080) | function getPath(points) {
  function buildPath (line 3150) | function buildPath(glyphs, glyph) {
  function parseGlyfTable (line 3166) | function parseGlyfTable(data, start, loca, font) {
  function parseTaggedListTable (line 3197) | function parseTaggedListTable(data, start) {
  function parseCoverageTable (line 3211) | function parseCoverageTable(data, start) {
  function parseClassDefTable (line 3235) | function parseClassDefTable(data, start) {
  function parsePairPosSubTable (line 3282) | function parsePairPosSubTable(data, start) {
  function parseLookupTable (line 3369) | function parseLookupTable(data, start) {
  function parseGposTable (line 3403) | function parseGposTable(data, start, font) {
  function parseHeadTable (line 3438) | function parseHeadTable(data, start) {
  function makeHeadTable (line 3462) | function makeHeadTable(options) {
  function parseHheaTable (line 3497) | function parseHheaTable(data, start) {
  function makeHheaTable (line 3517) | function makeHheaTable(options) {
  function parseHmtxTable (line 3553) | function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) {
  function makeHmtxTable (line 3570) | function makeHmtxTable(glyphs) {
  function parseKernTable (line 3597) | function parseKernTable(data, start) {
  function parseLocaTable (line 3637) | function parseLocaTable(data, start, numGlyphs, shortVersion) {
  function parseMaxpTable (line 3669) | function parseMaxpTable(data, start) {
  function makeMaxpTable (line 3693) | function makeMaxpTable(numGlyphs) {
  function parseNameTable (line 3743) | function parseNameTable(data, start) {
  function makeNameRecord (line 3787) | function makeNameRecord(platformID, encodingID, languageID, nameID, leng...
  function addMacintoshNameRecord (line 3798) | function addMacintoshNameRecord(t, recordID, s, offset) {
  function addWindowsNameRecord (line 3807) | function addWindowsNameRecord(t, recordID, s, offset) {
  function makeNameTable (line 3816) | function makeNameTable(options) {
  function getUnicodeRange (line 3993) | function getUnicodeRange(unicode) {
  function parseOS2Table (line 4005) | function parseOS2Table(data, start) {
  function makeOS2Table (line 4058) | function makeOS2Table(options) {
  function parsePostTable (line 4125) | function parsePostTable(data, start) {
  function makePostTable (line 4170) | function makePostTable() {
  function log2 (line 4209) | function log2(v) {
  function computeCheckSum (line 4213) | function computeCheckSum(bytes) {
  function makeTableRecord (line 4230) | function makeTableRecord(tag, checkSum, offset, length) {
  function makeSfntTable (line 4239) | function makeSfntTable(tables) {
  function metricsForChar (line 4295) | function metricsForChar(font, chars, notFoundMetrics) {
  function average (line 4307) | function average(vs) {
  function fontToSfntTable (line 4318) | function fontToSfntTable(font) {
  function constant (line 4506) | function constant(v) {
  function succeed (line 4977) | function succeed(r) {
  function handleReadyState (line 4983) | function handleReadyState(r, success, error) {
  function setHeaders (line 4998) | function setHeaders(http, o) {
  function setCredentials (line 5014) | function setCredentials(http, o) {
  function generalCallback (line 5020) | function generalCallback(data) {
  function urlappend (line 5024) | function urlappend (url, s) {
  function handleJsonp (line 5028) | function handleJsonp(o, fn, err, url) {
  function getRequest (line 5088) | function getRequest(fn, err) {
  function Reqwest (line 5136) | function Reqwest(o, fn) {
  function setType (line 5143) | function setType(header) {
  function init (line 5151) | function init(o, fn) {
  function reqwest (line 5333) | function reqwest(o, fn) {
  function normalize (line 5338) | function normalize(s) {
  function serial (line 5342) | function serial(el, cb) {
  function eachFormElement (line 5384) | function eachFormElement() {
  function serializeQueryString (line 5403) | function serializeQueryString() {
  function serializeHash (line 5408) | function serializeHash() {
  function buildParams (line 5469) | function buildParams(prefix, obj, traditional, add) {
  function _isPowerOf2 (line 6764) | function _isPowerOf2 (value){
  function flatten (line 7171) | function flatten(arr){
  function turnVectorArrayIntoNumberArray (line 7184) | function turnVectorArrayIntoNumberArray(arr){
  function launchFullscreen (line 12821) | function launchFullscreen(element) {
  function exitFullscreen (line 12840) | function exitFullscreen() {
  function typeMatches (line 12979) | function typeMatches(defType, argType, arg) {
  function report (line 13006) | function report(message, func, color) {
  function friendlyWelcome (line 13154) | function friendlyWelcome() {
  function makeLoader (line 13658) | function makeLoader(theFile) {
  function attachListener (line 13723) | function attachListener(ev, fxn, ctx) {
  function calculateOffset (line 14011) | function calculateOffset(object) {
  function getMousePos (line 18115) | function getMousePos(canvas, evt) {
  function getTouchInfo (line 18569) | function getTouchInfo(canvas, e, i) {
  function buildBlurKernel (line 19225) | function buildBlurKernel(r) {
  function blurARGB (line 19261) | function blurARGB(canvas, radius) {
  function _sAssign (line 19775) | function _sAssign(sVal, iVal) {
  function makeObject (line 21730) | function makeObject(row, headers) {
  function escapeHelper (line 22285) | function escapeHelper(content) {
  function _checkFileExtension (line 22476) | function _checkFileExtension(filename, extension) {
  function destroyClickedElement (line 22518) | function destroyClickedElement(event) {
  function cacheKey (line 27104) | function cacheKey() {
  function doNf (line 27916) | function doNf() {
  function doNfc (line 27996) | function doNfc() {
  function addNfp (line 28066) | function addNfp() {
  function addNfs (line 28119) | function addNfs() {

FILE: p5-faceOsc-flocking/libraries/p5.sound.js
  function fixSetTarget (line 86) | function fixSetTarget(param) {
  function getPeaksAtThreshold (line 1808) | function getPeaksAtThreshold(data, threshold) {
  function countIntervalsBetweenNearbyPeaks (line 1824) | function countIntervalsBetweenNearbyPeaks(peaksObj) {
  function groupNeighborsByTempo (line 1860) | function groupNeighborsByTempo(intervalCounts, sampleRate) {
  function getPeaksAtTopTempo (line 1887) | function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) {
  function mapTempo (line 1914) | function mapTempo(theoreticalTempo) {
  function isUndef (line 2711) | function isUndef(val) {
  function TempConstructor (line 2972) | function TempConstructor() {
  function createDCOffset (line 4460) | function createDCOffset() {
  function playNextPart (line 6570) | function playNextPart(aScore) {
  function interleave (line 6846) | function interleave(leftChannel, rightChannel) {
  function writeUTFBytes (line 6857) | function writeUTFBytes(view, offset, string) {

FILE: p5-faceOsc-flocking/sketch.js
  function setup (line 16) | function setup() {
  function draw (line 22) | function draw() {
  function mouseDragged (line 70) | function mouseDragged() {
  function Flock (line 81) | function Flock() {
  function Boid (line 103) | function Boid(x,y) {
  function receiveOsc (line 268) | function receiveOsc(address, value) {
  function setupOsc (line 310) | function setupOsc(oscPortIn, oscPortOut) {

FILE: p5-faceOsc/libraries/p5.dom.js
  function getContainer (line 158) | function getContainer(p) {
  function wrapElement (line 174) | function wrapElement(elt) {
  function addElement (line 224) | function addElement(elt, pInst, media) {
  function handleFileSelect (line 706) | function handleFileSelect(evt) {
  function createMedia (line 744) | function createMedia(pInst, type, src, callback) {

FILE: p5-faceOsc/libraries/p5.js
  function s (line 2) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
  function line (line 27) | function line(ctx, x1, y1, x2, y2) {
  function DefaultEncoding (line 163) | function DefaultEncoding(font) {
  function CmapEncoding (line 184) | function CmapEncoding(cmap) {
  function CffEncoding (line 192) | function CffEncoding(encoding, charset) {
  function GlyphNames (line 203) | function GlyphNames(post) {
  function addGlyphNames (line 241) | function addGlyphNames(font) {
  function Font (line 286) | function Font(options) {
  function assert (line 486) | function assert(predicate, message) {
  function assertStringAttribute (line 492) | function assertStringAttribute(attrName) {
  function getPathDefinition (line 562) | function getPathDefinition(glyph, path) {
  function Glyph (line 586) | function Glyph(options) {
  function drawCircles (line 745) | function drawCircles(l, x, y, scale) {
  function GlyphSet (line 840) | function GlyphSet(font, glyphs) {
  function glyphLoader (line 865) | function glyphLoader(font, index) {
  function ttfGlyphLoader (line 875) | function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPa...
  function cffGlyphLoader (line 890) | function cffGlyphLoader(font, index, parseCFFCharstring, charstring) {
  function toArrayBuffer (line 942) | function toArrayBuffer(buffer) {
  function loadFromFile (line 952) | function loadFromFile(path, callback) {
  function loadFromUrl (line 963) | function loadFromUrl(url, callback) {
  function parseBuffer (line 983) | function parseBuffer(buffer) {
  function load (line 1110) | function load(url, callback) {
  function Parser (line 1229) | function Parser(data, offset) {
  function Path (line 1355) | function Path() {
  function floatToString (line 1452) | function floatToString(v) {
  function packValues (line 1460) | function packValues() {
  function Table (line 1527) | function Table(tableName, fields, options) {
  function equals (line 1590) | function equals(a, b) {
  function parseCFFIndex (line 1612) | function parseCFFIndex(data, start, conversionFn) {
  function parseFloatOperand (line 1648) | function parseFloatOperand(parser) {
  function parseOperand (line 1674) | function parseOperand(parser, b0) {
  function entriesToObject (line 1716) | function entriesToObject(entries) {
  function parseCFFDict (line 1740) | function parseCFFDict(data, start, size) {
  function getCFFString (line 1772) | function getCFFString(strings, index) {
  function interpretDict (line 1784) | function interpretDict(dict, meta, strings) {
  function parseCFFHeader (line 1807) | function parseCFFHeader(data, start) {
  function parseCFFTopDict (line 1850) | function parseCFFTopDict(data, strings) {
  function parseCFFPrivateDict (line 1856) | function parseCFFPrivateDict(data, start, size, strings) {
  function parseCFFCharset (line 1864) | function parseCFFCharset(data, start, nGlyphs, strings) {
  function parseCFFEncoding (line 1907) | function parseCFFEncoding(data, start, charset) {
  function parseCFFCharstring (line 1940) | function parseCFFCharstring(font, glyph, code) {
  function calcCFFSubroutineBias (line 2345) | function calcCFFSubroutineBias(subrs) {
  function parseCFFTable (line 2359) | function parseCFFTable(data, start, font) {
  function encodeString (line 2413) | function encodeString(s, strings) {
  function makeHeader (line 2434) | function makeHeader() {
  function makeNameIndex (line 2443) | function makeNameIndex(fontNames) {
  function makeDict (line 2456) | function makeDict(meta, attrs, strings) {
  function makeTopDict (line 2474) | function makeTopDict(attrs, strings) {
  function makeTopDictIndex (line 2482) | function makeTopDictIndex(topDict) {
  function makeStringIndex (line 2490) | function makeStringIndex(strings) {
  function makeGlobalSubrIndex (line 2502) | function makeGlobalSubrIndex() {
  function makeCharsets (line 2509) | function makeCharsets(glyphNames, strings) {
  function glyphToOps (line 2522) | function glyphToOps(glyph) {
  function makeCharStringsIndex (line 2591) | function makeCharStringsIndex(glyphs) {
  function makePrivateDict (line 2605) | function makePrivateDict(attrs, strings) {
  function makePrivateDictIndex (line 2613) | function makePrivateDictIndex(privateDict) {
  function makeCFFTable (line 2621) | function makeCFFTable(glyphs, options) {
  function parseCmapTable (line 2710) | function parseCmapTable(data, start) {
  function addSegment (line 2790) | function addSegment(t, code, glyphIndex) {
  function addTerminatorSegment (line 2799) | function addTerminatorSegment(t) {
  function makeCmapTable (line 2808) | function makeCmapTable(glyphs) {
  function parseGlyphCoordinate (line 2897) | function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask...
  function parseGlyph (line 2923) | function parseGlyph(glyph, data, start) {
  function transformPoints (line 3047) | function transformPoints(points, transform) {
  function getContours (line 3063) | function getContours(points) {
  function getPath (line 3080) | function getPath(points) {
  function buildPath (line 3150) | function buildPath(glyphs, glyph) {
  function parseGlyfTable (line 3166) | function parseGlyfTable(data, start, loca, font) {
  function parseTaggedListTable (line 3197) | function parseTaggedListTable(data, start) {
  function parseCoverageTable (line 3211) | function parseCoverageTable(data, start) {
  function parseClassDefTable (line 3235) | function parseClassDefTable(data, start) {
  function parsePairPosSubTable (line 3282) | function parsePairPosSubTable(data, start) {
  function parseLookupTable (line 3369) | function parseLookupTable(data, start) {
  function parseGposTable (line 3403) | function parseGposTable(data, start, font) {
  function parseHeadTable (line 3438) | function parseHeadTable(data, start) {
  function makeHeadTable (line 3462) | function makeHeadTable(options) {
  function parseHheaTable (line 3497) | function parseHheaTable(data, start) {
  function makeHheaTable (line 3517) | function makeHheaTable(options) {
  function parseHmtxTable (line 3553) | function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) {
  function makeHmtxTable (line 3570) | function makeHmtxTable(glyphs) {
  function parseKernTable (line 3597) | function parseKernTable(data, start) {
  function parseLocaTable (line 3637) | function parseLocaTable(data, start, numGlyphs, shortVersion) {
  function parseMaxpTable (line 3669) | function parseMaxpTable(data, start) {
  function makeMaxpTable (line 3693) | function makeMaxpTable(numGlyphs) {
  function parseNameTable (line 3743) | function parseNameTable(data, start) {
  function makeNameRecord (line 3787) | function makeNameRecord(platformID, encodingID, languageID, nameID, leng...
  function addMacintoshNameRecord (line 3798) | function addMacintoshNameRecord(t, recordID, s, offset) {
  function addWindowsNameRecord (line 3807) | function addWindowsNameRecord(t, recordID, s, offset) {
  function makeNameTable (line 3816) | function makeNameTable(options) {
  function getUnicodeRange (line 3993) | function getUnicodeRange(unicode) {
  function parseOS2Table (line 4005) | function parseOS2Table(data, start) {
  function makeOS2Table (line 4058) | function makeOS2Table(options) {
  function parsePostTable (line 4125) | function parsePostTable(data, start) {
  function makePostTable (line 4170) | function makePostTable() {
  function log2 (line 4209) | function log2(v) {
  function computeCheckSum (line 4213) | function computeCheckSum(bytes) {
  function makeTableRecord (line 4230) | function makeTableRecord(tag, checkSum, offset, length) {
  function makeSfntTable (line 4239) | function makeSfntTable(tables) {
  function metricsForChar (line 4295) | function metricsForChar(font, chars, notFoundMetrics) {
  function average (line 4307) | function average(vs) {
  function fontToSfntTable (line 4318) | function fontToSfntTable(font) {
  function constant (line 4506) | function constant(v) {
  function succeed (line 4977) | function succeed(r) {
  function handleReadyState (line 4983) | function handleReadyState(r, success, error) {
  function setHeaders (line 4998) | function setHeaders(http, o) {
  function setCredentials (line 5014) | function setCredentials(http, o) {
  function generalCallback (line 5020) | function generalCallback(data) {
  function urlappend (line 5024) | function urlappend (url, s) {
  function handleJsonp (line 5028) | function handleJsonp(o, fn, err, url) {
  function getRequest (line 5088) | function getRequest(fn, err) {
  function Reqwest (line 5136) | function Reqwest(o, fn) {
  function setType (line 5143) | function setType(header) {
  function init (line 5151) | function init(o, fn) {
  function reqwest (line 5333) | function reqwest(o, fn) {
  function normalize (line 5338) | function normalize(s) {
  function serial (line 5342) | function serial(el, cb) {
  function eachFormElement (line 5384) | function eachFormElement() {
  function serializeQueryString (line 5403) | function serializeQueryString() {
  function serializeHash (line 5408) | function serializeHash() {
  function buildParams (line 5469) | function buildParams(prefix, obj, traditional, add) {
  function _isPowerOf2 (line 6764) | function _isPowerOf2 (value){
  function flatten (line 7171) | function flatten(arr){
  function turnVectorArrayIntoNumberArray (line 7184) | function turnVectorArrayIntoNumberArray(arr){
  function launchFullscreen (line 12821) | function launchFullscreen(element) {
  function exitFullscreen (line 12840) | function exitFullscreen() {
  function typeMatches (line 12979) | function typeMatches(defType, argType, arg) {
  function report (line 13006) | function report(message, func, color) {
  function friendlyWelcome (line 13154) | function friendlyWelcome() {
  function makeLoader (line 13658) | function makeLoader(theFile) {
  function attachListener (line 13723) | function attachListener(ev, fxn, ctx) {
  function calculateOffset (line 14011) | function calculateOffset(object) {
  function getMousePos (line 18115) | function getMousePos(canvas, evt) {
  function getTouchInfo (line 18569) | function getTouchInfo(canvas, e, i) {
  function buildBlurKernel (line 19225) | function buildBlurKernel(r) {
  function blurARGB (line 19261) | function blurARGB(canvas, radius) {
  function _sAssign (line 19775) | function _sAssign(sVal, iVal) {
  function makeObject (line 21730) | function makeObject(row, headers) {
  function escapeHelper (line 22285) | function escapeHelper(content) {
  function _checkFileExtension (line 22476) | function _checkFileExtension(filename, extension) {
  function destroyClickedElement (line 22518) | function destroyClickedElement(event) {
  function cacheKey (line 27104) | function cacheKey() {
  function doNf (line 27916) | function doNf() {
  function doNfc (line 27996) | function doNfc() {
  function addNfp (line 28066) | function addNfp() {
  function addNfs (line 28119) | function addNfs() {

FILE: p5-faceOsc/libraries/p5.sound.js
  function fixSetTarget (line 86) | function fixSetTarget(param) {
  function getPeaksAtThreshold (line 1808) | function getPeaksAtThreshold(data, threshold) {
  function countIntervalsBetweenNearbyPeaks (line 1824) | function countIntervalsBetweenNearbyPeaks(peaksObj) {
  function groupNeighborsByTempo (line 1860) | function groupNeighborsByTempo(intervalCounts, sampleRate) {
  function getPeaksAtTopTempo (line 1887) | function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) {
  function mapTempo (line 1914) | function mapTempo(theoreticalTempo) {
  function isUndef (line 2711) | function isUndef(val) {
  function TempConstructor (line 2972) | function TempConstructor() {
  function createDCOffset (line 4460) | function createDCOffset() {
  function playNextPart (line 6570) | function playNextPart(aScore) {
  function interleave (line 6846) | function interleave(leftChannel, rightChannel) {
  function writeUTFBytes (line 6857) | function writeUTFBytes(view, offset, string) {

FILE: p5-faceOsc/sketch.js
  function setup (line 14) | function setup() {
  function draw (line 19) | function draw() {
  function receiveOsc (line 46) | function receiveOsc(address, value) {
  function setupOsc (line 88) | function setupOsc(oscPortIn, oscPortOut) {

FILE: p5-kinect/libraries/p5.dom.js
  function getContainer (line 158) | function getContainer(p) {
  function wrapElement (line 174) | function wrapElement(elt) {
  function addElement (line 224) | function addElement(elt, pInst, media) {
  function handleFileSelect (line 706) | function handleFileSelect(evt) {
  function createMedia (line 744) | function createMedia(pInst, type, src, callback) {

FILE: p5-kinect/libraries/p5.js
  function s (line 2) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
  function line (line 27) | function line(ctx, x1, y1, x2, y2) {
  function DefaultEncoding (line 163) | function DefaultEncoding(font) {
  function CmapEncoding (line 184) | function CmapEncoding(cmap) {
  function CffEncoding (line 192) | function CffEncoding(encoding, charset) {
  function GlyphNames (line 203) | function GlyphNames(post) {
  function addGlyphNames (line 241) | function addGlyphNames(font) {
  function Font (line 286) | function Font(options) {
  function assert (line 486) | function assert(predicate, message) {
  function assertStringAttribute (line 492) | function assertStringAttribute(attrName) {
  function getPathDefinition (line 562) | function getPathDefinition(glyph, path) {
  function Glyph (line 586) | function Glyph(options) {
  function drawCircles (line 745) | function drawCircles(l, x, y, scale) {
  function GlyphSet (line 840) | function GlyphSet(font, glyphs) {
  function glyphLoader (line 865) | function glyphLoader(font, index) {
  function ttfGlyphLoader (line 875) | function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPa...
  function cffGlyphLoader (line 890) | function cffGlyphLoader(font, index, parseCFFCharstring, charstring) {
  function toArrayBuffer (line 942) | function toArrayBuffer(buffer) {
  function loadFromFile (line 952) | function loadFromFile(path, callback) {
  function loadFromUrl (line 963) | function loadFromUrl(url, callback) {
  function parseBuffer (line 983) | function parseBuffer(buffer) {
  function load (line 1110) | function load(url, callback) {
  function Parser (line 1229) | function Parser(data, offset) {
  function Path (line 1355) | function Path() {
  function floatToString (line 1452) | function floatToString(v) {
  function packValues (line 1460) | function packValues() {
  function Table (line 1527) | function Table(tableName, fields, options) {
  function equals (line 1590) | function equals(a, b) {
  function parseCFFIndex (line 1612) | function parseCFFIndex(data, start, conversionFn) {
  function parseFloatOperand (line 1648) | function parseFloatOperand(parser) {
  function parseOperand (line 1674) | function parseOperand(parser, b0) {
  function entriesToObject (line 1716) | function entriesToObject(entries) {
  function parseCFFDict (line 1740) | function parseCFFDict(data, start, size) {
  function getCFFString (line 1772) | function getCFFString(strings, index) {
  function interpretDict (line 1784) | function interpretDict(dict, meta, strings) {
  function parseCFFHeader (line 1807) | function parseCFFHeader(data, start) {
  function parseCFFTopDict (line 1850) | function parseCFFTopDict(data, strings) {
  function parseCFFPrivateDict (line 1856) | function parseCFFPrivateDict(data, start, size, strings) {
  function parseCFFCharset (line 1864) | function parseCFFCharset(data, start, nGlyphs, strings) {
  function parseCFFEncoding (line 1907) | function parseCFFEncoding(data, start, charset) {
  function parseCFFCharstring (line 1940) | function parseCFFCharstring(font, glyph, code) {
  function calcCFFSubroutineBias (line 2345) | function calcCFFSubroutineBias(subrs) {
  function parseCFFTable (line 2359) | function parseCFFTable(data, start, font) {
  function encodeString (line 2413) | function encodeString(s, strings) {
  function makeHeader (line 2434) | function makeHeader() {
  function makeNameIndex (line 2443) | function makeNameIndex(fontNames) {
  function makeDict (line 2456) | function makeDict(meta, attrs, strings) {
  function makeTopDict (line 2474) | function makeTopDict(attrs, strings) {
  function makeTopDictIndex (line 2482) | function makeTopDictIndex(topDict) {
  function makeStringIndex (line 2490) | function makeStringIndex(strings) {
  function makeGlobalSubrIndex (line 2502) | function makeGlobalSubrIndex() {
  function makeCharsets (line 2509) | function makeCharsets(glyphNames, strings) {
  function glyphToOps (line 2522) | function glyphToOps(glyph) {
  function makeCharStringsIndex (line 2591) | function makeCharStringsIndex(glyphs) {
  function makePrivateDict (line 2605) | function makePrivateDict(attrs, strings) {
  function makePrivateDictIndex (line 2613) | function makePrivateDictIndex(privateDict) {
  function makeCFFTable (line 2621) | function makeCFFTable(glyphs, options) {
  function parseCmapTable (line 2710) | function parseCmapTable(data, start) {
  function addSegment (line 2790) | function addSegment(t, code, glyphIndex) {
  function addTerminatorSegment (line 2799) | function addTerminatorSegment(t) {
  function makeCmapTable (line 2808) | function makeCmapTable(glyphs) {
  function parseGlyphCoordinate (line 2897) | function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask...
  function parseGlyph (line 2923) | function parseGlyph(glyph, data, start) {
  function transformPoints (line 3047) | function transformPoints(points, transform) {
  function getContours (line 3063) | function getContours(points) {
  function getPath (line 3080) | function getPath(points) {
  function buildPath (line 3150) | function buildPath(glyphs, glyph) {
  function parseGlyfTable (line 3166) | function parseGlyfTable(data, start, loca, font) {
  function parseTaggedListTable (line 3197) | function parseTaggedListTable(data, start) {
  function parseCoverageTable (line 3211) | function parseCoverageTable(data, start) {
  function parseClassDefTable (line 3235) | function parseClassDefTable(data, start) {
  function parsePairPosSubTable (line 3282) | function parsePairPosSubTable(data, start) {
  function parseLookupTable (line 3369) | function parseLookupTable(data, start) {
  function parseGposTable (line 3403) | function parseGposTable(data, start, font) {
  function parseHeadTable (line 3438) | function parseHeadTable(data, start) {
  function makeHeadTable (line 3462) | function makeHeadTable(options) {
  function parseHheaTable (line 3497) | function parseHheaTable(data, start) {
  function makeHheaTable (line 3517) | function makeHheaTable(options) {
  function parseHmtxTable (line 3553) | function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) {
  function makeHmtxTable (line 3570) | function makeHmtxTable(glyphs) {
  function parseKernTable (line 3597) | function parseKernTable(data, start) {
  function parseLocaTable (line 3637) | function parseLocaTable(data, start, numGlyphs, shortVersion) {
  function parseMaxpTable (line 3669) | function parseMaxpTable(data, start) {
  function makeMaxpTable (line 3693) | function makeMaxpTable(numGlyphs) {
  function parseNameTable (line 3743) | function parseNameTable(data, start) {
  function makeNameRecord (line 3787) | function makeNameRecord(platformID, encodingID, languageID, nameID, leng...
  function addMacintoshNameRecord (line 3798) | function addMacintoshNameRecord(t, recordID, s, offset) {
  function addWindowsNameRecord (line 3807) | function addWindowsNameRecord(t, recordID, s, offset) {
  function makeNameTable (line 3816) | function makeNameTable(options) {
  function getUnicodeRange (line 3993) | function getUnicodeRange(unicode) {
  function parseOS2Table (line 4005) | function parseOS2Table(data, start) {
  function makeOS2Table (line 4058) | function makeOS2Table(options) {
  function parsePostTable (line 4125) | function parsePostTable(data, start) {
  function makePostTable (line 4170) | function makePostTable() {
  function log2 (line 4209) | function log2(v) {
  function computeCheckSum (line 4213) | function computeCheckSum(bytes) {
  function makeTableRecord (line 4230) | function makeTableRecord(tag, checkSum, offset, length) {
  function makeSfntTable (line 4239) | function makeSfntTable(tables) {
  function metricsForChar (line 4295) | function metricsForChar(font, chars, notFoundMetrics) {
  function average (line 4307) | function average(vs) {
  function fontToSfntTable (line 4318) | function fontToSfntTable(font) {
  function constant (line 4506) | function constant(v) {
  function succeed (line 4977) | function succeed(r) {
  function handleReadyState (line 4983) | function handleReadyState(r, success, error) {
  function setHeaders (line 4998) | function setHeaders(http, o) {
  function setCredentials (line 5014) | function setCredentials(http, o) {
  function generalCallback (line 5020) | function generalCallback(data) {
  function urlappend (line 5024) | function urlappend (url, s) {
  function handleJsonp (line 5028) | function handleJsonp(o, fn, err, url) {
  function getRequest (line 5088) | function getRequest(fn, err) {
  function Reqwest (line 5136) | function Reqwest(o, fn) {
  function setType (line 5143) | function setType(header) {
  function init (line 5151) | function init(o, fn) {
  function reqwest (line 5333) | function reqwest(o, fn) {
  function normalize (line 5338) | function normalize(s) {
  function serial (line 5342) | function serial(el, cb) {
  function eachFormElement (line 5384) | function eachFormElement() {
  function serializeQueryString (line 5403) | function serializeQueryString() {
  function serializeHash (line 5408) | function serializeHash() {
  function buildParams (line 5469) | function buildParams(prefix, obj, traditional, add) {
  function _isPowerOf2 (line 6764) | function _isPowerOf2 (value){
  function flatten (line 7171) | function flatten(arr){
  function turnVectorArrayIntoNumberArray (line 7184) | function turnVectorArrayIntoNumberArray(arr){
  function launchFullscreen (line 12821) | function launchFullscreen(element) {
  function exitFullscreen (line 12840) | function exitFullscreen() {
  function typeMatches (line 12979) | function typeMatches(defType, argType, arg) {
  function report (line 13006) | function report(message, func, color) {
  function friendlyWelcome (line 13154) | function friendlyWelcome() {
  function makeLoader (line 13658) | function makeLoader(theFile) {
  function attachListener (line 13723) | function attachListener(ev, fxn, ctx) {
  function calculateOffset (line 14011) | function calculateOffset(object) {
  function getMousePos (line 18115) | function getMousePos(canvas, evt) {
  function getTouchInfo (line 18569) | function getTouchInfo(canvas, e, i) {
  function buildBlurKernel (line 19225) | function buildBlurKernel(r) {
  function blurARGB (line 19261) | function blurARGB(canvas, radius) {
  function _sAssign (line 19775) | function _sAssign(sVal, iVal) {
  function makeObject (line 21730) | function makeObject(row, headers) {
  function escapeHelper (line 22285) | function escapeHelper(content) {
  function _checkFileExtension (line 22476) | function _checkFileExtension(filename, extension) {
  function destroyClickedElement (line 22518) | function destroyClickedElement(event) {
  function cacheKey (line 27104) | function cacheKey() {
  function doNf (line 27916) | function doNf() {
  function doNfc (line 27996) | function doNfc() {
  function addNfp (line 28066) | function addNfp() {
  function addNfs (line 28119) | function addNfs() {

FILE: p5-kinect/libraries/p5.sound.js
  function fixSetTarget (line 86) | function fixSetTarget(param) {
  function getPeaksAtThreshold (line 1808) | function getPeaksAtThreshold(data, threshold) {
  function countIntervalsBetweenNearbyPeaks (line 1824) | function countIntervalsBetweenNearbyPeaks(peaksObj) {
  function groupNeighborsByTempo (line 1860) | function groupNeighborsByTempo(intervalCounts, sampleRate) {
  function getPeaksAtTopTempo (line 1887) | function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) {
  function mapTempo (line 1914) | function mapTempo(theoreticalTempo) {
  function isUndef (line 2711) | function isUndef(val) {
  function TempConstructor (line 2972) | function TempConstructor() {
  function createDCOffset (line 4460) | function createDCOffset() {
  function playNextPart (line 6570) | function playNextPart(aScore) {
  function interleave (line 6846) | function interleave(leftChannel, rightChannel) {
  function writeUTFBytes (line 6857) | function writeUTFBytes(view, offset, string) {

FILE: p5-kinect/sketch.js
  function setup (line 3) | function setup() {
  function draw (line 8) | function draw() {
  function receiveOsc (line 22) | function receiveOsc(address, value) {
  function setupOsc (line 34) | function setupOsc(oscPortIn, oscPortOut) {
Condensed preview — 40 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,937K chars).
[
  {
    "path": ".gitignore",
    "chars": 42,
    "preview": "node_modules/\n.DS_Store\npackage-lock.json\n"
  },
  {
    "path": "Applications.md",
    "chars": 6050,
    "preview": "### osc in p5.js\n\nadapted from [osc-web](https://github.com/automata/osc-web).\n\n#### setup\n\n1) install [node](https://no"
  },
  {
    "path": "README.md",
    "chars": 1544,
    "preview": "### osc in p5.js\n\nadapted from [osc-web](https://github.com/automata/osc-web).\n\n#### setup\n\nInstall [node](https://nodej"
  },
  {
    "path": "bridge.js",
    "chars": 782,
    "preview": "var osc = require('node-osc');\nvar io = require('socket.io')(8081);\n\n\nvar oscServer, oscClient;\n\nvar isConnected = false"
  },
  {
    "path": "p5-ableton/basic-percussion/Icon\r",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "p5-ableton/index.html",
    "chars": 363,
    "preview": "<html>\n\n<head>\n  \t<meta charset=\"UTF-8\">\n\t<script src=\"http://127.0.0.1:8081/socket.io/socket.io.js\"></script>\n  \t<scrip"
  },
  {
    "path": "p5-ableton/libraries/p5.dom.js",
    "chars": 63386,
    "preview": "/*! p5.dom.js v0.2.6 November 10, 2015 */\n/**\n * <p>The web is much more than just canvas and p5.dom makes it easy to in"
  },
  {
    "path": "p5-ableton/libraries/p5.js",
    "chars": 825738,
    "preview": "/*! p5.js v0.4.19 November 11, 2015 */\n(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.ex"
  },
  {
    "path": "p5-ableton/libraries/p5.sound.js",
    "chars": 249266,
    "preview": "/*! p5.sound.js v0.2.16 2015-11-03 */\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd)\n    "
  },
  {
    "path": "p5-ableton/libraries/socket.io.js",
    "chars": 2443,
    "preview": "\n/*!\n * socket.io-node\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n/**\n * Module dependenc"
  },
  {
    "path": "p5-ableton/sketch.js",
    "chars": 1632,
    "preview": "/*\nThis sketch will move a ball on our p5 canvas and\nsend an OSC message each time the ball hits a wall.\n- Billy Bennett"
  },
  {
    "path": "p5-basic/ProcessingOSC/ProcessingOSC.pde",
    "chars": 681,
    "preview": "/**\n this Processing sketch will send its mouse\n position over OSC to the p5.js sketch in the folder \"p5-basic\".\n you ne"
  },
  {
    "path": "p5-basic/index.html",
    "chars": 364,
    "preview": "<html>\n\n<head>\n  \t<meta charset=\"UTF-8\">\n\t<script src=\"http://127.0.0.1:8081/socket.io/socket.io.js\"></script>\n  \t<scrip"
  },
  {
    "path": "p5-basic/libraries/p5.dom.js",
    "chars": 63386,
    "preview": "/*! p5.dom.js v0.2.6 November 10, 2015 */\n/**\n * <p>The web is much more than just canvas and p5.dom makes it easy to in"
  },
  {
    "path": "p5-basic/libraries/p5.js",
    "chars": 825738,
    "preview": "/*! p5.js v0.4.19 November 11, 2015 */\n(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.ex"
  },
  {
    "path": "p5-basic/libraries/p5.sound.js",
    "chars": 249266,
    "preview": "/*! p5.sound.js v0.2.16 2015-11-03 */\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd)\n    "
  },
  {
    "path": "p5-basic/libraries/socket.io.js",
    "chars": 2443,
    "preview": "\n/*!\n * socket.io-node\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n/**\n * Module dependenc"
  },
  {
    "path": "p5-basic/sketch.js",
    "chars": 983,
    "preview": "var x, y;\n\nfunction setup() {\n\tcreateCanvas(500, 500);\n\tsetupOsc(12000, 3334);\n}\n\nfunction draw() {\n\tbackground(0, 0, 25"
  },
  {
    "path": "p5-faceOsc/index.html",
    "chars": 363,
    "preview": "<html>\n\n<head>\n  \t<meta charset=\"UTF-8\">\n\t<script src=\"http://127.0.0.1:8081/socket.io/socket.io.js\"></script>\n  \t<scrip"
  },
  {
    "path": "p5-faceOsc/libraries/p5.dom.js",
    "chars": 63386,
    "preview": "/*! p5.dom.js v0.2.6 November 10, 2015 */\n/**\n * <p>The web is much more than just canvas and p5.dom makes it easy to in"
  },
  {
    "path": "p5-faceOsc/libraries/p5.js",
    "chars": 825738,
    "preview": "/*! p5.js v0.4.19 November 11, 2015 */\n(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.ex"
  },
  {
    "path": "p5-faceOsc/libraries/p5.sound.js",
    "chars": 249266,
    "preview": "/*! p5.sound.js v0.2.16 2015-11-03 */\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd)\n    "
  },
  {
    "path": "p5-faceOsc/libraries/socket.io.js",
    "chars": 2443,
    "preview": "\n/*!\n * socket.io-node\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n/**\n * Module dependenc"
  },
  {
    "path": "p5-faceOsc/sketch.js",
    "chars": 2443,
    "preview": "var face = [];\nvar position = {x:0, y:0};\nvar scale = 0;\nvar orientation = {x:0, y:0, z:0};\nvar mouthWidth = 0;\nvar mout"
  },
  {
    "path": "p5-faceOsc-flocking/index.html",
    "chars": 363,
    "preview": "<html>\n\n<head>\n  \t<meta charset=\"UTF-8\">\n\t<script src=\"http://127.0.0.1:8081/socket.io/socket.io.js\"></script>\n  \t<scrip"
  },
  {
    "path": "p5-faceOsc-flocking/libraries/p5.dom.js",
    "chars": 63386,
    "preview": "/*! p5.dom.js v0.2.6 November 10, 2015 */\n/**\n * <p>The web is much more than just canvas and p5.dom makes it easy to in"
  },
  {
    "path": "p5-faceOsc-flocking/libraries/p5.js",
    "chars": 825738,
    "preview": "/*! p5.js v0.4.19 November 11, 2015 */\n(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.ex"
  },
  {
    "path": "p5-faceOsc-flocking/libraries/p5.sound.js",
    "chars": 249266,
    "preview": "/*! p5.sound.js v0.2.16 2015-11-03 */\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd)\n    "
  },
  {
    "path": "p5-faceOsc-flocking/libraries/socket.io.js",
    "chars": 2443,
    "preview": "\n/*!\n * socket.io-node\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n/**\n * Module dependenc"
  },
  {
    "path": "p5-faceOsc-flocking/sketch.js",
    "chars": 8611,
    "preview": "var face = [];\nvar position = {x:0, y:0};\nvar scale = 0;\nvar orientation = {x:0, y:0, z:0};\nvar mouthWidth = 0;\nvar mout"
  },
  {
    "path": "p5-kinect/index.html",
    "chars": 363,
    "preview": "<html>\n\n<head>\n  \t<meta charset=\"UTF-8\">\n\t<script src=\"http://127.0.0.1:8081/socket.io/socket.io.js\"></script>\n  \t<scrip"
  },
  {
    "path": "p5-kinect/libraries/p5.dom.js",
    "chars": 63386,
    "preview": "/*! p5.dom.js v0.2.6 November 10, 2015 */\n/**\n * <p>The web is much more than just canvas and p5.dom makes it easy to in"
  },
  {
    "path": "p5-kinect/libraries/p5.js",
    "chars": 825738,
    "preview": "/*! p5.js v0.4.19 November 11, 2015 */\n(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.ex"
  },
  {
    "path": "p5-kinect/libraries/p5.sound.js",
    "chars": 249266,
    "preview": "/*! p5.sound.js v0.2.16 2015-11-03 */\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd)\n    "
  },
  {
    "path": "p5-kinect/libraries/socket.io.js",
    "chars": 2443,
    "preview": "\n/*!\n * socket.io-node\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n/**\n * Module dependenc"
  },
  {
    "path": "p5-kinect/sketch.js",
    "chars": 1233,
    "preview": "var joints = []\n\nfunction setup() {\n\tcreateCanvas(640, 480);\n\tsetupOsc(6448, 3334);\n}\n\nfunction draw() {\n\tbackground(0, "
  },
  {
    "path": "package.json",
    "chars": 1014,
    "preview": "{\n  \"name\": \"p5js-osc\",\n  \"description\": \"OSC (Open Sound Control) Web Bridge for p5.js, adapted from https://github.com"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the genekogan/p5js-osc GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 40 files (5.5 MB), approximately 1.4M tokens, and a symbol index with 835 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!