commit 641ffac406328baf32a7d101bd11a72d35c1e72e Author: Craig Rowe Date: Sat Aug 10 13:15:52 2013 +0100 Initial hacky commit diff --git a/go.js b/go.js new file mode 100644 index 0000000..218b7d9 --- /dev/null +++ b/go.js @@ -0,0 +1,65 @@ +var express = require('express'); +var engines = require('consolidate'); +var nodecr = require('nodecr'); +var fs = require('fs'); +var app = express(); + +app.engine('html', engines.hogan); +app.set('view engine', 'html'); +app.set('views', __dirname); + +var lastPng; + +app.get('/', function(req, res) +{ + res.render('index'); +}); + +app.get('/image', function(req, res) +{ + if(lastPng) + { + res.writeHead(200, {'Content-Type:': 'image/png' }); + res.end(lastPng); + } +}); + +var arDrone = require('ar-drone'); +var client = arDrone.createClient(); + +//client.takeoff(); +/*client.after(5000, function() +{ + var pngEncoder = client.getPngStream(); + pngEncoder + .on('error', console.log) + .on('data', function(pngBugger) + { + lastPng = pngBuffer; + }); +}); +*/ +/*client + .after(5000, function() { + this.clockwise(0.5); + }) + //.after(3000, function() { + // this.animate('flipLeft', 15); + //}) + .after(1000, function() { + this.stop(); + this.land(); + }); +*/ + +nodecr.process(__dirname + '/stop.png', function(err, text) +{ + if(err) + { + console.error(err); + }else{ + console.log("OCR Text: " + text); + } +}); + +//app.listen(8080); diff --git a/index.html b/index.html new file mode 100644 index 0000000..30236f4 --- /dev/null +++ b/index.html @@ -0,0 +1,8 @@ + + + + +

Test

+ + + diff --git a/node_modules/.bin/express b/node_modules/.bin/express new file mode 120000 index 0000000..b741d99 --- /dev/null +++ b/node_modules/.bin/express @@ -0,0 +1 @@ +../express/bin/express \ No newline at end of file diff --git a/node_modules/ar-drone/.npmignore b/node_modules/ar-drone/.npmignore new file mode 100644 index 0000000..d523a71 --- /dev/null +++ b/node_modules/ar-drone/.npmignore @@ -0,0 +1,3 @@ +*.swp +*.un~ +/node_modules diff --git a/node_modules/ar-drone/.travis.yml b/node_modules/ar-drone/.travis.yml new file mode 100644 index 0000000..baa0031 --- /dev/null +++ b/node_modules/ar-drone/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - 0.8 diff --git a/node_modules/ar-drone/CONTRIBUTING.md b/node_modules/ar-drone/CONTRIBUTING.md new file mode 100644 index 0000000..dadf38f --- /dev/null +++ b/node_modules/ar-drone/CONTRIBUTING.md @@ -0,0 +1,109 @@ +# Contributing + +## Running the test suite + +```js +$ git clone +$ cd +$ npm install +$ npm test +``` + +## Running an individual test + +```js +$ node test/unit/control/test-AtCommandCreator.js +``` + +## TODOS + +If you are looking for something to work on, here are a few things I'd like to +see in this module: + +### arDrone.createCsvRecorder() + +This feature would allow users to easily record control, navdata and other +flight related data for later analysis / plotting. + +I'm not sure how this should work exactly, but here is one idea: + +```js +var recorder = arDrone.createCsvRecorder(); +var control = arDrone.createUdpControl({recorder: recorder}); +var navdata = arDrone.createUdpNavdataStream({recorder: recorder}); + +recorder.pipe(fs.createWritableStream(__dirname + '/recording.csv')); +``` + +The approach could also be inversed: + +```js +var control = arDrone.createUdpControl(); +var navdata = arDrone.createUdpNavdataStream(); +var recorder = arDrone.createCsvRecorder(); + +recorder.add(navdata); +recorder.add(control); +``` + +Custom events could be tracked through an EventEmitter-like interface: + +```js +recorder.emit('myEvent', 'a string, object, array, buffer, number, etc.'); +``` + +So if you have ideas for this / want to work on it, let me know. My favorite +module for generating the CSV output would be: +[ya-csv](https://github.com/koles/ya-csv). + +### Client API + +The Client API is still lacking an important feature: + +* `client.config()` - allow sending custom config values to a client. This is + needed to configure things like the 'navdata' and 'camera' settings. + +### Parse remaining navdata options + +Currently a lot of navdata packages are still not implemented, so have a look +at `lib/navdata/parseNavdata.js` if you'd like to help. + +### Streaming to HTML5 video tag + +This one is difficult. Right now this library can turn the drone video stream +into a series of PNG buffers which can be rendered using an image tag. However, +this only works well for up to ~5-10 frames per second and is very hacky. + +So what would be really cool is playing the video inside an actual video tag. +However, the video data received from the drone is a raw H264 stream. In order +for it to be played inside a browser, it would have to be embedded into a +container format browsers understand (probably quicktime/mp4). FFMPEG does not +seem capable of doing this (the output stream will not be playable until the input +stream has ended). There is a chance that this is because the quicktime/mp4 +format does not allow this kind of "streaming", but it could also have other +reasons. + +So somebody needs to figure out if ffmpeg is a dead end for this, or if there +is some way to do this. + +If ffmpeg turns out to be unviable, another approach would be to implement +a container format (like quicktime/mp4) in JavaScript (I looked into this, +it will be tons of work), or create bindings to something like +[l-smash](http://code.google.com/p/l-smash/) (was recommended to me in #ffmpeg). + +Another angle at tackling this problem is not use a video tag, but decode the +h264 stream on a canvas tag instead. This may be very feasable given that there +is already a h264 decoder for JS: [Broadway.js](https://github.com/mbebenita/Broadway) +which could probably be modified for this. + +So, if you're looking for a very difficult but interesting problem, let me know +and I'll try to help you on this as much as I can. + +### AR Drone 1.0 + +It [appears](https://github.com/felixge/node-ar-drone/issues/11#issuecomment-9402270) that this library is compatible with 1.0 drones as well, +but feel free to submit bugs / patches if you find any problems. + +### Fixing bugs + +Bug fixes are always welcome. Please add a test! diff --git a/node_modules/ar-drone/LICENSE b/node_modules/ar-drone/LICENSE new file mode 100644 index 0000000..c7ff12a --- /dev/null +++ b/node_modules/ar-drone/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/node_modules/ar-drone/Makefile b/node_modules/ar-drone/Makefile new file mode 100644 index 0000000..c0bb004 --- /dev/null +++ b/node_modules/ar-drone/Makefile @@ -0,0 +1,6 @@ +SHELL := /bin/bash + +test: + npm test + +.PHONY: test diff --git a/node_modules/ar-drone/NEXT.md b/node_modules/ar-drone/NEXT.md new file mode 100644 index 0000000..4426c61 --- /dev/null +++ b/node_modules/ar-drone/NEXT.md @@ -0,0 +1,53 @@ +* Undo stupid changes to master branch and push newClient into master + +* Disable emergency mode + +* Figure out a better way to record control (to include config commands) + +* Discard / log out of order navdata + +* Decide on name for Navdata data +* Parse pwm and rawMeasures again + +* Rename clockSpin/clockWise + +* Maybe change udpControlStream interface to accept buffers + +* Do sensor data stuff + +* ClientControl.config +* 'tricks' / 'leds' object +* Convert everything to functional style +* move createAtCommand one level up + +* Map battery event +* Document events and properties +* Create client.sensors, client.commands streams + +* Document new AR Drone libs +* Finish AR Drone Png thingy +* Delete old shit +* Document what needs to be done +* Logging ! +* Build new AR Drone client + +# Features + +* control.flip() (POST /control/flip) + +# Consistency + +* client.navdata.raw -> client.navdata.udpStream +* message / command: number -> message.sequenceNumber +* Rename navdata message to navdata + +# Logging + +* node version +* v8 version +* get drone config +* get memory usage +* get operating systme +* raw video stream +* raw at stream +* raw navdata stream diff --git a/node_modules/ar-drone/README.md b/node_modules/ar-drone/README.md new file mode 100644 index 0000000..84e0947 --- /dev/null +++ b/node_modules/ar-drone/README.md @@ -0,0 +1,409 @@ +# ar-drone + +[![Build Status](https://secure.travis-ci.org/felixge/node-ar-drone.png)](http://travis-ci.org/felixge/node-ar-drone) + +An implementation of the networking protocols used by the +[Parrot AR Drone 2.0](http://ardrone2.parrot.com/). It appears that 1.0 drones are also [compatible](https://github.com/felixge/node-ar-drone/issues/11#issuecomment-9402270). + +Install via Github to get the *latest* version: + +```bash +npm install git://github.com/felixge/node-ar-drone.git +``` + +Or, if you're fine with missing some cutting edge stuff, go for npm: + +```bash +npm install ar-drone +``` + +## Introduction + +The AR Drone is an affordable, yet surprisingly capable quadcopter. The drone +itself runs a proprietary firmware that can be controlled via WiFi using the official +FreeFlight mobile app +(available for [iOS](http://itunes.apple.com/us/app/freeflight/id373065271?mt=8) and [Android](https://play.google.com/store/apps/details?id=com.parrot.freeflight&hl=en)). + +Unlike the firmware, the client protocol is open, and Parrot publishes an [SDK](https://projects.ardrone.org/projects/show/ardrone-api) +(signup required to download) including a good amount of documentation and C +code. Their target audience seems to be mobile developers who can use this +SDK to create games and other apps for people to have more fun with their drones. + +However, the protocol can also be used to receive video and sensor data, enabling +developers to write autonomous programs for the upcoming robot revolution. + +## Status + +This module is still under [heavy development](./node-ar-drone/blob/master/CONTRIBUTING.md), so please don't be suprised if +you find some functionality missing or undocumented. + +However, the documented parts are tested and should work well for most parts. + +## Client + +This module exposes a high level Client API that tries to support all drone +features, while making them easy to use. + +The best way to get started is to create a `repl.js` file like this: + +```js +var arDrone = require('ar-drone'); +var client = arDrone.createClient(); +client.createRepl(); +``` + +Using this REPL, you should be able to have some fun: + +```js +$ node repl.js +// Make the drone takeoff +drone> takeoff() +true +// Wait for the drone to takeoff +drone> clockwise(0.5) +0.5 +// Let the drone spin for a while +drone> land() +true +// Wait for the drone to land +``` + +Now you could write an autonomous program that does the same: + +```js +var arDrone = require('ar-drone'); +var client = arDrone.createClient(); + +client.takeoff(); + +client + .after(5000, function() { + this.clockwise(0.5); + }) + .after(3000, function() { + this.stop(); + this.land(); + }); +``` + +Ok, but what if you want to make your drone to interact with something? Well, +you could start by looking at the sensor data: + +```js +client.on('navdata', console.log); +``` + +Not all of this is handled by the Client library yet, but you should at the +very least be able to receive `droneState` and `demo` data. + +A good initial challenge might be to try flying to a certain altitude based +on the `navdata.demo.altitudeMeters` property. + +Once you have manged this, you may want to try looking at the camera image. Here +is a simple way to get this as PngBuffers (requires a recent ffmpeg version to +be found in your `$PATH`): + +```js +var pngStream = client.getPngStream(); +pngStream.on('data', console.log); +``` + +Your first challenge might be to expose these png images as a node http web +server. Once you have done that, you should try feeding them into the +[opencv](https://npmjs.org/package/opencv) module. + +### Client API + +#### arDrone.createClient([options]) + +Returns a new `Client` object. `options` include: + +* `ip`: The IP of the drone. Defaults to `'192.168.1.1'`. + +#### client.createREPL() + +Launches an interactive interface with all client methods available in the +active scope. Additionally `client` resolves to the `client` instance itself. + +#### client.getPngStream() + +Returns a `PngEncoder` object that emits individual png image buffers as `'data'` +events. Multiple calls to this method returns the same object. Connection lifecycle +(e.g. reconnect on error) is managed by the client. + +#### client.getVideoStream() + +Returns a `TcpVideoStream` object that emits raw tcp packets as `'data'` +events. Multiple calls to this method returns the same object. Connection lifecycle +(e.g. reconnect on error) is managed by the client. + +#### client.takeoff(cb) + +Sets the internal `fly` state to `true`, `cb` is invoked after the drone +reports that it is hovering. + +#### client.land(cb) + +Sets the internal `fly` state to `false`, `cb` is invoked after the drone +reports it has landed. + +#### client.up(speed) / client.down(speed) + +Makes the drone gain or reduce altitude. `speed` can be a value from `0` to `1`. + +#### client.clockwise(speed) / client.counterClockwise(speed) + +Causes the drone to spin. `speed` can be a value from `0` to `1`. + +#### client.front(speed) / client.back(speed) + +Controls the pitch, which a horizontal movement using the camera +as a reference point. `speed` can be a value from `0` to `1`. + +#### client.left(speed) / client.right(speed) + +Controls the roll, which is a horizontal movement using the camera +as a reference point. `speed` can be a value from `0` to `1`. + +#### client.stop() + +Sets all drone movement commands to `0`, making it effectively hover in place. + +#### client.config(key, value) + +Sends a config command to the drone. You will need to download the drone +[SDK](https://projects.ardrone.org/projects/show/ardrone-api) to find a full list of commands in the `ARDrone_Developer_Guide.pdf`. + +For example, this command can be used to instruct the drone to send all navdata. + +```js +client.config('general:navdata_demo', 'FALSE'); +``` + + +#### client.animate(animation, duration) + +Performs a pre-programmed flight sequence for a given `duration` (in ms). +`animation` can be one of the following: + + +```js +['phiM30Deg', 'phi30Deg', 'thetaM30Deg', 'theta30Deg', 'theta20degYaw200deg', +'theta20degYawM200deg', 'turnaround', 'turnaroundGodown', 'yawShake', +'yawDance', 'phiDance', 'thetaDance', 'vzDance', 'wave', 'phiThetaMixed', +'doublePhiThetaMixed', 'flipAhead', 'flipBehind', 'flipLeft', 'flipRight'] +``` + +Example: + +```js +client.animate('flipLeft', 1500); +``` + +Please note that the drone will need a good amount of altitude and headroom +to perform a flip. So be careful! + +#### client.animateLeds(animation, hz, duration) + +Performs a pre-programmed led sequence at given `hz` frequency and `duration` +(in sec!). `animation` can be one of the following: + +```js +['blinkGreenRed', 'blinkGreen', 'blinkRed', 'blinkOrange', 'snakeGreenRed', +'fire', 'standard', 'red', 'green', 'redSnake', 'blank', 'rightMissile', +'leftMissile', 'doubleMissile', 'frontLeftGreenOthersRed', +'frontRightGreenOthersRed', 'rearRightGreenOthersRed', +'rearLeftGreenOthersRed', 'leftGreenRightRed', 'leftRedRightGreen', +'blinkStandard'] +``` + +Example: + +```js +client.animateLeds('blinkRed', 5, 2) +``` + +#### client.disableEmergency() + +Causes the emergency REF bit to be set to 1 until +`navdata.droneState.emergencyLanding` is 0. This recovers a drone that has +flipped over and is showing red lights to be flyable again and show green +lights. It is also done implicitly when creating a new high level client. + +#### Events + +A client will emit landed, hovering, flying, landing, batteryChange, and altitudeChange events as long as demo navdata is enabled. + +To enable demo navdata use + +```js +client.config('general:navdata_demo', 'FALSE'); +``` + +## UdpControl + +This is a low level API. If you prefer something simpler, check out the Client +docs. + +The drone is controlled by sending UDP packets on port 5556. Because UDP +does not guarantee message ordering or delivery, clients must repeatedly send +their instructions and include an incrementing sequence number with each +command. + +For example, the command used for takeoff/landing (REF), with a sequence number +of 1, and a parameter of 512 (takeoff) looks like this: + +``` +AT*REF=1,512\r +``` + +To ease the creation and sending of these packets, this module exposes an +`UdpControl` class handling this task. For example, the following program will +cause your drone to takeoff and hover in place. + +```js +var arDrone = require('ar-drone'); +var control = arDrone.createUdpControl(); + +setInterval(function() { + // The emergency: true option recovers your drone from emergency mode that can + // be caused by flipping it upside down or the drone crashing into something. + // In a real program you probably only want to send emergency: true for one + // second in the beginning, otherwise your drone may attempt to takeoff again + // after a crash. + control.ref({fly: true, emergency: true}); + // This command makes sure your drone hovers in place and does not drift. + control.pcmd(); + // This causes the actual udp message to be send (multiple commands are + // combined into one message) + control.flush(); +}, 30); +``` + +Now that you are airborne, you can fly around by passing an argument to the +`pcmd()` method: + +```js +control.pcmd({ + front: 0.5, // fly forward with 50% speed + up: 0.3, // and also fly up with 30% speed +}); +``` + +That's it! A full list of all `pcmd()` options can be found in the API docs +below. + +With what you have learned so far, you could create a simple program +like this: + +```js +var arDrone = require('ar-drone'); +var control = arDrone.createUdpControl(); +var start = Date.now(); + +var ref = {}; +var pcmd = {}; + +console.log('Recovering from emergency mode if there was one ...'); +ref.emergency = true; +setTimeout(function() { + console.log('Takeoff ...'); + + ref.emergency = false; + ref.fly = true; + +}, 1000); + +setTimeout(function() { + console.log('Turning clockwise ...'); + + pcmd.clockwise = 0.5; +}, 6000); + +setTimeout(function() { + console.log('Landing ...'); + + ref.fly = false; + pcmd = {}; +}, 8000); + + +setInterval(function() { + control.ref(ref); + control.pcmd(pcmd); + control.flush(); +}, 30); +``` + +### UdpControl API + +#### arDrone.createUdpControl([options]) / new arDrone.UdpControl([options]) + +Creates a new UdpControl instance where `options` can include: + +* `ip`: The drone IP address, defaults to `'192.168.1.1'`. +* `port`: The port to use, defaults to `5556`. + +#### udpControl.raw(command, [arg1, arg2, ...]) + +Enqueues a raw `AT*` command. This is useful if you want full control. + +For example, a takeoff instructions be send like this: + +```js +udpControl.raw('REF', (1 << 9)); +``` + +#### udpControl.ref([options]) + +Enqueues a `AT*REF` command, options are: + +* `fly`: Set this to `true` for takeoff / staying in air, or `false` to initiate + landing / stay on the ground. Defaults to `false`. +* `emergency`: Set this to `true` to set the emergency bit, or `false` to not + set it. Details on this can be found in the official SDK Guide. Defaults to + `false`. + +#### udpControl.pcmd([options]) + +Enqueues a `AT*PCMD` (progressive) command, options are: + +* `front` or `back`: Fly towards or away from front camera direction. +* `left` or/ `right`: Fly towards the left or right of the front camera. +* `up` or `down`: Gain or reduce altitude. +* `clockwise` or `counterClockwise`: Rotate around the center axis. + +The values for each option are the speed to use for the operation and can range +from 0 to 1. You can also use negative values like `{front: -0.5}`, which is +the same as `{back: 0.5}`. + +#### udpControl.flush() + +Sends all enqueued commands as an UDP packet to the drone. + +## Video + +@TODO Document the low level video API. + +## Navdata + +@TODO Document the low level navdata API. + +## Environment variables + +* DEFAULT_DRONE_IP + +## Camera access + +You can access the head camera and the bottom camera, you just have the change +the config: + +```javascript +// access the head camera +client.config('video:video_channel', 0); + +// access the bottom camera +client.config('video:video_channel', 3); +``` + + diff --git a/node_modules/ar-drone/examples/png-stream.js b/node_modules/ar-drone/examples/png-stream.js new file mode 100644 index 0000000..2dcca4c --- /dev/null +++ b/node_modules/ar-drone/examples/png-stream.js @@ -0,0 +1,31 @@ +// Run this to receive a png image stream from your drone. + +var arDrone = require('..'); +var http = require('http'); + +console.log('Connecting png stream ...'); + +var pngStream = arDrone.createClient().getPngStream(); + +var lastPng; +pngStream + .on('error', console.log) + .on('data', function(pngBuffer) { + lastPng = pngBuffer; + }); + +var server = http.createServer(function(req, res) { + if (!lastPng) { + res.writeHead(503); + res.end('Did not receive any png data yet.'); + return; + } + + res.writeHead(200, {'Content-Type': 'image/png'}); + res.end(lastPng); +}); + +server.listen(8080, function() { + console.log('Serving latest png on port 8080 ...'); +}); + diff --git a/node_modules/ar-drone/examples/tcp-video-stream.js b/node_modules/ar-drone/examples/tcp-video-stream.js new file mode 100644 index 0000000..5cdb2a1 --- /dev/null +++ b/node_modules/ar-drone/examples/tcp-video-stream.js @@ -0,0 +1,8 @@ +// Run this to receive the raw video stream from your drone as buffers. + +var arDrone = require('..'); + +var video = arDrone.createClient().getVideoStream(); + +video.on('data', console.log); +video.on('error', console.log); diff --git a/node_modules/ar-drone/examples/udp-control.js b/node_modules/ar-drone/examples/udp-control.js new file mode 100644 index 0000000..ce5eb28 --- /dev/null +++ b/node_modules/ar-drone/examples/udp-control.js @@ -0,0 +1,23 @@ +// Run this to make your drone take off for 5 seconds and then land itself +// again. + +var UdpControl = require('../lib/control/UdpControl'); + +var control = new UdpControl(); +var fly = true; +var emergency = true; + +setInterval(function() { + control.ref({fly: fly, emergency: emergency}); + control.pcmd(); + control.flush(); +}, 30); + +// For the first second, disable emergency if there was one +setTimeout(function() { + emergency = false; +}, 1000); + +setTimeout(function() { + fly = false; +}, 5000); diff --git a/node_modules/ar-drone/index.js b/node_modules/ar-drone/index.js new file mode 100644 index 0000000..1ff14ca --- /dev/null +++ b/node_modules/ar-drone/index.js @@ -0,0 +1,28 @@ +var arDrone = exports; + +exports.Client = require('./lib/Client'); +exports.UdpControl = require('./lib/control/UdpControl'); +exports.PngStream = require('./lib/video/PngStream'); +exports.UdpNavdataStream = require('./lib/navdata/UdpNavdataStream'); + +exports.createClient = function(options) { + var client = new arDrone.Client(options); + client.resume(); + return client; +}; + +exports.createUdpControl = function(options) { + return new arDrone.UdpControl(options); +}; + +exports.createPngStream = function(options) { + var stream = new arDrone.PngStream(options); + stream.resume(); + return stream; +}; + +exports.createUdpNavdataStream = function(options) { + var stream = new arDrone.UdpNavdataStream(options); + stream.resume(); + return stream; +}; diff --git a/node_modules/ar-drone/journal/2012-11-06.md b/node_modules/ar-drone/journal/2012-11-06.md new file mode 100644 index 0000000..11e204e --- /dev/null +++ b/node_modules/ar-drone/journal/2012-11-06.md @@ -0,0 +1,99 @@ +I want to improve the API for the library to help with a few things: + +* debugging +* logging +* ease of use + +The new API I imagine would be like this: + +```js +var client = arDrone.createClient() +client.control.takeoff(function(err, result) { + client.control.up(1); + + console.log(client.toJSON()); + // { + // navdata: { ... }, + // control: { ... }, + // } + +}); +``` + +# Separation of APIs + +```js +client.navdata.on('data'); +client.control.on('data'); +client.video.on('data'); +var h264 = client.video.h264(); +``` + +# Logging + +Another important aspect is to get logging right. I could imagine this to work: + +```js +client.log.tsv('prefix'); +client.log.json('file'); +``` + + +# Control + +Let's define the control API + +```js +control.upDown = 0; +control.leftRight = 0; +control.frontBack = 0; +control.upDown = 0; +control.fly = 0; +control.emergency = 0; +control.configs = []; +``` + +# Nadata + +```js +navdata.batteryPercentage = 0; +navdata.altitudeMeters = 0; +``` + +# Output folder + +/example + /navdata.tsv + /control.movement.tsv + /control.config.tsv + /log.txt + + +# Re-desiging the AT interface + + +```js +client.control.atUdpStream.write(message); +client.control.atUdpStream.on('data', function(message) { + // message.id keeps track of the packet number + // message.commands holds individual at commands +}); +``` + +``` +atMessage.write(new AtCommand('ref', 121, 12)); +atMessage.write(new AtCommand('pcmd', 121, 12)); +``` + +More thinking on message / at command streams: + +```js +var commands [ + atCommandSequence.ref(...), + atCommandSequence.pcmd(...), + atCommandSequence.config(...), +]; + +var message = atMessageSequence.next(commands); +return message; +``` diff --git a/node_modules/ar-drone/journal/2012-11-07.md b/node_modules/ar-drone/journal/2012-11-07.md new file mode 100644 index 0000000..eeda4e6 --- /dev/null +++ b/node_modules/ar-drone/journal/2012-11-07.md @@ -0,0 +1,133 @@ +I am stuck again, I am unsure about the sensor data. Should I make it look like +this? + +```js +{ + state: undefined, + batteryLevel: undefined, + flyState: undefined, + emergency: undefined, + altitudeMeters: undefined, + frontBackDegrees: undefined, + leftRightDegrees: undefined, + clockSpinDegrees: undefined, + frontBackSpeed: undefined, + leftRightSpeed: undefined, + upDownSpeed: undefined, + .flying: undefined, + videoEnabled: undefined, + visionEnabled: undefined, + controlAlgorithm: undefined, + altitudeControlAlgorithm: undefined, + startButtonState: undefined, + controlCommandAck: undefined, + cameraReady: undefined, + travellingEnabled: undefined, + usbReady: undefined, + navdataDemo: undefined, + navdataBootstrap: undefined, + motorProblem: undefined, + communicationLost: undefined, + softwareFault: undefined, + lowBattery: undefined, + userEmergencyLanding: undefined, + timerElapsed: undefined, + magnometerNeedsCalibration: undefined, + anglesOutOfRange: undefined, + tooMuchWind: undefined, + ultrasonicSensorDeaf: undefined, + cutoutDetected: undefined, + picVersionNumberOk: undefined, + atCodecThreadOn: undefined, + navdataThreadOn: undefined, + videoThreadOn: undefined, + acquisitionThreadOn: undefined, + controlWatchdogDelay: undefined, + adcWatchdogDelay: undefined, + comWatchdogProblem: undefined, + emergencyLanding: undefined, +} +``` + +Or like this: + +```js +{ + batteryLevel: undefined, + controlStatus: undefined, + flyStatus: undefined, + altitudeMeters: undefined, + gyros:{ + frontBack: undefined, + leftRight: undefined, + clockWise: undefined, + }, + speed: { + frontBack: undefined, + leftRight: undefined, + upDown: undefined, + } + status: { + flying: undefined, + videoEnabled: undefined, + visionEnabled: undefined, + controlAlgorithm: undefined, + altitudeControlAlgorithm: undefined, + startButtonState: undefined, + controlCommandAck: undefined, + cameraReady: undefined, + travellingEnabled: undefined, + usbReady: undefined, + navdataDemo: undefined, + navdataBootstrap: undefined, + motorProblem: undefined, + communicationLost: undefined, + softwareFault: undefined, + lowBattery: undefined, + userEmergencyLanding: undefined, + timerElapsed: undefined, + magnometerNeedsCalibration: undefined, + anglesOutOfRange: undefined, + tooMuchWind: undefined, + ultrasonicSensorDeaf: undefined, + cutoutDetected: undefined, + picVersionNumberOk: undefined, + atCodecThreadOn: undefined, + navdataThreadOn: undefined, + videoThreadOn: undefined, + acquisitionThreadOn: undefined, + controlWatchdogDelay: undefined, + adcWatchdogDelay: undefined, + comWatchdogProblem: undefined, + emergencyLanding: undefined, + }, +} +``` + +So this continue to be hard. I am wondering: + +* should I rename 'sensors' to 'navdata' ? +* should my option sparsers "augment" the data object, or produce their own + results + +The latter questions seems more interesting, so let's contrast the approaches. + +a) Augment data + +Pro: +* No need to "merge" / easier to achieve the combined data structure I want + +Con: +* Worse to test +* Bad design + +b) Return data + +Pro: +* Clean design +* Easy to test + +Con: +* Needs to merge the data structure +* Final data structure is not documented in one place +* Missing options will cause missing elements in final data structure diff --git a/node_modules/ar-drone/journal/2012-11-08.md b/node_modules/ar-drone/journal/2012-11-08.md new file mode 100644 index 0000000..28731b2 --- /dev/null +++ b/node_modules/ar-drone/journal/2012-11-08.md @@ -0,0 +1,48 @@ +# control <-> navdata circular dependency + +So I have a circular dependency between navdata and control: + +* control needs navdata to provide a callback to takeoff +* navdata needs control to request more navdata as needed + +The following solutions seem feasable: + +## a) Create circular dependency + +Problems: +* Nasty +* Means I have to manipulate the navdata object after creating it to give + it control. +* Breaks the isolation of navdata and control + +## b) Move higher level control to client + +Example: + +``` +client.takeoff(); +client.land(); +``` + +Problems: +* Unclear what the client object should do and what the control object should + do. + + +## c) Have the control listen to all navdata events + +Problems: +* None, as long as I'm ok with emitting all navdata events + +# Side quest: emit 'data' events if not all navdata is included? + +Problems: +* may cause navdata events to not be emitted for an unknown amount of time + +# control internals + +I'm wondering how to do the control internals, this may be right: + +* control.atStream.ref(); control.atStream.flush(); -> emits 'data' ControlMessage +* control.atStream.pipe(control.udpStream); +* udp emits what it is sending diff --git a/node_modules/ar-drone/lib/Client.js b/node_modules/ar-drone/lib/Client.js new file mode 100644 index 0000000..73e842c --- /dev/null +++ b/node_modules/ar-drone/lib/Client.js @@ -0,0 +1,268 @@ +var EventEmitter = require('events').EventEmitter; +var util = require('util'); + +Client.UdpControl = require('./control/UdpControl'); +Client.Repl = require('./Repl'); +Client.UdpNavdataStream = require('./navdata/UdpNavdataStream'); +Client.PngStream = require('./video/PngStream'); +Client.PngEncoder = require('./video/PngEncoder'); +Client.TcpVideoStream = require('./video/TcpVideoStream'); + +module.exports = Client; +util.inherits(Client, EventEmitter); +function Client(options) { + EventEmitter.call(this); + + options = options || {}; + + this._options = options; + this._udpControl = options.udpControl || new Client.UdpControl(options); + this._udpNavdatasStream = options.udpNavdataStream || new Client.UdpNavdataStream(options); + this._pngStream = null; + this._tcpStream = null; + this._interval = null; + this._ref = {}; + this._pcmd = {}; + this._repeaters = []; + this._afterOffset = 0; + this._disableEmergency = false; + this._lastState = 'CTRL_LANDED'; + this._lastBattery = 100; + this._lastAltitude = 0; +} + +Client.prototype.after = function(duration, fn) { + setTimeout(fn.bind(this), this._afterOffset + duration); + this._afterOffset += duration; + return this; +}; + +Client.prototype.createRepl = function() { + var repl = new Client.Repl(this); + repl.resume(); + return repl; +}; + +Client.prototype.createPngStream = function() { + console.warn("Client.createPngStream is deprecated. Use Client.getPngStream instead."); + return this.getPngStream(); +}; + +Client.prototype.getPngStream = function() { + if (this._pngStream == null) { + this._pngStream = this._newPngStream(); + } + return this._pngStream; +} + +Client.prototype.getVideoStream = function() { + if (this._tcpVideoStream == null) { + this._tcpVideoStream = this._newTcpVideoStream(); + } + return this._tcpVideoStream; +} + +Client.prototype._newTcpVideoStream = function() { + var stream = new Client.TcpVideoStream(this._options); + var callback = function(err) { + if (err !== null) { + console.log('TcpVideoStream error: %s', err.message); + setTimeout(function () { + console.log('Attempting to reconnect to TcpVideoStream...'); + stream.connect(callback); + }, 1000); + } + } + + stream.connect(callback); + stream.on('error', callback); + return stream; +} + +Client.prototype._newPngStream = function() { + var videoStream = this.getVideoStream(); + var pngEncoder = new Client.PngEncoder(this._options); + + videoStream.on('data', function(data) { + pngEncoder.write(data); + }); + + return pngEncoder; +} + +Client.prototype.resume = function() { + // request basic navdata by default + this.config('general:navdata_demo', 'TRUE'); + this.disableEmergency(); + this._setInterval(30); + + this._udpNavdatasStream.removeAllListeners(); + this._udpNavdatasStream.resume(); + this._udpNavdatasStream + .on('error', this._maybeEmitError.bind(this)) + .on('data', this._handleNavdata.bind(this)); +}; + +Client.prototype._handleNavdata = function(navdata) { + if (navdata.droneState && navdata.droneState.emergencyLanding && this._disableEmergency) { + this._ref.emergency = true; + } else { + this._ref.emergency = false; + this._disableEmergency = false; + } + + this.emit('navdata', navdata); + this._processNavdata(navdata); +}; + +Client.prototype._processNavdata = function(navdata) { + if (navdata.droneState && navdata.demo) { + // controlState events + var cstate = navdata.demo.controlState; + var emitState = (function(e, state) { + if (cstate === state && this._lastState !== state) { + return this.emit(e); + } + }).bind(this); + emitState('landing', 'CTRL_TRANS_LANDING'); + emitState('landed', 'CTRL_LANDED'); + emitState('takeoff', 'CTRL_TRANS_TAKEOFF'); + emitState('hovering', 'CTRL_HOVERING'); + emitState('flying', 'CTRL_FLYING'); + this._lastState = cstate; + + // battery events + var battery = navdata.demo.batteryPercentage; + if (navdata.droneState.lowBattery === 1) { + this.emit('lowBattery', battery); + } + if (navdata.demo.batteryPercentage !== this._lastBattery) { + this.emit('batteryChange', battery); + this._lastBattery = battery; + } + + // altitude events + var altitude = navdata.demo.altitudeMeters; + if (altitude !== this._lastAltitude) { + this.emit('altitudeChange', altitude); + this._lastAltitude = altitude; + } + } + +}; + +// emits an 'error' event, but only if somebody is listening. This avoids +// making node's EventEmitter throwing an exception for non-critical errors +Client.prototype._maybeEmitError = function(err) { + if (this.listeners('error').length > 0) { + this.emit('error', err); + } +}; + +Client.prototype._setInterval = function(duration) { + clearInterval(this._interval); + this._interval = setInterval(this._sendCommands.bind(this), duration); +}; + +Client.prototype._sendCommands = function() { + this._udpControl.ref(this._ref); + this._udpControl.pcmd(this._pcmd); + this._udpControl.flush(); + + this._repeaters + .forEach(function(repeat) { + repeat.times--; + repeat.method(); + }); + + this._repeaters = this._repeaters.filter(function(repeat) { + return repeat.times > 0; + }); +}; + +Client.prototype.disableEmergency = function() { + this._disableEmergency = true; +}; + +Client.prototype.takeoff = function(cb) { + this.once('hovering', cb || function() {}); + this._ref.fly = true; + return true; +}; + +Client.prototype.land = function(cb) { + this.once('landed', cb || function() {}); + this._ref.fly = false; + return true; +}; + +Client.prototype.stop = function() { + this._pcmd = {}; + return true; +}; + +Client.prototype.calibrate = function(device_num) { + this._udpControl.calibrate(device_num); +}; + +Client.prototype.config = function(key, value) { + // @TODO Figure out if we can get a ACK for this, so we don't need to + // repeat it blindly like this + var self = this; + this._repeat(10, function() { + self._udpControl.config(key, value); + }); +}; + +Client.prototype.animate = function(animation, duration) { + // @TODO Figure out if we can get a ACK for this, so we don't need to + // repeat it blindly like this + var self = this; + this._repeat(10, function() { + self._udpControl.animate(animation, duration); + }); +}; + +Client.prototype.animateLeds = function(animation, hz, duration) { + // @TODO Figure out if we can get a ACK for this, so we don't need to + // repeat it blindly like this + var self = this; + this._repeat(10, function() { + self._udpControl.animateLeds(animation, hz, duration); + }); +}; + +Client.prototype.battery = function() { + return this._lastBattery; +}; + +Client.prototype._repeat = function(times, fn) { + this._repeaters.push({times: times, method: fn}); +}; + +var pcmdOptions = [ + ['up', 'down'], + ['left', 'right'], + ['front', 'back'], + ['clockwise', 'counterClockwise'], +] + +pcmdOptions.forEach(function(pair) { + Client.prototype[pair[0]] = function(speed) { + speed = parseFloat(speed); + + this._pcmd[pair[0]] = speed; + delete this._pcmd[pair[1]]; + + return speed; + }; + + Client.prototype[pair[1]] = function(speed) { + speed = parseFloat(speed); + + this._pcmd[pair[1]] = speed; + delete this._pcmd[pair[0]]; + + return speed; + }; +}); diff --git a/node_modules/ar-drone/lib/Repl.js b/node_modules/ar-drone/lib/Repl.js new file mode 100644 index 0000000..3b10a40 --- /dev/null +++ b/node_modules/ar-drone/lib/Repl.js @@ -0,0 +1,79 @@ +var repl = require('repl'); +var vm = require('vm'); + +module.exports = Repl; +function Repl(client) { + this._client = client; + this._repl = null; + this._nodeEval = null; +} + +Repl.prototype.resume = function() { + this._repl = repl.start({ + prompt : 'drone> ', + }); + + this._nodeEval = this._repl.eval; + + // @TODO This does not seem to work for animate('yawShake', 2000), need + // to fix this. + //this._repl.eval = this._eval.bind(this); + + this._setupAutocomplete(); +}; + +Repl.prototype._setupAutocomplete = function() { + for (var property in this._client) { + if (property.substr(0, 1) === '_') { + // Skip "private" properties + continue; + } + + var value = this._client[property]; + if (typeof value === 'function') { + value = value.bind(this._client); + } + + this._repl.context[property] = value; + } + + this._repl.context.client = this._client; +}; + +Repl.prototype._eval = function(code, context, filename, cb) { + var args = code.match(/[^() \n]+/g); + if (!args) { + return this._nodeEval.apply(this._repl, arguments); + } + + var property = args.shift(); + if (!this._client[property]) { + return this._nodeEval.apply(this._repl, arguments); + } + + var type = typeof this._client[property]; + + if (type === 'function') { + try { + cb(null, this._client[property].apply(this._client, args)); + } catch (err) { + cb(err); + } + return; + } + + if (args.length > 1) { + // Don't accept more than 1 argument + cb(new Error('Cannot set property "' + property + '". Too many arguments.')); + return; + } + + if (args.length === 1) { + // Set a client property + cb(null, this._client[property] = args[1]); + return; + } + + // args.length === 0, return property value + cb(null, this._client[property]); +}; diff --git a/node_modules/ar-drone/lib/constants.js b/node_modules/ar-drone/lib/constants.js new file mode 100644 index 0000000..8fad95c --- /dev/null +++ b/node_modules/ar-drone/lib/constants.js @@ -0,0 +1,153 @@ +// Constants required to decode/encode the network communication with the drone. +// Names taken from the official SDK are not renamed, but: +// +// * Consistent prefixes/suffixes are stripped +// * Always converted to UPPER_CASE + +var constants = module.exports; + +constants.getName = function(group, value) { + group = this[group]; + + for (var name in group) { + if (group[name] === value) { + return name; + } + } +}; + +constants.DEFAULT_DRONE_IP = process.env.DEFAULT_DRONE_IP || '192.168.1.1'; + +// from ARDrone_SDK_2_0/ARDroneLib/Soft/Common/config.h +constants.ports = { + FTP : 5551, + AUTH : 5552, + VIDEO_RECORDER : 5553, + NAVDATA : 5554, + VIDEO : 5555, + AT : 5556, + RAW_CAPTURE : 5557, + PRINTF : 5558, + CONTROL : 5559 +}; + +// from ARDrone_SDK_2_0/ARDroneLib/Soft/Common/config.h +constants.droneStates = { + FLY_MASK : 1 << 0, /*!< FLY MASK : (0) ardrone is landed, (1) ardrone is flying */ + VIDEO_MASK : 1 << 1, /*!< VIDEO MASK : (0) video disable, (1) video enable */ + VISION_MASK : 1 << 2, /*!< VISION MASK : (0) vision disable, (1) vision enable */ + CONTROL_MASK : 1 << 3, /*!< CONTROL ALGO : (0) euler angles control, (1) angular speed control */ + ALTITUDE_MASK : 1 << 4, /*!< ALTITUDE CONTROL ALGO : (0) altitude control inactive (1) altitude control active */ + USER_FEEDBACK_START : 1 << 5, /*!< USER feedback : Start button state */ + COMMAND_MASK : 1 << 6, /*!< Control command ACK : (0) None, (1) one received */ + CAMERA_MASK : 1 << 7, /*!< CAMERA MASK : (0) camera not ready, (1) Camera ready */ + TRAVELLING_MASK : 1 << 8, /*!< Travelling mask : (0) disable, (1) enable */ + USB_MASK : 1 << 9, /*!< USB key : (0) usb key not ready, (1) usb key ready */ + NAVDATA_DEMO_MASK : 1 << 10, /*!< Navdata demo : (0) All navdata, (1) only navdata demo */ + NAVDATA_BOOTSTRAP : 1 << 11, /*!< Navdata bootstrap : (0) options sent in all or demo mode, (1) no navdata options sent */ + MOTORS_MASK : 1 << 12, /*!< Motors status : (0) Ok, (1) Motors problem */ + COM_LOST_MASK : 1 << 13, /*!< Communication Lost : (1) com problem, (0) Com is ok */ + SOFTWARE_FAULT : 1 << 14, /*!< Software fault detected - user should land as quick as possible (1) */ + VBAT_LOW : 1 << 15, /*!< VBat low : (1) too low, (0) Ok */ + USER_EL : 1 << 16, /*!< User Emergency Landing : (1) User EL is ON, (0) User EL is OFF*/ + TIMER_ELAPSED : 1 << 17, /*!< Timer elapsed : (1) elapsed, (0) not elapsed */ + MAGNETO_NEEDS_CALIB : 1 << 18, /*!< Magnetometer calibration state : (0) Ok, no calibration needed, (1) not ok, calibration needed */ + ANGLES_OUT_OF_RANGE : 1 << 19, /*!< Angles : (0) Ok, (1) out of range */ + WIND_MASK : 1 << 20, /*!< WIND MASK: (0) ok, (1) Too much wind */ + ULTRASOUND_MASK : 1 << 21, /*!< Ultrasonic sensor : (0) Ok, (1) deaf */ + CUTOUT_MASK : 1 << 22, /*!< Cutout system detection : (0) Not detected, (1) detected */ + PIC_VERSION_MASK : 1 << 23, /*!< PIC Version number OK : (0) a bad version number, (1) version number is OK */ + ATCODEC_THREAD_ON : 1 << 24, /*!< ATCodec thread ON : (0) thread OFF (1) thread ON */ + NAVDATA_THREAD_ON : 1 << 25, /*!< Navdata thread ON : (0) thread OFF (1) thread ON */ + VIDEO_THREAD_ON : 1 << 26, /*!< Video thread ON : (0) thread OFF (1) thread ON */ + ACQ_THREAD_ON : 1 << 27, /*!< Acquisition thread ON : (0) thread OFF (1) thread ON */ + CTRL_WATCHDOG_MASK : 1 << 28, /*!< CTRL watchdog : (1) delay in control execution (> 5ms), (0) control is well scheduled */ + ADC_WATCHDOG_MASK : 1 << 29, /*!< ADC Watchdog : (1) delay in uart2 dsr (> 5ms), (0) uart2 is good */ + COM_WATCHDOG_MASK : 1 << 30, /*!< Communication Watchdog : (1) com problem, (0) Com is ok */ + EMERGENCY_MASK : 1 << 31 /*!< Emergency landing : (0) no emergency, (1) emergency */ +}; + + +// from ARDrone_SDK_2_0/ARDroneLib/Soft/Common/navdata_keys.h +constants.options = { + DEMO : 0, + TIME : 1, + RAW_MEASURES : 2, + PHYS_MEASURES : 3, + GYROS_OFFSETS : 4, + EULER_ANGLES : 5, + REFERENCES : 6, + TRIMS : 7, + RC_REFERENCES : 8, + PWM : 9, + ALTITUDE : 10, + VISION_RAW : 11, + VISION_OF : 12, + VISION : 13, + VISION_PERF : 14, + TRACKERS_SEND : 15, + VISION_DETECT : 16, + WATCHDOG : 17, + ADC_DATA_FRAME : 18, + VIDEO_STREAM : 19, + GAMES : 20, + PRESSURE_RAW : 21, + MAGNETO : 22, + WIND_SPEED : 23, + KALMAN_PRESSURE : 24, + HDVIDEO_STREAM : 25, + WIFI : 26, + ZIMMU_3000 : 27, + CKS : 65535 +}; + +constants.CAD_TYPE = { + HORIZONTAL : 0, /* 0) { + this.emit('error', err); + } + return; + } + + // Ignore out of order messages + if (navdata.sequenceNumber > this._sequenceNumber) { + this._sequenceNumber = navdata.sequenceNumber; + this.emit('data', navdata); + } + + this._setTimeout(); +}; diff --git a/node_modules/ar-drone/lib/navdata/maskingFunctions.js b/node_modules/ar-drone/lib/navdata/maskingFunctions.js new file mode 100644 index 0000000..8f924e1 --- /dev/null +++ b/node_modules/ar-drone/lib/navdata/maskingFunctions.js @@ -0,0 +1,25 @@ +var constants = require('../constants'); + +exports.NAVDATA_NUM_TAGS = Object.keys(constants.options).length; +exports.NAVDATA_OPTION_FULL_MASK = (1<> 21; + // last 21 bits are microseconds + var microseconds = (time << 11) >> 11; + + // Convert to ms (which is idiomatic for time in JS) + return seconds * 1000 + microseconds / 1000; +}; + +var exports = module.exports = function parseNavdata(buffer) { + var reader = new NavdataReader(buffer); + + var navdata = {}; + + navdata.header = reader.uint32(); + if (navdata.header !== exports.NAVDATA_HEADER) { + throw new Error('Invalid header: 0x' + navdata.header.toString(16)); + } + + navdata.droneState = reader.mask32(exports.DRONE_STATES); + navdata.sequenceNumber = reader.uint32(); + navdata.visionFlag = reader.uint32(); + + while (true) { + var optionId = reader.uint16(); + var optionName = exports.OPTION_IDS[optionId]; + var length = reader.uint16(); + + // length includes header size (4 bytes) + var optionReader = new NavdataReader(reader.buffer(length - 4)); + + if (optionName == 'checksum') { + var expectedChecksum = 0; + for (var i = 0; i < buffer.length - length; i++) { + expectedChecksum += buffer[i]; + } + + var checksum = optionReader.uint32(); + + if (checksum !== expectedChecksum) { + throw new Error('Invalid checksum, expected: ' + expectedChecksum + ', got: ' + checksum); + } + + // checksum is the last option + break; + } + + // parse option according to ARDrone_SDK_2_0/ARDroneLib/Soft/Common/navdata_common.h) + navdata[optionName] = (exports.OPTION_PARSERS[optionName]) + ? exports.OPTION_PARSERS[optionName](optionReader) + : new Error('Option not implemented yet: ' + optionName + ' (0x' + optionId.toString(16) + ')'); + } + + return navdata; +}; + +exports.OPTION_PARSERS = { + 'demo': function(reader) { + // simplified version of ctrl_state_str (in ARDrone_SDK_2_0/Examples/Linux/Navigation/Sources/navdata_client/navdata_ihm.c) + var flyState = exports.FLY_STATES[reader.uint16()]; + var controlState = exports.CONTROL_STATES[reader.uint16()]; + var batteryPercentage = reader.uint32(); + var theta = reader.float32() / 1000; // [mdeg] + var phi = reader.float32() / 1000; // [mdeg] + var psi = reader.float32() / 1000; // [mdeg] + var altitude = reader.int32() / 1000; // [mm] + var velocity = reader.vector31(); // [mm/s] + var frameIndex = reader.uint32(); + var detection = { + camera: { + rotation : reader.matrix33(), + translation : reader.vector31() + }, + tagIndex: reader.uint32() + }; + detection.camera.type = reader.uint32(); + var drone = { + camera: { + rotation : reader.matrix33(), + translation : reader.vector31() + } + }; + var rotation = { + frontBack : theta, + pitch : theta, + theta : theta, + y : theta, + leftRight : phi, + roll : phi, + phi : phi, + x : phi, + clockwise : psi, + yaw : psi, + psi : psi, + z : psi + }; + + return { + controlState : controlState, + flyState : flyState, + batteryPercentage : batteryPercentage, + rotation : rotation, + frontBackDegrees : theta, + leftRightDegrees : phi, + clockwiseDegrees : psi, + altitude : altitude, + altitudeMeters : altitude, + velocity : velocity, + xVelocity : velocity.x, + yVelocity : velocity.y, + zVelocity : velocity.z, + frameIndex : frameIndex, + detection : detection, + drone : drone + }; + }, + + 'time': function(reader) { + var time = reader.uint32(); + return droneTimeToMilliSeconds(time); + }, + + 'rawMeasures': function(reader) { + var accelerometers = { + x: reader.uint16(), // [LSB] + y: reader.uint16(), // [LSB] + z: reader.uint16() // [LSB] + }; + var gyroscopes = { + x: reader.int16(), // [LSB] + y: reader.int16(), // [LSB] + z: reader.int16() // [LSB] + }; + // gyroscopes x/y 110 deg/s (@TODO figure out what that means) + var gyroscopes110 = { + x: reader.int16(), // [LSB] + y: reader.int16() // [LSB] + }; + var batteryMilliVolt = reader.uint32(); // [mV] + // no idea what any of those are + var usEcho = { + start : reader.uint16(), // [LSB] + end : reader.uint16(), // [LSB] + association : reader.uint16(), // [LSB?] + distance : reader.uint16() // [LSB] + }; + var usCurve = { + time : reader.uint16(), // [LSB] + value : reader.uint16(), // [LSB] + ref : reader.uint16() // [LSB] + }; + var echo = { + flagIni : reader.uint16(), // [LSB] + num : reader.uint16(), // [LSB] (is key `num` OR `name`?) + sum : reader.uint32() // [LSB] + }; + var altTemp = reader.int32(); // [mm] + + return { + accelerometers : accelerometers, + gyroscopes : gyroscopes, + gyrometers : gyroscopes, + gyroscopes110 : gyroscopes110, + gyrometers110 : [gyroscopes110.x, gyroscopes110.y], + batteryMilliVolt : batteryMilliVolt, + us : {echo: usEcho, curve: usCurve}, + usDebutEcho : usEcho.start, + usFinEcho : usEcho.end, + usAssociationEcho : usEcho.association, + usDistanceEcho : usEcho.distance, + usCourbeTemps : usCurve.time, + usCourbeValeur : usCurve.value, + usCourbeRef : usCurve.ref, + echo : echo, + flagEchoIni : echo.flagIni, + nbEcho : echo.num, + sumEcho : echo.sum, + altTemp : altTemp, + altTempRaw : altTemp + }; + }, + + 'physMeasures': function(reader) { + return { + temperature: { + accelerometer: reader.float32(), // [K] + gyroscope: reader.uint16() // [LSB] + }, + accelerometers : reader.vector31(), // [mg] + gyroscopes : reader.vector31(), // [deg/s] + alim3V3 : reader.uint32(), // [LSB] + vrefEpson : reader.uint32(), // [LSB] + vrefIDG : reader.uint32() // [LSB] + }; + }, + + 'gyrosOffsets': function(reader) { + return reader.vector31(); // [LSB] + }, + + 'eulerAngles': function(reader) { + return { + theta : reader.float32(), // [mdeg?] + phi : reader.float32() // [mdeg?] + }; + }, + + 'references': function(reader) { + return { + theta : reader.int32(), // [mdeg] + phi : reader.int32(), // [mdeg] + thetaI : reader.int32(), // [mdeg] + phiI : reader.int32(), // [mdeg] + pitch : reader.int32(), // [mdeg] + roll : reader.int32(), // [mdeg] + yaw : reader.int32(), // [mdeg/s] + psi : reader.int32(), // [mdeg] + + vx : reader.float32(), + vy : reader.float32(), + thetaMod : reader.float32(), + phiMod : reader.float32(), + + kVX : reader.float32(), + kVY : reader.float32(), + kMode : reader.uint32(), + + ui : { + time : reader.float32(), + theta : reader.float32(), + phi : reader.float32(), + psi : reader.float32(), + psiAccuracy : reader.float32(), + seq : reader.int32() + } + }; + }, + + 'trims': function(reader) { + return { + angularRates : { + r : reader.float32() + }, + eulerAngles : { + theta : reader.float32(), // [mdeg?] + phi : reader.float32() // [mdeg?] + } + }; + }, + + 'rcReferences': function(reader) { + return { + pitch : reader.int32(), // [mdeg?] + roll : reader.int32(), // [mdeg?] + yaw : reader.int32(), // [mdeg/s?] + gaz : reader.int32(), + ag : reader.int32() + }; + }, + + 'pwm': function(reader) { + return { + motors : timesMap(4, reader.uint8, reader), // [PWM] + satMotors : timesMap(4, reader.uint8, reader), // [PWM] + gazFeedForward : reader.float32(), // [PWM] + gazAltitude : reader.float32(), // [PWM] + altitudeIntegral : reader.float32(), // [mm/s] + vzRef : reader.float32(), // [mm/s] + uPitch : reader.int32(), // [PWM] + uRoll : reader.int32(), // [PWM] + uYaw : reader.int32(), // [PWM] + yawUI : reader.float32(), // [PWM] yaw_u_I + uPitchPlanif : reader.int32(), // [PWM] + uRollPlanif : reader.int32(), // [PWM] + uYawPlanif : reader.int32(), // [PWM] + uGazPlanif : reader.float32(), // [PWM] + motorCurrents : timesMap(4, reader.uint16, reader), // [mA] + altitudeProp : reader.float32(), // [PWM] + altitudeDer : reader.float32() // [PWM] + }; + }, + + 'altitude': function(reader) { + return { + vision : reader.int32(), // [mm] + velocity : reader.float32(), // [mm/s] + ref : reader.int32(), // [mm] + raw : reader.int32(), // [mm] + observer : { + acceleration : reader.float32(), // [m/s2] + altitude : reader.float32(), // [m] + x : reader.vector31(), + state : reader.uint32() + }, + estimated : { + vb : { + x : reader.float32(), + y : reader.float32() + }, + state : reader.uint32() + } + }; + }, + + 'visionRaw': function(reader) { + return { + tx : reader.float32(), + ty : reader.float32(), + tz : reader.float32() + }; + }, + + 'visionOf': function(reader) { + return { + dx : timesMap(5, reader.float32, reader), + dy : timesMap(5, reader.float32, reader) + }; + }, + + 'vision': function(reader) { + return { + state : reader.uint32(), + misc : reader.int32(), + phi: { + trim : reader.float32(), // [rad] + refProp : reader.float32() // [rad] + }, + theta: { + trim : reader.float32(), // [rad] + refProp : reader.float32() // [rad] + }, + newRawPicture : reader.int32(), + capture : { + theta : reader.float32(), + phi : reader.float32(), + psi : reader.float32(), + altitude : reader.int32(), + time : droneTimeToMilliSeconds(reader.uint32()) + }, + bodyV : reader.vector31(), // [mm/s] + delta : { + phi : reader.float32(), + theta : reader.float32(), + psi : reader.float32() + }, + gold : { + defined : reader.uint32(), + reset : reader.uint32(), + x : reader.float32(), + y : reader.float32() + } + }; + }, + + 'visionPerf': function(reader) { + return { + szo : reader.float32(), + corners : reader.float32(), + compute : reader.float32(), + tracking : reader.float32(), + trans : reader.float32(), + update : reader.float32(), + custom : timesMap(20, reader.float32, reader) + }; + }, + + 'trackersSend': function(reader) { + return { + locked : timesMap(30, reader.int32, reader), + point : timesMap(30, reader.screenPoint, reader) + }; + }, + + 'visionDetect': function(reader) { + return { + nbDetected : reader.uint32(), + type : timesMap(4, reader.uint32, reader), + xc : timesMap(4, reader.uint32, reader), + yc : timesMap(4, reader.uint32, reader), + width : timesMap(4, reader.uint32, reader), + height : timesMap(4, reader.uint32, reader), + dist : timesMap(4, reader.uint32, reader), + orientationAngle : timesMap(4, reader.uint32, reader), + rotation : timesMap(4, reader.matrix33, reader), + translation : timesMap(4, reader.vector31, reader), + cameraSource : timesMap(4, reader.uint32, reader) + }; + }, + + 'watchdog': function(reader) { + return reader.uint32(); + }, + + 'adcDataFrame': function(reader) { + return { + version : reader.uint32(), + dataFrame : timesMap(32, reader.uint8, reader) + }; + }, + + 'videoStream': function(reader) { + return { + quant : reader.uint8(), + frame : { + size : reader.uint32(), // [bytes] + number : reader.uint32() + }, + atcmd : { + sequence : reader.uint32(), + meanGap : reader.uint32(), // [ms] + varGap : reader.float32(), // [SU] + quality : reader.uint32() + }, + bitrate : { + out : reader.uint32(), + desired : reader.uint32() + }, + data : timesMap(5, reader.int32, reader), + tcpQueueLevel : reader.uint32(), + fifoQueueLevel : reader.uint32() + }; + }, + + 'games': function(reader) { + return { + counters: { + doubleTap : reader.uint32(), + finishLine : reader.uint32() + } + }; + }, + + 'pressureRaw': function(reader) { + return { + up : reader.int32(), // [LSB] (UP?) + ut : reader.int16(), // [LSB] (UT?) + temperature : reader.int32(), // [0_1C] + pressure : reader.int32() // [Pa] + }; + }, + + 'magneto': function(reader) { + return { + mx : reader.int16(), // [LSB] + my : reader.int16(), // [LSB] + mz : reader.int16(), // [LSB] + raw : reader.vector31(), // [mG] + rectified : reader.vector31(), // [mG] + offset : reader.vector31(), // [mG] + heading : { + unwrapped: reader.float32(), // [deg] + gyroUnwrapped: reader.float32(), // [deg] + fusionUnwrapped: reader.float32() // [mdeg] + }, + ok : reader.char(), + state : reader.uint32(), // [SU] + radius : reader.float32(), // [mG] + error : { + mean : reader.float32(), // [mG] + variance : reader.float32() // [mG2] + } + }; + }, + + 'windSpeed': function(reader) { + return { + speed: reader.float32(), // [m/s] + angle: reader.float32(), // [deg] + compensation: { + theta: reader.float32(), // [rad] + phi: reader.float32() + }, + stateX: timesMap(6, reader.float32, reader), // [SU] + debug: timesMap(3, reader.float32, reader) + }; + }, + + 'kalmanPressure': function(reader) { + return { + offsetPressure: reader.float32(), // [Pa] + estimated: { + altitude: reader.float32(), // [mm] + velocity: reader.float32(), // [m/s] + angle: { + pwm: reader.float32(), // [m/s2] + pressure: reader.float32() // [Pa] + }, + us: { + offset: reader.float32(), // [m] + prediction: reader.float32() // [mm] + }, + covariance: { + alt: reader.float32(), // [m] + pwm: reader.float32(), + velocity: reader.float32() // [m/s] + }, + groundEffect: reader.bool(), // [SU] + sum: reader.float32(), // [mm] + reject: reader.bool(), // [SU] + uMultisinus: reader.float32(), + gazAltitude: reader.float32(), + flagMultisinus: reader.bool(), + flagMultisinusStart: reader.bool() + } + }; + }, + + 'hdvideoStream': function(reader) { + var values = { + hdvideoState : reader.uint32(), + storageFifo : { + nbPackets : reader.uint32(), + size : reader.uint32() + }, + usbkey : { + size : reader.uint32(), + freespace : reader.uint32() + }, + frameNumber : reader.uint32() + }; + values.usbkey.remainingTime = reader.uint32(); + + return values; + }, + + 'wifi': function(reader) { + return { + // from ARDrone_SDK_2_0/ControlEngine/iPhone/Classes/Controllers/MainViewController.m + linkQuality: (1 - (reader.float32())) + }; + }, + + 'zimmu3000': function(reader) { + return { + vzimmuLSB: reader.int32(), // [LSB] + vzfind: reader.float32() + }; + } +}; + + +// Constants + +exports.NAVDATA_HEADER = 0x55667788; + +// from ARDrone_SDK_2_0/ARDroneLib/Soft/Common/config.h +exports.DRONE_STATES = { + flying : 1 << 0, /*!< FLY MASK : (0) ardrone is landed, (1) ardrone is flying */ + videoEnabled : 1 << 1, /*!< VIDEO MASK : (0) video disable, (1) video enable */ + visionEnabled : 1 << 2, /*!< VISION MASK : (0) vision disable, (1) vision enable */ + controlAlgorithm : 1 << 3, /*!< CONTROL ALGO : (0) euler angles control, (1) angular speed control */ + altitudeControlAlgorithm : 1 << 4, /*!< ALTITUDE CONTROL ALGO : (0) altitude control inactive (1) altitude control active */ + startButtonState : 1 << 5, /*!< USER feedback : Start button state */ + controlCommandAck : 1 << 6, /*!< Control command ACK : (0) None, (1) one received */ + cameraReady : 1 << 7, /*!< CAMERA MASK : (0) camera not ready, (1) Camera ready */ + travellingEnabled : 1 << 8, /*!< Travelling mask : (0) disable, (1) enable */ + usbReady : 1 << 9, /*!< USB key : (0) usb key not ready, (1) usb key ready */ + navdataDemo : 1 << 10, /*!< Navdata demo : (0) All navdata, (1) only navdata demo */ + navdataBootstrap : 1 << 11, /*!< Navdata bootstrap : (0) options sent in all or demo mode, (1) no navdata options sent */ + motorProblem : 1 << 12, /*!< Motors status : (0) Ok, (1) Motors problem */ + communicationLost : 1 << 13, /*!< Communication Lost : (1) com problem, (0) Com is ok */ + softwareFault : 1 << 14, /*!< Software fault detected - user should land as quick as possible (1) */ + lowBattery : 1 << 15, /*!< VBat low : (1) too low, (0) Ok */ + userEmergencyLanding : 1 << 16, /*!< User Emergency Landing : (1) User EL is ON, (0) User EL is OFF*/ + timerElapsed : 1 << 17, /*!< Timer elapsed : (1) elapsed, (0) not elapsed */ + MagnometerNeedsCalibration : 1 << 18, /*!< Magnetometer calibration state : (0) Ok, no calibration needed, (1) not ok, calibration needed */ + anglesOutOfRange : 1 << 19, /*!< Angles : (0) Ok, (1) out of range */ + tooMuchWind : 1 << 20, /*!< WIND MASK: (0) ok, (1) Too much wind */ + ultrasonicSensorDeaf : 1 << 21, /*!< Ultrasonic sensor : (0) Ok, (1) deaf */ + cutoutDetected : 1 << 22, /*!< Cutout system detection : (0) Not detected, (1) detected */ + picVersionNumberOk : 1 << 23, /*!< PIC Version number OK : (0) a bad version number, (1) version number is OK */ + atCodecThreadOn : 1 << 24, /*!< ATCodec thread ON : (0) thread OFF (1) thread ON */ + navdataThreadOn : 1 << 25, /*!< Navdata thread ON : (0) thread OFF (1) thread ON */ + videoThreadOn : 1 << 26, /*!< Video thread ON : (0) thread OFF (1) thread ON */ + acquisitionThreadOn : 1 << 27, /*!< Acquisition thread ON : (0) thread OFF (1) thread ON */ + controlWatchdogDelay : 1 << 28, /*!< CTRL watchdog : (1) delay in control execution (> 5ms), (0) control is well scheduled */ + adcWatchdogDelay : 1 << 29, /*!< ADC Watchdog : (1) delay in uart2 dsr (> 5ms), (0) uart2 is good */ + comWatchdogProblem : 1 << 30, /*!< Communication Watchdog : (1) com problem, (0) Com is ok */ + emergencyLanding : 1 << 31 /*!< Emergency landing : (0) no emergency, (1) emergency */ +}; + +exports.OPTION_IDS = { + 0 : 'demo', + 1 : 'time', + 2 : 'rawMeasures', + 3 : 'physMeasures', + 4 : 'gyrosOffsets', + 5 : 'eulerAngles', + 6 : 'references', + 7 : 'trims', + 8 : 'rcReferences', + 9 : 'pwm', + 10 : 'altitude', + 11 : 'visionRaw', + 12 : 'visionOf', + 13 : 'vision', + 14 : 'visionPerf', + 15 : 'trackersSend', + 16 : 'visionDetect', + 17 : 'watchdog', + 18 : 'adcDataFrame', + 19 : 'videoStream', + 20 : 'games', + 21 : 'pressureRaw', + 22 : 'magneto', + 23 : 'windSpeed', + 24 : 'kalmanPressure', + 25 : 'hdvideoStream', + 26 : 'wifi', + 27 : 'zimmu3000', + 65535 : 'checksum' +}; + +exports.CONTROL_STATES = { + 0: 'CTRL_DEFAULT', + 1: 'CTRL_INIT', + 2: 'CTRL_LANDED', + 3: 'CTRL_FLYING', + 4: 'CTRL_HOVERING', + 5: 'CTRL_TEST', + 6: 'CTRL_TRANS_TAKEOFF', + 7: 'CTRL_TRANS_GOTOFIX', + 8: 'CTRL_TRANS_LANDING', + 9: 'CTRL_TRANS_LOOPING' +}; + +exports.FLY_STATES = { + 0: 'FLYING_OK', + 1: 'FLYING_LOST_ALT', + 2: 'FLYING_LOST_ALT_GO_DOWN', + 3: 'FLYING_ALT_OUT_ZONE', + 4: 'FLYING_COMBINED_YAW', + 5: 'FLYING_BRAKE', + 6: 'FLYING_NO_VISION' +}; diff --git a/node_modules/ar-drone/lib/video/PaVEParser.js b/node_modules/ar-drone/lib/video/PaVEParser.js new file mode 100644 index 0000000..25cad78 --- /dev/null +++ b/node_modules/ar-drone/lib/video/PaVEParser.js @@ -0,0 +1,96 @@ +// The AR Drone 2.0 allows a tcp client to receive H264 (MPEG4.10 AVC) video +// from the drone. However, the frames are wrapped by Parrot Video +// Encapsulation (PaVE), which this class parses. + +var util = require('util'); +var Stream = require('stream').Stream; +var buffy = require('buffy'); + +module.exports = PaVEParser; +util.inherits(PaVEParser, Stream); +function PaVEParser() { + Stream.call(this); + + this.writable = true; + this.readable = true; + + this._parser = buffy.createReader(); + this._state = 'header'; + this._frame = undefined; +} + +PaVEParser.HEADER_SIZE_SHORT = 64; +PaVEParser.HEADER_SIZE_LONG = 68; + +PaVEParser.prototype.write = function(buffer) { + var parser = this._parser; + + parser.write(buffer); + + while (true) { + switch (this._state) { + case 'header': + if (parser.bytesAhead() < PaVEParser.HEADER_SIZE_LONG) { + return; + } + + this._frame = { + signature : parser.ascii(4), + version : parser.uint8(), + video_codec : parser.uint8(), + header_size : parser.uint16LE(), + payload_size : parser.uint32LE(), + encoded_stream_width : parser.uint16LE(), + encoded_stream_height : parser.uint16LE(), + display_width : parser.uint16LE(), + display_height : parser.uint16LE(), + frame_number : parser.uint32LE(), + timestamp : parser.uint32LE(), + total_chunks : parser.uint8(), + chunk_index : parser.uint8(), + frame_type : parser.uint8(), + control : parser.uint8(), + stream_byte_position_lw : parser.uint32LE(), + stream_byte_position_uw : parser.uint32LE(), + stream_id : parser.uint16LE(), + total_slices : parser.uint8(), + slice_index : parser.uint8(), + header1_size : parser.uint8(), + header2_size : parser.uint8(), + reserved2 : parser.buffer(2), + advertised_size : parser.uint32LE(), + reserved3 : parser.buffer(12), + payload : null, + }; + + if (this._frame.signature !== 'PaVE') { + this.emit('error', new Error('Invalid signature: ' + JSON.stringify(this._frame.signature))); + // TODO: skip forward until next frame + return; + } + + // stupid kludge for https://projects.ardrone.org/issues/show/159 + parser.buffer(this._frame.header_size - PaVEParser.HEADER_SIZE_SHORT); + + this._state = 'payload'; + break; + case 'payload': + if (parser.bytesAhead() < this._frame.payload_size) { + return; + } + + this._frame.payload = parser.buffer(this._frame.payload_size); + + this.emit('data', this._frame); + this._frame = undefined; + this._state = 'header'; + break; + } + } + + return true; +}; + +PaVEParser.prototype.end = function() { + // nothing to do, just here so pipe() does not complain +}; diff --git a/node_modules/ar-drone/lib/video/PngEncoder.js b/node_modules/ar-drone/lib/video/PngEncoder.js new file mode 100644 index 0000000..a1d13dc --- /dev/null +++ b/node_modules/ar-drone/lib/video/PngEncoder.js @@ -0,0 +1,108 @@ +// Converts a video stream into a stream of png buffers. Each 'data' event +// is guaranteed to contain exactly 1 png image. + +// @TODO handle ffmpeg exit (and trigger "error" if unexpected) + +var Stream = require('stream').Stream; +var util = require('util'); +var spawn = require('child_process').spawn; +var PngSplitter = require('./PngSplitter'); + +module.exports = PngEncoder; +util.inherits(PngEncoder, Stream); +function PngEncoder(options) { + Stream.call(this); + + options = options || {}; + + this.writable = true; + this.readable = true; + + this._spawn = options.spawn || spawn; + this._frameRate = options.frameRate || 5; + this._pngSplitter = options.pngSplitter || new PngSplitter(); + this._log = options.log; + this._ffmpeg = undefined; + this._ending = false; +} + +PngEncoder.prototype.write = function(buffer) { + if (!this._ffmpeg) { + this._initFfmpegAndPipes(); + } + + return this._ffmpeg.stdin.write(buffer); +}; + +PngEncoder.prototype._initFfmpegAndPipes = function() { + this._ffmpeg = this._spawnFfmpeg(); + + // @TODO: Make this more sophisticated for somehow and figure out how it + // will work with the planned new data recording system. + if (this._log) { + this._ffmpeg.stderr.pipe(this._log); + } + + this._ffmpeg.stdout.pipe(this._pngSplitter); + this._pngSplitter.on('data', this.emit.bind(this, 'data')); + + // 'error' can be EPIPE if ffmpeg does not exist. We handle this with the + // 'exit' event below. + this._ffmpeg.stdin.on('error', function() {}); + + this._ffmpeg.stdin.on('drain', this.emit.bind(this, 'drain')); + + var self = this; + // Since node 0.10, spawn emits 'error' when the child can't be spawned. + // http://nodejs.org/api/child_process.html#child_process_event_error + this._ffmpeg.on('error', function(err) { + if (err.code === 'ENOENT') { + self.emit('error', new Error('Ffmpeg was not found. Have you installed the ffmpeg package?')); + } else { + self.emit('error', new Error('Unexpected error when launching ffmpeg:' + err.toString())); + } + }); + + this._ffmpeg.on('exit', function(code) { + if (code === 0) { + // we expected ffmpeg to exit + if (self._ending) { + self.emit('end'); + return; + } + + self.emit('error', new Error('Unexpected ffmpeg exit with code 0.')); + return; + } + + // 127 is used by the OS to indicate that ffmpeg was not found + // required when using node < 0.10 + if (code === 127) { + self.emit('error', new Error('Ffmpeg was not found / exit code 127.')); + return; + } + + self.emit('error', new Error('Ffmpeg exited with error code: ' + code)); + }); +}; + +PngEncoder.prototype._spawnFfmpeg = function() { + // @TODO allow people to configure the ffmpeg path + return this._spawn('ffmpeg', [ + '-i' ,'-', + '-f', 'image2pipe', + '-vcodec', 'png', + '-r', this._frameRate, + '-', + ]); +}; + +PngEncoder.prototype.end = function() { + // No data handled yet? Nothing to do for ending. + if (!this._ffmpeg) { + return; + } + + this._ending = true; + this._ffmpeg.stdin.end(); +}; diff --git a/node_modules/ar-drone/lib/video/PngSplitter.js b/node_modules/ar-drone/lib/video/PngSplitter.js new file mode 100644 index 0000000..d6328c7 --- /dev/null +++ b/node_modules/ar-drone/lib/video/PngSplitter.js @@ -0,0 +1,101 @@ +var EventEmitter = require('events').EventEmitter; +var util = require('util'); + +module.exports = PngSplitter; +util.inherits(PngSplitter, EventEmitter); +function PngSplitter() { + EventEmitter.call(this); + + this.writable = true; + this._buffer = new Buffer(0); + this._offset = 0; + this._pngStartOffset = null; + this._state = 'header'; + this._chunk = null; +} + +PngSplitter.prototype.write = function(buffer) { + this._buffer = Buffer.concat([this._buffer, buffer]); + + while (true) { + switch (this._state) { + case 'header': + this._pngStartOffset = this._offset; + + if (this.remainingBytes() < 8) { + return; + } + + this._offset += 8; + this._state = 'chunk.header'; + break; + case 'chunk.header': + if (this.remainingBytes() < 8) { + return; + } + + this._chunk = { + length : this.unsignedNumber(4), + type : this.array(4).join(' '), + }; + + this._state = 'chunk.data'; + break; + case 'chunk.data': + var chunkSize = this._chunk.length + 4; // 4 bytes = CRC + if (this.remainingBytes() < chunkSize) { + return; + } + + this._offset += chunkSize; + + // IEND chunk + if (this._chunk.type == '73 69 78 68') { + var png = this._buffer.slice(this._pngStartOffset, this._offset); + this.emit('data', png); + + this._buffer = this._buffer.slice(this._offset); + this._offset = 0; + this._state = 'header'; + break; + } + + this._state = 'chunk.header' + break; + } + } + + return true; +}; + +PngSplitter.prototype.remainingBytes = function() { + return this._buffer.length - this._offset; +}; + +PngSplitter.prototype.array = function(bytes) { + var array = []; + + for (var i = 0; i < bytes; i++) { + array.push(this._buffer[this._offset++]); + } + + return array; +}; + +PngSplitter.prototype.unsignedNumber = function(bytes) { + var bytesRead = 0; + var value = 0; + + while (bytesRead < bytes) { + var byte = this._buffer[this._offset++]; + + value += byte * Math.pow(256, bytes - bytesRead - 1); + + bytesRead++; + } + + return value; +}; + +PngSplitter.prototype.end = function() { +}; diff --git a/node_modules/ar-drone/lib/video/PngStream.js b/node_modules/ar-drone/lib/video/PngStream.js new file mode 100644 index 0000000..3be7018 --- /dev/null +++ b/node_modules/ar-drone/lib/video/PngStream.js @@ -0,0 +1,44 @@ +PngStream.TcpVideoStream = require('./TcpVideoStream'); +PngStream.PngEncoder = require('./PngEncoder'); + +var Stream = require('stream').Stream; +var util = require('util'); + +module.exports = PngStream; +util.inherits(PngStream, Stream); +function PngStream(options) { + console.warn('The PngStream class is deprecated. Use client.getPngStream() instead.'); + Stream.call(this); + + options = options || {}; + + this.readable = true; + this._options = options; + this._tcpVideoStream = null; + this._pngEncoder = null; +} + +PngStream.prototype.resume = function() { + this._resume(); +}; + +PngStream.prototype._resume = function() { + var self = this; + + this._tcpVideoStream = new PngStream.TcpVideoStream(this._options); + this._pngEncoder = new PngStream.PngEncoder(this._options); + + this._tcpVideoStream.on('error', function(err) { + self._pngEncoder.end(); + self._resume(); + + if (self.listeners('error').length > 0) { + self.emit('error', err); + } + }); + + this._tcpVideoStream.connect(); + this._tcpVideoStream.pipe(this._pngEncoder); + this._pngEncoder.on('data', this.emit.bind(this, 'data')); + this._pngEncoder.on('error', this.emit.bind(this, 'error')); +}; diff --git a/node_modules/ar-drone/lib/video/TcpVideoStream.js b/node_modules/ar-drone/lib/video/TcpVideoStream.js new file mode 100644 index 0000000..5be24c5 --- /dev/null +++ b/node_modules/ar-drone/lib/video/TcpVideoStream.js @@ -0,0 +1,60 @@ +var Stream = require('stream').Stream; +var util = require('util'); +var net = require('net'); +var constants = require('../constants'); + +module.exports = TcpVideoStream; +util.inherits(TcpVideoStream, Stream); +function TcpVideoStream(options) { + Stream.call(this); + + options = options || {}; + + this.readable = true; + this._socket = options.socket || new net.Socket; + this._port = options.port || constants.ports.VIDEO; + this._ip = options.ip || constants.DEFAULT_DRONE_IP; + this._timeout = options.timeout || 1 * 1000; + this._expectFIN = false; +} + +TcpVideoStream.prototype.connect = function(cb) { + cb = cb || function() {}; + + this._socket.removeAllListeners(); // To avoid duplicates when re-connecting + this._socket.connect(this._port, this._ip); + this._socket.setTimeout(this._timeout); + + var self = this; + this._socket + .on('connect', function() { + cb(null); + }) + .on('data', function(buffer) { + self.emit('data', buffer); + }) + .on('timeout', function() { + var err = new Error('TcpVideoStream timeout after ' + self._timeout + ' ms.'); + self.emit('error', err); + self.emit('close', err); + self._socket.destroy(); + }) + .on('error', function(err) { + cb(err); + }) + .on('end', function() { + if (self._expectFIN) { + self.emit('close'); + return; + } + + var err = new Error('TcpVideoStream received FIN unexpectedly.'); + self.emit('error', err); + self.emit('close', err); + }); +}; + +TcpVideoStream.prototype.end = function() { + this._expectFIN = true; + this._socket.end(); +}; diff --git a/node_modules/ar-drone/node_modules/buffy/.npmignore b/node_modules/ar-drone/node_modules/buffy/.npmignore new file mode 100644 index 0000000..8a3e27e --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/.npmignore @@ -0,0 +1,4 @@ +*.un~ +/node_modules +/benchmarks/fixtures/*.bin +/benchmarks/node_modules diff --git a/node_modules/ar-drone/node_modules/buffy/CONTRIBUTING.md b/node_modules/ar-drone/node_modules/buffy/CONTRIBUTING.md new file mode 100644 index 0000000..175775f --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing + +## Running the test suite + +```js +$ git clone +$ cd +$ npm install +$ make test +``` + +## Running an individual test + +```js +$ node test/unit/test-Reader.js +``` + +## TODOS + +If you are looking for something to work on, here are a few things I'd like to +see in this module: + +* Implement benchmark suite (with some nice R analysis) +* Implement `reader.compact()` and/or `new Reader({compact: true})`. Allows for + the internal `this._buffer` to shrink. (The current behavior is to grow the + internal buffer until it can hold the biggest buffer passed into `write()`). +* Implement Writer class. Will probably create many internal buffers and flatten + them into one at the end. Should also support to be initialized with a length + in which case small buffers are not created all the time. + +And of course, feel free to send patches for any open tickets / bugs. diff --git a/node_modules/ar-drone/node_modules/buffy/LICENSE b/node_modules/ar-drone/node_modules/buffy/LICENSE new file mode 100644 index 0000000..c7ff12a --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/node_modules/ar-drone/node_modules/buffy/Makefile b/node_modules/ar-drone/node_modules/buffy/Makefile new file mode 100644 index 0000000..9213861 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/Makefile @@ -0,0 +1,6 @@ +SHELL := /bin/bash + +test: + node test/run.js + +.PHONY: test diff --git a/node_modules/ar-drone/node_modules/buffy/README.md b/node_modules/ar-drone/node_modules/buffy/README.md new file mode 100644 index 0000000..edaef7f --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/README.md @@ -0,0 +1,111 @@ +# buffy (The Buffer Slayer) + +A module to read / write binary data and streams. + +## Install + +```bash +npm install buffy +``` + +## Usage + +Let's say you want to parse a simple C struct, buffy can help: + +```js +var buffy = require('buffy'); + +var buffer = new Buffer([23, 0, 0, 0, 15, 116, 101, 115, 116]); +var reader = buffy.createReader(buffer); + +var record = { + version : reader.uint8(), + id : reader.uint32(), + name : reader.ascii(4), +}; + +// {version: 23, id: 15, name: 'test'} +``` + +Parsing a buffer is nice, but what about streams? Well, buffy has your back: + +```js +var buffy = require('buffy'); +var net = require('net'); +var connection = net.createConnection(1337, 'example.org'); + +var reader = buffy.createReader(); +connection.pipe(reader); + +reader.on('data', function() { + while (reader.bytesAhead() >= 9) { + var record = { + version : reader.uint8(), + id : reader.uint32(), + name : reader.ascii(4), + }; + } +}); +``` + +Future version may also support a declarative syntax for defining structs and +their sequences. + +## Reader API + +### reader.write(buffer) + +Appends the given `buffer` to the internal buffer. Whenever possible, existing +space inside the internal buffer will be reused, otherwise a new / bigger buffer +will be created. + +### reader.bytesAhead() + +Returns the number of unread bytes available to the reader. + +### reader.bytesBuffered() + +Returns the number of bytes that are buffered by the Reader internally. + +### reader.int8() / reader.uint8() + +Returns the next (un)signed 8 bit integer. + +### reader.int16BE() / reader.uint16BE() / reader.int16LE() / reader.uint16LE() + +Returns the next (un)signed 16 bit integer in the chosen endianness. + +### reader.int32BE() / reader.uint32BE() / reader.int32LE() / reader.uint32LE() + +Returns the next (un)signed 32 bit integer in the chosen endianness. + +### reader.float32BE() / reader.float32LE() + +Returns the next 32 bit float in the chosen endianness. + +### reader.double64BE() / reader.double64LE() + +Returns the next 64 bit double in the chosen endianness. + +### reader.ascii([bytes]) / reader.utf8([bytes]) + +Returns the next `bytes` as a string of the chosen encoding. If `bytes` is +omitted, a null terminated string is assumed. + +### reader.buffer([bytes]) + +Returns the next `bytes` as a buffer. + +### reader.skip(bytes) + +Skips `bytes` bytes of the buffer. + + +## Writer API + +The Writer has not been implemented yet. + +## Error Handling + +The reader will throw an exception whenever an operation exceeds the boundary +of the internal buffer. diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/Makefile b/node_modules/ar-drone/node_modules/buffy/benchmarks/Makefile new file mode 100644 index 0000000..8937f06 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/Makefile @@ -0,0 +1,8 @@ +results/ascii-strings-binary.csv: binary.js fixtures/ascii-strings.bin + node $^ | tee $@ + +results/ascii-strings-buffy.csv: buffy.js fixtures/ascii-strings.bin + node $^ | tee $@ + +fixtures/ascii-strings.bin: fixtures/generate-strings.js + node $^ $@ diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/Readme.md b/node_modules/ar-drone/node_modules/buffy/benchmarks/Readme.md new file mode 100644 index 0000000..83191d6 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/Readme.md @@ -0,0 +1,3 @@ +# Benchmarks + +Work in progress ... diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/binary.js b/node_modules/ar-drone/node_modules/buffy/benchmarks/binary.js new file mode 100644 index 0000000..aec02b1 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/binary.js @@ -0,0 +1,28 @@ +var benchmark = require('./lib/benchmark')('binary', process.argv[2]); + +benchmark('ascii-strings', function(binary, stream, cb) { + var checksum = 0; + var reachedEnd = false; + + var ws = binary() + .loop(function (end) { + this + .word8('stringLength') + .buffer('string', 'stringLength') + .tap(function(vars) { + checksum += vars.string.length; + + if (checksum === 650303) { + cb(null, checksum); + } + }) + }); + + stream + .on('data', function(buffer) { + ws.write(buffer); + }) + .on('end', function() { + ws.end(); + }); +}); diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/buffy.js b/node_modules/ar-drone/node_modules/buffy/benchmarks/buffy.js new file mode 100644 index 0000000..e0e4d69 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/buffy.js @@ -0,0 +1,35 @@ +var benchmark = require('./lib/benchmark')('buffy', process.argv[2]); + +benchmark('ascii-strings', function(buffy, stream, cb) { + var reader = buffy.createReader(); + + var checksum = 0; + var stringLength = undefined; + + stream + .on('data', function(buffer) { + reader.write(buffer); + + while (true) { + if (stringLength === undefined) { + if (reader.bytesAhead() < 1) { + break; + } + + stringLength = reader.uint8(); + } + + if (reader.bytesAhead() < stringLength) { + break; + } + + var string = reader.ascii(stringLength); + + checksum += stringLength; + stringLength = undefined; + } + }) + .on('end', function() { + cb(null, checksum); + }); +}); diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/fixtures/generate-strings.js b/node_modules/ar-drone/node_modules/buffy/benchmarks/fixtures/generate-strings.js new file mode 100644 index 0000000..0d8df72 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/fixtures/generate-strings.js @@ -0,0 +1,41 @@ +var fs = require('fs'); +var loremIpsum = require('lorem-ipsum') + +var gigabit = (1000 * 1000 * 1000) / 8; +var bufferSize = 64 * 1024; + +var filename = process.argv[2]; +fs.writeFileSync(filename, new Buffer(0)); + +var fileOffset = 0; +while (fileOffset < gigabit) { + var bufferOffset = 0; + var buffer = (gigabit - fileOffset < bufferSize) + ? new Buffer(gigabit - fileOffset) + : new Buffer(bufferSize); + + while (bufferOffset < buffer.length) { + var stringLength = Math.floor(Math.random() * 256); + if (stringLength + 1 > buffer.length - bufferOffset) { + stringLength = buffer.length - bufferOffset - 1; + } + + var string = loremIpsum({ + count: 50, + units: 'words', + paragraphPrefix: '', + paragraphSuffix: '', + }).substr(0, stringLength); + + buffer[bufferOffset++] = stringLength; + buffer.write(string, bufferOffset); + bufferOffset += stringLength; + } + + fs.appendFileSync(filename, buffer); + fileOffset += buffer.length; + + process.stdout.write('\rCreating ' + filename + ' (' + (fileOffset * 100 / gigabit).toFixed(2) + ' %)'); +} + +process.stdout.write('\n'); diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/lib/FixtureStream.js b/node_modules/ar-drone/node_modules/buffy/benchmarks/lib/FixtureStream.js new file mode 100644 index 0000000..8f69a4b --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/lib/FixtureStream.js @@ -0,0 +1,35 @@ +var fs = require('fs'); +var Stream = require('stream').Stream; +var util = require('util'); + +module.exports = FixtureStream; +util.inherits(FixtureStream, Stream); +function FixtureStream(path, bufferSize) { + bufferSize = bufferSize || 64 * 1024; + + this.readable = true; + this._buffers = []; + + var buffer = fs.readFileSync(path).slice(0, bufferSize * 10); + var start = 0; + + while (start < buffer.length) { + var bytesLeft = buffer.length - start ; + var size = (bytesLeft >= bufferSize) + ? bufferSize + : bytesLeft; + + this._buffers.push(buffer.slice(start, start + size)); + start += size; + } + + this.length = buffer.length; +} + +FixtureStream.prototype.resume = function() { + for (var i = 0; i < this._buffers.length; i++) { + this.emit('data', this._buffers[i]); + } + + this.emit('end'); +}; diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/lib/benchmark.js b/node_modules/ar-drone/node_modules/buffy/benchmarks/lib/benchmark.js new file mode 100644 index 0000000..313b72d --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/lib/benchmark.js @@ -0,0 +1,59 @@ +var path = require('path'); +var FixtureStream = require('./FixtureStream'); + +module.exports = function(moduleName, fixturePath) { + var lib = require(moduleName); + var packageJSON = require(moduleName + '/package.json'); + + var fixtureName = path.basename(fixturePath, '.bin'); + + return function benchmark(name, benchmarkFn) { + if (name !== fixtureName) { + return; + } + + run(benchmarkFn, fixturePath, lib, packageJSON); + }; +}; + +function run(benchmarkFn, fixturePath, lib, packageJSON) { + var stream = new FixtureStream(fixturePath); + var iterations = 100; + + console.log(['time', 'bytesPerSec', 'memoryUsage', 'lib', 'version'].join('\t')); + + function nextIteration() { + var start = Date.now(); + + benchmarkFn(lib, stream, function(err, checksum) { + if (err) throw err; + + var duration = Date.now() - start; + + if (checksum !== 124067628) { + //throw new Error('bad checksum: ' + checksum); + } + + stream.removeAllListeners(); + + var bytesPerSec = Math.round(stream.length / (duration / 1000)); + + console.log([ + Date.now(), + bytesPerSec, + process.memoryUsage().rss, + packageJSON.name, + packageJSON.version + ].join('\t')); + + iterations--; + if (iterations) { + process.nextTick(nextIteration); + } + }); + + stream.resume(); + } + + nextIteration(); +} diff --git a/node_modules/ar-drone/node_modules/buffy/benchmarks/package.json b/node_modules/ar-drone/node_modules/buffy/benchmarks/package.json new file mode 100644 index 0000000..93985ac --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/benchmarks/package.json @@ -0,0 +1,15 @@ +{ + "author": "Felix Geisendörfer (http://debuggable.com/)", + "name": "buffy-benchmarks", + "private": true, + "version": "0.0.0", + "dependencies": { + "binary": "~0.3.0", + "lorem-ipsum": "0.0.7" + }, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + } +} diff --git a/node_modules/ar-drone/node_modules/buffy/index.js b/node_modules/ar-drone/node_modules/buffy/index.js new file mode 100644 index 0000000..64b42e6 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/index.js @@ -0,0 +1,6 @@ +var buffy = exports; + +buffy.Reader = require('./lib/Reader'); +buffy.createReader = function(options) { + return new buffy.Reader(options); +}; diff --git a/node_modules/ar-drone/node_modules/buffy/lib/Reader.js b/node_modules/ar-drone/node_modules/buffy/lib/Reader.js new file mode 100644 index 0000000..59c3635 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/lib/Reader.js @@ -0,0 +1,181 @@ +var util = require('util'); +var EventEmitter = require('events').EventEmitter; + +module.exports = Reader; +util.inherits(Reader, EventEmitter); +function Reader(options) { + EventEmitter.call(this); + + if (Buffer.isBuffer(options)) { + options = {buffer: options}; + } + + options = options || {}; + + this.writable = true; + + this._buffer = options.buffer || new Buffer(0); + this._offset = options.offset || 0; + this._paused = false; +} + +Reader.prototype.write = function(newBuffer) { + var bytesAhead = this.bytesAhead(); + + // existing buffer has enough space in the beginning? + var reuseBuffer = (this._offset >= newBuffer.length); + + if (reuseBuffer) { + // move unread bytes forward to make room for the new + this._buffer.copy(this._buffer, this._offset - newBuffer.length, this._offset); + this._offset -= newBuffer.length; + + // add the new bytes at the end + newBuffer.copy(this._buffer, this._buffer.length - newBuffer.length); + } else { + var oldBuffer = this._buffer; + + // grow a new buffer that can hold both + this._buffer = new Buffer(bytesAhead + newBuffer.length); + + // copy the old and new buffer into it + oldBuffer.copy(this._buffer, 0, this._offset); + newBuffer.copy(this._buffer, bytesAhead); + this._offset = 0; + } + + return !this._paused; +}; + +Reader.prototype.pause = function() { + this._paused = true; +}; + +Reader.prototype.resume = function() { + this._paused = false; +}; + +Reader.prototype.bytesAhead = function() { + return this._buffer.length - this._offset; +}; + +Reader.prototype.bytesBuffered = function() { + return this._buffer.length; +}; + +Reader.prototype.uint8 = function() { + return this._buffer.readUInt8(this._offset++); +}; + +Reader.prototype.int8 = function() { + return this._buffer.readInt8(this._offset++); +}; + +Reader.prototype.uint16BE = function() { + this._offset += 2; + return this._buffer.readUInt16BE(this._offset - 2); +}; + +Reader.prototype.int16BE = function() { + this._offset += 2; + return this._buffer.readInt16BE(this._offset - 2); +}; + +Reader.prototype.uint16LE = function() { + this._offset += 2; + return this._buffer.readUInt16LE(this._offset - 2); +}; + +Reader.prototype.int16LE = function() { + this._offset += 2; + return this._buffer.readInt16LE(this._offset - 2); +}; + +Reader.prototype.uint32BE = function() { + this._offset += 4; + return this._buffer.readUInt32BE(this._offset - 4); +}; + +Reader.prototype.int32BE = function() { + this._offset += 4; + return this._buffer.readInt32BE(this._offset - 4); +}; + +Reader.prototype.uint32LE = function() { + this._offset += 4; + return this._buffer.readUInt32LE(this._offset - 4); +}; + +Reader.prototype.int32LE = function() { + this._offset += 4; + return this._buffer.readInt32LE(this._offset - 4); +}; + +Reader.prototype.float32BE = function() { + this._offset += 4; + return this._buffer.readFloatBE(this._offset - 4); +}; + +Reader.prototype.float32LE = function() { + this._offset += 4; + return this._buffer.readFloatLE(this._offset - 4); +}; + +Reader.prototype.double64BE = function() { + this._offset += 8; + return this._buffer.readDoubleBE(this._offset - 8); +}; + +Reader.prototype.double64LE = function() { + this._offset += 8; + return this._buffer.readDoubleLE(this._offset - 8); +}; + +Reader.prototype.ascii = function(bytes) { + return this._string('ascii', bytes); +}; + +Reader.prototype.utf8 = function(bytes) { + return this._string('utf8', bytes); +}; + +Reader.prototype._string = function(encoding, bytes) { + var nullTerminated = (bytes === undefined); + if (nullTerminated) { + bytes = this._nullDistance(); + } + + var offset = this._offset; + this._offset += bytes; + + var value = this._buffer.toString(encoding, offset, this._offset); + + if (nullTerminated) { + this._offset++; + } + + return value; +}; + +Reader.prototype._nullDistance = function() { + for (var i = this._offset; i < this._buffer.length; i++) { + var byte = this._buffer[i]; + if (byte === 0) { + return i - this._offset; + } + } +}; + +Reader.prototype.buffer = function(bytes) { + this._offset += bytes; + var ret = new Buffer(bytes); + this._buffer.copy(ret, 0, this._offset - bytes, this._offset); + return ret; +}; + +Reader.prototype.skip = function(bytes) { + if (bytes > this.bytesAhead() || bytes < 0) { + this.emit('error', new Error('tried to skip outsite of the buffer')); + } + this._offset += bytes; +}; diff --git a/node_modules/ar-drone/node_modules/buffy/package.json b/node_modules/ar-drone/node_modules/buffy/package.json new file mode 100644 index 0000000..066121e --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/package.json @@ -0,0 +1,45 @@ +{ + "author": { + "name": "Felix Geisendörfer", + "email": "felix@debuggable.com", + "url": "http://debuggable.com/" + }, + "contributors": [ + { + "name": "Bernhard K. Weisshuhn", + "email": "bkw@codingforce.com" + } + ], + "name": "buffy", + "description": "A module to read / write binary data and streams.", + "version": "0.0.4", + "homepage": "https://github.com/felixge/node-buffy", + "repository": { + "type": "git", + "url": "git://github.com/felixge/node-buffy.git" + }, + "main": "./index", + "scripts": { + "test": "make test" + }, + "dependencies": {}, + "optionalDependencies": {}, + "devDependencies": { + "utest": "0.0.6", + "urun": "0.0.6" + }, + "engines": { + "node": "*" + }, + "readme": "# buffy (The Buffer Slayer)\n\nA module to read / write binary data and streams.\n\n## Install\n\n```bash\nnpm install buffy\n```\n\n## Usage\n\nLet's say you want to parse a simple C struct, buffy can help:\n\n```js\nvar buffy = require('buffy');\n\nvar buffer = new Buffer([23, 0, 0, 0, 15, 116, 101, 115, 116]);\nvar reader = buffy.createReader(buffer);\n\nvar record = {\n version : reader.uint8(),\n id : reader.uint32(),\n name : reader.ascii(4),\n};\n\n// {version: 23, id: 15, name: 'test'}\n```\n\nParsing a buffer is nice, but what about streams? Well, buffy has your back:\n\n```js\nvar buffy = require('buffy');\nvar net = require('net');\nvar connection = net.createConnection(1337, 'example.org');\n\nvar reader = buffy.createReader();\nconnection.pipe(reader);\n\nreader.on('data', function() {\n while (reader.bytesAhead() >= 9) {\n var record = {\n version : reader.uint8(),\n id : reader.uint32(),\n name : reader.ascii(4),\n };\n }\n});\n```\n\nFuture version may also support a declarative syntax for defining structs and\ntheir sequences.\n\n## Reader API\n\n### reader.write(buffer)\n\nAppends the given `buffer` to the internal buffer. Whenever possible, existing\nspace inside the internal buffer will be reused, otherwise a new / bigger buffer\nwill be created.\n\n### reader.bytesAhead()\n\nReturns the number of unread bytes available to the reader.\n\n### reader.bytesBuffered()\n\nReturns the number of bytes that are buffered by the Reader internally.\n\n### reader.int8() / reader.uint8()\n\nReturns the next (un)signed 8 bit integer.\n\n### reader.int16BE() / reader.uint16BE() / reader.int16LE() / reader.uint16LE()\n\nReturns the next (un)signed 16 bit integer in the chosen endianness.\n\n### reader.int32BE() / reader.uint32BE() / reader.int32LE() / reader.uint32LE()\n\nReturns the next (un)signed 32 bit integer in the chosen endianness.\n\n### reader.float32BE() / reader.float32LE()\n\nReturns the next 32 bit float in the chosen endianness.\n\n### reader.double64BE() / reader.double64LE()\n\nReturns the next 64 bit double in the chosen endianness.\n\n### reader.ascii([bytes]) / reader.utf8([bytes])\n\nReturns the next `bytes` as a string of the chosen encoding. If `bytes` is\nomitted, a null terminated string is assumed.\n\n### reader.buffer([bytes])\n\nReturns the next `bytes` as a buffer.\n\n### reader.skip(bytes)\n\nSkips `bytes` bytes of the buffer.\n\n\n## Writer API\n\nThe Writer has not been implemented yet.\n\n## Error Handling\n\nThe reader will throw an exception whenever an operation exceeds the boundary\nof the internal buffer.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/felixge/node-buffy/issues" + }, + "_id": "buffy@0.0.4", + "dist": { + "shasum": "d208104fbd9b47a87cbb01fe3b2ef2df54300df8" + }, + "_from": "buffy@0.0.4", + "_resolved": "https://registry.npmjs.org/buffy/-/buffy-0.0.4.tgz" +} diff --git a/node_modules/ar-drone/node_modules/buffy/test/common.js b/node_modules/ar-drone/node_modules/buffy/test/common.js new file mode 100644 index 0000000..24c5833 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/test/common.js @@ -0,0 +1,5 @@ +var common = exports; +var path = require('path'); + +common.root = path.join(__dirname, '..'); +common.lib = path.join(common.root, 'lib'); diff --git a/node_modules/ar-drone/node_modules/buffy/test/run.js b/node_modules/ar-drone/node_modules/buffy/test/run.js new file mode 100644 index 0000000..37dc3b4 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/test/run.js @@ -0,0 +1,2 @@ +var urun = require('urun'); +urun(__dirname); diff --git a/node_modules/ar-drone/node_modules/buffy/test/unit/test-Reader.js b/node_modules/ar-drone/node_modules/buffy/test/unit/test-Reader.js new file mode 100644 index 0000000..d8503e8 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/test/unit/test-Reader.js @@ -0,0 +1,302 @@ +var common = require('../common'); +var test = require('utest'); +var assert = require('assert'); +var Reader = require(common.lib + '/Reader'); + +test('Constructor', { + 'offset option': function() { + var buffer = new Buffer([0, 127]); + var reader = new Reader({buffer: buffer, offset: 1}); + + assert.equal(reader.uint8(), 127); + }, +}); + +test('WritableStream interface', { + 'is writable by default': function() { + var reader = new Reader(); + assert.equal(reader.writable, true); + }, + + 'write: returns true when active': function() { + var reader = new Reader(); + assert.equal(reader.write(new Buffer(0)), true); + }, + + 'write: returns false when paused': function() { + var reader = new Reader(); + + reader.pause(); + assert.equal(reader.write(new Buffer(0)), false); + }, + + 'write: returns true when resumed': function() { + var reader = new Reader(); + + reader.pause(); + assert.equal(reader.write(new Buffer(0)), false); + + reader.resume(); + assert.equal(reader.write(new Buffer(0)), true); + }, + + 'write: collects buffer data': function() { + var reader = new Reader(); + + reader.write(new Buffer([1, 2])); + assert.equal(reader.uint8(), 1); + + reader.write(new Buffer([3])); + assert.equal(reader.uint8(), 2); + assert.equal(reader.uint8(), 3); + }, + + 'write: uses existing buffer if possible': function() { + var reader = new Reader(); + + reader.write(new Buffer([1, 2, 3])); + assert.equal(reader.uint8(), 1); + reader.write(new Buffer([4])); + + assert.equal(reader.bytesBuffered(), 3); + assert.equal(reader.uint8(), 2); + assert.equal(reader.uint8(), 3); + assert.equal(reader.uint8(), 4); + }, + + 'write: grows buffer if neccessary': function() { + var reader = new Reader(); + + reader.write(new Buffer([1, 2])); + assert.equal(reader.uint8(), 1); + reader.write(new Buffer([3, 4, 5])); + assert.equal(reader.uint8(), 2); + assert.equal(reader.uint8(), 3); + assert.equal(reader.uint8(), 4); + assert.equal(reader.uint8(), 5); + }, +}); + +test('Read Methods', { + 'bytesAhead': function() { + var buffer = new Buffer([1, 127, 128, 255]); + var reader = new Reader(buffer); + + assert.equal(reader.bytesAhead(), 4); + reader.uint8(); + reader.uint8(); + + assert.equal(reader.bytesAhead(), 2); + }, + + 'bytesAhead: reports correctly with smaller buffer': function() { + var reader = new Reader(); + + reader.write(new Buffer([1, 2])); + reader.buffer(2); + reader.write(new Buffer([3])); + assert.equal(reader.bytesAhead(), 1); + }, + + 'uint8': function() { + var buffer = new Buffer([1, 127, 128, 255]); + var reader = new Reader(buffer); + + assert.equal(reader.uint8(), 1); + assert.equal(reader.uint8(), 127); + assert.equal(reader.uint8(), 128); + assert.equal(reader.uint8(), 255); + }, + + 'int8': function() { + var buffer = new Buffer([1, 127, 128, 255]); + var reader = new Reader(buffer); + + assert.equal(reader.int8(), 1); + assert.equal(reader.int8(), 127); + assert.equal(reader.int8(), -128); + assert.equal(reader.int8(), -1); + }, + + 'uint16BE': function() { + var buffer = new Buffer([1, 127, 128, 255]); + var reader = new Reader(buffer); + + assert.equal(reader.uint16BE(), 1 * 256 + 127); + assert.equal(reader.uint16BE(), 128 * 256 + 255); + }, + + 'int16BE': function() { + var buffer = new Buffer([1, 127, 128, 255]); + var reader = new Reader(buffer); + + assert.equal(reader.int16BE(), 1 * 256 + 127); + assert.equal(reader.int16BE(), -128 * 256 + 255); + }, + + 'uint16LE': function() { + var buffer = new Buffer([1, 127, 128, 255]); + var reader = new Reader(buffer); + + assert.equal(reader.uint16LE(), 1 + 127 * 256); + assert.equal(reader.uint16LE(), 128 + 255 * 256); + }, + + 'int16LE': function() { + var buffer = new Buffer([1, 127, 128, 255]); + var reader = new Reader(buffer); + + assert.equal(reader.int16LE(), 1 + 127 * 256); + assert.equal(reader.int16LE(), -128); + }, + + 'uint32BE': function() { + var buffer = new Buffer([1, 2, 3, 4, 5, 6, 7, 8]); + var reader = new Reader(buffer); + + assert.equal(reader.uint32BE(), 16909060); + assert.equal(reader.uint32BE(), 84281096); + }, + + 'int32BE': function() { + var buffer = new Buffer([1, 2, 3, 4, 255, 254, 253, 252]); + var reader = new Reader(buffer); + + assert.equal(reader.int32BE(), 16909060); + assert.equal(reader.int32BE(), -66052); + }, + + 'uint32LE': function() { + var buffer = new Buffer([1, 2, 3, 4, 5, 6, 7, 8]); + var reader = new Reader(buffer); + + assert.equal(reader.uint32LE(), 67305985); + assert.equal(reader.uint32LE(), 134678021); + }, + + 'int32LE': function() { + var buffer = new Buffer([1, 2, 3, 4, 255, 254, 253, 252]); + var reader = new Reader(buffer); + + assert.equal(reader.int32LE(), 67305985); + assert.equal(reader.int32LE(), -50462977); + }, + + 'float32BE': function() { + var buffer = new Buffer([ + 0x41, 0xb8, 0x00, 0x00, // 23 + 0xbf, 0x80, 0x00, 0x00, // -1 + ]); + + var reader = new Reader(buffer); + + assert.equal(reader.float32BE(), 23); + assert.equal(reader.float32BE(), -1); + }, + + 'float32LE': function() { + var buffer = new Buffer([ + 0x00, 0x00, 0xb8, 0x41, // 23 + 0x00, 0x00, 0x80, 0xbf, // -1 + ]); + var reader = new Reader(buffer); + + assert.equal(reader.float32LE(), 23); + assert.equal(reader.float32LE(), -1); + }, + + 'double64BE': function() { + var buffer = new Buffer([ + 0x40, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbf, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]); + var reader = new Reader(buffer); + + assert.equal(reader.double64BE(), 23); + assert.equal(reader.double64BE(), -1); + }, + + 'double64LE': function() { + var buffer = new Buffer([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbf, + ]); + var reader = new Reader(buffer); + + assert.equal(reader.double64LE(), 23); + assert.equal(reader.double64LE(), -1); + }, + + 'ascii: fixed length ascii': testParseFixedLengthAsciiWith('ascii'), + 'ascii: fixed length snowman': testParseFixedLengthSnowmanWith('ascii'), + 'ascii: null terminated ascii': testParseNullTerminatedAsciiWith('ascii'), + + 'utf8: fixed length ascii': testParseFixedLengthAsciiWith('utf8'), + 'utf8: fixed length snowman': testParseFixedLengthSnowmanWith('utf8'), + 'utf8: null terminated ascii': testParseNullTerminatedAsciiWith('utf8'), + + 'buffer': function() { + var buffer = new Buffer([1, 2, 3, 4, 5]); + var reader = new Reader(buffer); + + assert.deepEqual(reader.buffer(3), new Buffer([1, 2, 3])); + assert.deepEqual(reader.buffer(2), new Buffer([4, 5])); + }, + 'buffer: return a copy' : function () { + var reader = new Reader(new Buffer([1])); + var origResult = reader.buffer(1); + reader.write(new Buffer([2])); + assert.deepEqual(origResult, new Buffer([1])); + }, + + 'skip' : function() { + var reader = new Reader(new Buffer([1, 2, 3, 4, 5])); + reader.skip(2); + assert.deepEqual(reader.buffer(3), new Buffer([3, 4, 5])); + assert.throws(function() { reader.skip(1); }); + assert.throws(function() { reader.skip(-1); }); + } +}); + +function testParseFixedLengthAsciiWith(encoding) { + return function() { + var buffer = new Buffer([ + 'a'.charCodeAt(), + 'b'.charCodeAt(), + 'c'.charCodeAt(), + 'd'.charCodeAt(), + 'e'.charCodeAt(), + ]); + var reader = new Reader(buffer); + + assert.equal(reader[encoding](3), 'abc'); + assert.equal(reader[encoding](2), 'de'); + }; +} + +function testParseFixedLengthSnowmanWith(encoding) { + return function() { + var buffer = new Buffer('\u2603', 'utf8'); + var reader = new Reader(buffer); + + assert.equal(reader[encoding](3), '☃'); + }; +} + +function testParseNullTerminatedAsciiWith(encoding) { + return function() { + var buffer = new Buffer([ + 'a'.charCodeAt(), + 'b'.charCodeAt(), + 'c'.charCodeAt(), + 0, + 'd'.charCodeAt(), + 'e'.charCodeAt(), + 0, + ]); + var reader = new Reader(buffer); + + assert.equal(reader[encoding](), 'abc'); + assert.equal(reader[encoding](), 'de'); + }; +} diff --git a/node_modules/ar-drone/node_modules/buffy/test/unit/test-buffy.js b/node_modules/ar-drone/node_modules/buffy/test/unit/test-buffy.js new file mode 100644 index 0000000..9c2a560 --- /dev/null +++ b/node_modules/ar-drone/node_modules/buffy/test/unit/test-buffy.js @@ -0,0 +1,17 @@ +var common = require('../common'); +var test = require('utest'); +var assert = require('assert'); +var buffy = require(common.root); +var Reader = require(common.lib + '/Reader'); + +test('buffy', { + 'exports: Reader': function() { + assert.strictEqual(buffy.Reader, Reader); + }, + + 'createReader: maps to Reader constructor': function() { + var reader = buffy.createReader(new Buffer(23)); + assert.equal(reader instanceof Reader, true); + assert.equal(reader.bytesAhead(), 23); + }, +}); diff --git a/node_modules/ar-drone/package.json b/node_modules/ar-drone/package.json new file mode 100644 index 0000000..3760d21 --- /dev/null +++ b/node_modules/ar-drone/package.json @@ -0,0 +1,42 @@ +{ + "author": { + "name": "Felix Geisendörfer", + "email": "felix@debuggable.com", + "url": "http://debuggable.com/" + }, + "name": "ar-drone", + "description": "A node.js client for controlling Parrot AR Drone 2.0 quad-copters.", + "version": "0.1.0", + "homepage": "https://github.com/felixge/node-ar-drone", + "repository": { + "type": "git", + "url": "git://github.com/felixge/node-ar-drone.git" + }, + "main": "./index", + "scripts": { + "test": "node test/run.js" + }, + "dependencies": { + "buffy": "0.0.4" + }, + "devDependencies": { + "utest": "0.0.6", + "urun": "0.0.6", + "sinon": "1.4.2" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "readme": "# ar-drone\n\n[![Build Status](https://secure.travis-ci.org/felixge/node-ar-drone.png)](http://travis-ci.org/felixge/node-ar-drone)\n\nAn implementation of the networking protocols used by the\n[Parrot AR Drone 2.0](http://ardrone2.parrot.com/). It appears that 1.0 drones are also [compatible](https://github.com/felixge/node-ar-drone/issues/11#issuecomment-9402270).\n\nInstall via Github to get the *latest* version:\n\n```bash\nnpm install git://github.com/felixge/node-ar-drone.git\n```\n\nOr, if you're fine with missing some cutting edge stuff, go for npm:\n\n```bash\nnpm install ar-drone\n```\n\n## Introduction\n\nThe AR Drone is an affordable, yet surprisingly capable quadcopter. The drone\nitself runs a proprietary firmware that can be controlled via WiFi using the official\nFreeFlight mobile app\n(available for [iOS](http://itunes.apple.com/us/app/freeflight/id373065271?mt=8) and [Android](https://play.google.com/store/apps/details?id=com.parrot.freeflight&hl=en)).\n\nUnlike the firmware, the client protocol is open, and Parrot publishes an [SDK](https://projects.ardrone.org/projects/show/ardrone-api)\n(signup required to download) including a good amount of documentation and C\ncode. Their target audience seems to be mobile developers who can use this\nSDK to create games and other apps for people to have more fun with their drones.\n\nHowever, the protocol can also be used to receive video and sensor data, enabling\ndevelopers to write autonomous programs for the upcoming robot revolution.\n\n## Status\n\nThis module is still under [heavy development](./node-ar-drone/blob/master/CONTRIBUTING.md), so please don't be suprised if\nyou find some functionality missing or undocumented.\n\nHowever, the documented parts are tested and should work well for most parts.\n\n## Client\n\nThis module exposes a high level Client API that tries to support all drone\nfeatures, while making them easy to use.\n\nThe best way to get started is to create a `repl.js` file like this:\n\n```js\nvar arDrone = require('ar-drone');\nvar client = arDrone.createClient();\nclient.createRepl();\n```\n\nUsing this REPL, you should be able to have some fun:\n\n```js\n$ node repl.js\n// Make the drone takeoff\ndrone> takeoff()\ntrue\n// Wait for the drone to takeoff\ndrone> clockwise(0.5)\n0.5\n// Let the drone spin for a while\ndrone> land()\ntrue\n// Wait for the drone to land\n```\n\nNow you could write an autonomous program that does the same:\n\n```js\nvar arDrone = require('ar-drone');\nvar client = arDrone.createClient();\n\nclient.takeoff();\n\nclient\n .after(5000, function() {\n this.clockwise(0.5);\n })\n .after(3000, function() {\n this.stop();\n this.land();\n });\n```\n\nOk, but what if you want to make your drone to interact with something? Well,\nyou could start by looking at the sensor data:\n\n```js\nclient.on('navdata', console.log);\n```\n\nNot all of this is handled by the Client library yet, but you should at the\nvery least be able to receive `droneState` and `demo` data.\n\nA good initial challenge might be to try flying to a certain altitude based\non the `navdata.demo.altitudeMeters` property.\n\nOnce you have manged this, you may want to try looking at the camera image. Here\nis a simple way to get this as PngBuffers (requires a recent ffmpeg version to\nbe found in your `$PATH`):\n\n```js\nvar pngStream = client.getPngStream();\npngStream.on('data', console.log);\n```\n\nYour first challenge might be to expose these png images as a node http web\nserver. Once you have done that, you should try feeding them into the\n[opencv](https://npmjs.org/package/opencv) module.\n\n### Client API\n\n#### arDrone.createClient([options])\n\nReturns a new `Client` object. `options` include:\n\n* `ip`: The IP of the drone. Defaults to `'192.168.1.1'`.\n\n#### client.createREPL()\n\nLaunches an interactive interface with all client methods available in the\nactive scope. Additionally `client` resolves to the `client` instance itself.\n\n#### client.getPngStream()\n\nReturns a `PngEncoder` object that emits individual png image buffers as `'data'`\nevents. Multiple calls to this method returns the same object. Connection lifecycle\n(e.g. reconnect on error) is managed by the client.\n\n#### client.getVideoStream()\n\nReturns a `TcpVideoStream` object that emits raw tcp packets as `'data'`\nevents. Multiple calls to this method returns the same object. Connection lifecycle\n(e.g. reconnect on error) is managed by the client.\n\n#### client.takeoff(cb)\n\nSets the internal `fly` state to `true`, `cb` is invoked after the drone\nreports that it is hovering.\n\n#### client.land(cb)\n\nSets the internal `fly` state to `false`, `cb` is invoked after the drone\nreports it has landed.\n\n#### client.up(speed) / client.down(speed)\n\nMakes the drone gain or reduce altitude. `speed` can be a value from `0` to `1`.\n\n#### client.clockwise(speed) / client.counterClockwise(speed)\n\nCauses the drone to spin. `speed` can be a value from `0` to `1`.\n\n#### client.front(speed) / client.back(speed)\n\nControls the pitch, which a horizontal movement using the camera\nas a reference point. `speed` can be a value from `0` to `1`.\n\n#### client.left(speed) / client.right(speed)\n\nControls the roll, which is a horizontal movement using the camera\nas a reference point. `speed` can be a value from `0` to `1`.\n\n#### client.stop()\n\nSets all drone movement commands to `0`, making it effectively hover in place.\n\n#### client.config(key, value)\n\nSends a config command to the drone. You will need to download the drone\n[SDK](https://projects.ardrone.org/projects/show/ardrone-api) to find a full list of commands in the `ARDrone_Developer_Guide.pdf`.\n\nFor example, this command can be used to instruct the drone to send all navdata.\n\n```js\nclient.config('general:navdata_demo', 'FALSE');\n```\n\n\n#### client.animate(animation, duration)\n\nPerforms a pre-programmed flight sequence for a given `duration` (in ms).\n`animation` can be one of the following:\n\n\n```js\n['phiM30Deg', 'phi30Deg', 'thetaM30Deg', 'theta30Deg', 'theta20degYaw200deg',\n'theta20degYawM200deg', 'turnaround', 'turnaroundGodown', 'yawShake',\n'yawDance', 'phiDance', 'thetaDance', 'vzDance', 'wave', 'phiThetaMixed',\n'doublePhiThetaMixed', 'flipAhead', 'flipBehind', 'flipLeft', 'flipRight']\n```\n\nExample:\n\n```js\nclient.animate('flipLeft', 1500);\n```\n\nPlease note that the drone will need a good amount of altitude and headroom\nto perform a flip. So be careful!\n\n#### client.animateLeds(animation, hz, duration)\n\nPerforms a pre-programmed led sequence at given `hz` frequency and `duration`\n(in sec!). `animation` can be one of the following:\n\n```js\n['blinkGreenRed', 'blinkGreen', 'blinkRed', 'blinkOrange', 'snakeGreenRed',\n'fire', 'standard', 'red', 'green', 'redSnake', 'blank', 'rightMissile',\n'leftMissile', 'doubleMissile', 'frontLeftGreenOthersRed',\n'frontRightGreenOthersRed', 'rearRightGreenOthersRed',\n'rearLeftGreenOthersRed', 'leftGreenRightRed', 'leftRedRightGreen',\n'blinkStandard']\n```\n\nExample:\n\n```js\nclient.animateLeds('blinkRed', 5, 2)\n```\n\n#### client.disableEmergency()\n\nCauses the emergency REF bit to be set to 1 until\n`navdata.droneState.emergencyLanding` is 0. This recovers a drone that has\nflipped over and is showing red lights to be flyable again and show green\nlights. It is also done implicitly when creating a new high level client.\n\n#### Events\n\nA client will emit landed, hovering, flying, landing, batteryChange, and altitudeChange events as long as demo navdata is enabled.\n\nTo enable demo navdata use\n\n```js\nclient.config('general:navdata_demo', 'FALSE');\n```\n\n## UdpControl\n\nThis is a low level API. If you prefer something simpler, check out the Client\ndocs.\n\nThe drone is controlled by sending UDP packets on port 5556. Because UDP\ndoes not guarantee message ordering or delivery, clients must repeatedly send\ntheir instructions and include an incrementing sequence number with each\ncommand.\n\nFor example, the command used for takeoff/landing (REF), with a sequence number\nof 1, and a parameter of 512 (takeoff) looks like this:\n\n```\nAT*REF=1,512\\r\n```\n\nTo ease the creation and sending of these packets, this module exposes an\n`UdpControl` class handling this task. For example, the following program will\ncause your drone to takeoff and hover in place.\n\n```js\nvar arDrone = require('ar-drone');\nvar control = arDrone.createUdpControl();\n\nsetInterval(function() {\n // The emergency: true option recovers your drone from emergency mode that can\n // be caused by flipping it upside down or the drone crashing into something.\n // In a real program you probably only want to send emergency: true for one\n // second in the beginning, otherwise your drone may attempt to takeoff again\n // after a crash.\n control.ref({fly: true, emergency: true});\n // This command makes sure your drone hovers in place and does not drift.\n control.pcmd();\n // This causes the actual udp message to be send (multiple commands are\n // combined into one message)\n control.flush();\n}, 30);\n```\n\nNow that you are airborne, you can fly around by passing an argument to the\n`pcmd()` method:\n\n```js\ncontrol.pcmd({\n front: 0.5, // fly forward with 50% speed\n up: 0.3, // and also fly up with 30% speed\n});\n```\n\nThat's it! A full list of all `pcmd()` options can be found in the API docs\nbelow.\n\nWith what you have learned so far, you could create a simple program\nlike this:\n\n```js\nvar arDrone = require('ar-drone');\nvar control = arDrone.createUdpControl();\nvar start = Date.now();\n\nvar ref = {};\nvar pcmd = {};\n\nconsole.log('Recovering from emergency mode if there was one ...');\nref.emergency = true;\nsetTimeout(function() {\n console.log('Takeoff ...');\n\n ref.emergency = false;\n ref.fly = true;\n\n}, 1000);\n\nsetTimeout(function() {\n console.log('Turning clockwise ...');\n\n pcmd.clockwise = 0.5;\n}, 6000);\n\nsetTimeout(function() {\n console.log('Landing ...');\n\n ref.fly = false;\n pcmd = {};\n}, 8000);\n\n\nsetInterval(function() {\n control.ref(ref);\n control.pcmd(pcmd);\n control.flush();\n}, 30);\n```\n\n### UdpControl API\n\n#### arDrone.createUdpControl([options]) / new arDrone.UdpControl([options])\n\nCreates a new UdpControl instance where `options` can include:\n\n* `ip`: The drone IP address, defaults to `'192.168.1.1'`.\n* `port`: The port to use, defaults to `5556`.\n\n#### udpControl.raw(command, [arg1, arg2, ...])\n\nEnqueues a raw `AT*` command. This is useful if you want full control.\n\nFor example, a takeoff instructions be send like this:\n\n```js\nudpControl.raw('REF', (1 << 9));\n```\n\n#### udpControl.ref([options])\n\nEnqueues a `AT*REF` command, options are:\n\n* `fly`: Set this to `true` for takeoff / staying in air, or `false` to initiate\n landing / stay on the ground. Defaults to `false`.\n* `emergency`: Set this to `true` to set the emergency bit, or `false` to not\n set it. Details on this can be found in the official SDK Guide. Defaults to\n `false`.\n\n#### udpControl.pcmd([options])\n\nEnqueues a `AT*PCMD` (progressive) command, options are:\n\n* `front` or `back`: Fly towards or away from front camera direction.\n* `left` or/ `right`: Fly towards the left or right of the front camera.\n* `up` or `down`: Gain or reduce altitude.\n* `clockwise` or `counterClockwise`: Rotate around the center axis.\n\nThe values for each option are the speed to use for the operation and can range\nfrom 0 to 1. You can also use negative values like `{front: -0.5}`, which is\nthe same as `{back: 0.5}`.\n\n#### udpControl.flush()\n\nSends all enqueued commands as an UDP packet to the drone.\n\n## Video\n\n@TODO Document the low level video API.\n\n## Navdata\n\n@TODO Document the low level navdata API.\n\n## Environment variables\n\n* DEFAULT_DRONE_IP\n\n## Camera access\n\nYou can access the head camera and the bottom camera, you just have the change\nthe config:\n\n```javascript\n// access the head camera\nclient.config('video:video_channel', 0);\n\n// access the bottom camera\nclient.config('video:video_channel', 3);\n```\n\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/felixge/node-ar-drone/issues" + }, + "_id": "ar-drone@0.1.0", + "dist": { + "shasum": "640c2df02b30edf15630896a3451b43e28b129e0" + }, + "_from": "ar-drone@", + "_resolved": "https://registry.npmjs.org/ar-drone/-/ar-drone-0.1.0.tgz" +} diff --git a/node_modules/ar-drone/test/common.js b/node_modules/ar-drone/test/common.js new file mode 100644 index 0000000..5f2b6dd --- /dev/null +++ b/node_modules/ar-drone/test/common.js @@ -0,0 +1,13 @@ +var common = exports; +var path = require('path'); + +common.root = path.join(__dirname, '..'); +common.lib = path.join(common.root, 'lib'); +common.fixtures = path.join(__dirname, 'fixtures'); + +common.UDP_PORT = 13571; +common.TCP_PORT = 13572; + +common.isTravisCi = function() { + return Boolean(process.env.CI); +}; diff --git a/node_modules/ar-drone/test/fixtures/navdata.bin b/node_modules/ar-drone/test/fixtures/navdata.bin new file mode 100644 index 0000000..d7c1df9 Binary files /dev/null and b/node_modules/ar-drone/test/fixtures/navdata.bin differ diff --git a/node_modules/ar-drone/test/fixtures/pave-68.bin b/node_modules/ar-drone/test/fixtures/pave-68.bin new file mode 100644 index 0000000..c31441c Binary files /dev/null and b/node_modules/ar-drone/test/fixtures/pave-68.bin differ diff --git a/node_modules/ar-drone/test/fixtures/pave.bin b/node_modules/ar-drone/test/fixtures/pave.bin new file mode 100644 index 0000000..ae351ea Binary files /dev/null and b/node_modules/ar-drone/test/fixtures/pave.bin differ diff --git a/node_modules/ar-drone/test/integration/control/UdpControl/test-message-flushing.js b/node_modules/ar-drone/test/integration/control/UdpControl/test-message-flushing.js new file mode 100644 index 0000000..28a9a6b --- /dev/null +++ b/node_modules/ar-drone/test/integration/control/UdpControl/test-message-flushing.js @@ -0,0 +1,26 @@ +var common = require('../../../common'); +var UdpControl = require(common.lib + '/control/UdpControl'); +var dgram = require('dgram'); +var assert = require('assert'); + +var receiver = dgram.createSocket('udp4'); +receiver.bind(common.UDP_PORT); + +var control = new UdpControl({ip: '127.0.0.1', port: common.UDP_PORT}); + +var expectMessage = control.ref() + control.pcmd(); +control.flush(); + +var receivedMessage = false; +receiver.on('message', function(buffer) { + assert.deepEqual(buffer.toString(), expectMessage); + + receiver.close(); + control.close(); + + receivedMessage = true; +}); + +process.on('exit', function() { + assert.equal(receivedMessage, true); +}); diff --git a/node_modules/ar-drone/test/integration/video/PngEncoder/test-sample-encode.js b/node_modules/ar-drone/test/integration/video/PngEncoder/test-sample-encode.js new file mode 100644 index 0000000..955f938 --- /dev/null +++ b/node_modules/ar-drone/test/integration/video/PngEncoder/test-sample-encode.js @@ -0,0 +1,34 @@ +var common = require('../../../common'); +var fs = require('fs'); +var assert = require('assert'); +var PngEncoder = require(common.lib + '/video/PngEncoder'); + +if (common.isTravisCi()) { + console.log('Skipping - travis does not have ffmpeg / apt-get ffmpeg seems to fail this test.'); + return; +} + +var encoder = new PngEncoder(); +var fixture = fs.createReadStream(common.fixtures + '/pave.bin'); + +fixture.pipe(encoder); + +var pngs = []; +encoder.on('data', function(buffer) { + pngs.push(buffer); +}); + + +process.on('exit', function() { + assert.equal(pngs.length, 6); + + for (var i = 0; i < pngs.length; i++) { + var png = pngs[i]; + + // Looks like a valid PNG + assert.equal(png.toString('ascii', 1, 4), 'PNG'); + + // Not the same as previous png + assert.ok(png !== pngs[i - 1]); + } +}); diff --git a/node_modules/ar-drone/test/integration/video/TcpVideoStream/test-connection-timeout.js b/node_modules/ar-drone/test/integration/video/TcpVideoStream/test-connection-timeout.js new file mode 100644 index 0000000..f4d7a9d --- /dev/null +++ b/node_modules/ar-drone/test/integration/video/TcpVideoStream/test-connection-timeout.js @@ -0,0 +1,30 @@ +var common = require('../../../common'); +var net = require('net'); +var assert = require('assert'); +var TcpVideoStream = require(common.lib + '/video/TcpVideoStream'); + +var server = net.createServer(function(connection) { +}); + +var events = []; +server.listen(common.TCP_PORT, function() { + var video = new TcpVideoStream({ip: 'localhost', port: common.TCP_PORT, timeout: 100}); + + video.connect(function(err) { + if (err) throw err; + + events.push('connectCb'); + }); + + video + .on('error', function(err) { + assert.equal(/timeout/i.test(err.message), true); + + events.push('close'); + server.close(); + }); +}); + +process.on('exit', function() { + assert.deepEqual(events, ['connectCb', 'close']); +}); diff --git a/node_modules/ar-drone/test/integration/video/TcpVideoStream/test-normal-connection.js b/node_modules/ar-drone/test/integration/video/TcpVideoStream/test-normal-connection.js new file mode 100644 index 0000000..6900364 --- /dev/null +++ b/node_modules/ar-drone/test/integration/video/TcpVideoStream/test-normal-connection.js @@ -0,0 +1,36 @@ +var common = require('../../../common'); +var net = require('net'); +var assert = require('assert'); +var TcpVideoStream = require(common.lib + '/video/TcpVideoStream'); + +var expectedData = 'some data'; +var server = net.createServer(function(connection) { + connection.write(expectedData); +}); + +var events = []; +server.listen(common.TCP_PORT, function() { + var video = new TcpVideoStream({ip: 'localhost', port: common.TCP_PORT}); + + video.connect(function(err) { + if (err) throw err; + + events.push('connectCb'); + }); + + video + .on('data', function(buffer) { + assert.equal(buffer.toString(), expectedData); + video.end(); + + events.push('data'); + }) + .on('close', function() { + events.push('close'); + server.close(); + }); +}); + +process.on('exit', function() { + assert.deepEqual(events, ['connectCb', 'data', 'close']); +}); diff --git a/node_modules/ar-drone/test/run.js b/node_modules/ar-drone/test/run.js new file mode 100644 index 0000000..37dc3b4 --- /dev/null +++ b/node_modules/ar-drone/test/run.js @@ -0,0 +1,2 @@ +var urun = require('urun'); +urun(__dirname); diff --git a/node_modules/ar-drone/test/unit/control/test-AtCommand.js b/node_modules/ar-drone/test/unit/control/test-AtCommand.js new file mode 100644 index 0000000..bee0c22 --- /dev/null +++ b/node_modules/ar-drone/test/unit/control/test-AtCommand.js @@ -0,0 +1,11 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var AtCommand = require(common.lib + '/control/AtCommand'); + +test('AtCommand', { + 'converting to string': function() { + var cmd = new AtCommand('FOO', 1, [2, '3']); + assert.equal(cmd.toString(), 'AT*FOO=1,2,3\r'); + }, +}); diff --git a/node_modules/ar-drone/test/unit/control/test-AtCommandCreator.js b/node_modules/ar-drone/test/unit/control/test-AtCommandCreator.js new file mode 100644 index 0000000..047c7a9 --- /dev/null +++ b/node_modules/ar-drone/test/unit/control/test-AtCommandCreator.js @@ -0,0 +1,135 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var AtCommandCreator = require(common.lib + '/control/AtCommandCreator'); +var at = require(common.lib + '/control/at'); + +test('AtCommandCreator', { + before: function() { + this.creator = new AtCommandCreator(); + }, + + 'command.number keeps incrementing': function() { + assert.equal(this.creator.ref().number, 0); + assert.equal(this.creator.ref().number, 1); + assert.equal(this.creator.ref().number, 2); + }, + + 'raw': function() { + var cmd = this.creator.raw('FOO', 1, 2, 3); + assert.equal(cmd.type, 'FOO'); + assert.deepEqual(cmd.args, [1, 2, 3]); + + // An array can be given as well + var cmd = this.creator.raw('FOO', [1, 2, 3]); + assert.equal(cmd.type, 'FOO'); + assert.deepEqual(cmd.args, [1, 2, 3]); + }, + + 'ref': function() { + var cmd = this.creator.ref(); + assert.equal(cmd.type, 'REF'); + assert.equal(cmd.args.length, 1); + assert.equal(cmd.args[0], 0); + + var cmd = this.creator.ref({fly: true}); + assert.ok(cmd.args[0] & AtCommandCreator.REF_FLAGS.takeoff); + + var cmd = this.creator.ref({emergency: true}); + assert.ok(cmd.args[0] & AtCommandCreator.REF_FLAGS.emergency); + }, + + 'pcmd': function() { + var cmd = this.creator.pcmd(); + assert.equal(cmd.type, 'PCMD'); + assert.equal(cmd.args.length, 5); + assert.deepEqual(cmd.args, [0, 0, 0, 0, 0]); + + // test all the aliases mapping to pcmd args + var val = 0.75; + assert.equal(this.creator.pcmd({left: val}).args[1], at.floatString(-val)); + assert.equal(this.creator.pcmd({right: val}).args[1], at.floatString(val)); + assert.equal(this.creator.pcmd({front: val}).args[2], at.floatString(-val)); + assert.equal(this.creator.pcmd({back: val}).args[2], at.floatString(val)); + assert.equal(this.creator.pcmd({up: val}).args[3], at.floatString(val)); + assert.equal(this.creator.pcmd({down: val}).args[3], at.floatString(-val)); + assert.equal(this.creator.pcmd({clockwise: val}).args[4], at.floatString(val)); + assert.equal(this.creator.pcmd({counterClockwise: val}).args[4], at.floatString(-val)); + + // test multiple aliases togeter + var cmd = this.creator.pcmd({left: 0.1, clockwise: 0.3}); + assert.equal(cmd.args[1], at.floatString(-0.1)); + assert.equal(cmd.args[4], at.floatString(0.3)); + + // test progressive bit being unset when no aliases are provided + var cmd = this.creator.pcmd(); + assert.equal(cmd.args[0] & AtCommandCreator.PCMD_FLAGS.progressive, false); + + // test progressive bit being set automatically + var cmd = this.creator.pcmd({left: 0.1}); + assert.ok(cmd.args[0] & (1 << 0)); + }, + + 'calibrate': function() { + var cmd = this.creator.calibrate(0); + assert.equal(cmd.type, 'CALIB'); + assert.equal(cmd.args.length, 1); + assert.equal(cmd.args[0], '0'); + cmd = this.creator.calibrate(1); + assert.equal(cmd.type, 'CALIB'); + assert.equal(cmd.args.length, 1); + assert.equal(cmd.args[0], '1'); + }, + + 'config': function() { + var cmd = this.creator.config('foo', 'bar'); + assert.equal(cmd.type, 'CONFIG'); + assert.equal(cmd.args.length, 2); + assert.equal(cmd.args[0], '"foo"'); + assert.equal(cmd.args[1], '"bar"'); + }, + + 'animateLeds() works as expected': function() { + var hz = 3; + var duration = 3; + + var cmd = this.creator.animateLeds('blinkGreen', hz, duration); + var expected = '1,' + at.floatString(hz) + ',' + duration; + + assert.equal(cmd.type, 'CONFIG'); + assert.equal(cmd.args.length, 2); + assert.equal(cmd.args[0], '"leds:leds_anim"'); + assert.equal(cmd.args[1], '"' + expected + '"'); + }, + + 'animateLeds() does a red snake at 2 hz for 3s by default': function() { + var cmd = this.creator.animateLeds(); + var expected = '9,' + at.floatString(2) + ',' + 3; + assert.equal(cmd.args[1], '"' + expected + '"'); + }, + + 'animateLeds() throws an error for unknown animations': function() { + var self = this; + assert.throws(function() { + self.creator.animateLeds('does not exist'); + },/animation/); + }, + + 'animate() works as expected': function() { + var duration = 2000; + var cmd = this.creator.animate('yawShake', duration); + var expected = '8,' + duration; + + assert.equal(cmd.type, 'CONFIG'); + assert.equal(cmd.args.length, 2); + assert.equal(cmd.args[0], '"control:flight_anim"'); + assert.equal(cmd.args[1], '"' + expected + '"'); + }, + + 'animate() throws an error for unknown animations': function() { + var self = this; + assert.throws(function() { + self.creator.animate('does not exist'); + },/animation/); + }, +}); diff --git a/node_modules/ar-drone/test/unit/control/test-UdpControl.js b/node_modules/ar-drone/test/unit/control/test-UdpControl.js new file mode 100644 index 0000000..5f6a258 --- /dev/null +++ b/node_modules/ar-drone/test/unit/control/test-UdpControl.js @@ -0,0 +1,60 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var sinon = require('sinon'); +var UdpControl = require(common.lib + '/control/UdpControl'); + +test('UdpControl', { + 'queues commands until flush() is invoked': function() { + var fakeSocket = {send: sinon.spy()}; + var fakePort = 12345; + var fakeIp = '255.0.23.42'; + + var control = new UdpControl({ + socket : fakeSocket, + port : fakePort, + ip : fakeIp, + }); + + var ref = control.ref(); + assert.equal(ref.type, 'REF'); + + var pcmd = control.pcmd(); + assert.equal(pcmd.type, 'PCMD'); + + control.flush(); + + assert.equal(fakeSocket.send.callCount, 1); + + var sendArgs = fakeSocket.send.getCall(0).args; + var buffer = sendArgs.shift(); + var offset = sendArgs.shift(); + var length = sendArgs.shift(); + var port = sendArgs.shift(); + var ip = sendArgs.shift(); + + assert.equal(Buffer.isBuffer(buffer), true); + assert.deepEqual(buffer.toString(), ref + pcmd); + assert.deepEqual(offset, 0); + assert.deepEqual(length, buffer.length); + assert.deepEqual(port, fakePort); + assert.deepEqual(ip, fakeIp); + + // there should be nothing to flush now + control.flush(); + assert.equal(fakeSocket.send.callCount, 1); + }, + + 'flush() does not do anything if no commands are queued': function() { + var control = new UdpControl(); + control.flush(); + }, + + 'close() is delgated to socket': function() { + var fakeSocket = {close: sinon.spy()}; + var control = new UdpControl({socket: fakeSocket}); + + control.close(); + assert.equal(fakeSocket.close.callCount, 1); + }, +}); diff --git a/node_modules/ar-drone/test/unit/control/test-at.js b/node_modules/ar-drone/test/unit/control/test-at.js new file mode 100644 index 0000000..e120777 --- /dev/null +++ b/node_modules/ar-drone/test/unit/control/test-at.js @@ -0,0 +1,14 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var at = require(common.lib + '/control/at'); + +test('at', { + '-0.8': function() { + assert.equal(at.floatString(-0.8), -1085485875); + }, + + '0': function() { + assert.equal(at.floatString(0), 0); + }, +}); diff --git a/node_modules/ar-drone/test/unit/misc/test-meta.js b/node_modules/ar-drone/test/unit/misc/test-meta.js new file mode 100644 index 0000000..1b457fd --- /dev/null +++ b/node_modules/ar-drone/test/unit/misc/test-meta.js @@ -0,0 +1,16 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var meta = require(common.lib + '/misc/meta'); + +function SampleClass() {} +SampleClass.prototype.a = function() {}; +SampleClass.prototype.b = function() {}; +SampleClass.prototype._c = function() {}; +SampleClass.prototype._d = function() {}; + +test('meta', { + 'methods': function() { + assert.deepEqual(meta.methods(SampleClass), ['a', 'b']); + }, +}); diff --git a/node_modules/ar-drone/test/unit/navdata/test-UdpNavdataStream.js b/node_modules/ar-drone/test/unit/navdata/test-UdpNavdataStream.js new file mode 100644 index 0000000..96581b2 --- /dev/null +++ b/node_modules/ar-drone/test/unit/navdata/test-UdpNavdataStream.js @@ -0,0 +1,176 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var sinon = require('sinon'); +var UdpNavdataStream = require(common.lib + '/navdata/UdpNavdataStream'); +var EventEmitter = require('events').EventEmitter; + +test('UdpNavdataStream', { + before: function() { + this.fakePort = 18943; + this.fakeIp = '23.42.1776.20'; + this.fakeTimeout = 100; + + this.fakeSocket = new EventEmitter(); + this.fakeSocket.bind = sinon.stub(); + this.fakeSocket.send = sinon.stub(); + this.fakeSocket.close = sinon.stub(); + + this.fakeParser = sinon.stub(); + + this.stream = new UdpNavdataStream({ + socket : this.fakeSocket, + port : this.fakePort, + ip : this.fakeIp, + parser : this.fakeParser, + timeout : this.fakeTimeout, + }); + + this.clock = sinon.useFakeTimers(); + }, + + after: function() { + this.clock.restore(); + }, + + 'is a readable stream': function() { + assert.equal(this.stream.readable, true); + assert.equal(typeof this.stream.pipe, 'function'); + }, + + 'resume() configures the socket': function() { + this.stream.resume(); + + // verify socket.bind() + assert.equal(this.fakeSocket.bind.callCount, 1); + + // verify socket.send() + assert.equal(this.fakeSocket.send.callCount, 1); + var sendArgs = this.fakeSocket.send.getCall(0).args; + var buffer = sendArgs.shift(); + var offset = sendArgs.shift(); + var length = sendArgs.shift(); + var port = sendArgs.shift(); + var ip = sendArgs.shift(); + assert.equal(Buffer.isBuffer(buffer), true); + assert.deepEqual(buffer, new Buffer([1])); + assert.equal(offset, 0); + assert.equal(length, buffer.length); + assert.equal(port, this.fakePort); + assert.equal(ip, this.fakeIp); + }, + + 'calling resume() does not rebind socket, but requests navdata again': function() { + this.stream.resume(); + this.stream.resume(); + + assert.equal(this.fakeSocket.bind.callCount, 1); + assert.equal(this.fakeSocket.send.callCount, 2); + }, + + 'navdata is requested again after timeout': function() { + this.stream.resume(); + assert.equal(this.fakeSocket.send.callCount, 1); + + this.clock.tick(this.fakeTimeout - 1); + assert.equal(this.fakeSocket.send.callCount, 1); + + this.clock.tick(1); + assert.equal(this.fakeSocket.send.callCount, 2); + }, + + 'timeout is reset by navdata arriving': function() { + this.stream.resume(); + + this.clock.tick(this.fakeTimeout - 1); + + this.fakeParser.returns({}); + this.fakeSocket.emit('message', new Buffer(0)); + + this.clock.tick(1); + assert.equal(this.fakeSocket.send.callCount, 1); + + this.clock.tick(this.fakeTimeout); + assert.equal(this.fakeSocket.send.callCount, 2); + }, + + 'incoming messages are parsed': function() { + var fakeBuffer = new Buffer([1, 2, 3]); + var fakeNavdata = {fake: 'navdata', sequenceNumber: 1}; + var dataSpy = sinon.spy(); + + this.fakeParser.returns(fakeNavdata); + + this.stream.on('data', dataSpy); + + this.stream.resume(); + this.fakeSocket.emit('message', fakeBuffer); + + assert.equal(this.fakeParser.callCount, 1); + assert.strictEqual(this.fakeParser.getCall(0).args[0], fakeBuffer); + + assert.equal(dataSpy.callCount, 1); + assert.strictEqual(dataSpy.getCall(0).args[0], fakeNavdata); + }, + + 'old navdata messages are ignored': function() { + var fakeNavdataA = {sequenceNumber: 1}; + var fakeNavdataB = {sequenceNumber: 2}; + var fakeNavdataC = {sequenceNumber: 3}; + + this.fakeParser.withArgs(1).returns(fakeNavdataA); + this.fakeParser.withArgs(2).returns(fakeNavdataB); + this.fakeParser.withArgs(3).returns(fakeNavdataC); + + var dataSpy = sinon.spy(); + this.stream.on('data', dataSpy); + + this.stream.resume(); + this.fakeSocket.emit('message', 1); + this.fakeSocket.emit('message', 3); + this.fakeSocket.emit('message', 2); + + assert.equal(this.fakeParser.callCount, 3); + assert.equal(dataSpy.callCount, 2); + + assert.equal(dataSpy.getCall(0).args[0].sequenceNumber, 1); + assert.equal(dataSpy.getCall(1).args[0].sequenceNumber, 3); + }, + + 'navdata errors are ignored by default': function() { + this.fakeParser.throws(new Error('bad')); + + var dataSpy = sinon.spy(); + this.stream.on('data', dataSpy); + + this.stream.resume(); + this.fakeSocket.emit('message', 1); + + assert.equal(this.fakeParser.callCount, 1); + assert.equal(dataSpy.callCount, 0); + }, + + 'navdata errors are emitted if there is an error handler': function() { + var fakeErr = new Error('bad'); + this.fakeParser.throws(fakeErr); + + var dataSpy = sinon.spy(); + var errorSpy = sinon.spy(); + + this.stream.on('data', dataSpy); + this.stream.on('error', errorSpy); + + this.stream.resume(); + this.fakeSocket.emit('message', 1); + + assert.equal(this.fakeParser.callCount, 1); + assert.equal(dataSpy.callCount, 0); + assert.equal(errorSpy.callCount, 1); + assert.strictEqual(errorSpy.getCall(0).args[0], fakeErr); + }, + + 'destroy() cleans up': function() { + this.stream.destroy(); + assert.equal(this.fakeSocket.close.callCount, 1); + }, +}); diff --git a/node_modules/ar-drone/test/unit/navdata/test-parseNavdata.js b/node_modules/ar-drone/test/unit/navdata/test-parseNavdata.js new file mode 100644 index 0000000..219bdc1 --- /dev/null +++ b/node_modules/ar-drone/test/unit/navdata/test-parseNavdata.js @@ -0,0 +1,827 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var parseNavdata = require(common.lib + '/navdata/parseNavdata'); +var fs = require('fs'); +var fixture = fs.readFileSync(common.fixtures + '/navdata.bin'); + +test('parseNavdata', { + 'parses main payload': function() { + var navdata = parseNavdata(fixture); + + assert.equal(navdata.header, parseNavdata.NAVDATA_HEADER); + + var droneState = navdata.droneState; + assert.equal(droneState.flying, 0); + assert.equal(droneState.videoEnabled, 0); + assert.equal(droneState.visionEnabled, 0); + assert.equal(droneState.controlAlgorithm, 0); + assert.equal(droneState.altitudeControlAlgorithm, 1); + assert.equal(droneState.startButtonState, 0); + assert.equal(droneState.controlCommandAck, 1); + assert.equal(droneState.cameraReady, 1); + assert.equal(droneState.travellingEnabled, 0); + assert.equal(droneState.usbReady, 0); + assert.equal(droneState.navdataDemo, 0); + assert.equal(droneState.navdataBootstrap, 0); + assert.equal(droneState.motorProblem, 0); + assert.equal(droneState.communicationLost, 0); + assert.equal(droneState.softwareFault, 0); + assert.equal(droneState.lowBattery, 0); + assert.equal(droneState.userEmergencyLanding, 0); + assert.equal(droneState.timerElapsed, 0); + assert.equal(droneState.MagnometerNeedsCalibration, 0); + assert.equal(droneState.anglesOutOfRange, 0); + assert.equal(droneState.tooMuchWind, 0); + assert.equal(droneState.ultrasonicSensorDeaf, 0); + assert.equal(droneState.cutoutDetected, 0); + assert.equal(droneState.picVersionNumberOk, 1); + assert.equal(droneState.atCodecThreadOn, 1); + assert.equal(droneState.navdataThreadOn, 1); + assert.equal(droneState.videoThreadOn, 1); + assert.equal(droneState.acquisitionThreadOn, 1); + assert.equal(droneState.controlWatchdogDelay, 0); + assert.equal(droneState.adcWatchdogDelay, 0); + assert.equal(droneState.comWatchdogProblem, 1); + assert.equal(droneState.emergencyLanding, 0); + + assert.equal(navdata.sequenceNumber, 300711); + assert.equal(navdata.visionFlag, 1); + }, + + 'parses demo option': function() { + var demo = parseNavdata(fixture).demo; + assert.equal(demo.flyState, 'FLYING_OK'); + assert.equal(demo.controlState, 'CTRL_LANDED'); + assert.equal(demo.batteryPercentage, 50); + + assert.equal(demo.frontBackDegrees, 2.974); + assert.equal(demo.leftRightDegrees, 0.55); + assert.equal(demo.clockwiseDegrees, 1.933); + + assert.equal(demo.rotation.frontBack, 2.974); + assert.equal(demo.rotation.leftRight, 0.55); + assert.equal(demo.rotation.clockwise, 1.933); + + assert.equal(demo.rotation.pitch, 2.974); + assert.equal(demo.rotation.roll, 0.55); + assert.equal(demo.rotation.yaw, 1.933); + + assert.equal(demo.rotation.theta, 2.974); + assert.equal(demo.rotation.phi, 0.55); + assert.equal(demo.rotation.psi, 1.933); + + assert.equal(demo.rotation.y, 2.974); + assert.equal(demo.rotation.x, 0.55); + assert.equal(demo.rotation.z, 1.933); + + assert.equal(demo.altitudeMeters, 0); + assert.equal(demo.altitude, 0); + + assert.equal(demo.xVelocity, 0.0585307739675045); + assert.equal(demo.yVelocity, -0.8817979097366333); + assert.equal(demo.zVelocity, 0); + assert.equal(demo.velocity.x, 0.0585307739675045); + assert.equal(demo.velocity.y, -0.8817979097366333); + assert.equal(demo.velocity.z, 0); + }, + + 'parses time option': function() { + var time = parseNavdata(fixture).time; + assert.equal(time, 362979.125); + }, + + 'parses rawMeasures option': function() { + var rawMeasures = parseNavdata(fixture).rawMeasures; + + assert.equal(rawMeasures.accelerometers.x, 2040); + assert.equal(rawMeasures.accelerometers.y, 2036); + assert.equal(rawMeasures.accelerometers.z, 2528); + + assert.equal(rawMeasures.gyrometers.x, -23); + assert.equal(rawMeasures.gyrometers.y, 15); + assert.equal(rawMeasures.gyrometers.z, 0); + assert.equal(rawMeasures.gyroscopes.x, -23); + assert.equal(rawMeasures.gyroscopes.y, 15); + assert.equal(rawMeasures.gyroscopes.z, 0); + + assert.equal(rawMeasures.gyrometers110[0], 0); + assert.equal(rawMeasures.gyrometers110[1], 0); + assert.equal(rawMeasures.gyrometers110.length, 2); + assert.equal(rawMeasures.gyroscopes110.x, 0); + assert.equal(rawMeasures.gyroscopes110.y, 0); + + assert.equal(rawMeasures.batteryMilliVolt, 11686); + + assert.equal(rawMeasures.usDebutEcho, 0); + assert.equal(rawMeasures.usFinEcho, 0); + assert.equal(rawMeasures.usAssociationEcho, 3758); + assert.equal(rawMeasures.usDistanceEcho, 0); + assert.equal(rawMeasures.us.echo.start, 0); + assert.equal(rawMeasures.us.echo.end, 0); + assert.equal(rawMeasures.us.echo.association, 3758); + assert.equal(rawMeasures.us.echo.distance, 0); + + assert.equal(rawMeasures.usCourbeTemps, 21423); + assert.equal(rawMeasures.usCourbeValeur, 0); + assert.equal(rawMeasures.usCourbeRef, 120); + assert.equal(rawMeasures.us.curve.time, 21423); + assert.equal(rawMeasures.us.curve.value, 0); + assert.equal(rawMeasures.us.curve.ref, 120); + + + assert.equal(rawMeasures.flagEchoIni, 1); + assert.equal(rawMeasures.nbEcho, 1); + assert.equal(rawMeasures.sumEcho, 3539193); + assert.equal(rawMeasures.echo.flagIni, 1); + assert.equal(rawMeasures.echo.num, 1); + assert.equal(rawMeasures.echo.sum, 3539193); + + assert.equal(rawMeasures.altTempRaw, 243); + assert.equal(rawMeasures.altTemp, 243); + }, + + 'parses physMeasures option': function() { + var actual = parseNavdata(fixture).physMeasures; + var expected = { + temperature : { + accelerometer : 45.309303283691406, + gyroscope : 55738 + }, + accelerometers : { + x : 80.2970962524414, + y : -33.318603515625, + z : -942.5283203125 + }, + gyroscopes : { + x : -0.11236488074064255, + y : 0.06872134655714035, + z : 0.06200997903943062 + }, + alim3V3 : 0, + vrefEpson : 0, + vrefIDG : 0 + }; + assert.equal(actual.temperature.accelerometer, expected.temperature.accelerometer); + assert.equal(actual.temperature.gyroscope, expected.temperature.gyroscope); + assert.equal(actual.accelerometers.x, expected.accelerometers.x); + assert.equal(actual.accelerometers.y, expected.accelerometers.y); + assert.equal(actual.accelerometers.z, expected.accelerometers.z); + assert.equal(actual.gyroscopes.x, expected.gyroscopes.x); + assert.equal(actual.gyroscopes.y, expected.gyroscopes.y); + assert.equal(actual.gyroscopes.z, expected.gyroscopes.z); + assert.equal(actual.alim3V3, expected.alim3V3); + assert.equal(actual.vrefEpson, expected.vrefEpson); + assert.equal(actual.vrefIDG, expected.vrefIDG); + }, + + 'parses gyrosOffsets option': function() { + var actual = parseNavdata(fixture).gyrosOffsets; + var expected = { + x : -0.5329172611236572, + y : 0.1788240224123001, + z : 0 + }; + + assert.equal(actual.x, expected.x); + assert.equal(actual.y, expected.y); + assert.equal(actual.z, expected.z); + }, + + 'parses eulerAngles option': function() { + var actual = parseNavdata(fixture).eulerAngles; + var expected = { + theta : 4866, + phi : 2024 + }; + + assert.equal(actual.theta, expected.theta); + assert.equal(actual.phi, expected.phi); + }, + + 'parses references option': function() { + var actual = parseNavdata(fixture).references; + var expected = { + theta : 0, + phi : 0, + thetaI : 0, + phiI : 0, + pitch : 0, + roll : 0, + yaw : 0, + psi : 0, + vx : 0, + vy : 0, + thetaMod : 0, + phiMod : 0, + kVX : 0, + kVY : 0, + kMode : 0, + ui : { + time : 0, + theta : 0, + phi : 0, + psi : 0, + psiAccuracy : 0, + seq : 0 + } + }; + + assert.equal(actual.theta, expected.theta); + assert.equal(actual.phi, expected.phi); + assert.equal(actual.thetaI, expected.thetaI); + assert.equal(actual.phiI, expected.phiI); + assert.equal(actual.pitch, expected.pitch); + assert.equal(actual.roll, expected.roll); + assert.equal(actual.yaw, expected.yaw); + assert.equal(actual.psi, expected.psi); + assert.equal(actual.vx, expected.vx); + assert.equal(actual.vy, expected.vy); + assert.equal(actual.thetaMod, expected.thetaMod); + assert.equal(actual.phiMod, expected.phiMod); + assert.equal(actual.kVX, expected.kVX); + assert.equal(actual.kVY, expected.kVY); + assert.equal(actual.kMode, expected.kMode); + assert.equal(actual.ui.time, expected.ui.time); + assert.equal(actual.ui.theta, expected.ui.theta); + assert.equal(actual.ui.phi, expected.ui.phi); + assert.equal(actual.ui.psi, expected.ui.psi); + assert.equal(actual.ui.psiAccuracy, expected.ui.psiAccuracy); + assert.equal(actual.ui.seq, expected.ui.seq); + }, + + 'parses trims option': function() { + var actual = parseNavdata(fixture).trims; + var expected = { + angularRates : { + r : 0 + }, + eulerAngles : { + theta : 3028.916015625, + phi : 1544.318359375 + } + }; + + assert.equal(actual.angularRates.r, expected.angularRates.r); + assert.equal(actual.eulerAngles.theta, expected.eulerAngles.theta); + assert.equal(actual.eulerAngles.phi, expected.eulerAngles.phi); + }, + + 'parses rcReferences option': function() { + var actual = parseNavdata(fixture).rcReferences; + var expected = { + pitch : 0, + roll : 0, + yaw : 0, + gaz : 0, + ag : 0 + }; + + assert.equal(actual.pitch, expected.pitch); + assert.equal(actual.roll, expected.roll); + assert.equal(actual.yaw, expected.yaw); + assert.equal(actual.gaz, expected.gaz); + assert.equal(actual.ag, expected.ag); + }, + + 'parses pwm option': function() { + var pwm = parseNavdata(fixture).pwm; + + assert.deepEqual(pwm.motors, [0, 0, 0, 0]); + assert.deepEqual(pwm.satMotors, [255, 255, 255, 255]); + assert.equal(pwm.gazFeedForward, 0); + assert.equal(pwm.gazAltitude, 0); + assert.equal(pwm.altitudeIntegral, 0); + assert.equal(pwm.vzRef, 0); + assert.equal(pwm.uPitch, 0); + assert.equal(pwm.uRoll, 0); + assert.equal(pwm.uYaw, 0); + assert.equal(pwm.yawUI, 0); + assert.equal(pwm.uPitchPlanif, 0); + assert.equal(pwm.uRollPlanif, 0); + assert.equal(pwm.uYawPlanif, 0); + assert.equal(pwm.uGazPlanif, 0); + assert.deepEqual(pwm.motorCurrents, [0, 0, 0, 0]); + assert.equal(pwm.altitudeProp, 0); + assert.equal(pwm.altitudeDer, 0); + }, + + 'parses altitude option': function() { + var actual = parseNavdata(fixture).altitude; + var expected = { + vision : 243, + velocity : 0, + ref : 0, + raw : 243, + observer : { + acceleration: 0, + altitude: 0, + x: { + x: 0, + y: 0, + z: 0 + }, + state: 0 + }, + estimated: { + vb: { + x: 0, + y: 0 + }, + state: 0 + } + }; + + assert.equal(actual.vision, expected.vision); + assert.equal(actual.velocity, expected.velocity); + assert.equal(actual.ref, expected.ref); + assert.equal(actual.raw, expected.raw); + assert.equal(actual.observer.acceleration, expected.observer.acceleration); + assert.equal(actual.observer.altitude, expected.observer.altitude); + assert.equal(actual.observer.x.x, expected.observer.x.x); + assert.equal(actual.observer.x.y, expected.observer.x.y); + assert.equal(actual.observer.x.z, expected.observer.x.z); + assert.equal(actual.observer.state, expected.observer.state); + assert.equal(actual.estimated.vb.x, expected.estimated.vb.x); + assert.equal(actual.estimated.vb.y, expected.estimated.vb.y); + assert.equal(actual.estimated.state, expected.estimated.state); + }, + + 'parses visionRaw option': function() { + var actual = parseNavdata(fixture).visionRaw; + var expected = { + tx: 1.3266397714614868, + ty: -0.7230937480926514, + tz: 0 + }; + + assert.equal(actual.tx, expected.tx); + assert.equal(actual.ty, expected.ty); + assert.equal(actual.tz, expected.tz); + }, + + 'parses visionOf option': function() { + var actual = parseNavdata(fixture).visionOf; + var expected = { + dx: [0, 0, 0, 0, 0], + dy: [0, 0, 0, 0, 0] + }; + + assert.deepEqual(actual.dx, expected.dx); + assert.deepEqual(actual.dy, expected.dy); + }, + + 'parses vision option': function() { + var actual = parseNavdata(fixture).vision; + var expected = { + state: 2, + misc: 0, + phi: { + trim: 0, + refProp: 0 + }, + theta: { + trim: 0, + refProp: 0 + }, + newRawPicture: 0, + capture: { + theta: 0.05190306529402733, + phi: 0.009620788507163525, + psi: 0.033727407455444336, + altitude: 243, + time: 362.969 + }, + bodyV: { + x: 0.05845191329717636, + y: -0.8817280530929565, + z: 0.011505687609314919 + }, + delta: { + phi: 0, + theta: 0, + psi: 0 + }, + gold: { + defined: 0, + reset: 0, + x: 0, + y: 0 + } + }; + + assert.equal(actual.state, expected.state); + assert.equal(actual.misc, expected.misc); + assert.deepEqual(actual.phi, expected.phi); + assert.deepEqual(actual.theta, expected.theta); + assert.equal(actual.newRawPicture, expected.newRawPicture); + assert.deepEqual(actual.capture, expected.capture); + assert.deepEqual(actual.bodyV, expected.bodyV); + assert.deepEqual(actual.delta, expected.delta); + assert.deepEqual(actual.gold, expected.gold); + }, + + 'parses visionPerf option': function() { + var actual = parseNavdata(fixture).visionPerf; + var expected = { + szo: 0, + corners: 0, + compute: 0, + tracking: 0, + trans: 0, + update: 0, + custom: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + }; + + assert.equal(actual.szo, expected.szo); + assert.equal(actual.corners, expected.corners); + assert.equal(actual.compute, expected.compute); + assert.equal(actual.tracking, expected.tracking); + assert.equal(actual.trans, expected.trans); + assert.equal(actual.update, expected.update); + assert.deepEqual(actual.custom, expected.custom); + }, + + 'parses trackersSend option': function() { + var actual = parseNavdata(fixture).trackersSend; + var expected = { + locked: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + point: [ + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 } + ] + }; + + assert.deepEqual(actual.locked, expected.locked); + assert.deepEqual(actual.point, expected.point); + }, + + 'parses visionDetect option': function() { + var actual = parseNavdata(fixture).visionDetect; + var expected = { + nbDetected: 0, + type: [0, 0, 0, 0], + xc: [0, 0, 0, 0], + yc: [0, 0, 0, 0], + width: [0, 0, 0, 0], + height: [0, 0, 0, 0], + dist: [0, 0, 0, 0], + orientationAngle: [0, 0, 0, 0], + rotation: [{ + m11: 0, + m12: 0, + m13: 0, + m21: 0, + m22: 0, + m23: 0, + m31: 0, + m32: 0, + m33: 0 + }, { + m11: 0, + m12: 0, + m13: 0, + m21: 0, + m22: 0, + m23: 0, + m31: 0, + m32: 0, + m33: 0 + }, { + m11: 0, + m12: 0, + m13: 0, + m21: 0, + m22: 0, + m23: 0, + m31: 0, + m32: 0, + m33: 0 + }, { + m11: 0, + m12: 0, + m13: 0, + m21: 0, + m22: 0, + m23: 0, + m31: 0, + m32: 0, + m33: 0 + }], + translation: [{ + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 0 + }], + cameraSource: [0, 0, 0, 0] + }; + + assert.equal(actual.nbDetected, expected.nbDetected); + assert.deepEqual(actual.type, expected.type); + assert.deepEqual(actual.xc, expected.xc); + assert.deepEqual(actual.yc, expected.yc); + assert.deepEqual(actual.width, expected.width); + assert.deepEqual(actual.height, expected.height); + assert.deepEqual(actual.dist, expected.dist); + assert.deepEqual(actual.orientationAngle, expected.orientationAngle); + assert.deepEqual(actual.rotation, expected.rotation); + assert.deepEqual(actual.translation, expected.translation); + assert.deepEqual(actual.cameraSource, expected.cameraSource); + }, + + 'parses watchdog option': function() { + var watchdog = parseNavdata(fixture).watchdog; + assert.equal(watchdog, 4822); + }, + + 'parses adcDataFrame option': function() { + var actual = parseNavdata(fixture).adcDataFrame; + var expected = { + version: 0, + dataFrame: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + }; + + assert.equal(actual.version, expected.version); + assert.deepEqual(actual.dataFrame, expected.dataFrame); + }, + + 'parses videoStream option': function() { + var actual = parseNavdata(fixture).videoStream; + var expected = { + quant: 0, + frame: { + size: 4597, + number: 46105 + }, + atcmd: { + sequence: 0, + meanGap: 0, + varGap: 0, + quality: 0 + }, + bitrate: { + out: 0, + desired: 0 + }, + data: [0, 0, 0, 0, 0], + tcpQueueLevel: 0, + fifoQueueLevel: 0 + }; + + assert.equal(actual.quant, expected.quant); + assert.deepEqual(actual.frame, expected.frame); + assert.deepEqual(actual.atcmd, expected.atcmd); + assert.deepEqual(actual.bitrate, expected.bitrate); + assert.deepEqual(actual.data, expected.data); + assert.equal(actual.tcpQueueLevel, expected.tcpQueueLevel); + assert.equal(actual.fifoQueueLevel, expected.fifoQueueLevel); + }, + + 'parses games option': function() { + var actual = parseNavdata(fixture).games; + var expected = { + counters: { + doubleTap: 0, + finishLine: 0 + } + }; + + assert.equal(actual.counters.doubleTap, expected.counters.doubleTap); + assert.equal(actual.counters.finishLine, expected.counters.finishLine); + }, + + 'parses pressureRaw option': function() { + var actual = parseNavdata(fixture).pressureRaw; + var expected = { + up: 39148, + ut: 32556, + temperature: 435, + pressure: 101586 + }; + + assert.equal(actual.up, expected.up); + assert.equal(actual.ut, expected.ut); + assert.equal(actual.temperature, expected.temperature); + assert.equal(actual.pressure, expected.pressure); + }, + + 'parses magneto option': function() { + var actual = parseNavdata(fixture).magneto; + var expected = { + mx: 30, + my: -56, + mz: 80, + raw: { + x: 189, + y: -100.8984375, + z: -278.4375 + }, + rectified: { + x: 145.08058166503906, + y: -84.93736267089844, + z: -287.18157958984375 + }, + offset: { + x: 29.21237564086914, + y: -13.282999038696289, + z: 0 + }, + heading: { + unwrapped: 0, + gyroUnwrapped: 0.00041322660399600863, + fusionUnwrapped: 1.933355689048767 + }, + ok: 1, + state: 513, + radius: -20.9833984375, + error: { + mean: 1129450962944, + variance: -1.9905589299967167e-20 + } + }; + + assert.equal(actual.mx, expected.mx); + assert.equal(actual.my, expected.my); + assert.deepEqual(actual.raw, expected.raw); + assert.deepEqual(actual.rectified, expected.rectified); + assert.deepEqual(actual.offset, expected.offset); + assert.deepEqual(actual.heading, expected.heading); + assert.equal(actual.mz, expected.mz); + assert.equal(actual.ok, expected.ok); + assert.equal(actual.state, expected.state); + assert.equal(actual.radius, expected.radius); + assert.deepEqual(actual.error, expected.error); + }, + + 'parses windSpeed option': function() { + var actual = parseNavdata(fixture).windSpeed; + var expected = { + speed: 0, + angle: 0, + compensation: { + theta: 0, + phi: 0 + }, + stateX: [0.05845191329717636, -0.8817280530929565, 0, 0, 305.5962829589844, -236.80516052246094], + debug: [0, 0, 0] + }; + + assert.equal(actual.speed, expected.speed); + assert.equal(actual.angle, expected.angle); + assert.deepEqual(actual.compensation, expected.compensation); + assert.deepEqual(actual.stateX, expected.stateX); + assert.deepEqual(actual.debug, expected.debug); + }, + + 'parses kalmanPressure option': function() { + var actual = parseNavdata(fixture).kalmanPressure; + var expected = { + offsetPressure: 101580, + estimated: { + altitude: 0, + velocity: 0, + angle: { + pwm: 0, + pressure: 0 + }, + us: { + offset: 0, + prediction: 0 + }, + covariance: { + alt: 0.0005193915567360818, + pwm: 0.6806257367134094, + velocity: 0.025059189647436142 + }, + groundEffect: true, + sum: 1.401298464324817e-45, + reject: false, + uMultisinus: 0, + gazAltitude: 0, + flagMultisinus: false, + flagMultisinusStart: false + } + }; + + assert.equal(actual.offsetPressure, expected.offsetPressure); + assert.equal(actual.estimated.altitude, expected.estimated.altitude); + assert.equal(actual.estimated.velocity, expected.estimated.velocity); + assert.deepEqual(actual.estimated.angle, expected.estimated.angle); + assert.deepEqual(actual.estimated.us, expected.estimated.us); + assert.deepEqual(actual.estimated.covariance, expected.estimated.covariance); + assert.equal(actual.estimated.groundEffect, expected.estimated.groundEffect); + assert.equal(actual.estimated.sum, expected.estimated.sum); + assert.equal(actual.estimated.reject, expected.estimated.reject); + assert.equal(actual.estimated.uMultisinus, expected.estimated.uMultisinus); + assert.equal(actual.estimated.gazAltitude, expected.estimated.gazAltitude); + assert.equal(actual.estimated.flagMultisinus, expected.estimated.flagMultisinus); + assert.equal(actual.estimated.flagMultisinusStart, expected.estimated.flagMultisinusStart); + }, + + 'parses hdvideoStream option': function() { + var actual = parseNavdata(fixture).hdvideoStream; + var expected = { + hdvideoState: 0, + storageFifo: { + nbPackets: 0, + size: 0 + }, + usbkey: { + size: 0, + freespace: 0, + remainingTime: 0 + }, + frameNumber: 0 + }; + + assert.equal(actual.hdvideoState, expected.hdvideoState); + assert.deepEqual(actual.storageFifo, expected.storageFifo); + assert.deepEqual(actual.usbkey, expected.usbkey); + assert.equal(actual.frameNumber, expected.frameNumber); + }, + + 'parses wifi option': function() { + var wifi = parseNavdata(fixture).wifi; + assert.equal(wifi.linkQuality, 1); + }, + + 'parses zimmu3000 option': function() { + var actual = parseNavdata(fixture).zimmu3000; + var expected = { + vzimmuLSB: 0, + vzfind: 0 + }; + + assert.equal(actual.vzimmuLSB, expected.vzimmuLSB); + assert.equal(actual.vzfind, expected.vzfind); + }, + + 'throws exception on invalid header': function() { + assert.throws(function() { + parseNavdata(new Buffer([1, 2, 3, 4])); + }, /header/i); + }, + + 'detects bad checksum': function() { + // hacky way to get a copy of our fixture + var fixtureCopy = Buffer.concat([new Buffer(0), fixture]); + + // corrupt a byte inside our fixture + fixtureCopy[23] = fixtureCopy[23] + 1; + + assert.throws(function() { + parseNavdata(fixtureCopy) + }, /checksum/i); + }, + + 'no infinite loop when checksum is cut off': function() { + var incompleteFixture = Buffer.concat([ + new Buffer(0), + fixture.slice(0, fixture.length - 8) // strip checksum from end + ]); + + assert.throws(function() { + parseNavdata(incompleteFixture) + }, /beyond/i); + }, +}); diff --git a/node_modules/ar-drone/test/unit/test-Client.js b/node_modules/ar-drone/test/unit/test-Client.js new file mode 100644 index 0000000..5ed9ac5 --- /dev/null +++ b/node_modules/ar-drone/test/unit/test-Client.js @@ -0,0 +1,515 @@ +var common = require('../common'); +var assert = require('assert'); +var test = require('utest'); +var sinon = require('sinon'); +var Client = require(common.lib + '/Client'); +var PngEncoder = Client.PngEncoder; +var TcpVideoStream = Client.TcpVideoStream; +var EventEmitter = require('events').EventEmitter; + +test('Client', { + before: function() { + this.fakeUdpControl = {}; + this.fakeUdpControl.ref = sinon.stub(); + this.fakeUdpControl.pcmd = sinon.stub(); + this.fakeUdpControl.animateLeds = sinon.stub(); + this.fakeUdpControl.animate = sinon.stub(); + this.fakeUdpControl.config = sinon.stub(); + this.fakeUdpControl.flush = sinon.stub(); + + this.fakeUdpNavdataStream = new EventEmitter; + this.fakeUdpNavdataStream.resume = sinon.stub(); + + this.pngEncoder = new PngEncoder(); + Client.PngEncoder = sinon.stub(); + Client.PngEncoder.returns(this.pngEncoder); + + this.tcpVideoStream = new TcpVideoStream(); + Client.TcpVideoStream = sinon.stub(); + Client.TcpVideoStream.returns(this.tcpVideoStream); + + this.options = { + udpControl : this.fakeUdpControl, + udpNavdataStream : this.fakeUdpNavdataStream, + }; + + this.client = new Client(this.options); + + this.clock = sinon.useFakeTimers(); + }, + + after: function() { + this.clock.restore(); + }, + + 'resume() calls _setInterval': function() { + sinon.spy(this.client, '_setInterval'); + this.client.resume(); + + assert.equal(this.client._setInterval.callCount, 1); + assert.equal(this.client._setInterval.getCall(0).args[0], 30); + }, + + 'resume() calls disableEmergency': function() { + sinon.spy(this.client, 'disableEmergency'); + this.client.resume(); + + assert.equal(this.client.disableEmergency.callCount, 1); + }, + + 'navdata "data" events are proxied': function() { + var fakeNavdata = {fake: 'navdata'}; + this.client.resume(); + + assert.equal(this.fakeUdpNavdataStream.resume.callCount, 1); + + var gotNavdata; + this.client.on('navdata', function(navdata) { + gotNavdata = navdata; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdata); + + assert.strictEqual(gotNavdata, fakeNavdata); + }, + + 'navdata custom controlState events are triggered': function() { + // takeoff event + var fakeNavdataTakeoff = { + droneState: 'navdata', + demo: {controlState: 'CTRL_TRANS_TAKEOFF'} + }; + this.client.resume(); + + var gotEventTakeoff; + this.client.on('takeoff', function() { + gotEventTakeoff = true; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdataTakeoff); + assert.equal(gotEventTakeoff, true); + + // hovering event + var fakeNavdataHovering = { + droneState: 'navdata', + demo: {controlState: 'CTRL_HOVERING'} + }; + + var gotEventHovering; + this.client.on('hovering', function() { + gotEventHovering = true; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdataHovering); + assert.equal(gotEventHovering, true); + + // flying event + var fakeNavdataFlying = { + droneState: 'navdata', + demo: {controlState: 'CTRL_FLYING'} + }; + + var gotEventFlying; + this.client.on('flying', function() { + gotEventFlying = true; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdataFlying); + assert.equal(gotEventFlying, true); + + // landing event + var fakeNavdataLanding = { + droneState: 'navdata', + demo: {controlState: 'CTRL_TRANS_LANDING'} + }; + + var gotEventLanding; + this.client.on('landing', function() { + gotEventLanding = true; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdataLanding); + assert.equal(gotEventLanding, true); + + // landed event + var fakeNavdataLanded = { + droneState: 'navdata', + demo: {controlState: 'CTRL_LANDED'} + }; + + var gotEventLanded; + this.client.on('landed', function() { + gotEventLanded = true; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdataLanded); + assert.equal(gotEventLanded, true); + }, + + 'navdata custom battery events are triggered': function() { + // takeoff event + var fakeNavdata = { + droneState: {lowBattery:1}, + demo: {batteryPercentage: 23} + }; + this.client.resume(); + + var gotEventLow; + this.client.on('lowBattery', function(level) { + assert.equal(level, fakeNavdata.demo.batteryPercentage); + gotEventLow = true; + }); + + var gotEventLevel; + this.client.on('batteryChange', function(level) { + assert.equal(level, fakeNavdata.demo.batteryPercentage); + gotEventLevel = true; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdata); + assert.equal(gotEventLow, true); + assert.equal(gotEventLevel, true); + }, + + 'navdata custom altitude events are triggered': function() { + // takeoff event + var fakeNavdata = { + droneState: 'navdata', + demo: {altitudeMeters: 23.5} + }; + this.client.resume(); + + var gotEvent; + this.client.on('altitudeChange', function(level) { + assert.equal(level, fakeNavdata.demo.altitudeMeters); + gotEvent = true; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdata); + assert.equal(gotEvent, true); + }, + + 'navdata "error" events are ignored by default': function() { + this.client.resume(); + + this.fakeUdpNavdataStream.emit('error', new Error('bad')); + }, + + 'navdata "error" events are proxied if there is an error listener': function() { + var errorStub = sinon.stub(); + this.client.on('error', errorStub); + this.client.resume(); + + var fakeErr = new Error('bad'); + this.fakeUdpNavdataStream.emit('error', fakeErr); + + assert.equal(errorStub.callCount, 1); + assert.strictEqual(errorStub.getCall(0).args[0], fakeErr); + }, + + 'resume() is idempotent': function() { + var fakeNavdata = {fake: 'navdata'}; + this.client.resume(); + this.client.resume(); + + var eventCount = 0; + this.client.on('navdata', function(navdata) { + eventCount++; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdata); + + assert.strictEqual(eventCount, 1); + }, + + 'resume() is idempotent': function() { + var fakeNavdata = {fake: 'navdata'}; + this.client.resume(); + this.client.resume(); + + var eventCount = 0; + this.client.on('navdata', function(navdata) { + eventCount++; + }); + + this.fakeUdpNavdataStream.emit('data', fakeNavdata); + + assert.strictEqual(eventCount, 1); + }, + + 'options are passed to internal UdpControl': function() { + var options = {fake: 'options'}; + + var gotOptions; + Client.UdpControl = function(options) { + gotOptions = options; + }; + + var client = new Client(options); + assert.strictEqual(gotOptions, options); + }, + + '_setInterval caused period ref / pcmd commands': function() { + this.client._setInterval(30); + assert.equal(this.fakeUdpControl.ref.callCount, 0); + assert.equal(this.fakeUdpControl.pcmd.callCount, 0); + assert.equal(this.fakeUdpControl.flush.callCount, 0); + + this.clock.tick(30); + assert.equal(this.fakeUdpControl.ref.callCount, 1); + assert.equal(this.fakeUdpControl.pcmd.callCount, 1); + assert.equal(this.fakeUdpControl.flush.callCount, 1); + assert.strictEqual(this.client._pcmd, this.fakeUdpControl.pcmd.getCall(0).args[0]); + assert.strictEqual(this.client._ref, this.fakeUdpControl.ref.getCall(0).args[0]); + + this.clock.tick(30); + assert.equal(this.fakeUdpControl.ref.callCount, 2); + assert.equal(this.fakeUdpControl.pcmd.callCount, 2); + }, + + '_setInterval clears previous interval if set': function() { + this.client._setInterval(30); + this.client._setInterval(20); + + this.clock.tick(20); + assert.equal(this.fakeUdpControl.ref.callCount, 1); + + this.clock.tick(10); + assert.equal(this.fakeUdpControl.ref.callCount, 1); + }, + + + 'ref options are exposed as methods': function() { + this.client.takeoff(); + assert.equal(this.client._ref.fly, true); + + this.client.land(); + assert.equal(this.client._ref.fly, false); + }, + + 'pcmd options are exposed as methods': function() { + this.client.up(0.5); + assert.equal(this.client._pcmd.up, 0.5); + assert.equal(this.client._pcmd.down, undefined); + + this.client.down(0.5); + assert.equal(this.client._pcmd.down, 0.5); + assert.equal(this.client._pcmd.up, undefined); + + this.client.left(0.5); + assert.equal(this.client._pcmd.left, 0.5); + assert.equal(this.client._pcmd.right, undefined); + + this.client.right(0.5); + assert.equal(this.client._pcmd.right, 0.5); + assert.equal(this.client._pcmd.left, undefined); + + this.client.front(0.5); + assert.equal(this.client._pcmd.front, 0.5); + assert.equal(this.client._pcmd.back, undefined); + + this.client.back(0.5); + assert.equal(this.client._pcmd.back, 0.5); + assert.equal(this.client._pcmd.front, undefined); + + this.client.clockwise(0.5); + assert.equal(this.client._pcmd.clockwise, 0.5); + assert.equal(this.client._pcmd.counterClockwise, undefined); + + this.client.counterClockwise(0.5); + assert.equal(this.client._pcmd.counterClockwise, 0.5); + assert.equal(this.client._pcmd.clockwise, undefined); + }, + + 'pcmd methods conver strings to floats': function() { + this.client.up('-0.5'); + assert.strictEqual(this.client._pcmd.up, -0.5); + + this.client.down('-0.5'); + assert.strictEqual(this.client._pcmd.down, -0.5); + }, + + 'stop resets pcmd commands': function() { + this.client.up(0.5); + + this.client.stop(); + assert.deepEqual(this.client._pcmd, {}); + }, + + 'config(): sends config command 10 times': function() { + return console.log('skipped - currently broken, needs investigation'); + // Skip broken test below, see issue #47 for discussion + this.client.resume(); + this.client.config('foo', 'bar'); + + for (var i = 1; i <= 10; i++) { + this.clock.tick(30); + assert.equal(this.fakeUdpControl.config.callCount, i); + } + + // Stop repeating after 10 intervals + this.clock.tick(30); + assert.equal(this.fakeUdpControl.config.callCount, 10); + + // Check that the arguments were right + var args = this.fakeUdpControl.config.getCall(0).args; + assert.equal(args.length, 2); + assert.equal(args[0], 'foo'); + assert.equal(args[1], 'bar'); + }, + + + 'animateLeds(): sends config command 10 times': function() { + this.client.resume(); + this.client.animateLeds('blinkGreen', 2, 5); + + for (var i = 1; i <= 10; i++) { + this.clock.tick(30); + assert.equal(this.fakeUdpControl.animateLeds.callCount, i); + } + + // Stop repeating after 10 intervals + this.clock.tick(30); + assert.equal(this.fakeUdpControl.animateLeds.callCount, 10); + + // Check that the arguments were right + var args = this.fakeUdpControl.animateLeds.getCall(0).args; + assert.equal(args.length, 3); + assert.equal(args[0], 'blinkGreen'); + assert.equal(args[1], 2); + assert.equal(args[2], 5); + }, + + 'animate(): sends config 10 times': function() { + this.client.resume(); + this.client.animate('yawShake', 2000); + + for (var i = 1; i <= 10; i++) { + this.clock.tick(30); + assert.equal(this.fakeUdpControl.animate.callCount, i); + } + + // Stop repeating after 10 intervals + this.clock.tick(30); + assert.equal(this.fakeUdpControl.animate.callCount, 10); + + // Check that the arguments were right + var args = this.fakeUdpControl.animate.getCall(0).args; + assert.equal(args.length, 2); + assert.equal(args[0], 'yawShake'); + assert.equal(args[1], 2000); + }, + + 'getPngStream creates and resume a single stream': function() { + sinon.stub(this.tcpVideoStream, 'connect'); + + var pngStream1 = this.client.getPngStream(); + var pngStream2 = this.client.getPngStream(); + + // check that the underlying TcpVideoStream and PngEncoder were constructed only once + assert.equal(Client.PngEncoder.callCount, 1); + assert.equal(Client.TcpVideoStream.callCount, 1); + assert.strictEqual(Client.TcpVideoStream.getCall(0).args[0], this.options); + assert.equal(this.tcpVideoStream.connect.callCount, 1); + + // check returned streams are always the same + assert.strictEqual(pngStream1, this.pngEncoder); + assert.strictEqual(pngStream2, this.pngEncoder); + }, + + 'getTcpVideoStream creates and resume a single stream': function() { + sinon.stub(this.tcpVideoStream, 'connect'); + + var videoStream1 = this.client.getVideoStream(); + var videoStream2 = this.client.getVideoStream(); + + // check that the PngStream was constructed only once + assert.equal(Client.TcpVideoStream.callCount, 1); + assert.strictEqual(Client.TcpVideoStream.getCall(0).args[0], this.options); + assert.equal(this.tcpVideoStream.connect.callCount, 1); + + // check returned streams are always the same + assert.strictEqual(videoStream1, this.tcpVideoStream); + assert.strictEqual(videoStream2, this.tcpVideoStream); + }, + + 'after methods are called in client context': function() { + var after = sinon.spy(); + + this.client.after(1000, after); + + this.clock.tick(1000); + assert.equal(after.callCount, 1); + assert.equal(after.getCall(0).thisValue, this.client); + }, + + 'after enqueues methods to run after each other': function() { + var after1 = sinon.spy(); + var after2 = sinon.spy(); + var after3 = sinon.spy(); + + this.client + .after(1000, after1) + .after(2000, after2) + .after(3000, after3); + + assert.equal(after1.callCount, 0); + assert.equal(after2.callCount, 0); + assert.equal(after3.callCount, 0); + + // Nothing should be triggered yet + this.clock.tick(500); + assert.equal(after1.callCount, 0); + assert.equal(after2.callCount, 0); + assert.equal(after3.callCount, 0); + + // First after callback should trigger + this.clock.tick(500); + assert.equal(after1.callCount, 1); + assert.equal(after2.callCount, 0); + assert.equal(after3.callCount, 0); + + // Second after callback should trigger + this.clock.tick(2000); + assert.equal(after1.callCount, 1); + assert.equal(after2.callCount, 1); + assert.equal(after3.callCount, 0); + + // Third after callback should trigger + this.clock.tick(3000); + assert.equal(after1.callCount, 1); + assert.equal(after2.callCount, 1); + assert.equal(after3.callCount, 1); + }, + + 'disableEmergency sets emergency bit to true until navdata confirms': function() { + // disable implicit disableEmergency for this test + sinon.stub(this.client, 'disableEmergency'); + this.client.resume(); + this.client.disableEmergency.restore(); + + // Initially emergency bit should be set to false + var navdata = {droneState: {emergencyLanding: true}}; + this.fakeUdpNavdataStream.emit('data', navdata); + assert.equal(this.client._ref.emergency, false); + + // But calling disableEmergency should flip it on + this.client.disableEmergency(); + this.fakeUdpNavdataStream.emit('data', navdata); + assert.equal(this.client._ref.emergency, true); + + // And make it stay on + this.fakeUdpNavdataStream.emit('data', navdata); + assert.equal(this.client._ref.emergency, true); + + // Until the emergencyLanding status goes to false + navdata.droneState.emergencyLanding = false; + this.fakeUdpNavdataStream.emit('data', navdata); + assert.equal(this.client._ref.emergency, false); + + // But this should only happen once + navdata.droneState.emergencyLanding = true; + this.fakeUdpNavdataStream.emit('data', navdata); + assert.equal(this.client._ref.emergency, false); + }, +}); diff --git a/node_modules/ar-drone/test/unit/test-index.js b/node_modules/ar-drone/test/unit/test-index.js new file mode 100644 index 0000000..f5b9b56 --- /dev/null +++ b/node_modules/ar-drone/test/unit/test-index.js @@ -0,0 +1,42 @@ +var common = require('../common'); +var assert = require('assert'); +var utest = require('utest'); +var sinon = require('sinon'); +var arDrone = require(common.root); + +utest('main api', { + before: function() { + sinon.stub(arDrone.PngStream.prototype, 'resume'); + sinon.stub(arDrone.UdpNavdataStream.prototype, 'resume'); + sinon.stub(arDrone.Client.prototype, 'resume'); + }, + + after: function() { + arDrone.PngStream.prototype.resume.restore(); + arDrone.UdpNavdataStream.prototype.resume.restore(); + arDrone.Client.prototype.resume.restore(); + }, + + 'createClient': function() { + var client = arDrone.createClient(); + assert.ok(client instanceof arDrone.Client); + assert.equal(client.resume.callCount, 1); + }, + + 'createPngStream': function() { + var pngStream = arDrone.createPngStream(); + assert.ok(pngStream instanceof arDrone.PngStream); + assert.equal(pngStream.resume.callCount, 1); + }, + + 'createUdpControl': function() { + var control = arDrone.createUdpControl(); + assert.ok(control instanceof arDrone.UdpControl); + }, + + 'createUdpNavdataStream': function() { + var stream = arDrone.createUdpNavdataStream(); + assert.ok(stream instanceof arDrone.UdpNavdataStream); + assert.equal(stream.resume.callCount, 1); + }, +}); diff --git a/node_modules/ar-drone/test/unit/video/test-PaVEParser.js b/node_modules/ar-drone/test/unit/video/test-PaVEParser.js new file mode 100644 index 0000000..96ed447 --- /dev/null +++ b/node_modules/ar-drone/test/unit/video/test-PaVEParser.js @@ -0,0 +1,114 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var PaVEParser = require(common.lib + '/video/PaVEParser'); +var fs = require('fs'); +var sinon = require('sinon'); +var fixture = fs.readFileSync(common.fixtures + '/pave.bin'); +var fixture68 = fs.readFileSync(common.fixtures + '/pave-68.bin'); + +test('PaVEParser', { + before: function() { + this.parser = new PaVEParser(); + }, + + 'parses fixture properly': function() { + var frames = []; + this.parser.on('data', function(frame) { + frames.push(frame); + }); + + this.parser.write(fixture); + + assert.equal(frames.length, 20); + + var first = frames[0]; + + assert.equal(first.signature, 'PaVE'); + assert.equal(first.version, 2); + assert.equal(first.video_codec, 4); + assert.equal(first.header_size, 64); + assert.equal(first.payload_size, 2632); + assert.equal(first.encoded_stream_width, 640); + assert.equal(first.encoded_stream_height, 368); + assert.equal(first.display_width, 640); + assert.equal(first.display_height, 360); + assert.equal(first.frame_number, 17368); + assert.equal(first.timestamp, 1792570814); + assert.equal(first.total_chunks, 1); + assert.equal(first.chunk_index, 0); + assert.equal(first.frame_type, 3); + assert.equal(first.control, 0); + assert.equal(first.stream_byte_position_lw, 72366960); + assert.equal(first.stream_byte_position_uw, 0); + assert.equal(first.stream_id, 5); + assert.equal(first.total_slices, 1); + assert.equal(first.slice_index, 0); + assert.equal(first.header1_size, 0); + assert.equal(first.header2_size, 0); + assert.equal(first.reserved2.length, 2); + assert.equal(first.advertised_size, 2632); + assert.equal(first.reserved3.length, 12); + assert.equal(first.payload.length, 2632); + }, + + 'parses 68 byte frames properly': function() { + var frames = []; + this.parser.on('data', function(frame) { + frames.push(frame); + }); + + this.parser.write(fixture68); + + assert.equal(frames.length, 5); + + var first = frames[0]; + + assert.equal(first.signature, 'PaVE'); + assert.equal(first.version, 2); + assert.equal(first.video_codec, 4); + assert.equal(first.header_size, 68); + assert.equal(first.payload_size, 10180); + assert.equal(first.encoded_stream_width, 640); + assert.equal(first.encoded_stream_height, 368); + assert.equal(first.display_width, 640); + assert.equal(first.display_height, 360); + assert.equal(first.frame_number, 245401); + assert.equal(first.timestamp, 8015353); + assert.equal(first.total_chunks, 1); + assert.equal(first.chunk_index, 0); + assert.equal(first.frame_type, 1); + assert.equal(first.control, 0); + assert.equal(first.stream_byte_position_lw, 1009151980); + assert.equal(first.stream_byte_position_uw, 0); + assert.equal(first.stream_id, 1); + assert.equal(first.total_slices, 1); + assert.equal(first.slice_index, 0); + assert.equal(first.header1_size, 14); + assert.equal(first.header2_size, 10); + assert.equal(first.reserved2.length, 2); + assert.equal(first.advertised_size, 10180); + assert.equal(first.reserved3.length, 12); + assert.equal(first.payload.length, 10180); + }, + + + 'emits error on bad signature': function() { + var buffer = new Buffer(68); + + // should be PaVE, not fuck + buffer.write('fuck'); + + var errorStub = sinon.stub(); + this.parser.on('error', errorStub); + + this.parser.write(buffer); + + assert.equal(errorStub.callCount, 1); + assert.equal(/signature/i.test(errorStub.getCall(0).args[0]), true); + }, + + 'end method exists, but does nothing': function() { + this.parser.end(); + }, +}); diff --git a/node_modules/ar-drone/test/unit/video/test-PngEncoder.js b/node_modules/ar-drone/test/unit/video/test-PngEncoder.js new file mode 100644 index 0000000..6fcb5c4 --- /dev/null +++ b/node_modules/ar-drone/test/unit/video/test-PngEncoder.js @@ -0,0 +1,228 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var sinon = require('sinon'); +var PngEncoder = require(common.lib + '/video/PngEncoder'); +var EventEmitter = require('events').EventEmitter; + + +test('PngEncoder', { + before: function() { + this.fakeFfmpeg = new EventEmitter(); + + this.fakeFfmpeg.stdin = new EventEmitter(); + this.fakeFfmpeg.stdin.write = sinon.stub(); + this.fakeFfmpeg.stdin.end = sinon.stub(); + + this.fakeFfmpeg.stdout = {pipe: sinon.spy()}; + this.fakeFfmpeg.stderr = {pipe: sinon.spy()}; + + this.fakeSpawn = sinon.stub(); + this.fakeSpawn.returns(this.fakeFfmpeg); + + this.fakePngSplitter = new EventEmitter(); + + this.fakeFrameRate = 23; + + this.fakeBuffer1 = new Buffer('123'); + this.fakeBuffer2 = new Buffer('456'); + + this.fakeLog = {}; + + this.encoder = new PngEncoder({ + spawn : this.fakeSpawn, + frameRate : this.fakeFrameRate, + pngSplitter : this.fakePngSplitter, + log : this.fakeLog, + }); + }, + + 'is a writable stream': function() { + assert.equal(this.encoder.writable, true); + assert.equal(typeof this.encoder.write, 'function'); + }, + + 'is a readable stream': function() { + assert.equal(this.encoder.readable, true); + assert.equal(typeof this.encoder.pipe, 'function'); + }, + + 'first write() spawns ffmpeg': function() { + this.encoder.write(new Buffer('foo')); + + assert.equal(this.fakeSpawn.callCount, 1); + assert.equal(this.fakeSpawn.getCall(0).args[0], 'ffmpeg'); + + // Another write does not spawn another ffmpeg + this.encoder.write(new Buffer('bar')); + assert.equal(this.fakeSpawn.callCount, 1); + }, + + 'write() spawn ffmpeg with the right arguments': function() { + this.encoder.write(new Buffer('foo')); + + var args = this.fakeSpawn.getCall(0).args[1]; + + // Read from stdin + var input = args.indexOf('-i'); + assert.equal(args[input + 1], '-'); + + // Use the image2pipe format + var format = args.indexOf('-f'); + assert.equal(args[format + 1], 'image2pipe'); + + // Use the png video codec + var vcodec = args.indexOf('-vcodec'); + assert.equal(args[vcodec + 1], 'png'); + + // Sets the right framerate + var frameRate = args.indexOf('-r'); + assert.equal(args[frameRate + 1], this.fakeFrameRate); + + // Pipe to stdout + assert.equal(args[args.length - 1], '-'); + }, + + 'write() pipes ffmpeg.stdout into PngSplitter': function() { + this.encoder.write(new Buffer('foo')); + + var stdoutPipe = this.fakeFfmpeg.stdout.pipe; + assert.equal(stdoutPipe.callCount, 1); + assert.strictEqual(stdoutPipe.getCall(0).args[0], this.fakePngSplitter); + }, + + 'proxies all pngSplitter "data"': function() { + var dataSpy = sinon.spy(); + this.encoder.on('data', dataSpy); + + this.encoder.write(new Buffer('foo')); + this.fakePngSplitter.emit('data', this.fakeBuffer1); + + assert.equal(dataSpy.callCount, 1); + assert.strictEqual(dataSpy.getCall(0).args[0], this.fakeBuffer1); + + this.fakePngSplitter.emit('data', this.fakeBuffer2); + assert.equal(dataSpy.callCount, 2); + assert.strictEqual(dataSpy.getCall(1).args[0], this.fakeBuffer2); + }, + + 'handles ffmpeg spawn error': function() { + var errorSpy = sinon.spy(); + this.encoder.on('error', errorSpy); + + this.encoder.write(new Buffer('foo')); + + // simulate ffmpeg not spawning correctly + var error = new Error('ENOENT'); + error.code = 'ENOENT'; + this.fakeFfmpeg.stdin.emit('error', new Error('EPIPE')); + this.fakeFfmpeg.emit('error', error); + + assert.equal(errorSpy.callCount, 1); + assert.equal(/ffmpeg.*not found/i.test(errorSpy.getCall(0).args[0]), true); + }, + + 'handles ffmpeg not existing': function() { + var errorSpy = sinon.spy(); + this.encoder.on('error', errorSpy); + + this.encoder.write(new Buffer('foo')); + + // simulate ffmpeg not existing + this.fakeFfmpeg.stdin.emit('error', new Error('EPIPE')); + this.fakeFfmpeg.emit('exit', 127); + + assert.equal(errorSpy.callCount, 1); + assert.equal(/ffmpeg.*not found/i.test(errorSpy.getCall(0).args[0]), true); + }, + + 'handles ffmpeg exit code > 0': function() { + var errorSpy = sinon.spy(); + this.encoder.on('error', errorSpy); + + this.encoder.write(new Buffer('foo')); + + // simulate an ffmpeg error + this.fakeFfmpeg.emit('exit', 1); + + assert.equal(errorSpy.callCount, 1); + assert.equal(/ffmpeg.*error/i.test(errorSpy.getCall(0).args[0]), true); + }, + + 'handles expected ffmpeg shutdown': function() { + var endSpy = sinon.spy(); + this.encoder.on('end', endSpy); + + this.encoder.write(new Buffer('foo')); + this.encoder.end(); + this.fakeFfmpeg.emit('exit', 0); + + assert.equal(endSpy.callCount, 1); + }, + + 'handles unexpected ffmpeg shutdown with exit code 0': function() { + var errorSpy = sinon.spy(); + this.encoder.on('error', errorSpy); + + this.encoder.write(new Buffer('foo')); + this.fakeFfmpeg.emit('exit', 0); + + assert.equal(errorSpy.callCount, 1); + assert.equal(/unexpected.*ffmpeg/i.test(errorSpy.getCall(0).args[0].message), true); + }, + + 'write() passes all data into ffmpeg.stdin': function() { + this.encoder.write(this.fakeBuffer1); + + var stdin = this.fakeFfmpeg.stdin; + assert.equal(stdin.write.callCount, 1); + assert.strictEqual(stdin.write.getCall(0).args[0], this.fakeBuffer1); + + this.encoder.write(this.fakeBuffer2); + assert.equal(stdin.write.callCount, 2); + assert.strictEqual(stdin.write.getCall(1).args[0], this.fakeBuffer2); + }, + + 'write() handles ffmpeg backpressure': function() { + this.fakeFfmpeg.stdin.write.returns(true); + var r = this.encoder.write(new Buffer('abc')); + assert.equal(r, true); + + this.fakeFfmpeg.stdin.write.returns(false); + r = this.encoder.write(new Buffer('abc')); + assert.equal(r, false); + + var drainCalled = false; + this.encoder.on('drain', function () { + drainCalled = true; + }); + this.fakeFfmpeg.stdin.emit('drain'); + assert.ok(drainCalled); + }, + + 'write() pipes ffmpeg stderr to log': function() { + this.encoder.write(new Buffer('abc')); + + var stderrPipe = this.fakeFfmpeg.stderr.pipe; + assert.equal(stderrPipe.callCount, 1); + assert.strictEqual(stderrPipe.getCall(0).args[0], this.fakeLog); + }, + + 'write() does not pipe to log if not set': function() { + this.encoder = new PngEncoder({spawn: this.fakeSpawn}); + + this.encoder.write(new Buffer('abc')); + assert.equal(this.fakeFfmpeg.stderr.pipe.callCount, 0); + }, + + 'end() closes ffmpeg.stdin': function() { + this.encoder.write(new Buffer('abc')); + this.encoder.end(); + + assert.equal(this.fakeFfmpeg.stdin.end.callCount, 1); + }, + + 'end() does not do anything if there is no ffmpeg yet': function() { + this.encoder.end(); + }, +}); diff --git a/node_modules/ar-drone/test/unit/video/test-PngStream.js b/node_modules/ar-drone/test/unit/video/test-PngStream.js new file mode 100644 index 0000000..e693ae0 --- /dev/null +++ b/node_modules/ar-drone/test/unit/video/test-PngStream.js @@ -0,0 +1,114 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var sinon = require('sinon'); +var PngStream = require(common.lib + '/video/PngStream'); +var TcpVideoStream = PngStream.TcpVideoStream; +var PngEncoder = PngStream.PngEncoder; + +test('PngStream', { + before: function() { + PngStream.TcpVideoStream = sinon.stub(); + PngStream.PngEncoder = sinon.stub(); + + this.tcpVideoStream = new TcpVideoStream(); + this.pngEncoder = new PngEncoder(); + + PngStream.TcpVideoStream.returns(this.tcpVideoStream); + PngStream.PngEncoder.returns(this.pngEncoder); + + this.fakeOptions = {}; + this.stream = new PngStream(this.fakeOptions); + }, + + 'is a readable stream': function() { + assert.equal(this.stream.readable, true); + assert.equal(typeof this.stream.pipe, 'function'); + }, + + 'resume connects new TcpVideoStream': function() { + sinon.stub(this.tcpVideoStream, 'connect'); + + this.stream.resume(); + + assert.equal(PngStream.TcpVideoStream.callCount, 1); + assert.strictEqual(PngStream.TcpVideoStream.getCall(0).args[0], this.fakeOptions); + assert.equal(this.tcpVideoStream.connect.callCount, 1); + }, + + 'resume passes TcpVideoStream data through PngEncoder': function() { + sinon.stub(this.tcpVideoStream, 'connect'); + + this.stream.resume(); + + assert.equal(PngStream.TcpVideoStream.callCount, 1); + assert.equal(PngStream.PngEncoder.callCount, 1); + + assert.strictEqual(PngStream.TcpVideoStream.getCall(0).args[0], this.fakeOptions); + assert.strictEqual(PngStream.PngEncoder.getCall(0).args[0], this.fakeOptions); + + sinon.stub(this.pngEncoder, 'write'); + + var fakeData = new Buffer([1]); + this.tcpVideoStream.emit('data', fakeData); + + assert.equal(this.pngEncoder.write.callCount, 1); + assert.strictEqual(this.pngEncoder.write.getCall(0).args[0], fakeData); + + var dataStub = sinon.stub(); + this.stream.on('data', dataStub); + + var fakePng = new Buffer([2]); + this.pngEncoder.emit('data', fakePng); + + assert.equal(dataStub.callCount, 1); + assert.strictEqual(dataStub.getCall(0).args[0], fakePng); + }, + + 'TcpVideoStream stream errors cause a new tcpVideoStream to be created': function() { + sinon.stub(this.tcpVideoStream, 'connect'); + sinon.stub(this.pngEncoder, 'end'); + + this.stream.resume(); + + var tcpVideoStream2 = new TcpVideoStream(); + sinon.stub(tcpVideoStream2, 'connect'); + PngStream.TcpVideoStream.returns(tcpVideoStream2); + + var fakeErr = new Error('bad shit'); + this.tcpVideoStream.emit('error', fakeErr); + + assert.equal(tcpVideoStream2.connect.callCount, 1); + assert.equal(this.pngEncoder.end.callCount, 1); + }, + + 'emits "error" events on tcpVideoStream errors, if there is a listener': function() { + sinon.stub(this.tcpVideoStream, 'connect'); + sinon.stub(this.pngEncoder, 'end'); + + var errStub = sinon.stub(); + this.stream.on('error', errStub); + this.stream.resume(); + + var fakeErr = new Error('bad shit'); + this.tcpVideoStream.emit('error', fakeErr); + + assert.equal(errStub.callCount, 1); + assert.strictEqual(errStub.getCall(0).args[0], fakeErr); + }, + + 'emits "error" events on pngEncoder errors, if there is a listener': function() { + sinon.stub(this.tcpVideoStream, 'connect'); + sinon.stub(this.pngEncoder, 'end'); + + var errStub = sinon.stub(); + this.stream.on('error', errStub); + this.stream.resume(); + + var fakeErr = new Error('bad shit'); + this.pngEncoder.emit('error', fakeErr); + + assert.equal(errStub.callCount, 1); + assert.strictEqual(errStub.getCall(0).args[0], fakeErr); + }, +}); diff --git a/node_modules/ar-drone/test/unit/video/test-TcpVideoStream.js b/node_modules/ar-drone/test/unit/video/test-TcpVideoStream.js new file mode 100644 index 0000000..b3bd614 --- /dev/null +++ b/node_modules/ar-drone/test/unit/video/test-TcpVideoStream.js @@ -0,0 +1,151 @@ +var common = require('../../common'); +var assert = require('assert'); +var test = require('utest'); +var sinon = require('sinon'); +var EventEmitter = require('events').EventEmitter; +var TcpVideoStream = require(common.lib + '/video/TcpVideoStream'); + +test('TcpVideoStream', { + before: function() { + this.fakeSocket = new EventEmitter(); + this.fakeSocket.connect = sinon.spy(); + this.fakeSocket.setTimeout = sinon.spy(); + this.fakeSocket.end = sinon.spy(); + this.fakeSocket.destroy = sinon.spy(); + + this.fakePort = 93321; + this.fakeIp = '255.0.124.24'; + this.fakeTimeout = 23 * 1000; + + this.stream = new TcpVideoStream({ + ip : this.fakeIp, + port : this.fakePort, + timeout : this.fakeTimeout, + socket : this.fakeSocket + }); + }, + + 'is a readable stream': function() { + assert.equal(this.stream.readable, true); + assert.equal(typeof this.stream.pipe, 'function'); + }, + + 'connect() calls socket.connect': function() { + this.stream.connect(); + assert.equal(this.fakeSocket.connect.callCount, 1); + + var args = this.fakeSocket.connect.getCall(0).args; + assert.equal(args.shift(), this.fakePort); + assert.equal(args.shift(), this.fakeIp); + }, + + 'connect() calls socket.setTimeout': function() { + this.stream.connect(); + + var setTimeout = this.fakeSocket.setTimeout; + assert.equal(setTimeout.callCount, 1); + assert.equal(setTimeout.getCall(0).args[0], this.fakeTimeout); + }, + + 'socket "timeout" events trigger "error", "close" and destroy()': function() { + var errorSpy = sinon.spy(); + var closeSpy = sinon.spy(); + this.stream.on('error', errorSpy); + this.stream.on('close', closeSpy); + + this.stream.connect(); + this.fakeSocket.emit('timeout'); + + assert.equal(errorSpy.callCount, 1); + var err = errorSpy.getCall(0).args[0]; + assert.equal(err instanceof Error, true); + assert.equal(/timeout/i.test(err), true); + + assert.equal(closeSpy.callCount, 1); + assert.strictEqual(closeSpy.getCall(0).args[0], err); + + assert.equal(this.fakeSocket.destroy.callCount, 1); + }, + + 'connect() calls back on success': function() { + var fakeCb = sinon.spy(); + this.stream.connect(fakeCb); + + assert.equal(fakeCb.callCount, 0); + + this.fakeSocket.emit('connect'); + assert.equal(fakeCb.callCount, 1); + assert.equal(fakeCb.getCall(0).args[0], null); + }, + + 'connect() calls back on error': function() { + var fakeCb = sinon.spy(); + this.stream.connect(fakeCb); + + assert.equal(fakeCb.callCount, 0); + + var fakeErr = new Error('something bad'); + this.fakeSocket.emit('error', fakeErr); + assert.equal(fakeCb.callCount, 1); + assert.strictEqual(fakeCb.getCall(0).args[0], fakeErr); + }, + + 'connect() callback is optional': function() { + this.stream.connect(); + this.fakeSocket.emit('connect'); + }, + + 'proxies "data" events': function() { + var fakeData1 = new Buffer('abc'); + var fakeData2 = new Buffer('efg'); + + var dataSpy = sinon.spy(); + this.stream.on('data', dataSpy); + this.stream.connect(); + + this.fakeSocket.emit('data', fakeData1); + assert.strictEqual(dataSpy.callCount, 1); + assert.strictEqual(dataSpy.getCall(0).args[0], fakeData1); + + this.fakeSocket.emit('data', fakeData2); + assert.strictEqual(dataSpy.callCount, 2); + assert.strictEqual(dataSpy.getCall(1).args[0], fakeData2); + }, + + 'end() ends the socket gracefully': function() { + this.stream.end(); + assert.equal(this.fakeSocket.end.callCount, 1); + }, + + 'emits an "error" on unexpected server FIN': function() { + var errorSpy = sinon.spy(); + var closeSpy = sinon.spy(); + + this.stream.on('error', errorSpy); + this.stream.on('close', closeSpy); + + this.stream.connect(); + + this.fakeSocket.emit('end'); + + assert.equal(errorSpy.callCount, 1); + var err = errorSpy.getCall(0).args[0]; + assert.equal(err instanceof Error, true); + assert.equal(/FIN/.test(err.message), true); + + assert.equal(closeSpy.callCount, 1); + assert.strictEqual(closeSpy.getCall(0).args[0], err); + }, + + 'proxies close event when expecting it': function() { + var closeSpy = sinon.spy(); + this.stream.on('close', closeSpy); + + this.stream.connect(); + this.stream.end(); + this.fakeSocket.emit('end'); + + assert.equal(closeSpy.callCount, 1); + assert.equal(closeSpy.getCall(0).args[0], null); + }, +}); diff --git a/node_modules/consolidate/.npmignore b/node_modules/consolidate/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/consolidate/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/consolidate/History.md b/node_modules/consolidate/History.md new file mode 100644 index 0000000..e6e5370 --- /dev/null +++ b/node_modules/consolidate/History.md @@ -0,0 +1,79 @@ +0.9.1 / 2013-04-29 +================== + + * Update ECT version + * Added support for Handlebars helpers with test. + * Invalidates built-in dust cache if caching disabled + +0.9.0 / 2013-03-28 +================== + + * dust-helpers support, latest version of dust + * Re-add doT - global leaks fixed + * improving templayed support + +0.8.0 / 2013-01-23 +================== + + * add templayed support + * add `then-jade` as an alternative to `jade` + +0.7.0 / 2012-12-28 +================== + + * add atpl support + +0.6.0 2012-12-22 +================== + + * add partials support + * add support for toffee templates + * remove dot it still leaks and the author has not fixed it + +0.5.0 / 2012-10-29 +================== + + * add `mote` support + * add support to `dust` partials + * add support for `ECT` + * add support for rendering without file + * add support for `JUST` + * improve Haml-Coffee caching. + +0.4.0 / 2012-07-30 +================== + + * add doT support [sannis] + * add mustache support [ForbesLindesay] + * add walrus support [kagd] + +0.3.1 / 2012-06-28 +================== + + * add QEJS support + * add underscore support + * change whiskers to use pre-defined `.__express` + * remove engines. Closes #37 + * remove kernel, cannot comply with our caching + +0.3.0 / 2012-04-18 +================== + + * Added partials loading for whiskers [gsf] + * Added dustjs-linkedin support + +0.2.0 / 2012-04-04 +================== + + * Added support for dust [fatjonny] + * Added handlebars support [jstewmon] + +0.1.0 / 2012-01-03 +================== + + * Added support for several more engines + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/consolidate/Makefile b/node_modules/consolidate/Makefile new file mode 100644 index 0000000..2bc56b4 --- /dev/null +++ b/node_modules/consolidate/Makefile @@ -0,0 +1,9 @@ + +REPORTER = spec + +test: + @./node_modules/.bin/mocha \ + --slow 30 \ + --reporter $(REPORTER) + +.PHONY: test \ No newline at end of file diff --git a/node_modules/consolidate/Readme.md b/node_modules/consolidate/Readme.md new file mode 100644 index 0000000..d00de1e --- /dev/null +++ b/node_modules/consolidate/Readme.md @@ -0,0 +1,153 @@ +# Consolidate.js + + Template engine consolidation library. + +## Installation + + $ npm install consolidate + +## Supported template engines + + - [atpl](https://github.com/soywiz/atpl.js) + - [dust](https://github.com/akdubya/dustjs) [(website)](http://akdubya.github.com/dustjs/) + - [eco](https://github.com/sstephenson/eco) + - [ect](https://github.com/baryshev/ect) [(website)](http://ectjs.com/) + - [ejs](https://github.com/visionmedia/ejs) + - [haml](https://github.com/visionmedia/haml.js) [(website)](http://haml-lang.com/) + - [haml-coffee](https://github.com/9elements/haml-coffee) [(website)](http://haml-lang.com/) + - [handlebars](https://github.com/wycats/handlebars.js/) [(website)](http://handlebarsjs.com/) + - [hogan](https://github.com/twitter/hogan.js) [(website)](http://twitter.github.com/hogan.js/) + - [jade](https://github.com/visionmedia/jade) [(website)](http://jade-lang.com/) + - [jazz](https://github.com/shinetech/jazz) + - [jqtpl](https://github.com/kof/node-jqtpl) [(website)](http://api.jquery.com/category/plugins/templates/) + - [JUST](https://github.com/baryshev/just) + - [liquor](https://github.com/chjj/liquor) + - [mustache](https://github.com/janl/mustache.js) + - [QEJS](https://github.com/jepso/QEJS) + - [swig](https://github.com/paularmstrong/swig) [(website)](http://paularmstrong.github.com/swig/) + - [templayed](http://archan937.github.com/templayed.js/) + - [toffee](https://github.com/malgorithms/toffee) + - [underscore](https://github.com/documentcloud/underscore) [(website)](http://documentcloud.github.com/underscore/) + - [walrus](https://github.com/jeremyruppel/walrus) [(website)](http://documentup.com/jeremyruppel/walrus/) + - [whiskers](https://github.com/gsf/whiskers.js/tree/) + +__NOTE__: you must still install the engines you wish to use, add them to your package.json dependencies. + +## API + + All templates supported by this library may be rendered using the signature `(path[, locals], callback)` as shown below, which happens to be the signature that Express 3.x supports so any of these engines may be used within Express. + +__NOTE__: All this example code uses cons.swig for the swig template engine. Replace swig with whatever templating you are using. For exmaple, use cons.hogan for hogan.js, cons.jade for jade, etc. `console.log(cons)` for the full list of identifiers. + +```js +var cons = require('consolidate'); +cons.swig('views/page.html', { user: 'tobi' }, function(err, html){ + if (err) throw err; + console.log(html); +}); +``` + + Or without options / local variables: + +```js +var cons = require('consolidate'); +cons.swig('views/page.html', function(err, html){ + if (err) throw err; + console.log(html); +}); +``` + + To dynamically pass the engine, simply use the subscript operator and a variable: + +```js +var cons = require('consolidate') + , name = 'swig'; + +cons[name]('views/page.html', { user: 'tobi' }, function(err, html){ + if (err) throw err; + console.log(html); +}); +``` + +## Caching + + To enable caching simply pass `{ cache: true }`. Engines _may_ use this option to cache things reading the file contents, compiled `Function`s etc. Engines which do _not_ support this may simply ignore it. All engines that consolidate.js implements I/O for will cache the file contents, ideal for production environments. + +```js +var cons = require('consolidate'); +cons.swig('views/page.html', { user: 'tobi' }, function(err, html){ + if (err) throw err; + console.log(html); +}); +``` + +## Express 3.x example + +```js +var express = require('express') + , cons = require('consolidate') + , app = express(); + +// assign the swig engine to .html files +app.engine('html', cons.swig); + +// set .html as the default extension +app.set('view engine', 'html'); +app.set('views', __dirname + '/views'); + +var users = []; +users.push({ name: 'tobi' }); +users.push({ name: 'loki' }); +users.push({ name: 'jane' }); + +app.get('/', function(req, res){ + res.render('index', { + title: 'Consolidate.js' + }); +}); + +app.get('/users', function(req, res){ + res.render('users', { + title: 'Users', + users: users + }); +}); + +app.listen(3000); +console.log('Express server listening on port 3000'); +``` + +## Running tests + + Install dev deps: + + $ npm install -d + + Run the tests: + + $ make test + +## License + +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/consolidate/index.js b/node_modules/consolidate/index.js new file mode 100644 index 0000000..4a0df17 --- /dev/null +++ b/node_modules/consolidate/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/consolidate'); \ No newline at end of file diff --git a/node_modules/consolidate/lib/consolidate.js b/node_modules/consolidate/lib/consolidate.js new file mode 100644 index 0000000..c04ab7f --- /dev/null +++ b/node_modules/consolidate/lib/consolidate.js @@ -0,0 +1,704 @@ +/*! + * consolidate + * Copyright(c) 2012 TJ Holowaychuk + * MIT Licensed + * + * Engines which do not support caching of their file contents + * should use the `read()` function defined in consolidate.js + * On top of this, when an engine compiles to a `Function`, + * these functions should either be cached within consolidate.js + * or the engine itself via `options.cache`. This will allow + * users and frameworks to pass `options.cache = true` for + * `NODE_ENV=production`, however edit the file(s) without + * re-loading the application in development. + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , path = require('path') + , join = path.join + , extname = path.extname + , dirname = path.dirname; + +var readCache = {}; + +/** + * Require cache. + */ + +var cacheStore = {}; + +/** + * Require cache. + */ + +var requires = {}; + +/** + * Clear the cache. + * + * @api public + */ + +exports.clearCache = function(){ + cacheStore = {}; +}; + +/** + * Conditionally cache `compiled` template based + * on the `options` filename and `.cache` boolean. + * + * @param {Object} options + * @param {Function} compiled + * @return {Function} + * @api private + */ + +function cache(options, compiled) { + // cachable + if (compiled && options.filename && options.cache) { + delete readCache[options.filename]; + cacheStore[options.filename] = compiled; + return compiled; + } + + // check cache + if (options.filename && options.cache) { + return cacheStore[options.filename]; + } + + return compiled; +} + +/** + * Read `path` with `options` with + * callback `(err, str)`. When `options.cache` + * is true the template string will be cached. + * + * @param {String} options + * @param {Function} fn + * @api private + */ + +function read(path, options, fn) { + var str = readCache[path]; + var cached = options.cache && str && 'string' == typeof str; + + // cached (only if cached is a string and not a compiled template function) + if (cached) return fn(null, str); + + // read + fs.readFile(path, 'utf8', function(err, str){ + if (err) return fn(err); + if (options.cache) readCache[path] = str; + fn(null, str); + }); +} + +/** + * Read `path` with `options` with + * callback `(err, str)`. When `options.cache` + * is true the partial string will be cached. + * + * @param {String} options + * @param {Function} fn + * @api private + */ + +function readPartials(path, options, fn) { + if (!options.partials) return fn(); + var partials = options.partials; + var keys = Object.keys(partials); + + function next(index) { + if (index == keys.length) return fn(null); + var key = keys[index]; + var file = join(dirname(path), partials[key] + extname(path)); + read(file, options, function(err, str){ + if (err) return fn(err); + options.partials[key] = str; + next(++index); + }); + } + + next(0); +} + +/** + * fromStringRenderer + */ + +function fromStringRenderer(name) { + return function(path, options, fn){ + options.filename = path; + readPartials(path, options, function (err) { + if (err) return fn(err); + if (cache(options)) { + exports[name].render('', options, fn); + } else { + read(path, options, function(err, str){ + if (err) return fn(err); + exports[name].render(str, options, fn); + }); + } + }); + }; +} + +/** + * Jade support. + */ + +exports.jade = function(path, options, fn){ + var engine = requires.jade; + if (!engine) { + try { + engine = requires.jade = require('jade'); + } catch (err) { + engine = requires.jade = require('then-jade'); + } + } + engine.renderFile(path, options, fn); +}; + +/** + * Jade string support. + */ + +exports.jade.render = function(str, options, fn){ + var engine = requires.jade; + if (!engine) { + try { + engine = requires.jade = require('jade'); + } catch (err) { + engine = requires.jade = require('then-jade'); + } + } + engine.render(str, options, fn); +}; + +/** + * Dust support. + */ + +exports.dust = fromStringRenderer('dust'); + +/** + * Dust string support. + */ + +exports.dust.render = function(str, options, fn){ + var engine = requires.dust; + if (!engine) { + try { + engine = requires.dust = require('dust'); + } catch (err) { + try { + engine = requires.dust = require('dustjs-helpers'); + } catch (err) { + engine = requires.dust = require('dustjs-linkedin'); + } + } + } + + var ext = 'dust' + , views = '.'; + + if (options) { + if (options.ext) ext = options.ext; + if (options.views) views = options.views; + if (options.settings && options.settings.views) views = options.settings.views; + } + if (!options || (options && !options.cache)) engine.cache = {}; + + engine.onLoad = function(path, callback){ + if ('' == extname(path)) path += '.' + ext; + if ('/' !== path[0]) path = views + '/' + path; + read(path, options, callback); + }; + + try { + var tmpl = cache(options) || cache(options, engine.compileFn(str)); + tmpl(options, fn); + } catch (err) { + fn(err); + } +}; + +/** + * Swig support. + */ + +exports.swig = fromStringRenderer('swig'); + +/** + * Swig string support. + */ + +exports.swig.render = function(str, options, fn){ + var engine = requires.swig || (requires.swig = require('swig')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; + +/** + * Atpl support. + */ + +exports.atpl = fromStringRenderer('atpl'); + +/** + * Atpl string support. + */ + +exports.atpl.render = function(str, options, fn){ + var engine = requires.atpl || (requires.atpl = require('atpl')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; + +/** + * Liquor support, + */ + +exports.liquor = fromStringRenderer('liquor'); + +/** + * Liquor string support. + */ + +exports.liquor.render = function(str, options, fn){ + var engine = requires.liquor || (requires.liquor = require('liquor')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; + +/** + * EJS support. + */ + +exports.ejs = fromStringRenderer('ejs'); + +/** + * EJS string support. + */ + +exports.ejs.render = function(str, options, fn){ + var engine = requires.ejs || (requires.ejs = require('ejs')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; + + +/** + * Eco support. + */ + +exports.eco = fromStringRenderer('eco'); + +/** + * Eco string support. + */ + +exports.eco.render = function(str, options, fn){ + var engine = requires.eco || (requires.eco = require('eco')); + try { + fn(null, engine.render(str, options)); + } catch (err) { + fn(err); + } +}; + +/** + * Jazz support. + */ + +exports.jazz = fromStringRenderer('jazz'); + +/** + * Jazz string support. + */ + +exports.jazz.render = function(str, options, fn){ + var engine = requires.jazz || (requires.jazz = require('jazz')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + tmpl.eval(options, function(str){ + fn(null, str); + }); + } catch (err) { + fn(err); + } +}; + +/** + * JQTPL support. + */ + +exports.jqtpl = fromStringRenderer('jqtpl'); + +/** + * JQTPL string support. + */ + +exports.jqtpl.render = function(str, options, fn){ + var engine = requires.jqtpl || (requires.jqtpl = require('jqtpl')); + try { + engine.template(str, str); + fn(null, engine.tmpl(str, options)); + } catch (err) { + fn(err); + } +}; + +/** + * Haml support. + */ + +exports.haml = fromStringRenderer('haml'); + +/** + * Haml string support. + */ + +exports.haml.render = function(str, options, fn){ + var engine = requires.hamljs || (requires.hamljs = require('hamljs')); + try { + options.locals = options; + fn(null, engine.render(str, options).trimLeft()); + } catch (err) { + fn(err); + } +}; + +/** + * Whiskers support. + */ + +exports.whiskers = function(path, options, fn){ + var engine = requires.whiskers || (requires.whiskers = require('whiskers')); + engine.__express(path, options, fn); +}; + +/** + * Whiskers string support. + */ + +exports.whiskers.render = function(str, options, fn){ + var engine = requires.whiskers || (requires.whiskers = require('whiskers')); + try { + fn(null, engine.render(str, options)); + } catch (err) { + fn(err); + } +}; + +/** + * Coffee-HAML support. + */ + +exports['haml-coffee'] = fromStringRenderer('haml-coffee'); + +/** + * Coffee-HAML string support. + */ + +exports['haml-coffee'].render = function(str, options, fn){ + var engine = requires.HAMLCoffee || (requires.HAMLCoffee = require('haml-coffee')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; + +/** + * Hogan support. + */ + +exports.hogan = fromStringRenderer('hogan'); + +/** + * Hogan string support. + */ + +exports.hogan.render = function(str, options, fn){ + var engine = requires.hogan || (requires.hogan = require('hogan.js')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl.render(options, options.partials)); + } catch (err) { + fn(err); + } +}; + +/** + * templayed.js support. + */ + +exports.templayed = fromStringRenderer('templayed'); + +/** + * templayed.js string support. + */ + +exports.templayed.render = function(str, options, fn){ + var engine = requires.templayed || (requires.templayed = require('templayed')); + try { + var tmpl = cache(options) || cache(options, engine(str)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; + +/** + * Handlebars support. + */ + +exports.handlebars = fromStringRenderer('handlebars'); + +/** + * Handlebars string support. + */ + +exports.handlebars.render = function(str, options, fn) { + var engine = requires.handlebars || (requires.handlebars = require('handlebars')); + try { + for (var partial in options.partials) { + engine.registerPartial(partial, options.partials[partial]); + } + for (var helper in options.helpers) { + engine.registerHelper(helper, options.helpers[helper]); + } + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +} + +/** + * Underscore support. + */ + +exports.underscore = fromStringRenderer('underscore'); + +/** + * Underscore string support. + */ + +exports.underscore.render = function(str, options, fn) { + var engine = requires.underscore || (requires.underscore = require('underscore')); + try { + var tmpl = cache(options) || cache(options, engine.template(str, null, options)); + fn(null, tmpl(options).replace(/\n$/, '')); + } catch (err) { + fn(err); + } +}; + + +/** + * QEJS support. + */ + +exports.qejs = function (path, options, fn) { + try { + var engine = requires.qejs || (requires.qejs = require('qejs')); + engine.renderFile(path, options).then(function (result) { + fn(null, result); + }, function (err) { + fn(err); + }).end(); + } catch (err) { + fn(err); + } +}; + +/** + * QEJS string support. + */ + +exports.qejs.render = function (str, options, fn) { + try { + var engine = requires.qejs || (requires.qejs = require('qejs')); + engine.render(str, options).then(function (result) { + fn(null, result); + }, function (err) { + fn(err); + }).end(); + } catch (err) { + fn(err); + } +}; + + +/** + * Walrus support. + */ + +exports.walrus = fromStringRenderer('walrus'); + +/** + * Walrus string support. + */ + +exports.walrus.render = function (str, options, fn) { + var engine = requires.walrus || (requires.walrus = require('walrus')); + try { + var tmpl = cache(options) || cache(options, engine.parse(str)); + fn(null, tmpl.compile(options)); + } catch (err) { + fn(err); + } +}; + +/** + * Mustache support. + */ + +exports.mustache = fromStringRenderer('mustache'); + +/** + * Mustache string support. + */ + +exports.mustache.render = function(str, options, fn) { + var engine = requires.mustache || (requires.mustache = require('mustache')); + try { + fn(null, engine.to_html(str, options, options.partials)); + } catch (err) { + fn(err); + } +}; + +/** + * Just support. + */ + +exports.just = function(path, options, fn){ + var engine = requires.just; + if (!engine) { + var JUST = require('just'); + engine = requires.just = new JUST(); + } + engine.configure({ useCache: options.cache }); + engine.render(path, options, fn); +}; + +/** + * Just string support. + */ + +exports.just.render = function(str, options, fn){ + var JUST = require('just'); + var engine = new JUST({ root: { page: str }}); + engine.render('page', options, fn); +}; + +/** + * ECT support. + */ + +exports.ect = function(path, options, fn){ + var engine = requires.ect; + if (!engine) { + var ECT = require('ect'); + engine = requires.ect = new ECT(); + } + engine.configure({ cache: options.cache }); + engine.render(path, options, fn); +}; + +/** + * ECT string support. + */ + +exports.ect.render = function(str, options, fn){ + var ECT = require('ect'); + var engine = new ECT({ root: { page: str }}); + engine.render('page', options, fn); +}; + +/** + * mote support. + */ + +exports.mote = fromStringRenderer('mote'); + +/** + * mote string support. + */ + +exports.mote.render = function(str, options, fn){ + var engine = requires.mote || (requires.mote = require('mote')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; + +/** + * Toffee support. + */ + +exports.toffee = function(path, options, fn){ + var toffee = requires.toffee || (requires.toffee = require('toffee')); + toffee.__consolidate_engine_render(path, options, fn); +}; + +/** + * Toffee string support. + */ + +exports.toffee.render = function(str, options, fn) { + var engine = requires.toffee || (requires.toffee = require('toffee')); + try { + engine.str_render(str, options,fn); + } catch (err) { + fn(err); + } +}; + +/** + * doT support. + */ + +exports.dot = fromStringRenderer('dot'); + +/** + * doT string support. + */ + +exports.dot.render = function (str, options, fn) { + var engine = requires.dot || (requires.dot = require('dot')); + try { + var tmpl = cache(options) || cache(options, engine.compile(str)); + fn(null, tmpl(options)); + } catch (err) { + fn(err); + } +}; diff --git a/node_modules/consolidate/package.json b/node_modules/consolidate/package.json new file mode 100644 index 0000000..c4eb2f7 --- /dev/null +++ b/node_modules/consolidate/package.json @@ -0,0 +1,56 @@ +{ + "name": "consolidate", + "version": "0.9.1", + "description": "Template engine consolidation library", + "keywords": [ + "template", + "engine", + "view" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "devDependencies": { + "mocha": "*", + "should": "*", + "jade": "0.26.0", + "ejs": "0.7.1", + "eco": "1.1.0-rc-3", + "swig": "0.12.0", + "jazz": "0.0.18", + "jqtpl": "1.1.0", + "liquor": "0.0.4", + "hamljs": "0.6.1", + "whiskers": "0.2.2", + "haml-coffee": "1.4.0", + "hogan.js": "2.0.0", + "dust": "0.3.0", + "dustjs-linkedin": "1.2", + "dustjs-helpers": "1.1.1", + "handlebars": "1.0.7", + "underscore": "1.3.3", + "qejs": "0.0.1", + "walrus": "0.9.0", + "mustache": "0.4.0", + "just": "0.1.8", + "ect": "0.3.5", + "mote": "0.2.0", + "toffee": "0.0.52", + "atpl": ">=0.5.5", + "templayed": ">=0.2.3", + "dot": "1.0.1" + }, + "main": "index", + "scripts": { + "test": "mocha" + }, + "readme": "# Consolidate.js\n\n Template engine consolidation library.\n\n## Installation\n\n $ npm install consolidate\n\n## Supported template engines\n\n - [atpl](https://github.com/soywiz/atpl.js)\n - [dust](https://github.com/akdubya/dustjs) [(website)](http://akdubya.github.com/dustjs/)\n - [eco](https://github.com/sstephenson/eco)\n - [ect](https://github.com/baryshev/ect) [(website)](http://ectjs.com/)\n - [ejs](https://github.com/visionmedia/ejs)\n - [haml](https://github.com/visionmedia/haml.js) [(website)](http://haml-lang.com/)\n - [haml-coffee](https://github.com/9elements/haml-coffee) [(website)](http://haml-lang.com/)\n - [handlebars](https://github.com/wycats/handlebars.js/) [(website)](http://handlebarsjs.com/)\n - [hogan](https://github.com/twitter/hogan.js) [(website)](http://twitter.github.com/hogan.js/)\n - [jade](https://github.com/visionmedia/jade) [(website)](http://jade-lang.com/)\n - [jazz](https://github.com/shinetech/jazz)\n - [jqtpl](https://github.com/kof/node-jqtpl) [(website)](http://api.jquery.com/category/plugins/templates/)\n - [JUST](https://github.com/baryshev/just)\n - [liquor](https://github.com/chjj/liquor)\n - [mustache](https://github.com/janl/mustache.js)\n - [QEJS](https://github.com/jepso/QEJS)\n - [swig](https://github.com/paularmstrong/swig) [(website)](http://paularmstrong.github.com/swig/)\n - [templayed](http://archan937.github.com/templayed.js/)\n - [toffee](https://github.com/malgorithms/toffee)\n - [underscore](https://github.com/documentcloud/underscore) [(website)](http://documentcloud.github.com/underscore/)\n - [walrus](https://github.com/jeremyruppel/walrus) [(website)](http://documentup.com/jeremyruppel/walrus/)\n - [whiskers](https://github.com/gsf/whiskers.js/tree/)\n\n__NOTE__: you must still install the engines you wish to use, add them to your package.json dependencies.\n\n## API\n\n All templates supported by this library may be rendered using the signature `(path[, locals], callback)` as shown below, which happens to be the signature that Express 3.x supports so any of these engines may be used within Express.\n\n__NOTE__: All this example code uses cons.swig for the swig template engine. Replace swig with whatever templating you are using. For exmaple, use cons.hogan for hogan.js, cons.jade for jade, etc. `console.log(cons)` for the full list of identifiers.\n\n```js\nvar cons = require('consolidate');\ncons.swig('views/page.html', { user: 'tobi' }, function(err, html){\n if (err) throw err;\n console.log(html);\n});\n```\n\n Or without options / local variables:\n\n```js\nvar cons = require('consolidate');\ncons.swig('views/page.html', function(err, html){\n if (err) throw err;\n console.log(html);\n});\n```\n\n To dynamically pass the engine, simply use the subscript operator and a variable:\n\n```js\nvar cons = require('consolidate')\n , name = 'swig';\n\ncons[name]('views/page.html', { user: 'tobi' }, function(err, html){\n if (err) throw err;\n console.log(html);\n});\n```\n\n## Caching\n\n To enable caching simply pass `{ cache: true }`. Engines _may_ use this option to cache things reading the file contents, compiled `Function`s etc. Engines which do _not_ support this may simply ignore it. All engines that consolidate.js implements I/O for will cache the file contents, ideal for production environments.\n\n```js\nvar cons = require('consolidate');\ncons.swig('views/page.html', { user: 'tobi' }, function(err, html){\n if (err) throw err;\n console.log(html);\n});\n```\n\n## Express 3.x example\n\n```js\nvar express = require('express')\n , cons = require('consolidate')\n , app = express();\n\n// assign the swig engine to .html files\napp.engine('html', cons.swig);\n\n// set .html as the default extension \napp.set('view engine', 'html');\napp.set('views', __dirname + '/views');\n\nvar users = [];\nusers.push({ name: 'tobi' });\nusers.push({ name: 'loki' });\nusers.push({ name: 'jane' });\n\napp.get('/', function(req, res){\n res.render('index', {\n title: 'Consolidate.js'\n });\n});\n\napp.get('/users', function(req, res){\n res.render('users', {\n title: 'Users',\n users: users\n });\n});\n\napp.listen(3000);\nconsole.log('Express server listening on port 3000');\n```\n\n## Running tests\n\n Install dev deps:\n \n $ npm install -d\n\n Run the tests:\n\n $ make test\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "_id": "consolidate@0.9.1", + "dist": { + "shasum": "61e5d83c1434664fa3a339986817a2be99102931" + }, + "_from": "consolidate@", + "_resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.9.1.tgz" +} diff --git a/node_modules/dronestream/.jshintrc b/node_modules/dronestream/.jshintrc new file mode 100644 index 0000000..2da4a4a --- /dev/null +++ b/node_modules/dronestream/.jshintrc @@ -0,0 +1,30 @@ +{ + "browser" : false, + "boss" : true, + "curly": true, + "debug": false, + "devel": true, + "eqeqeq": true, + "evil": false, + "forin": true, + "immed": true, + "indent": 4, + "jquery": true, + "laxbreak": false, + "laxcomma": true, + "newcap": true, + "noarg": false, + "noempty": true, + "nonew": true, + "nomen": false, + "onevar": true, + "plusplus": false, + "regexp": false, + "trailing": true, + "undef": true, + "sub": false, + "strict": true, + "globalstrict": true, + "white": true, + "node" : true +} diff --git a/node_modules/dronestream/.npmignore b/node_modules/dronestream/.npmignore new file mode 100644 index 0000000..9fab2ca --- /dev/null +++ b/node_modules/dronestream/.npmignore @@ -0,0 +1,4 @@ +node_modules +dist/broadway.js +.*.swp +.DS_Store diff --git a/node_modules/dronestream/Gruntfile.js b/node_modules/dronestream/Gruntfile.js new file mode 100644 index 0000000..2ca5668 --- /dev/null +++ b/node_modules/dronestream/Gruntfile.js @@ -0,0 +1,49 @@ +module.exports = function (grunt) { + 'use strict'; + // load all grunt tasks + require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); + + grunt.initConfig({ + + pkg: grunt.file.readJSON('package.json'), + + jshint: { + options: { + jshintrc: '.jshintrc' + }, + all: [ + 'Gruntfile.js', + 'lib/{,*/}*.js', + 'dist/nodecopter-stream.js' + ] + }, + + uglify: { + dist: { + files: { + 'dist/broadway.js' : [ + 'dist/vendor/broadway/glUtils.js', + 'dist/vendor/broadway/util.js', + 'dist/vendor/broadway/avc.js', + 'dist/vendor/broadway/canvas.js', + 'dist/nodecopter-stream.js' + ] + } + } + }, + concat: { + options: { + banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' + }, + dist: { + src: [ + 'dist/vendor/broadway/sylvester.js', + 'dist/vendor/broadway/avc-codec.js', + 'dist/broadway.js' + ], + dest: 'dist/nodecopter-client.js' + } + } + }); + grunt.registerTask('default', ['jshint', 'uglify', 'concat']); +}; diff --git a/node_modules/dronestream/History.md b/node_modules/dronestream/History.md new file mode 100644 index 0000000..1413a55 --- /dev/null +++ b/node_modules/dronestream/History.md @@ -0,0 +1,50 @@ +0.1.0 / 2012-10-20 +================== + + * Initial version, unreleased + +0.2.0 / 2012-10-20 +================== + + * released as npm package dronestream + +1.0.0 / 2012-12-15 +================== + + * add support for multiple browser clients + * add support for browser reloads + * reconnect to drone on failure + * add support for bare http sockers + * remove express dependency + * export as a module + * added examples for using in other applications + +1.0.1 / 2012-12-16 +================== + + * update documentation + * add changelog + +1.0.2 / 2012-12-27 +================== + + * use requestAnimationFrame() for rendering video frames + * cleaned up express example + * update ar-drone and buffy dependencies to latest versions + +1.0.3 / 2013-03-19 +================== + + * add custom drone ip to server options + * fix static files on webserver + +1.1.0 / 2013-08-07 +================== + + * add support for custom host and port to client + * support passing an existing video stream + * switch to grunt for building + * express fixes + * remove constants for strict mode + * bump ws and ar-drone dependencies + * add hook for postprocessors diff --git a/node_modules/dronestream/LICENSE b/node_modules/dronestream/LICENSE new file mode 100644 index 0000000..f97c4f9 --- /dev/null +++ b/node_modules/dronestream/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Bernhard K. Weisshuhn (bkw@codingforce.com) and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +This code includes files from the Boradway.js project: +https://github.com/mbebenita/Broadway . + +License and author information in included in the directory +public/js/vendor/broadway. + + diff --git a/node_modules/dronestream/README.md b/node_modules/dronestream/README.md new file mode 100644 index 0000000..6b8b99a --- /dev/null +++ b/node_modules/dronestream/README.md @@ -0,0 +1,75 @@ +# node-dronestream + +Get a realtime live video stream from your +[Parrot AR Drone 2.0](http://ardrone2.parrot.com/) straight to your browser. + +## Requirements + +You'll need a decent and current browser and some cpu horsepower. +This code uses web-sockets and the incredibly awesome +[Broadway.js](https://github.com/mbebenita/Broadway) to render the video frames +in your browser using a WebGL canvas. + +## How to use + +Please see the http.createServer and Express 3.0 examples in the 'examples' dir. +You attach the stream to your server like this: +```javascript +// in node: +// +// note that the 'server' object points to a server instance and NOT an express app. +require("dronestream").listen(server); +// if your drone is on a different IP +require("dronestream").listen(server, { ip: "192.168.2.155" }); +``` + +We serve the client in the same manner as Socket.IO. Add a reference to +**/dronestream/nodecopter-client.js** in your template. Then attach the stream to a DOM node: +```html + + + +``` + +## How it works + +The drone sends a proprietary video feed on 192.168.1.1 port 5555. This is +mostly a h264 baseline video, but adds custom framing. These frames are parsed +and mostly disposed of. The remaining h264 payload is split into NAL units and +sent to the browser via web sockets. + +In the browser broadway takes care of the rendering of the WebGL canvas. + +## Status + +Node-dronestream has gained some stability in the last release. It attempts +to recover lost connections to the drone, and it handles multiple clients, +disconnections, etc. See "How to use" for API. + +## Thanks + +- Triple high fives to Felix 'felixge' Geisendörfer for getting the whole + NodeCopter movement started and being extremely helpful in the process of + getting this together. + +- André 'zoddy' Kussmann for supplying the drone and allowing me to keep + hacking on it, even when he had to cancel the NodeCopter event for himself. + +- Michael Bebenita, Alon Zakai, Andreas Gal and Mathieu 'p01' Henri for the + magic of Broadway.js + +- Johann Phillip Strathausen for being a great team mate at NodeCopter 2012 + Berlin. + +- Brian Leroux for being not content with the original solution and for + cleaning up the predecessor, nodecopter-stream. + +- @karlwestin for picking up where I was to lazy to actually make this usable. + +## Demo + +Watch @felixge demoing node-dronestream live at german user group cgnjs: +http://www.youtube.com/watch?v=nwGNNMJt4mE&t=19m52 diff --git a/node_modules/dronestream/dist/nodecopter-client.js b/node_modules/dronestream/dist/nodecopter-client.js new file mode 100644 index 0000000..f9ebef1 --- /dev/null +++ b/node_modules/dronestream/dist/nodecopter-client.js @@ -0,0 +1,5 @@ +/*! dronestream 07-08-2013 */ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{})) +function a(b){throw b}var aa=void 0,ca=true,ha=null,ka=false,ma=[],na=typeof process==="object",oa=typeof window==="object",ua=typeof importScripts==="function",La=!oa&&!na&&!ua;if(na){print=(function(b){process.stdout.write(b+"\n")});printErr=(function(b){process.stderr.write(b+"\n")});var Ma=require("fs");read=(function(b){var c=Ma.readFileSync(b).toString();!c&&b[0]!="/"&&(b=__dirname.split("/").slice(0,-1).join("/")+"/src/"+b,c=Ma.readFileSync(b).toString());return c});ma=process.argv.slice(2)}else{La?(this.read||(read=(function(b){snarf(b)})),ma=this.arguments?arguments:scriptArgs):oa?(print=printErr=(function(b){console.log(b)}),read=(function(b){var c=new XMLHttpRequest;c.open("GET",b,ka);c.send(ha);return c.responseText}),this.arguments&&(ma=arguments)):ua?load=importScripts:a("Unknown runtime environment. Where are we?")}function Wa(b){eval.call(ha,b)}typeof load=="undefined"&&typeof read!="undefined"&&(load=(function(b){Wa(read(b))}));typeof printErr==="undefined"&&(printErr=(function(){}));typeof print==="undefined"&&(print=printErr);try{this.Module=Module}catch(ab){this.Module=Module={}}if(!Module.arguments){Module.arguments=ma}if(Module.print){print=Module.print}function bb(b){var c=m;m+=b;m=m+3>>2<<2;return c}function vb(b){var c=xb;xb+=b;xb=xb+3>>2<<2;if(xb>=yb){for(;yb<=xb;){yb=Math.ceil(2*yb/zb)*zb}var b=q,d=new ArrayBuffer(yb);q=new Int8Array(d);x=new Int16Array(d);y=new Int32Array(d);A=new Uint8Array(d);Gb=new Uint16Array(d);F=new Uint32Array(d);Hb=new Float32Array(d);q.set(b)}return c}var Kb=4,Mb={},Ob={N:0,v:0,Ma:{},La:(function(b,c){c||(this.v++,this.v>=this.N&&Nb("\n\nToo many corrections!"))}),print:(function(){})},I=0,Pb,J;function Nb(b){print(b+":\n"+Error().stack);a("Assertion: "+b)}function Sb(b,c){b||Nb("Assertion failed: "+c)}var ac=this;Module.ccall=(function(b,c,d,f){try{var g=eval("_"+b)}catch(e){try{g=ac.Module["_"+b]}catch(i){}}Sb(g,"Cannot call unknown function "+b+" (perhaps LLVM optimizations or closure removed it?)");var h=0,b=f?f.map((function(b){if(d[h++]=="string"){var c=m;bb(b.length+1);bc(b,c);b=c}return b})):[];return(function(b,c){return c=="string"?cc(b):b})(g.apply(ha,b),c)});function dc(b,c,d){d=d||"i8";d[d.length-1]==="*"&&(d="i32");switch(d){case"i1":q[b]=c;break;case"i8":q[b]=c;break;case"i16":x[b>>1]=c;break;case"i32":y[b>>2]=c;break;case"i64":y[b>>2]=c;break;case"float":Hb[b>>2]=c;break;case"double":ec[0]=c;y[b>>2]=gc[0];y[b+4>>2]=gc[1];break;default:Nb("invalid type for setValue: "+d)}}Module.setValue=dc;Module.getValue=(function(b,c){c=c||"i8";c[c.length-1]==="*"&&(c="i32");switch(c){case"i1":return q[b];case"i8":return q[b];case"i16":return x[b>>1];case"i32":return y[b>>2];case"i64":return y[b>>2];case"float":return Hb[b>>2];case"double":return gc[0]=y[b>>2],gc[1]=y[b+4>>2],ec[0];default:Nb("invalid type for setValue: "+c)}return ha});var M=2;Module.ALLOC_NORMAL=0;Module.ALLOC_STACK=1;Module.ALLOC_STATIC=M;function P(b,c,d){var f,g;typeof b==="number"?(f=ca,g=b):(f=ka,g=b.length);var e=typeof c==="string"?c:ha,d=[jc,bb,vb][d===aa?M:d](Math.max(g,e?1:c.length));if(f){return kc(d,0,g),d}for(var i=0;i>2);Hb.subarray(uc>>2);var ec=(new Float64Array(q.buffer)).subarray(uc>>3);mc=uc+8;xb=Math.ceil(mc/zb)*zb;function vc(b){for(;b.length>0;){var c=b.shift(),d=c.C;typeof d==="number"&&(d=lc[d]);d(c.ra===aa?ha:c.ra)}}var wc=[],xc=[];function zc(b,c){return Array.prototype.slice.call(q.subarray(b,b+c))}Module.Array_copy=zc;Module.TypedArray_copy=(function(b,c){for(var d=new Uint8Array(c),f=0;f255&&(g&=255);d.push(g);f+=1}c||d.push(0);return d}Module.intArrayFromString=rc;Module.intArrayToString=(function(b){for(var c=[],d=0;d255&&(f&=255);c.push(String.fromCharCode(f))}return c.join("")});function bc(b,c,d){for(var f=0;f255&&(g&=255);q[c+f]=g;f+=1}d||(q[c+f]=0)}Module.writeStringToMemory=bc;var Q=[];function Bc(b){return(b|0)<0?-b|0:b}function Cc(b,c,d){return(d|0)<(b|0)?b:(d|0)>(c|0)?c:d}function Dc(b,c,d,f){var g,e=A[Q.n+c|0]&255,i=A[Q.o+c|0]&255,c=y[Ec+i*12>>2]<>2]<>2]<>2]=y[b>>2]*c|0);d=(f&65436|0)==0;a:do{if(d){if((f&98|0)==0){if(g=y[b>>2]+32>>6,(g+512|0)>>>0>1023){var k=1;g=18}else{y[b+60>>2]=g,y[b+56>>2]=g,y[b+52>>2]=g,y[b+48>>2]=g,y[b+44>>2]=g,y[b+40>>2]=g,y[b+36>>2]=g,y[b+32>>2]=g,y[b+28>>2]=g,y[b+24>>2]=g,y[b+20>>2]=g,y[b+16>>2]=g,y[b+12>>2]=g,y[b+8>>2]=g,y[b+4>>2]=g,y[b>>2]=g,g=17}}else{var l=b+4|0,j=y[l>>2]*h|0;g=b+20|0;var n=y[g>>2]*c|0,p=b+8|0,i=b+24|0,r=y[i>>2]*h|0,o=b+12|0,t=y[b>>2],s=t-n|0,u=(j>>1)-r|0,j=j+(r>>1)|0,t=t+(n+32)|0,n=t+j>>6;y[b>>2]=n;r=s+32|0;s=r+u>>6;y[l>>2]=s;l=r-u>>6;y[p>>2]=l;p=t-j>>6;y[o>>2]=p;y[b+48>>2]=n;y[b+32>>2]=n;y[b+16>>2]=n;y[b+52>>2]=s;y[b+36>>2]=s;y[g>>2]=s;y[b+56>>2]=l;y[b+40>>2]=l;y[i>>2]=l;y[b+60>>2]=p;y[b+44>>2]=p;y[b+28>>2]=p;(n+512|0)>>>0>1023?(k=1,g=18):(s+512|0)>>>0>1023?(k=1,g=18):(l+512|0)>>>0>1023?(k=1,g=18):(p+512|0)>>>0>1023?(k=1,g=18):g=17}}else{var w=b+4|0,i=b+56|0,s=y[i>>2],o=b+60|0,v=y[w>>2]*h|0,u=y[o>>2]*e|0,z=b+8|0,B=y[z>>2],D=b+20|0,C=b+16|0,E=y[D>>2]*c|0,G=y[C>>2]*e|0,t=b+32|0,H=b+12|0,K=y[H>>2],L=b+24|0,N=y[t>>2]*h|0,O=y[L>>2]*h|0,R=b+28|0,U=y[R>>2],p=b+48|0,r=b+36|0,n=y[r>>2],Y=y[p>>2]*e|0,X=b+40|0,ba=b+44|0,$=y[ba>>2],l=b+52|0,j=y[X>>2]*e|0,ja=y[l>>2]*h|0,sa=y[b>>2],Ea=E+sa|0,E=sa-E|0,sa=(v>>1)-O|0,v=(O>>1)+v|0;y[b>>2]=v+Ea|0;y[w>>2]=sa+E|0;y[z>>2]=E-sa|0;y[H>>2]=Ea-v|0;w=h*(U+B)|0;B=(B-U)*h|0;U=(G>>1)-Y|0;G=(Y>>1)+G|0;y[C>>2]=G+w|0;y[D>>2]=U+B|0;y[L>>2]=B-U|0;y[R>>2]=w-G|0;D=c*($+K)|0;K=(K-$)*c|0;$=(N>>1)-ja|0;N=(ja>>1)+N|0;y[t>>2]=N+D|0;y[r>>2]=$+K|0;y[X>>2]=K-$|0;y[ba>>2]=D-N|0;t=h*(s+n)|0;s=(n-s)*h|0;n=(j>>1)-u|0;u=(u>>1)+j|0;y[p>>2]=u+t|0;y[l>>2]=n+s|0;y[i>>2]=s-n|0;y[o>>2]=t-u|0;for(i=0;;){s=b+(i<<2)|0;o=b+(i+12<<2)|0;l=b+(i+4<<2)|0;p=b+(i+8<<2)|0;if((i|0)==4){g=17;break a}t=y[s>>2];r=y[p>>2];n=t-r|0;j=y[l>>2];X=y[o>>2];u=(j>>1)-X|0;j=(X>>1)+j|0;r=t+(r+32)|0;t=r+j>>6;y[s>>2]=t;n=n+32|0;s=n+u>>6;y[l>>2]=s;l=n-u>>6;y[p>>2]=l;p=r-j>>6;y[o>>2]=p;if((t+512|0)>>>0>1023){k=1;g=18;break a}if((s+512|0)>>>0>1023){k=1;g=18;break a}if((l+512|0)>>>0>1023){k=1;g=18;break a}if((p+512|0)>>>0>1023){k=1;g=18;break a}i=i+1|0}}}while(0);g==17&&(k=0);return k}Dc.X=1;function Gc(b,c){var d=A[Q.o+c|0],f=A[Q.n+c|0],g=b+8|0,e=y[g>>2],i=b+20|0,h=y[i>>2],k=b+16|0,l=y[k>>2],j=b+32|0,n=y[j>>2],p=b+12|0,r=y[p>>2],o=b+24|0,t=y[o>>2],s=b+28|0,u=y[s>>2],w=b+48|0,v=y[w>>2],z=b+36|0,B=y[z>>2],D=b+40|0,C=y[D>>2],E=b+44|0,G=y[E>>2],H=b+52|0,K=y[H>>2],L=b+4|0,N=y[b>>2],O=h+N|0,R=N-h|0,U=y[L>>2],Y=U-t|0,X=t+U|0,ba=X+O|0;y[b>>2]=ba;var $=Y+R|0;y[L>>2]=$;var ja=R-Y|0;y[g>>2]=ja;var sa=O-X|0;y[p>>2]=sa;var Ea=u+e|0,Xa=e-u|0,ea=l-v|0,fa=v+l|0,va=fa+Ea|0;y[k>>2]=va;var ob=ea+Xa|0;y[i>>2]=ob;var wa=Xa-ea|0;y[o>>2]=wa;var pb=Ea-fa|0;y[s>>2]=pb;var gb=G+r|0,Ib=r-G|0,Fa=n-K|0,qb=K+n|0,Ya=qb+gb|0;y[j>>2]=Ya;var Na=Fa+Ib|0;y[z>>2]=Na;var za=Ib-Fa|0;y[D>>2]=za;var da=gb-qb|0;y[E>>2]=da;var Oa=b+56|0,Za=b+60|0,Aa=y[Oa>>2],hb=Aa+B|0,Ga=B-Aa|0,Pa=y[Za>>2],$a=C-Pa|0,Ab=Pa+C|0,cb=Ab+hb|0;y[w>>2]=cb;var rb=$a+Ga|0;y[H>>2]=rb;var Qa=Ga-$a|0;y[Oa>>2]=Qa;var pa=hb-Ab|0;y[Za>>2]=pa;var ia=f&255,qa=F[Ec+(d&255)*12>>2],Ra=c>>>0>11;a:do{if(Ra){var ra=qa<>2]=(db+ib)*ra|0;y[k>>2]=(jb+sb)*ra|0;y[j>>2]=(sb-jb)*ra|0;y[w>>2]=(ib-db)*ra|0;var Sa=Na+$|0,kb=$-Na|0,ta=ob-rb|0,Bb=rb+ob|0;y[L>>2]=(Bb+Sa)*ra|0;y[i>>2]=(ta+kb)*ra|0;y[z>>2]=(kb-ta)*ra|0;y[H>>2]=(Sa-Bb)*ra|0;var Ha=za+ja|0,ya=ja-za|0,xa=wa-Qa|0,Ba=Qa+wa|0;y[g>>2]=(Ba+Ha)*ra|0;y[o>>2]=(xa+ya)*ra|0;y[D>>2]=(ya-xa)*ra|0;y[Oa>>2]=(Ha-Ba)*ra|0;var Ca=da+sa|0,Ta=sa-da|0,lb=pb-pa|0,Jb=pa+pb|0;y[p>>2]=(Jb+Ca)*ra|0;y[s>>2]=(lb+Ta)*ra|0;y[E>>2]=(Ta-lb)*ra|0;y[Za>>2]=(Ca-Jb)*ra|0}else{for(var eb=(c-6|0)>>>0<6?1:2,Da=2-ia|0,Ia=0,mb=ba;;){var Ua=b+(Ia+8<<2)|0,Ja=b+(Ia+4<<2)|0,Ka=b+(Ia+12<<2)|0,Cb=y[Ua>>2],Db=Cb+mb|0,Eb=mb-Cb|0,tb=y[Ja>>2],Va=y[Ka>>2],fb=tb-Va|0,ub=Va+tb|0;y[b+(Ia<<2)>>2]=(ub+Db)*qa+eb>>Da;y[Ja>>2]=(fb+Eb)*qa+eb>>Da;y[Ua>>2]=(Eb-fb)*qa+eb>>Da;y[Ka>>2]=(Db-ub)*qa+eb>>Da;var nb=Ia+1|0;if((nb|0)==4){break a}var Fb=y[b+(nb<<2)>>2],Ia=nb,mb=Fb}}}while(0)}Gc.X=1;function Hc(b,c){var d=y[Ec+(A[Q.o+c|0]&255)*12>>2];if(c>>>0>5){var f=0;d<<=(A[Q.n+c|0]&255)-1}else{f=1}var g=y[b>>2],e=b+8|0,i=y[e>>2],h=i+g|0,g=g-i|0,i=b+4|0,k=y[i>>2],l=b+12|0,j=y[l>>2],n=k-j|0,k=j+k|0;y[b>>2]=(k+h)*d>>f;y[i>>2]=(h-k)*d>>f;y[e>>2]=(n+g)*d>>f;y[l>>2]=(g-n)*d>>f;var e=b+16|0,i=y[e>>2],h=b+24|0,l=y[h>>2],g=l+i|0,i=i-l|0,l=b+20|0,j=y[l>>2],n=b+28|0,p=y[n>>2],k=j-p|0,j=p+j|0;y[e>>2]=(j+g)*d>>f;y[l>>2]=(g-j)*d>>f;y[h>>2]=(k+i)*d>>f;y[n>>2]=(i-k)*d>>f}Hc.X=1;function Ic(b,c,d){var f=F[b+(d<<2)>>2],g=d+1|0,e=g>>>0>>0&(y[b+(g<<2)>>2]|0)!=(f|0);a:do{if(e){for(var i=d+2|0,h=0;;){var k=i+h|0;if(!(k>>>0>>0&(y[b+(k<<2)>>2]|0)!=(f|0))){var l=k;break a}h=h+1|0}}else{l=g}}while(0);return(l|0)==(c|0)?0:l}function Lc(b,c){var d=F[b+4>>2],f=(c>>>0)%(d>>>0),g=c-f|0,d=y[b+8>>2]*d|0,e=y[b>>2];y[b+12>>2]=e+((g<<8)+(f<<4))|0;f=(d<<8)+(f<<3)+(g<<6)|0;y[b+16>>2]=e+f|0;y[b+20>>2]=e+(f+(d<<6))|0}function Mc(b,c,d,f){var g,e=c>>>0>3;a:do{if(e){if(q[b]<<24>>24!=0){g=17}else{if(q[b+1|0]<<24>>24!=0){g=17}else{if((A[b+2|0]&254|0)!=0){g=17}else{for(var i=2,h=0;;){var k=h+3|0;if((k|0)==(c|0)){y[f>>2]=c;var l=1;g=30;break a}var j=q[h+(b+2)|0];if(j==0){i=i+1|0}else{if(j==1&&i>>>0>1){break}i=0}h=h+1|0}for(var h=h+4|0,n=i=0,p=0,j=0;;){var r=h+j|0,o=A[b+(k+j)|0],t=o<<24>>24!=0,p=(t&1^1)+p|0,n=o<<24>>24==3&(p|0)==2?1:n;if(o<<24>>24==1&p>>>0>1){g=j-p|0;y[d+12>>2]=g;var s=i,u=n,w=k,v=p-(p>>>0<3?p:3)|0,z=g;g=18;break a}t&&(i=p>>>0>2?1:i,p=0);if((r|0)!=(c|0)){j=j+1|0}else{g=r-k-p|0;y[d+12>>2]=g;s=i;u=n;w=k;v=p;z=g;g=18;break a}}}}}}else{g=17}}while(0);g==17&&(y[d+12>>2]=c,s=0,u=1,v=w=0,z=c,g=18);a:do{if(g==18){if(c=b+w|0,k=d|0,y[k>>2]=c,y[d+4>>2]=c,y[d+8>>2]=0,y[d+16>>2]=0,c=d+12|0,y[f>>2]=w+v+z|0,(s|0)!=0){l=1}else{if((u|0)!=0){l=k=y[k>>2];e=y[c>>2];h=j=0;b:for(;;){for(var B=k+h|0,i=e-1|0,r=j,j=0;;){var D=l+j|0,n=j+1|0,C=l+n|0;if((e|0)==(j|0)){break b}var E=A[D];if((r|0)!=2){break}if(E<<24>>24==3){if((i|0)==(j|0)){l=1;break a}if((A[C]&255)>3){l=1;break a}r=0;j=n}else{if((E&255)<3){l=1;break a}break}}r=E<<24>>24==0?r+1|0:0;q[B]=E;l=C;e=i-j|0;j=r;h=h+1|0}y[c>>2]=B-D+y[c>>2]|0}l=0}}}while(0);return l}Mc.X=1;function Nc(b,c){var d=(y[b>>2]|0)==(y[c>>2]|0);a:do{if(d){if((y[b+4>>2]|0)!=(y[c+4>>2]|0)){var f=1}else{if((y[b+12>>2]|0)!=(y[c+12>>2]|0)){f=1}else{if(f=y[b+16>>2],(f|0)!=(y[c+16>>2]|0)){f=1}else{if((y[b+44>>2]|0)!=(y[c+44>>2]|0)){f=1}else{if((y[b+48>>2]|0)!=(y[c+48>>2]|0)){f=1}else{if((y[b+52>>2]|0)!=(y[c+52>>2]|0)){f=1}else{if((y[b+56>>2]|0)!=(y[c+56>>2]|0)){f=1}else{var g=F[b+60>>2];if((g|0)!=(y[c+60>>2]|0)){f=1}else{if((y[b+80>>2]|0)!=(y[c+80>>2]|0)){f=1}else{b:do{if(f==0){if((y[b+20>>2]|0)!=(y[c+20>>2]|0)){f=1;break a}}else{if(f==1){if((y[b+24>>2]|0)!=(y[c+24>>2]|0)){f=1;break a}if((y[b+28>>2]|0)!=(y[c+28>>2]|0)){f=1;break a}if((y[b+32>>2]|0)!=(y[c+32>>2]|0)){f=1;break a}var e=F[b+36>>2];if((e|0)!=(y[c+36>>2]|0)){f=1;break a}for(var i=b+40|0,h=c+40|0,k=0;;){if(k>>>0>=e>>>0){break b}if((y[y[i>>2]+(k<<2)>>2]|0)!=(y[y[h>>2]+(k<<2)>>2]|0)){f=1;break a}k=k+1|0}}}}while(0);if((g|0)!=0){if((y[b+64>>2]|0)!=(y[c+64>>2]|0)){f=1;break}if((y[b+68>>2]|0)!=(y[c+68>>2]|0)){f=1;break}if((y[b+72>>2]|0)!=(y[c+72>>2]|0)){f=1;break}if((y[b+76>>2]|0)!=(y[c+76>>2]|0)){f=1;break}}f=0}}}}}}}}}}else{f=1}}while(0);return f}Nc.X=1;function Oc(b,c){var d=m;m+=4;Pc(c,0,92);var f=S(b,8),g=(f|0)==-1;a:do{if(g){var e=1}else{if(y[c>>2]=f,S(b,1),S(b,1),(S(b,1)|0)==-1){e=1}else{if((S(b,5)|0)==-1){e=1}else{var i=S(b,8);if((i|0)==-1){e=1}else{e=c+4|0;y[e>>2]=i;var i=c+8|0,h=T(b,i);if((h|0)!=0){e=h}else{if(F[i>>2]>>>0>31){e=1}else{if(i=T(b,d),(i|0)!=0){e=i}else{if(i=F[d>>2],i>>>0>12){e=1}else{if(y[c+12>>2]=1<>2],i>>>0>2){e=1}else{y[c+16>>2]=i;b:do{if(i==0){h=T(b,d);if((h|0)!=0){e=h;break a}h=F[d>>2];if(h>>>0>12){e=1;break a}y[c+20>>2]=1<>2]=(h|0)==1&1;h=Qc(b,c+28|0);if((h|0)!=0){e=h;break a}h=Qc(b,c+32|0);if((h|0)!=0){e=h;break a}var h=c+36|0,k=T(b,h);if((k|0)!=0){e=k;break a}k=F[h>>2];if(k>>>0>255){e=1;break a}if((k|0)==0){y[c+40>>2]=0}else{var l=jc(k<<2),k=c+40|0;y[k>>2]=l;if((l|0)==0){e=65535;break a}for(l=0;;){if(l>>>0>=F[h>>2]>>>0){break b}var j=Qc(b,y[k>>2]+(l<<2)|0);if((j|0)!=0){e=j;break a}l=l+1|0}}}}}while(0);i=c+44|0;h=T(b,i);if((h|0)!=0){e=h}else{if(F[i>>2]>>>0>16){e=1}else{if(h=S(b,1),(h|0)==-1){e=1}else{if(y[c+48>>2]=(h|0)==1&1,h=T(b,d),(h|0)!=0){e=h}else{if(k=c+52|0,y[k>>2]=y[d>>2]+1|0,h=T(b,d),(h|0)!=0){e=h}else{if(h=c+56|0,y[h>>2]=y[d>>2]+1|0,l=S(b,1),l==-1||l==0){e=1}else{if((S(b,1)|0)==-1){e=1}else{if(l=S(b,1),(l|0)==-1){e=1}else{l=(l|0)==1;y[c+60>>2]=l&1;if(l){l=c+64|0;j=T(b,l);if((j|0)!=0){e=j;break}var j=c+68|0,n=T(b,j);if((n|0)!=0){e=n;break}var n=c+72|0,p=T(b,n);if((p|0)!=0){e=p;break}var p=c+76|0,r=T(b,p);if((r|0)!=0){e=r;break}k=y[k>>2];if((y[l>>2]|0)>((k<<3)-1-y[j>>2]|0)){e=1;break}h=y[h>>2];if((y[n>>2]|0)>((h<<3)-1-y[p>>2]|0)){e=1;break}}else{k=y[k>>2],h=y[h>>2]}h=h*k|0;e=y[e>>2];k=aa;if(e==10){var o=99,t=152064,k=15}else{if(e==11){o=396,t=345600,k=15}else{if(e==12){o=396,t=912384,k=15}else{if(e==13){o=396,t=912384,k=15}else{if(e==20){o=396,t=912384,k=15}else{if(e==21){o=792,t=1824768,k=15}else{if(e==22){o=1620,t=3110400,k=15}else{if(e==30){o=1620,t=3110400,k=15}else{if(e==31){o=3600,t=6912e3,k=15}else{if(e==32){o=5120,t=7864320,k=15}else{if(e==40){o=8192,t=12582912,k=15}else{if(e==41){o=8192,t=12582912,k=15}else{if(e==42){o=8704,t=13369344,k=15}else{if(e==50){o=22080,t=42393600,k=15}else{if(e==51){o=36864,t=70778880,k=15}else{var s=2147483647,k=17}}}}}}}}}}}}}}}k==15&&(o>>>0>>0?s=2147483647:(s=Math.floor((t>>>0)/((h*384|0)>>>0)),s=s>>>0<16?s:16));e=s;y[d>>2]=e;h=F[i>>2];(e|0)==2147483647|h>>>0>e>>>0?y[d>>2]=h:h=e;e=c+88|0;y[e>>2]=h;h=S(b,1);if((h|0)==-1){e=1}else{h=(h|0)==1;y[c+80>>2]=h&1;do{if(h){j=l=jc(952);k=c+84|0;y[k>>2]=j;if((l|0)==0){e=65535;break a}l=Rc(b,j);if((l|0)!=0){e=l;break a}k=y[k>>2];if((y[k+920>>2]|0)!=0){l=F[k+948>>2];if(F[k+944>>2]>>>0>l>>>0){e=1;break a}if(l>>>0>2]>>>0){e=1;break a}if(l>>>0>F[e>>2]>>>0){e=1;break a}y[e>>2]=(l|0)==0?1:l}}}while(0);S(b,8-y[b+8>>2]|0);e=0}}}}}}}}}}}}}}}}}}}}while(0);m=d;return e}Oc.X=1;function Sc(b,c){var d=m;m+=8;var f=d+4;Pc(c,0,72);var g=c|0,e=T(b,g),i=(e|0)==0;a:do{if(i){if(F[g>>2]>>>0>255){var h=1}else{var h=c+4|0,k=T(b,h);if((k|0)!=0){h=k}else{if(F[h>>2]>>>0>31){h=1}else{if((S(b,1)|0)!=0){h=1}else{if(h=S(b,1),(h|0)==-1){h=1}else{if(y[c+8>>2]=(h|0)==1&1,h=T(b,d),(h|0)==0){if(k=y[d>>2]+1|0,h=c+12|0,y[h>>2]=k,k>>>0>8){h=1}else{k=k>>>0>1;b:do{if(k){var l=c+16|0,j=T(b,l);if((j|0)!=0){h=j;break a}l=F[l>>2];if(l>>>0>6){h=1;break a}if(l==0){j=jc(y[h>>2]<<2);l=c+20|0;y[l>>2]=j;if((j|0)==0){h=65535;break a}for(j=0;;){if(j>>>0>=F[h>>2]>>>0){break b}var n=T(b,d);if((n|0)!=0){h=n;break a}y[(y[l>>2]+(j<<2)|0)>>2]=y[d>>2]+1|0;j=j+1|0}}else{if(l==2){j=jc((y[h>>2]<<2)-4|0);l=c+24|0;y[l>>2]=j;n=jc((y[h>>2]<<2)-4|0);j=c+28|0;y[j>>2]=n;if((y[l>>2]|0)==0|(n|0)==0){h=65535;break a}for(n=0;;){if(n>>>0>=(y[h>>2]-1|0)>>>0){break b}var p=T(b,d);if((p|0)!=0){h=p;break a}y[(y[l>>2]+(n<<2)|0)>>2]=y[d>>2];p=T(b,d);if((p|0)!=0){h=p;break a}y[(y[j>>2]+(n<<2)|0)>>2]=y[d>>2];n=n+1|0}}else{if(l==3||l==4||l==5){l=S(b,1);if((l|0)==-1){h=1;break a}y[c+32>>2]=(l|0)==1&1;l=T(b,d);if((l|0)!=0){h=l;break a}y[c+36>>2]=y[d>>2]+1|0}else{if(l==6){l=T(b,d);if((l|0)!=0){h=l;break a}j=y[d>>2]+1|0;l=c+40|0;y[l>>2]=j;n=jc(j<<2);j=c+44|0;y[j>>2]=n;if((n|0)==0){h=65535;break a}n=y[Tc+(y[h>>2]-1<<2)>>2];for(p=0;;){if(p>>>0>=F[l>>2]>>>0){break b}var r=S(b,n);y[(y[j>>2]+(p<<2)|0)>>2]=r;if(F[y[j>>2]+(p<<2)>>2]>>>0>=F[h>>2]>>>0){h=1;break a}p=p+1|0}}}}}}}while(0);h=T(b,d);(h|0)==0&&(h=F[d>>2],h>>>0>31?h=1:(y[c+48>>2]=h+1|0,h=T(b,d),(h|0)==0&&(F[d>>2]>>>0>31?h=1:(S(b,1)|0)!=0?h=1:S(b,2)>>>0>2?h=1:(h=Qc(b,f),(h|0)==0&&(h=y[f>>2]+26|0,h>>>0>51?h=1:(y[c+52>>2]=h,h=Qc(b,f),(h|0)==0&&((y[f>>2]+26|0)>>>0>51?h=1:(h=Qc(b,f),(h|0)==0&&(h=F[f>>2],(h+12|0)>>>0>24?h=1:(y[c+56>>2]=h,h=S(b,1),(h|0)==-1?h=1:(y[c+60>>2]=(h|0)==1&1,h=S(b,1),(h|0)==-1?h=1:(y[c+64>>2]=(h|0)==1&1,h=S(b,1),(h|0)==-1?h=1:(y[c+68>>2]=(h|0)==1&1,S(b,8-y[b+8>>2]|0),h=0)))))))))))))}}}}}}}}else{h=e}}while(0);m=d;return h}Sc.X=1;function Uc(b,c,d,f,g){var e=m;m+=8;var i=e+4;Pc(c,0,988);var h=y[d+56>>2]*y[d+52>>2]|0,k=T(b,e),l=(k|0)==0;a:do{if(l){var j=F[e>>2];y[c>>2]=j;if(j>>>0>>0){if(j=T(b,e),(j|0)==0){var j=y[e>>2],n=c+4|0;y[n>>2]=j;if(!(j==2||j==7)){if(j==0||j==5){if((y[g>>2]|0)==5){j=1;break}if((y[d+44>>2]|0)==0){j=1;break}}else{j=1;break}}j=T(b,e);if((j|0)==0){if(j=y[e>>2],y[c+8>>2]=j,(j|0)!=(y[f>>2]|0)){j=1}else{var p=d+12|0,j=F[p>>2],r=(j|0)==0;b:do{if(r){var o=-1}else{for(var t=0;;){var s=t+1|0;if((j>>>(s>>>0)|0)==0){o=t;break b}t=s}}}while(0);r=S(b,o);if((r|0)==-1){j=1}else{if(j=g|0,(y[j>>2]|0)!=5|(r|0)==0){y[c+12>>2]=r;if((y[j>>2]|0)==5){r=T(b,e);if((r|0)!=0){j=r;break}r=F[e>>2];y[c+16>>2]=r;if(r>>>0>65535){j=1;break}}r=d+16|0;t=F[r>>2];if((t|0)==0){var t=d+20|0,s=F[t>>2],u=(s|0)==0;b:do{if(u){var w=-1}else{for(var v=0;;){var z=v+1|0;if((s>>>(z>>>0)|0)==0){w=v;break b}v=z}}}while(0);u=S(b,w);if((u|0)==-1){j=1;break}s=c+20|0;y[s>>2]=u;if((y[f+8>>2]|0)!=0){u=Qc(b,i);if((u|0)!=0){j=u;break}y[c+24>>2]=y[i>>2]}if((y[j>>2]|0)==5){s=F[s>>2];if(s>>>0>F[t>>2]>>>1>>>0){j=1;break}t=y[c+24>>2];if((s|0)!=(((t|0)>0?0:-t|0)|0)){j=1;break}}r=y[r>>2]}else{r=t}r=(r|0)==1;do{if(r&&(y[d+24>>2]|0)==0){t=Qc(b,i);if((t|0)!=0){j=t;break a}t=c+28|0;y[t>>2]=y[i>>2];if((y[f+8>>2]|0)!=0){s=Qc(b,i);if((s|0)!=0){j=s;break a}y[c+32>>2]=y[i>>2]}if((y[j>>2]|0)==5&&(t=y[t>>2],s=y[d+32>>2]+t+y[c+32>>2]|0,(((t|0)<(s|0)?t:s)|0)!=0)){j=1;break a}}}while(0);if((y[f+68>>2]|0)!=0){r=T(b,e);if((r|0)!=0){j=r;break}r=F[e>>2];y[c+36>>2]=r;if(r>>>0>127){j=1;break}}r=F[n>>2];if(r==0||r==5){r=S(b,1);if((r|0)==-1){j=1;break}y[c+40>>2]=r;if((r|0)==0){r=F[f+48>>2];if(r>>>0>16){j=1;break}y[c+44>>2]=r}else{r=T(b,e);if((r|0)!=0){j=r;break}r=F[e>>2];if(r>>>0>15){j=1;break}y[c+44>>2]=r+1|0}n=y[n>>2]}else{n=r}if(n==0||n==5){n=b;r=c+68|0;t=y[c+44>>2];p=y[p>>2];s=m;m+=8;u=s+4;v=S(n,1);z=(v|0)==-1;b:do{if(z){var B=1}else{y[r>>2]=v;if((v|0)!=0){for(B=0;;){var D=r+4+B*12+4|0,C=r+4+B*12+8|0,E=r+4+B*12|0;if(B>>>0>t>>>0){B=1;break b}var G=T(n,u);if((G|0)!=0){B=G;break b}G=F[u>>2];if(G>>>0>3){B=1;break b}y[E>>2]=G;E=G>>>0<2;do{if(E){var H=T(n,s);if((H|0)!=0){B=H;break b}H=F[s>>2];if(H>>>0>=p>>>0){B=1;break b}y[D>>2]=H+1|0}else{if((G|0)==2){H=T(n,s);if((H|0)!=0){B=H;break b}y[C>>2]=y[s>>2]}}}while(0);if((G|0)==3){break}B=B+1|0}if((B|0)==0){B=1;break}}B=0}}while(0);m=s;p=B;if((p|0)!=0){j=p;break}}if((y[g+4>>2]|0)!=0&&(j=Vc(b,c+276|0,y[j>>2],y[d+44>>2]),(j|0)!=0)){break}j=Qc(b,i);if((j|0)==0){if(j=y[i>>2],y[c+48>>2]=j,j=j+y[f+52>>2]|0,y[i>>2]=j,j>>>0>51){j=1}else{j=(y[f+60>>2]|0)==0;do{if(!j){p=T(b,e);if((p|0)!=0){j=p;break a}p=F[e>>2];y[c+52>>2]=p;if(p>>>0>2){j=1;break a}if((p|0)!=1){p=Qc(b,i);if((p|0)!=0){j=p;break a}p=F[i>>2];if((p+6|0)>>>0>12){j=1;break a}y[c+56>>2]=p<<1;p=Qc(b,i);if((p|0)!=0){j=p;break a}p=F[i>>2];if((p+6|0)>>>0>12){j=1;break a}y[c+60>>2]=p<<1}}}while(0);j=F[f+12>>2]>>>0>1;do{if(j&&(y[f+16>>2]-3|0)>>>0<3){p=f+36|0;n=y[p>>2];n=(((h>>>0)%(n>>>0)|0)==0?1:2)+Math.floor((h>>>0)/(n>>>0))|0;for(r=0;;){var K=r+1|0;if((-1<>2]=n;if((n|0)==-1){j=1;break a}y[c+64>>2]=n;p=F[p>>2];if(n>>>0>Math.floor(((h-1+p|0)>>>0)/(p>>>0))>>>0){j=1;break a}}}while(0);j=0}}}else{j=1}}}}}}else{j=1}}else{j=k}}while(0);m=e;return j}Uc.X=1;function Vc(b,c,d,f){var g=m;m+=8;var e,i=g+4,d=(d|0)==5,h=S(b,1),k=(h|0)==-1;a:do{if(d){if(k){var l=1;e=24;break}y[c>>2]=h;var j=S(b,1);if((j|0)==-1){l=1;e=24;break}y[c+4>>2]=j;if((f|0)!=0|(j|0)==0){e=23;break}}else{if(k){l=1;e=24;break}y[c+8>>2]=h;if((h|0)==0){e=23;break}for(var j=(f<<1)+2|0,n=0,p=0,r=0,o=0,t=0;;){var s=c+12+t*20+4|0,u=c+12+t*20+8|0,w=c+12+t*20+12|0,v=c+12+t*20+16|0;e=c+12+t*20|0;if(t>>>0>j>>>0){l=1;e=24;break a}var z=T(b,i);if((z|0)!=0){l=z;e=24;break a}z=F[i>>2];if(z>>>0>6){l=1;e=24;break a}y[e>>2]=z;do{if(z==3||z==1){e=T(b,g);if((e|0)!=0){l=e;e=24;break a}y[s>>2]=y[g>>2]+1|0;if(z==2){e=13}else{if(z==6||z==3){e=15}else{if(z==4){e=17}else{var B=o;e=20}}}}else{z==2?e=13:z==6?e=15:z==4?e=17:(B=o,e=20)}}while(0);do{if(e==13){B=T(b,g);if((B|0)!=0){l=B;e=24;break a}y[u>>2]=y[g>>2];B=o;e=20}else{if(e==15){e=T(b,g);if((e|0)!=0){l=e;e=24;break a}y[w>>2]=y[g>>2];(z|0)==4?e=17:(B=o,e=20)}}}while(0);if(e==17){B=T(b,g);if((B|0)!=0){l=B;e=24;break a}B=F[g>>2];if(B>>>0>f>>>0){l=1;e=24;break a}y[v>>2]=(B|0)==0?65535:B-1|0;B=o+1|0}v=((z|0)==5&1)+r|0;u=((z|0)!=0&z>>>0<4&1)+n|0;w=((z|0)==6&1)+p|0;if((z|0)==0){break}n=u;p=w;r=v;o=B;t=t+1|0}if(B>>>0>1|v>>>0>1|w>>>0>1){l=1;e=24;break}if((u|0)==0|(v|0)==0){e=23;break}}l=1;e=24}while(0);e==23&&(l=0);m=g;return l}Vc.X=1;function Wc(b,c){var d=m;m+=24;var f=d+4,g=f|0;y[f>>2]=y[b>>2];y[f+4>>2]=y[b+4>>2];y[f+8>>2]=y[b+8>>2];y[f+12>>2]=y[b+12>>2];y[f+16>>2]=y[b+16>>2];f=T(g,d);(f|0)==0?(f=T(g,d),(f|0)!=0?g=f:(g=T(g,d),(g|0)==0&&(g=F[d>>2],g>>>0>255?g=1:(y[c>>2]=g,g=0)))):g=f;m=d;return g}function Xc(b,c,d,f){var g=m;m+=24;var e=g+4,i=e|0;y[e>>2]=y[b>>2];y[e+4>>2]=y[b+4>>2];y[e+8>>2]=y[b+8>>2];y[e+12>>2]=y[b+12>>2];y[e+16>>2]=y[b+16>>2];b=T(i,g);e=(b|0)==0;do{if(e){var h=T(i,g);if((h|0)==0&&(h=T(i,g),(h|0)==0)){var h=F[c+12>>2],k=(h|0)==0;a:do{if(k){var l=-1}else{for(var j=0;;){var n=j+1|0;if((h>>>(n>>>0)|0)==0){l=j;break a}j=n}}}while(0);if((S(i,l)|0)==-1){h=1}else{if((d|0)==5&&(h=T(i,g),(h|0)!=0)){break}h=F[c+20>>2];k=(h|0)==0;a:do{if(k){var p=-1}else{for(j=0;;){n=j+1|0;if((h>>>(n>>>0)|0)==0){p=j;break a}j=n}}}while(0);h=S(i,p);(h|0)==-1?h=1:(y[f>>2]=h,h=0)}}}else{h=b}}while(0);m=g;return h}Xc.X=1;function bd(b,c,d,f){var g=m;m+=24;var e=g+4,i=e|0;y[e>>2]=y[b>>2];y[e+4>>2]=y[b+4>>2];y[e+8>>2]=y[b+8>>2];y[e+12>>2]=y[b+12>>2];y[e+16>>2]=y[b+16>>2];b=T(i,g);e=(b|0)==0;do{if(e){var h=T(i,g);if((h|0)==0&&(h=T(i,g),(h|0)==0)){var h=F[c+12>>2],k=(h|0)==0;a:do{if(k){var l=-1}else{for(var j=0;;){var n=j+1|0;if((h>>>(n>>>0)|0)==0){l=j;break a}j=n}}}while(0);if((S(i,l)|0)==-1){h=1}else{if((d|0)==5&&(h=T(i,g),(h|0)!=0)){break}h=F[c+20>>2];k=(h|0)==0;a:do{if(k){var p=-1}else{for(j=0;;){n=j+1|0;if((h>>>(n>>>0)|0)==0){p=j;break a}j=n}}}while(0);h=(S(i,p)|0)==-1?1:Qc(i,f)}}}else{h=b}}while(0);m=g;return h}bd.X=1;function cd(b){return b==1||b==0?1:b==2||b==3?2:4}function dd(b){return b>>>0<6?2:(b|0)!=6&1}function ed(b,c,d,f){var g=m;m+=28;var e=g+4,i=g+8,h=i|0;y[i>>2]=y[c>>2];y[i+4>>2]=y[c+4>>2];y[i+8>>2]=y[c+8>>2];y[i+12>>2]=y[c+12>>2];y[i+16>>2]=y[c+16>>2];c=T(h,g);i=(c|0)==0;a:do{if(i){var k=T(h,g);if((k|0)==0&&(k=T(h,g),(k|0)==0)){var k=F[d+12>>2],l=(k|0)==0;b:do{if(l){var j=-1}else{for(var n=0;;){var p=n+1|0;if((k>>>(p>>>0)|0)==0){j=n;break b}n=p}}}while(0);if((S(h,j)|0)==-1){k=1}else{if(k=T(h,g),(k|0)==0){k=d+16|0;l=F[k>>2];if((l|0)==0){l=F[d+20>>2];n=(l|0)==0;b:do{if(n){var r=-1}else{for(p=0;;){var o=p+1|0;if((l>>>(o>>>0)|0)==0){r=p;break b}p=o}}}while(0);if((S(h,r)|0)==-1){k=1;break}if((y[f+8>>2]|0)!=0&&(l=Qc(h,e),(l|0)!=0)){k=l;break}k=y[k>>2]}else{k=l}k=(k|0)==1;do{if(k&&(y[d+24>>2]|0)==0){l=Qc(h,e);if((l|0)!=0){k=l;break a}if((y[f+8>>2]|0)!=0&&(l=Qc(h,e),(l|0)!=0)){k=l;break a}}}while(0);if((y[f+68>>2]|0)!=0&&(k=T(h,g),(k|0)!=0)){break}k=S(h,1);y[b>>2]=k;k=(k|0)==-1&1}}}}else{k=c}}while(0);m=g;return k}ed.X=1;function fd(b,c,d,f){var g=m;m+=440;var e,i=g+432,h=g+436,k=g+(-g&15)|0,l=F[c+3376>>2],j=y[f>>2];y[i>>2]=0;var n=c+1192|0;y[n>>2]=y[n>>2]+1|0;var p=c+1200|0;y[p>>2]=0;var r=c+12|0;y[h>>2]=y[f+48>>2]+y[y[r>>2]+52>>2]|0;var o=f+36|0,t=c+1212|0,s=f+4|0,u=c+1176|0,w=l+12|0,v=l|0,z=f+44|0,B=c+1220|0,D=c+1172|0,C=f+52|0,E=f+56|0,f=f+60|0,G=0,H=0,K=0,L=y[t>>2];a:for(;;){if((y[o>>2]|0)==0&&(y[L+j*216+196>>2]|0)!=0){var N=1;break}L=L+j*216|0;e=y[C>>2];var O=y[E>>2],R=y[f>>2],U=y[y[r>>2]+56>>2];y[L+4>>2]=y[n>>2];y[L+8>>2]=e;y[L+12>>2]=O;y[L+16>>2]=R;y[L+24>>2]=U;L=F[s>>2];do{if(L==2||L==7){e=10}else{if((H|0)!=0){e=10}else{e=T(b,i);if((e|0)!=0){N=e;break a}e=F[i>>2];if(e>>>0>(y[u>>2]-j|0)>>>0){N=1;break a}if((e|0)==0){var Y=y[s>>2];e=12}else{Pc(w,0,164);y[v>>2]=0;var X=e,ba=1;e=11}}}}while(0);e==10&&((K|0)==0?(Y=L,e=12):(X=K,ba=H,e=11));if(e==12){var $=gd(b,l,y[t>>2]+j*216|0,Y,y[z>>2]);if(($|0)!=0){N=$;break}var ja=$=0}else{e==11&&(ja=X-1|0,y[i>>2]=ja,$=ba)}H=hd(y[t>>2]+j*216|0,l,d,B,h,j,y[y[r>>2]+64>>2],k);if((H|0)!=0){N=H;break}L=F[t>>2];G=((y[L+j*216+196>>2]|0)==1&1)+G|0;H=y[b+12>>2]<<3;K=y[b+16>>2];e=H-K|0;K=(ja|((H|0)==(K|0)?0:e>>>0>8?1:(id(b)>>>((32-e|0)>>>0)|0)!=(1<>2];if(H==2||H==7){y[p>>2]=j}H=F[u>>2];j=Ic(y[D>>2],H,j);if(K&(j|0)==0){N=1;break}if(K){H=$,K=ja}else{b=c+1196|0;c=y[b>>2]+G|0;if(c>>>0>H>>>0){N=1;break}y[b>>2]=c;N=0;break}}m=g;return N}fd.X=1;function jd(b,c){var d=F[b+1192>>2],f=y[b+1200>>2],g=(f|0)==0,e=b+1212|0;a:do{if(g){var i=c}else{for(var h=b+16|0,k=f,l=0;;){for(var l=l+1|0,j=k-1|0,n=0;;){var p=j-n|0;if(p>>>0<=c>>>0){i=p;break a}if((y[y[e>>2]+(k-n)*216-212>>2]|0)==(d|0)){break}n=n+1|0}k=F[y[h>>2]+52>>2];if(l>>>0>=(k>>>0>10?k:10)>>>0){i=p;break a}k=p}}}while(0);f=b+1172|0;for(g=b+1176|0;;){h=y[e>>2];if((y[h+i*216+4>>2]|0)!=(d|0)){break}h=h+i*216+196|0;p=y[h>>2];if((p|0)==0){break}y[h>>2]=p-1|0;i=Ic(y[f>>2],y[g>>2],i);if((i|0)==0){break}}}jd.X=1;function gd(b,c,d,f,g){var e=m;m+=8;var i,h=e+4;Pc(c,0,2088);i=T(b,e);var k=F[e>>2];if(f==7||f==2){if(f=k+6|0,f>>>0<32&(i|0)==0){var l=y[c>>2]=f;i=5}else{var j=1;i=24}}else{f=k+1|0,f>>>0<32&(i|0)==0?(l=y[c>>2]=f,i=5):(j=1,i=24)}a:do{if(i==5){j=c|0;f=(l|0)==31;b:do{if(f){for(;;){if(((y[b+8>>2]|0)==0&1|0)!=0){var n=0;break}if((S(b,1)|0)!=0){j=1;break a}}for(;;){k=c+328+(n<<2)|0;if(n>>>0>=384){break b}var p=S(b,8);y[e>>2]=p;if((p|0)==-1){j=1;break a}y[k>>2]=p;n=n+1|0}}else{var r=dd(l);if((r|0)==2){if((cd(l)|0)!=4){i=14}else{var o=kd(b,c+176|0,l,g);i=15}}else{i=14}i==14&&(o=ld(b,c+12|0,l,g));if((o|0)!=0){j=o;break a}if(k=(r|0)==1){k=y[j>>2],p=k-7|0,r=p>>>2,y[c+4>>2]=(p>>>0>11?r+268435453|0:r)<<4|(k>>>0>18?15:0)}else{var t=b,p=e,s=(r|0)==0&1,r=m;m+=4;(T(t,r)|0)==0?(t=F[r>>2],t>>>0>47?p=1:(y[p>>2]=A[((s|0)==0?Q.S:Q.T)+t|0]&255,p=0)):p=1;m=r;if((p|0)!=0){j=p;break a}p=y[e>>2];y[c+4>>2]=p;if(!((p|0)!=0|k)){break}}k=c+4|0;if((Qc(b,h)|0)!=0){j=1;break a}p=F[h>>2];if((p+26|0)>>>0>51){j=1;break a}y[c+8>>2]=p;k=md(b,c+272|0,d,y[j>>2],y[k>>2]);y[b+16>>2]=(y[b+4>>2]-y[b>>2]<<3)+y[b+8>>2]|0;if((k|0)!=0){j=k;break a}}}while(0);j=0}}while(0);m=e;return j}gd.X=1;function kd(b,c,d,f){var g=m;m+=8;for(var e,i=g+4,h=0;;){var k=c+(h<<2)|0;if(h>>>0>=4){e=5;break}if((T(b,g)|0)!=0){var l=1;e=19;break}var j=F[g>>2];if(j>>>0>3){l=1;e=19;break}y[k>>2]=j;h=h+1|0}a:do{if(e==5){h=f>>>0<2|(d|0)==5;b:do{if(h){var n=0;e=11}else{k=f>>>0>2&1;for(l=0;;){j=c+16+(l<<2)|0;if(l>>>0>=4){n=0;break b}if((nd(b,g,k)|0)!=0){l=1;break a}var p=F[g>>2];if(p>>>0>=f>>>0){l=1;break a}y[j>>2]=p;l=l+1|0}}}while(0);b:for(;;){if(n>>>0>=4){l=0;break a}h=y[c+(n<<2)>>2]==0?1:y[c+(n<<2)>>2]==1||y[c+(n<<2)>>2]==2?2:4;y[g>>2]=h;for(var r=h-1|0,o=0;;){l=c+32+(n<<4)+(o<<2)|0;k=c+32+(n<<4)+(o<<2)+2|0;if((h|0)==(o|0)){break}j=Qc(b,i);if((j|0)!=0){var t=j;break b}x[l>>1]=y[i>>2]&65535;l=Qc(b,i);if((l|0)!=0){t=l;break b}x[k>>1]=y[i>>2]&65535;o=o+1|0}y[g>>2]=r-o|0;n=n+1|0}y[g>>2]=r-o|0;l=t}}while(0);m=g;return l}kd.X=1;function ld(b,c,d,f){var g=m;m+=8;var e,i=g+4,h=dd(d);a:do{if(h==2){var k=f>>>0>1,l=cd(d);b:do{if(k){for(var j=f>>>0>2&1,n=0;;){var p=c+132+(n<<2)|0;if((l|0)==(n|0)){var r=0;break b}if((nd(b,g,j)|0)!=0){var o=1;e=21;break a}var t=F[g>>2];if(t>>>0>=f>>>0){o=1;e=21;break a}y[p>>2]=t;n=n+1|0}}else{r=0,e=7}}while(0);for(;;){k=c+148+(r<<2)+2|0;j=c+148+(r<<2)|0;if((l|0)==(r|0)){o=0;e=21;break a}n=Qc(b,i);if((n|0)!=0){o=n;e=21;break a}x[j>>1]=y[i>>2]&65535;j=Qc(b,i);if((j|0)!=0){o=j;e=21;break a}x[k>>1]=y[i>>2]&65535;r=r+1|0}}else{if(h==0){for(var l=0,s=I;;){var u=l<<3,w=c+64+(u<<2)|0,j=u|7,k=c+64+(j<<2)|0,j=c+(j<<2)|0,p=u|6,n=c+64+(p<<2)|0,p=c+(p<<2)|0,v=u|5,t=c+64+(v<<2)|0,v=c+(v<<2)|0,z=u|4,B=c+64+(z<<2)|0,z=c+(z<<2)|0,D=u|3,C=c+64+(D<<2)|0,D=c+(D<<2)|0,E=u|2,G=c+64+(E<<2)|0,E=c+(E<<2)|0,H=u|1,K=c+64+(H<<2)|0,H=c+(H<<2)|0;if((l|0)>=2){y[i>>2]=l;y[g>>2]=s;e=17;break a}var s=id(b),L=s>>>31;y[(c+(u<<2)|0)>>2]=L;u=s<<1;(L|0)==0?(y[w>>2]=s>>>28&7,w=1,u=s<<4):w=0;s=u>>>31;y[H>>2]=s;(s|0)==0?(y[K>>2]=u>>>28&7,w=w+1|0,u<<=4):u<<=1;s=u>>>31;y[E>>2]=s;(s|0)==0?(y[G>>2]=u>>>28&7,G=w+1|0,w=u<<4):(G=w,w=u<<1);E=w>>>31;y[D>>2]=E;(E|0)==0?(y[C>>2]=w>>>28&7,C=G+1|0,D=w<<4):(C=G,D=w<<1);G=D>>>31;y[z>>2]=G;(G|0)==0?(y[B>>2]=D>>>28&7,B=C+1|0,z=D<<4):(B=C,z=D<<1);C=z>>>31;y[v>>2]=C;(C|0)==0?(y[t>>2]=z>>>28&7,t=B+1|0,v=z<<4):(t=B,v=z<<1);B=v>>>31;y[p>>2]=B;(B|0)==0?(y[n>>2]=v>>>28&7,n=t+1|0,p=v<<4):(n=t,p=v<<1);t=p>>>31;y[j>>2]=t;(t|0)==0?(y[k>>2]=p>>>28&7,k=n+1|0,j=p<<4):(k=n,j=p<<1);if((od(b,k*3+8|0)|0)==-1){y[i>>2]=l;y[g>>2]=j;o=1;e=21;break a}l=l+1|0;s=j}}else{h==1?e=17:(o=0,e=21)}}}while(0);e==17&&((T(b,g)|0)!=0?o=1:(b=F[g>>2],b>>>0>3?o=1:(y[c+128>>2]=b,o=0)));m=g;return o}ld.X=1;function md(b,c,d,f,g){var e=c|0;if((dd(f)|0)==1){if(f=pd(b,c+1592|0,qd(d,0,e),16),(f&15|0)!=0){var i=f,f=22}else{x[c+48>>1]=f>>>4&255;var h=0,f=3}}else{h=1,f=3}a:do{if(f==3){for(var k=0,l=g,j=0;;){if((j|0)==4){break}var n=l>>>1,l=(l&1|0)==0;b:do{if(l){var p=k+4|0}else{for(var r=0;;){var o=k+r|0,t=c+1720+(o<<2)|0,s=c+56+(o<<6)+4|0,u=c+(o<<1)|0,w=c+56+(o<<6)|0;if((r|0)==4){p=o;break b}o=qd(d,o,e);h?(s=w=pd(b,w,o,16),w>>>=16):(s=w=pd(b,s,o,15),w>>>=15);y[t>>2]=w;if((s&15|0)!=0){i=s;break a}x[u>>1]=s>>>4&255;r=r+1|0}}}while(0);k=p;l=n;j=j+1|0}if((l&3|0)!=0){j=pd(b,c+1656|0,-1,4);if((j&15|0)!=0){i=j;break}x[c+50>>1]=j>>>4&255;j=pd(b,c+1672|0,-1,4);if((j&15|0)!=0){i=j;break}x[c+52>>1]=j>>>4&255}if((l&2|0)==0){i=0}else{for(j=0;;){r=k+j|0;n=c+1720+(r<<2)|0;l=c+(r<<1)|0;if((j|0)==8){i=0;break a}r=pd(b,c+56+(r<<6)+4|0,qd(d,r,e),15);if((r&15|0)!=0){i=r;break a}x[l>>1]=r>>>4&255;y[n>>2]=r>>>15;j=j+1|0}}}}while(0);return i}md.X=1;function hd(b,c,d,f,g,e,i,h){var k=F[c>>2];y[b>>2]=k;var l=b+196|0;y[l>>2]=y[l>>2]+1|0;Lc(d,e);var j=(k|0)==31;do{if(j){if(y[b+20>>2]=0,F[l>>2]>>>0>1){x[b+28>>1]=16;x[b+30>>1]=16;x[b+32>>1]=16;x[b+34>>1]=16;x[b+36>>1]=16;x[b+38>>1]=16;x[b+40>>1]=16;x[b+42>>1]=16;x[b+44>>1]=16;x[b+46>>1]=16;x[b+48>>1]=16;x[b+50>>1]=16;x[b+52>>1]=16;x[b+54>>1]=16;x[b+56>>1]=16;x[b+58>>1]=16;x[b+60>>1]=16;x[b+62>>1]=16;x[b+64>>1]=16;x[b+66>>1]=16;x[b+68>>1]=16;x[b+70>>1]=16;x[b+72>>1]=16;x[b+74>>1]=16;var n=0}else{for(n=0;;){var p=n<<4;x[b+28+(n<<1)>>1]=16;var r=h+(p|1)|0,o=h+(p|2)|0,t=h+(p|3)|0,s=h+(p|4)|0,u=h+(p|5)|0,w=h+(p|6)|0,v=h+(p|7)|0,z=h+(p|8)|0,B=h+(p|9)|0,D=h+(p|10)|0,C=h+(p|11)|0,E=h+(p|12)|0,G=h+(p|13)|0,H=h+(p|14)|0,K=h+(p|15)|0,L=c+328+(n<<6)+4|0,N=c+328+(n<<6)+8|0,O=c+328+(n<<6)+12|0,R=c+328+(n<<6)+16|0,U=c+328+(n<<6)+20|0,Y=c+328+(n<<6)+24|0,X=c+328+(n<<6)+28|0,ba=c+328+(n<<6)+32|0,$=c+328+(n<<6)+36|0,ja=c+328+(n<<6)+40|0,sa=c+328+(n<<6)+44|0,Ea=c+328+(n<<6)+48|0,Xa=c+328+(n<<6)+52|0,ea=c+328+(n<<6)+56|0,fa=c+328+(n<<6)+60|0;q[h+p|0]=y[c+328+(n<<6)>>2]&255;q[r]=y[L>>2]&255;q[o]=y[N>>2]&255;q[t]=y[O>>2]&255;q[s]=y[R>>2]&255;q[u]=y[U>>2]&255;q[w]=y[Y>>2]&255;q[v]=y[X>>2]&255;q[z]=y[ba>>2]&255;q[B]=y[$>>2]&255;q[D]=y[ja>>2]&255;q[C]=y[sa>>2]&255;q[E]=y[Ea>>2]&255;q[G]=y[Xa>>2]&255;q[H]=y[ea>>2]&255;q[K]=y[fa>>2]&255;n=n+1|0;if((n|0)==24){break}}rd(d,h);n=0}}else{n=b+28|0;if((k|0)==0){Pc(n,0,54),y[b+20>>2]=y[g>>2]}else{if(sd(n,c+272|0,54),n=y[c+8>>2],p=y[g>>2],(n|0)==0?n=p:(n=p+n|0,y[g>>2]=n,(n|0)<0?(n=n+52|0,y[g>>2]=n):(n|0)>51&&(n=n-52|0,y[g>>2]=n)),y[b+20>>2]=n,n=td(b,c+328|0,c+1992|0),(n|0)!=0){break}}if((dd(k)|0)==2){n=ud(b,c,f,e,d,h)}else{n=b;t=c;p=d;z=e;s=i;r=h;o=m;m+=72;B=aa;u=o+40;w=o|0;v=u|0;vd(p,w,v,z);z=(dd(y[n>>2])|0)==1;do{if(z){B=wd(n,r,t+328|0,w,v,s);if((B|0)==0){B=3;break}var va=B}else{B=xd(n,r,t,w,v,s);if((B|0)==0){B=3;break}va=B}B=6}while(0);B==3&&(va=yd(n,r+256|0,t+1352|0,o+21|0,u+16|0,y[t+140>>2],s),(va|0)==0&&(F[n+196>>2]>>>0>1||rd(p,r),va=0));m=o;n=va}if((n|0)!=0){break}n=0}}while(0);return n}hd.X=1;function td(b,c,d){var f,g=(dd(y[b>>2])|0)==1;a:do{if(g){if(x[b+76>>1]<<16>>16==0){var e=b+20|0}else{f=b+20|0,Gc(c+1536|0,y[f>>2]),e=f}for(var i=0;;){var h=c+(i<<6)|0,k=b+28+(i<<1)|0,l=d+(i<<2)|0;if((i|0)==16){break}f=y[c+1536+(y[zd+(i<<2)>>2]<<2)>>2];y[h>>2]=f;(f|0)==0?x[k>>1]<<16>>16!=0?f=9:(y[h>>2]=16777215,f=11):f=9;if(f==9&&(Dc(h,y[e>>2],1,y[l>>2])|0)!=0){var j=1;f=27;break a}i=i+1|0}var n=l,p=k,r=h,o=b+20|0;f=18}else{e=b+20|0;for(i=0;;){var t=c+(i<<6)|0,s=b+28+(i<<1)|0,u=d+(i<<2)|0;if((i|0)==16){n=u;p=s;r=t;o=e;f=18;break a}if(x[s>>1]<<16>>16==0){y[t>>2]=16777215}else{if((Dc(t,y[e>>2],0,y[u>>2])|0)!=0){j=1;f=27;break a}}i=i+1|0}}}while(0);a:do{if(f==18){d=r;g=y[Ad+(Cc(0,51,y[b+24>>2]+y[o>>2]|0)<<2)>>2];if(x[b+78>>1]<<16>>16==0){if(x[b+80>>1]<<16>>16==0){var w=0;f=21}else{f=20}}else{f=20}f==20&&(Hc(c+1600|0,g),w=0);for(;;){h=d+(w<<6)|0;f=p+(w<<1)|0;k=n+(w<<2)|0;if((w|0)==8){j=0;break a}l=y[c+1600+(w<<2)>>2];y[h>>2]=l;(l|0)==0?x[f>>1]<<16>>16!=0?f=24:(y[h>>2]=16777215,f=26):f=24;if(f==24&&(Dc(h,g,1,y[k>>2])|0)!=0){j=1;break a}w=w+1|0}}}while(0);return j}td.X=1;function id(b){var c=F[b+4>>2],d=y[b+12>>2]<<3,f=F[b+16>>2],g=d-f|0,e=(g|0)>31;a:do{if(e){var i=F[b+8>>2],h=(A[c+1|0]&255)<<16|(A[c]&255)<<24|A[c+3|0]&255|(A[c+2|0]&255)<<8,i=(i|0)==0?h:(A[c+4|0]&255)>>>((8-i|0)>>>0)|h<0){var k=F[b+8>>2],l=(A[c]&255)<0){for(var h=k+d-16-f|0,k=k+16|0,j=l,n=0;;){l=n+1|0;n=n*-8|0;j|=(A[c+l|0]&255)<>2]+c|0;y[d>>2]=f;y[b+8>>2]=f&7;f>>>0>y[b+12>>2]<<3>>>0?d=-1:(y[b+4>>2]=y[b>>2]+(f>>>3)|0,d=0);return d}function Bd(b,c){if(c>>>0<2){var d=b>>>0>32767?1:b>>>0>3071?Gb[Cd+(b>>>10<<1)>>1]&65535:b>>>0>255?Gb[Dd+(b>>>6<<1)>>1]&65535:b>>>0>31?Gb[je+((b>>>2)-8<<1)>>1]&65535:Gb[ke+(b<<1)>>1]&65535}else{c>>>0<4?d=b>>>0>32767?(b&16384|0)!=0?2:2082:b>>>0>4095?Gb[le+(b>>>10<<1)>>1]&65535:b>>>0>511?Gb[me+(b>>>7<<1)>>1]&65535:Gb[ne+(b>>>2<<1)>>1]&65535:c>>>0<8?(d=b>>>10,d=(d-8|0)>>>0<56?Gb[oe+(d<<1)>>1]&65535:Gb[pe+(b>>>6<<1)>>1]&65535):c>>>0<17?d=Gb[qe+(b>>>10<<1)>>1]&65535:(d=b>>>13,d=(d|0)!=0?Gb[re+(d<<1)>>1]&65535:Gb[se+(b>>>8<<1)>>1]&65535)}return d}Bd.X=1;function qd(b,c,d){var f=te+(c<<3)|0,g=ue+(c<<3)|0,e=A[f+4|0],c=A[g+4|0],g=(y[g>>2]|0)==4;(y[f>>2]|0)==4?(e=x[d+((e&255)<<1)>>1]<<16>>16,g?b=e+1+(x[d+((c&255)<<1)>>1]<<16>>16)>>1:(d=F[b+204>>2],b=(ve(b,d)|0)==0?e:e+1+(x[d+28+((c&255)<<1)>>1]<<16>>16)>>1)):g?(c=x[d+((c&255)<<1)>>1]<<16>>16,d=F[b+200>>2],b=(ve(b,d)|0)==0?c:c+1+(x[d+28+((e&255)<<1)>>1]<<16>>16)>>1):(d=F[b+200>>2],(ve(b,d)|0)==0?d=e=0:(e=x[d+28+((e&255)<<1)>>1]<<16>>16,d=1),f=F[b+204>>2],(ve(b,f)|0)==0?b=e:(b=x[f+28+((c&255)<<1)>>1]<<16>>16,b=(d|0)==0?b:b+(e+1)>>1));return b}qd.X=1;function S(b,c){var d=id(b);return(od(b,c)|0)==0?d>>>((32-c|0)>>>0):-1}function T(b,c){var d=id(b);if((d|0)<0){od(b,1),d=y[c>>2]=0}else{if(d>>>0>1073741823){(od(b,3)|0)==-1?d=1:(y[c>>2]=(d>>>29&1)+1|0,d=0)}else{if(d>>>0>536870911){(od(b,5)|0)==-1?d=1:(y[c>>2]=(d>>>27&3)+3|0,d=0)}else{if(d>>>0>268435455){(od(b,7)|0)==-1?d=1:(y[c>>2]=(d>>>25&7)+7|0,d=0)}else{var f;f=134217728;for(var g=0;;){if((f|0)==0){break}if((f&d|0)!=0){break}f>>>=1;g=g+1|0}f=g;d=f+4|0;(d|0)==32?(y[c>>2]=0,od(b,32),(S(b,1)|0)!=1?d=1:(d=id(b),(od(b,32)|0)==-1?d=1:d==0?(y[c>>2]=-1,d=0):(d==1&&(y[c>>2]=-1),d=1))):(od(b,f+5|0),f=S(b,d),(f|0)==-1?d=1:(y[c>>2]=(1<>2]=0;var f=T(b,d),g=y[d>>2],e=(g|0)==-1,f=(f|0)==0;do{if(e){if(f){var i=1;break}y[c>>2]=-2147483648}else{if(!f){i=1;break}i=(g+1|0)>>>1;y[c>>2]=(g&1|0)!=0?i:-i|0}i=0}while(0);m=d;return i}function nd(b,c,d){(d|0)==0?(b=S(b,1),y[c>>2]=b,(b|0)==-1?c=1:(y[c>>2]=b^1,c=0)):c=T(b,c);return c}function pd(b,c,d,f){var g=m;m+=128;var e,i=g+64,h=id(b),d=Bd(h>>>16,d),k=(d|0)==0;a:do{if(k){var l=1}else{var l=d&31,j=h<>>11&31;if(p>>>0>f>>>0){l=1}else{var r=d>>>5&63,o=(p|0)==0;b:do{if(o){var t=n,s=0}else{if((r|0)==0){var u=n,w=j,v=0}else{if(n>>>0>>0){if((od(b,l)|0)==-1){l=1;break a}v=32;w=id(b)}else{v=n,w=j}var z=w>>>((32-r|0)>>>0);w<<=r;for(var B=1<>2]=(B&z|0)!=0?-1:1;B>>>=1;var D=u+1|0;if((B|0)==0){break}u=D}u=v-r|0;v=D}z=r>>>0<3;if(p>>>0>10&z){var C=u,E=w,G=1}else{C=u,E=w,G=0}for(w=0;;){B=v+w|0;u=g+(B<<2)|0;if(B>>>0>=p>>>0){break}if(C>>>0<16){if((od(b,32-C|0)|0)==-1){l=1;break a}var H=32,E=id(b)}else{H=C}C=E>>>16;e=aa;if(C>>>0>32767){var K=0;e=16}else{if(C>>>0>16383){K=1,e=16}else{if(C>>>0>8191){K=2,e=16}else{if(C>>>0>4095){K=3,e=16}else{if(C>>>0>2047){K=4,e=16}else{if(C>>>0>1023){K=5,e=16}else{if(C>>>0>511){K=6,e=16}else{if(C>>>0>255){K=7,e=16}else{if(C>>>0>127){K=8,e=16}else{if(C>>>0>63){K=9,e=16}else{if(C>>>0>31){K=10,e=16}else{if(C>>>0>15){K=11,e=16}else{if(C>>>0>7){K=12,e=16}else{if(C>>>0>3){K=13,e=16}else{if(C>>>0>1){K=14,e=16}else{if((C|0)==0){var L=-2;e=17}else{K=15,e=16}}}}}}}}}}}}}}}}e==16&&(L=K);C=L;if((C|0)==-2){l=1;break a}e=C+1|0;E<<=e;H=H-e|0;if(C>>>0<14){var N=G;e=21}else{if(e=(G|0)!=0,(C|0)==14){N=e?G:4,e=21}else{var O=e?G:1,R=O,U=12,Y=(O|0)==0,O=C<>>0>>0){if((od(b,32-H|0)|0)==-1){l=1;break a}X=32;$=id(b)}else{X=H,$=E}X=X-U|0;ba=$<>>((32-U|0)>>>0))+O|0;ja=R;sa=Y}G=(B|0)==(r|0)&z?$+2|0:$;E=(G+2|0)>>>1;y[u>>2]=E;B=sa?1:ja;B=(E|0)>(3<>>0<6&1)+B|0:B;(G&1|0)!=0&&(y[u>>2]=-E|0);C=X;E=ba;G=B;w=w+1|0}if(p>>>0>>0){if(C>>>0<9){if((od(b,32-C|0)|0)==-1){l=1;break a}z=32;w=id(b)}else{z=C,w=E}v=we(w>>>23,p,(f|0)==4&1);if((v|0)==0){l=1;break a}u=v&15;z=z-u|0;w<<=u;u=v>>>4&15}else{z=C,w=E,u=0}v=p-1|0;G=w;w=u;for(u=0;;){B=i+(u<<2)|0;if(u>>>0>=v>>>0){break}if((w|0)==0){y[B>>2]=1,B=z,E=G,w=0}else{if(z>>>0<11){if((od(b,32-z|0)|0)==-1){l=1;break a}E=32;z=id(b)}else{E=z,z=G}G=xe(z>>>21,w);if((G|0)==0){l=1;break a}C=G&15;z<<=C;E=E-C|0;G=G>>>4&15;y[B>>2]=G+1|0;B=E;E=z;w=w-G|0}z=B;G=E;u=u+1|0}y[c+(w<<2)>>2]=y[g+(v<<2)>>2];B=1<>2]+E|0,B|=1<>2]=y[g+(G<<2)>>2],w=w+1|0,(w|0)==(v|0)){t=z;s=B;break b}}}}}while(0);l=(od(b,32-t|0)|0)!=0?1:s<<16|p<<4}}}while(0);m=g;return l}pd.X=1;function we(b,c,d){(d|0)==0?c==1?(c=Q.ha+(b>>>4)|0,b=b>>>0>31?A[c]&255:A[Q.ia+b|0]&255):b=c==2?A[Q.ja+(b>>>3)|0]&255:c==3?A[Q.ka+(b>>>3)|0]&255:c==4?A[Q.la+(b>>>4)|0]&255:c==5?A[Q.ma+(b>>>4)|0]&255:c==6?A[Q.na+(b>>>3)|0]&255:c==7?A[Q.oa+(b>>>3)|0]&255:c==8?A[Q.pa+(b>>>3)|0]&255:c==9?A[Q.qa+(b>>>3)|0]&255:c==10?A[Q.ca+(b>>>4)|0]&255:c==11?A[Q.da+(b>>>5)|0]&255:c==12?A[Q.ea+(b>>>5)|0]&255:c==13?A[Q.fa+(b>>>6)|0]&255:c==14?A[Q.ga+(b>>>7)|0]&255:b>>>0>255?17:1:b=b>>>0>255?1:(c|0)==3?17:b>>>0>127?18:(c|0)==2?34:b>>>0>63?35:51;return b}we.X=1;function xe(b,c){if(c==1){var d=A[Q.U+(b>>>10)|0]&255}else{c==2?d=A[Q.V+(b>>>9)|0]&255:c==3?d=A[Q.W+(b>>>9)|0]&255:c==4?d=A[Q.Y+(b>>>8)|0]&255:c==5?d=A[Q.Z+(b>>>8)|0]&255:c==6?d=A[Q.$+(b>>>8)|0]&255:(d=b>>>0>255?7-(b>>>8)<<4|3:b>>>0>127?116:b>>>0>63?133:b>>>0>31?150:b>>>0>15?167:b>>>0>7?184:b>>>0>3?201:b>>>0>1?218:(b|0)==0?0:235,d=(d>>>4&15)>>>0>c>>>0?0:d)}return d}xe.X=1;function ye(b,c){return c==0?y[b+200>>2]:c==1?y[b+204>>2]:c==2?y[b+208>>2]:c==3?y[b+212>>2]:c==4?b:0}function ve(b,c){return(c|0)==0?0:(y[b+4>>2]|0)!=(y[c+4>>2]|0)?0:1}function ze(b,c){var d,f=y[c+8>>2],g=b+20+(f<<2)|0,e=y[g>>2],i=(e|0)==0;do{if(i){if(d=jc(92),y[g>>2]=d,(d|0)==0){var h=65535;d=8;break}}else{d=b+8|0;if((f|0)!=(y[d>>2]|0)){Ae(y[e+40>>2]);y[(y[g>>2]+40|0)>>2]=0;Ae(y[y[g>>2]+84>>2]);y[(y[g>>2]+84|0)>>2]=0;d=7;break}var k=b+16|0;if((Nc(c,y[k>>2])|0)==0){f=c+40|0;Ae(y[f>>2]);y[f>>2]=0;f=c+84|0;Ae(y[f>>2]);h=y[f>>2]=0;d=8;break}Ae(y[e+40>>2]);y[(y[g>>2]+40|0)>>2]=0;Ae(y[y[g>>2]+84>>2]);y[(y[g>>2]+84|0)>>2]=0;y[d>>2]=33;y[b+4>>2]=257;y[k>>2]=0;y[b+12>>2]=0}d=7}while(0);if(d==7){f=c>>2;g=y[g>>2]>>2;for(e=f+23;f>2],g=b+148+(f<<2)|0,e=y[g>>2],i=(e|0)==0;do{if(i){if(d=jc(72),y[g>>2]=d,(d|0)==0){var h=65535;d=8;break}}else{d=b+4|0;if((f|0)==(y[d>>2]|0)){(y[c+4>>2]|0)==(y[b+8>>2]|0)?f=e:(y[d>>2]=257,f=y[g>>2]);Ae(y[f+20>>2]);y[(y[g>>2]+20|0)>>2]=0;Ae(y[y[g>>2]+24>>2]);y[(y[g>>2]+24|0)>>2]=0;Ae(y[y[g>>2]+28>>2]);y[(y[g>>2]+28|0)>>2]=0;Ae(y[y[g>>2]+44>>2]);y[(y[g>>2]+44|0)>>2]=0;d=7;break}Ae(y[e+20>>2]);y[(y[g>>2]+20|0)>>2]=0;Ae(y[y[g>>2]+24>>2]);y[(y[g>>2]+24|0)>>2]=0;Ae(y[y[g>>2]+28>>2]);y[(y[g>>2]+28|0)>>2]=0;Ae(y[y[g>>2]+44>>2]);y[(y[g>>2]+44|0)>>2]=0}d=7}while(0);if(d==7){h=c>>2;g=y[g>>2]>>2;for(f=h+18;h>2],e=(g|0)==0;a:do{if(e){var i=1}else{var i=y[g+4>>2],h=y[b+20+(i<<2)>>2];if((h|0)==0){i=1}else{if(h=De(g,y[h+52>>2],y[h+56>>2]),(h|0)!=0){i=h}else{var h=b+4|0,k=y[h>>2],l=(k|0)==256;do{if(l){y[h>>2]=c;var j=y[f>>2];y[b+12>>2]=j;j=y[j+4>>2];y[b+8>>2]=j;var n=y[b+20+(j<<2)>>2];y[b+16>>2]=n;j=n+52|0;n=n+56|0;y[b+1176>>2]=y[n>>2]*y[j>>2]|0;y[b+1340>>2]=y[j>>2];y[b+1344>>2]=y[n>>2];y[b+3380>>2]=1}else{if(j=b+3380|0,(y[j>>2]|0)==0){if((k|0)!=(c|0)){if(n=b+8|0,(i|0)==(y[n>>2]|0)){y[h>>2]=c,y[b+12>>2]=y[f>>2]}else{if((d|0)==0){i=1;break a}y[h>>2]=c;var p=y[f>>2];y[b+12>>2]=p;p=y[p+4>>2];y[n>>2]=p;p=y[b+20+(p<<2)>>2];y[b+16>>2]=p;n=p+52|0;p=p+56|0;y[b+1176>>2]=y[p>>2]*y[n>>2]|0;y[b+1340>>2]=y[n>>2];y[b+1344>>2]=y[p>>2];y[j>>2]=1}}}else{y[j>>2]=0;n=b+1212|0;Ae(y[n>>2]);y[n>>2]=0;j=b+1172|0;Ae(y[j>>2]);y[j>>2]=0;var r=b+1176|0,p=jc(y[r>>2]*216|0);y[n>>2]=p;p=jc(y[r>>2]<<2);y[j>>2]=p;j=y[n>>2];if((j|0)==0|(p|0)==0){i=65535;break a}Pc(j,0,y[r>>2]*216|0);var j=b+16|0,n=y[n>>2],p=y[y[j>>2]+52>>2],r=y[r>>2],o=aa,t=(r|0)==0;b:do{if(!t){for(var s=p-1|0,u=1-p|0,w=p^-1,v=0,z=0,B=0;;){var o=n+v*216+204|0,D=n+v*216+208|0,C=n+v*216+212|0,E=n+(v-p)*216|0,G=n+(u+v)*216|0,H=n+(v+w)*216|0,K=(B|0)!=0;y[n+v*216+200>>2]=K?n+(v-1)*216|0:0;var L=(z|0)!=0;if(L){if(y[o>>2]=E,B>>>0>>0){var N=G,o=8}else{o=7}}else{y[o>>2]=0,o=7}o==7&&(N=0);y[D>>2]=N;y[C>>2]=L&K?H:0;D=B+1|0;D=(B=(D|0)==(p|0))?0:D;v=v+1|0;if((v|0)==(r|0)){break b}z=(B&1)+z|0;B=D}}}while(0);p=(y[b+1216>>2]|0)==0;j=y[j>>2];b:do{if(p){if((y[j+16>>2]|0)==2){n=1}else{n=(y[j+80>>2]|0)==0;do{if(!n&&(r=y[j+84>>2],(y[r+920>>2]|0)!=0&&(y[r+944>>2]|0)==0)){n=1;break b}}while(0);n=0}}else{n=1}}while(0);p=b+1220|0;r=y[j+56>>2]*y[j+52>>2]|0;t=y[j+88>>2];s=y[j+44>>2];j=y[j+12>>2];Ee(p);j=Fe(p,r,t,s,j,n);if((j|0)!=0){i=j;break a}}}}while(0);i=0}}}}while(0);return i}Ce.X=1;Module._get_h264bsdClip=(function(){return Q.a|0});function De(b,c,d){var f,d=d*c|0,g=F[b+12>>2],e=g>>>0>1;a:do{if(e){var i=F[b+16>>2];if(i==0){for(var i=b+20|0,h=0;;){if(h>>>0>=g>>>0){f=15;break a}if(F[y[i>>2]+(h<<2)>>2]>>>0>d>>>0){var k=1;f=16;break a}h=h+1|0}}else{if(i==2){for(var i=g-1|0,h=b+24|0,l=b+28|0,j=0;;){if(j>>>0>=i>>>0){f=15;break a}var n=F[y[h>>2]+(j<<2)>>2],p=F[y[l>>2]+(j<<2)>>2];if(!(n>>>0<=p>>>0&p>>>0>>0)){k=1;f=16;break a}if((n>>>0)%(c>>>0)>>>0>(p>>>0)%(c>>>0)>>>0){k=1;f=16;break a}j=j+1|0}}else{if((i-3|0)>>>0<3){if(F[b+36>>2]>>>0>d>>>0){k=1;f=16;break}}else{if((i|0)!=6){f=15;break}if(F[b+40>>2]>>>0>>0){k=1;f=16;break}}f=15}}}else{f=15}}while(0);f==15&&(k=0);return k}De.X=1;function Ge(b,c,d,f,g,e){var i=e*g|0,h=(i|0)==0,e=c-1|0;a:do{if(!h){for(var k=0;;){if(y[b+(k<<2)>>2]=e,k=k+1|0,(k|0)==(i|0)){break a}}}}while(0);i=(e|0)==0;a:do{if(!i){h=c-2|0;for(k=0;;){var l=h-k|0,j=F[d+(l<<2)>>2],n=Math.floor((j>>>0)/(g>>>0)),j=(j>>>0)%(g>>>0),p=F[(f+(l<<2)|0)>>2],r=Math.floor((p>>>0)/(g>>>0)),p=(p>>>0)%(g>>>0),o=n>>>0>r>>>0;b:do{if(!o){for(var t=j>>>0>p>>>0,s=j+n*g|0,u=j+1|0,w=n+1|0,v=0;;){var z=s+v*g|0,B=w+v|0;c:do{if(!t){for(var D=0;;){var C=u+D|0;y[b+(z+D<<2)>>2]=l;if(C>>>0>p>>>0){break c}D=D+1|0}}}while(0);if(B>>>0>r>>>0){break b}v=v+1|0}}}while(0);k=k+1|0;if((k|0)==(e|0)){break a}}}}while(0)}Ge.X=1;function He(b,c,d,f,g){var e=g*f|0,i=(e|0)==0;a:do{if(!i){for(var h=0;;){if(y[b+(h<<2)>>2]=1,h=h+1|0,(h|0)==(e|0)){break a}}}}while(0);e=(f-c|0)>>>1;i=(g-c|0)>>>1;h=(d|0)==0;a:do{if(!h){for(var k=c<<1,l=k-1|0,j=f-1|0,k=1-k|0,n=g-1|0,p=i,r=e,o=c-1|0,t=0,s=c,u=e,w=i,v=e,z=i;;){var B=b+(p*f+r<<2)|0,D=(y[B>>2]|0)==1,C=D&1;D&&(y[B>>2]=0);(o|0)==-1&(r|0)==(u|0)?(r=u-1|0,u=r=(r|0)>0?r:0,B=l,D=0):(o|0)==1&(r|0)==(v|0)?(r=v+1|0,v=r=(r|0)<(j|0)?r:j,B=k,D=0):(s|0)==-1&(p|0)==(w|0)?(p=w-1|0,w=p=(p|0)>0?p:0,B=0,D=k):(s|0)==1&(p|0)==(z|0)?(p=z+1|0,z=p=(p|0)<(n|0)?p:n,B=0,D=l):(B=s,D=o,r=o+r|0,p=s+p|0);t=C+t|0;if(t>>>0>=d>>>0){break a}o=D;s=B}}}while(0)}He.X=1;function Ie(b,c,d,f){var g=m;m+=28;var e,i=g+4,h=g+8,k=g+12,l=g+16,j=g+20;y[f>>2]=0;var n=c|0,p=F[n>>2],r=(p-6|0)>>>0<6|(p-13|0)>>>0<6;a:do{if(r){y[f>>2]=1;var o=0}else{if(p==1||p==5){var t=d+1332|0;(y[t>>2]|0)!=0&&(y[f>>2]=1,y[t>>2]=0);var s=Wc(b,g);if((s|0)!=0){o=s}else{var u=F[d+148+(y[g>>2]<<2)>>2];if((u|0)==0){o=65520}else{var w=y[u+4>>2],v=F[d+20+(w<<2)>>2];if((v|0)==0){o=65520}else{var z=y[d+8>>2];if(!((z|0)==32|(w|0)==(z|0))&&(y[n>>2]|0)!=5){o=65520}else{var B=d+1300|0,D=y[d+1304>>2],C=y[c+4>>2];(D|0)!=(C|0)&&(D|0)==0|(C|0)==0&&(y[f>>2]=1);var E=d+1300|0,G=(y[n>>2]|0)==5;e=(y[E>>2]|0)==5?G?17:16:G?16:17;e==16&&(y[f>>2]=1);var H=v+12|0,K=b,L=y[H>>2],N=i,O=m;m+=24;var R=O+4,U=R|0;y[R>>2]=y[K>>2];y[R+4>>2]=y[K+4>>2];y[R+8>>2]=y[K+8>>2];y[R+12>>2]=y[K+12>>2];y[R+16>>2]=y[K+16>>2];var Y=T(U,O),X=(Y|0)==0;do{if(X){var ba=T(U,O);if((ba|0)!=0){var $=ba}else{var ja=T(U,O);if((ja|0)!=0){$=ja}else{var sa=(L|0)==0;b:do{if(sa){var Ea=-1}else{for(var Xa=0;;){var ea=Xa+1|0;if((L>>>(ea>>>0)|0)==0){Ea=Xa;break b}Xa=ea}}}while(0);var fa=S(U,Ea);(fa|0)==-1?$=1:(y[N>>2]=fa,$=0)}}}else{$=Y}}while(0);m=O;if(($|0)!=0){o=1}else{var va=d+1308|0,ob=y[i>>2];(y[va>>2]|0)!=(ob|0)&&(y[va>>2]=ob,y[f>>2]=1);var wa=y[n>>2];if((wa|0)==5){var pb=b,gb=y[H>>2],Ib=wa,Fa=h,qb=m;m+=24;var Ya=qb+4,Na=(Ib|0)==5;do{if(Na){var za=Ya|0,da=Ya,Oa=pb;y[da>>2]=y[Oa>>2];y[da+4>>2]=y[Oa+4>>2];y[da+8>>2]=y[Oa+8>>2];y[da+12>>2]=y[Oa+12>>2];y[da+16>>2]=y[Oa+16>>2];var Za=T(za,qb);if((Za|0)!=0){var Aa=Za}else{var hb=T(za,qb);if((hb|0)!=0){Aa=hb}else{var Ga=T(za,qb);if((Ga|0)!=0){Aa=Ga}else{var Pa=(gb|0)==0;b:do{if(Pa){var $a=-1}else{for(var Ab=0;;){var cb=Ab+1|0;if((gb>>>(cb>>>0)|0)==0){$a=Ab;break b}Ab=cb}}}while(0);Aa=(S(za,$a)|0)==-1?1:T(za,Fa)}}}}else{Aa=1}}while(0);m=qb;if((Aa|0)!=0){o=1;break}if((y[E>>2]|0)==5){var rb=d+1312|0,Qa=y[h>>2];if((y[rb>>2]|0)==(Qa|0)){var pa=Qa,ia=rb}else{y[f>>2]=1,pa=Qa,ia=rb}}else{pa=y[h>>2],ia=d+1312|0}y[ia>>2]=pa}var qa=y[v+16>>2];do{if(qa==0){if((Xc(b,v,y[n>>2],k)|0)!=0){o=1;break a}var Ra=d+1316|0,ra=y[k>>2];(y[Ra>>2]|0)!=(ra|0)&&(y[Ra>>2]=ra,y[f>>2]=1);if((y[u+8>>2]|0)!=0){var ib=bd(b,v,y[n>>2],l);if((ib|0)!=0){o=ib;break a}var sb=d+1320|0,jb=y[l>>2];(y[sb>>2]|0)!=(jb|0)&&(y[sb>>2]=jb,y[f>>2]=1)}}else{if(qa==1&&(y[v+24>>2]|0)==0){var db=u+8|0,Sa=j|0,kb,ta=b,Bb=v,Ha=y[n>>2],ya=y[db>>2],xa=Sa,Ba=m;m+=24;var Ca=Ba+4,Ta=Ca|0;y[Ca>>2]=y[ta>>2];y[Ca+4>>2]=y[ta+4>>2];y[Ca+8>>2]=y[ta+8>>2];y[Ca+12>>2]=y[ta+12>>2];y[Ca+16>>2]=y[ta+16>>2];var lb=T(Ta,Ba),Jb=(lb|0)==0;do{if(Jb){var eb=T(Ta,Ba);if((eb|0)!=0){var Da=eb}else{var Ia=T(Ta,Ba);if((Ia|0)!=0){Da=Ia}else{var mb=F[Bb+12>>2],Ua=(mb|0)==0;b:do{if(Ua){var Ja=-1}else{for(var Ka=0;;){var Cb=Ka+1|0;if((mb>>>(Cb>>>0)|0)==0){Ja=Ka;break b}Ka=Cb}}}while(0);if((S(Ta,Ja)|0)==-1){Da=1}else{if((Ha|0)==5){var Db=T(Ta,Ba);if((Db|0)!=0){Da=Db;break}}var Eb=Qc(Ta,xa);if((Eb|0)!=0){Da=Eb}else{if((ya|0)!=0){var tb=Qc(Ta,xa+4|0);if((tb|0)!=0){Da=tb;break}}Da=0}}}}}else{Da=lb}}while(0);m=Ba;kb=Da;if((kb|0)!=0){o=kb;break a}var Va=d+1324|0,fb=y[Sa>>2];(y[Va>>2]|0)!=(fb|0)&&(y[Va>>2]=fb,y[f>>2]=1);if((y[db>>2]|0)!=0){var ub=d+1328|0,nb=y[j+4>>2];(y[ub>>2]|0)!=(nb|0)&&(y[ub>>2]=nb,y[f>>2]=1)}}}}while(0);var Fb=c,Qb=B,wb=y[Fb+4>>2];y[Qb>>2]=y[Fb>>2];y[Qb+4>>2]=wb;o=0}}}}}}else{o=0}}}while(0);m=g;return o}Ie.X=1;function Je(b,c,d,f,g){var e=g*f|0,i=F[c+12>>2],h=(i|0)==1;a:do{if(h){Pc(b,0,e<<2)}else{var k=F[c+16>>2];if((k-3|0)>>>0<3){var l=y[c+36>>2]*d|0,l=l>>>0>>0?l:e,j=(k-4|0)>>>0<2?(y[c+32>>2]|0)==0?l:e-l|0:0}else{l=j=0}if(k==0){var k=b,l=i,j=y[c+20>>2],n=e,p=0,r=0;b:for(;;){for(var o=r>>>0>>0;;){if(p>>>0>>0&o){break}if(!o){break b}p=0}for(var o=j+(p<<2)|0,t=0;;){var s=r+t|0,u=F[o>>2];if(!(t>>>0>>0&s>>>0>>0)){break}y[k+(s<<2)>>2]=p;t=t+1|0}p=p+1|0;r=u+r|0}}else{if(k==1){k=b;l=i;j=f;n=g*j|0;r=(n|0)==0;b:do{if(!r){for(p=0;;){if(y[(k+(p<<2)|0)>>2]=((((Math.floor((p>>>0)/(j>>>0))*l|0)>>>1)+(p>>>0)%(j>>>0)|0)>>>0)%(l>>>0),p=p+1|0,(p|0)==(n|0)){break b}}}}while(0)}else{if(k==2){Ge(b,i,y[c+24>>2],y[c+28>>2],f,g)}else{if(k==3){He(b,y[c+32>>2],l,f,g)}else{if(k==4){k=b;l=y[c+32>>2];n=e;r=(n|0)==0;b:do{if(!r){p=1-l|0;for(o=0;;){if(y[k+(o<<2)>>2]=o>>>0>>0?l:p,o=o+1|0,(o|0)==(n|0)){break b}}}}while(0)}else{if(k==5){k=b;l=y[c+32>>2];n=f;r=g;p=(n|0)==0;b:do{if(!p){for(var o=(r|0)==0,t=1-l|0,w=s=0;;){if(!o){for(var v=0;;){if(y[k+(s+v*n<<2)>>2]=(w+v|0)>>>0>>0?l:t,v=v+1|0,(v|0)==(r|0)){break}}w=w+r|0}s=s+1|0;if((s|0)==(n|0)){break b}}}}while(0)}else{if((e|0)!=0){k=c+44|0;for(l=0;;){if(y[b+(l<<2)>>2]=y[y[k>>2]+(l<<2)>>2],l=l+1|0,(l|0)==(e|0)){break a}}}}}}}}}}}while(0)}Je.X=1;function vd(b,c,d,f){var g=(f|0)==0;do{if(!g){var e=F[b+4>>2],i=y[b+8>>2],h=Math.floor((f>>>0)/(e>>>0)),k=b|0,l=F[k>>2],j=(h|0)!=0;if(j){for(var n=e*(h*240-16)+(f<<4)-1|0,p=0;;){if(q[c+p|0]=q[l+(n+p)|0],p=p+1|0,(p|0)==21){break}}n=c+21|0}else{n=c}if(p=(h*e|0)!=(f|0)){var r=(f-(f>>>0)%(e>>>0))*240+(f<<4)-1|0,o=e<<4;q[d]=q[l+r|0];q[d+1|0]=q[l+(r+o)|0];q[d+2|0]=q[l+(r+(e<<5))|0];q[d+3|0]=q[l+(r+e*48)|0];q[d+4|0]=q[l+(r+(e<<6))|0];q[d+5|0]=q[l+(r+e*80)|0];q[d+6|0]=q[l+(r+e*96)|0];q[d+7|0]=q[l+(r+e*112)|0];q[d+8|0]=q[l+(r+(e<<7))|0];q[d+9|0]=q[l+(r+e*144)|0];q[d+10|0]=q[l+(r+e*160)|0];q[d+11|0]=q[l+(r+e*176)|0];q[d+12|0]=q[l+(r+e*192)|0];q[d+13|0]=q[l+(r+e*208)|0];q[d+14|0]=q[l+(r+e*224)|0];q[d+15|0]=q[l+(r+e*240)|0];l=d+16|0}else{l=d}k=F[k>>2];if(j){var j=h*56|0,r=f<<3,o=e<<3&2147483640,t=e*((i<<8)+j)+r-1-o|0;q[n]=q[k+t|0];q[n+1|0]=q[t+(k+1)|0];q[n+2|0]=q[t+(k+2)|0];q[n+3|0]=q[t+(k+3)|0];q[n+4|0]=q[t+(k+4)|0];q[n+5|0]=q[t+(k+5)|0];q[n+6|0]=q[t+(k+6)|0];q[n+7|0]=q[t+(k+7)|0];q[n+8|0]=q[t+(k+8)|0];j=e*(i*320+j)+r-9-o|0;q[n+9|0]=q[j+(k+8)|0];q[n+10|0]=q[j+(k+9)|0];q[n+11|0]=q[j+(k+10)|0];q[n+12|0]=q[j+(k+11)|0];q[n+13|0]=q[j+(k+12)|0];q[n+14|0]=q[j+(k+13)|0];q[n+15|0]=q[j+(k+14)|0];q[n+16|0]=q[j+(k+15)|0];q[n+17|0]=q[j+(k+16)|0]}if(p){var n=e<<3&2147483640,s=h*56|0,u=f<<3,w=e*((i<<8)+s)+u-1|0;q[l]=q[k+w|0];q[l+1|0]=q[k+(w+n)|0];h=e<<4;q[l+2|0]=q[k+(w+h)|0];p=n*3|0;q[l+3|0]=q[k+(w+p)|0];j=e<<5;q[l+4|0]=q[k+(w+j)|0];r=n*5|0;q[l+5|0]=q[k+(w+r)|0];o=n*6|0;q[l+6|0]=q[k+(w+o)|0];t=n*7|0;q[l+7|0]=q[k+(w+t)|0];e=t+(e*(i*320+s-64)+u+n-1)|0;q[l+8|0]=q[k+e|0];q[l+9|0]=q[k+(e+n)|0];q[l+10|0]=q[k+(e+h)|0];q[l+11|0]=q[k+(e+p)|0];q[l+12|0]=q[k+(e+j)|0];q[l+13|0]=q[k+(e+r)|0];q[l+14|0]=q[k+(e+o)|0];q[l+15|0]=q[k+(e+t)|0]}}}while(0)}vd.X=1;function Ke(b,c){for(var d=c+1|0,f=c+2|0,g=c+3|0,e=c+4|0,i=c+5|0,h=c+6|0,k=c+7|0,l=c+8|0,j=c+9|0,n=c+10|0,p=c+11|0,r=c+12|0,o=c+13|0,t=c+14|0,s=c+15|0,u=0;;){var w=u<<4,v=b+(w|1)|0,z=b+(w|2)|0,B=b+(w|3)|0,D=b+(w|4)|0,C=b+(w|5)|0,E=b+(w|6)|0,G=b+(w|7)|0,H=b+(w|8)|0,K=b+(w|9)|0,L=b+(w|10)|0,N=b+(w|11)|0,O=b+(w|12)|0,R=b+(w|13)|0,U=b+(w|14)|0,Y=b+(w|15)|0;q[b+w|0]=q[c];q[v]=q[d];q[z]=q[f];q[B]=q[g];q[D]=q[e];q[C]=q[i];q[E]=q[h];q[G]=q[k];q[H]=q[l];q[K]=q[j];q[L]=q[n];q[N]=q[p];q[O]=q[r];q[R]=q[o];q[U]=q[t];q[Y]=q[s];u=u+1|0;if((u|0)==16){break}}}Ke.X=1;function wd(b,c,d,f,g,e){var i=y[b+200>>2],h=ve(b,i),e=(e|0)==0,i=(h|0)==0|e?h:(dd(y[i>>2])|0)!=2?h:0,h=y[b+204>>2],k=ve(b,h),h=(k|0)==0|e?k:(dd(y[h>>2])|0)!=2?k:0,k=y[b+212>>2],l=ve(b,k),e=(l|0)==0|e?l:(dd(y[k>>2])|0)!=2?l:0,k=y[b>>2]+1&3;do{if(k==0){if((h|0)==0){var j=1,b=18;break}Ke(c,f+1|0)}else{if(k==1){if((i|0)==0){j=1;b=18;break}Le(c,g)}else{if(k==2){Me(c,f+1|0,g,i,h)}else{if((i|0)==0|(h|0)==0|(e|0)==0){j=1;b=18;break}Ne(c,f+1|0,g)}}}b=17}while(0);b==17&&(Oe(c,d|0,0),Oe(c,d+64|0,1),Oe(c,d+128|0,2),Oe(c,d+192|0,3),Oe(c,d+256|0,4),Oe(c,d+320|0,5),Oe(c,d+384|0,6),Oe(c,d+448|0,7),Oe(c,d+512|0,8),Oe(c,d+576|0,9),Oe(c,d+640|0,10),Oe(c,d+704|0,11),Oe(c,d+768|0,12),Oe(c,d+832|0,13),Oe(c,d+896|0,14),Oe(c,d+960|0,15),j=0);return j}wd.X=1;function xd(b,c,d,f,g,e){var i=m;m+=36;for(var h=i+12,e=(e|0)==0,k=i|0,l=h|0,j=i+20,h=h+1|0,n=i+1|0,p=i+4|0,r=i+5|0,o=0;;){var t=d+328+(o<<6)|0;if(o>>>0>=16){var s=0;break}var u=te+(o<<3)|0,w=ye(b,y[u>>2]),v=ve(b,w),v=(v|0)==0|e?v:(dd(y[w>>2])|0)!=2?v:0,z=ue+(o<<3)|0,B=z|0,B=ye(b,y[B>>2]),D=ve(b,B),D=(D|0)==0|e?D:(dd(y[B>>2])|0)!=2?D:0,C=(v|0)!=0;(C&(D|0)!=0&1|0)==0?u=2:(u=(dd(y[w>>2])|0)==0?A[w+82+(y[u+4>>2]&255)|0]&255:2,w=(dd(y[B>>2])|0)==0?A[B+82+(y[(z+4|0)>>2]&255)|0]&255:2,u=u>>>0>>0?u:w);(y[d+12+(o<<2)>>2]|0)==0&&(w=F[d+76+(o<<2)>>2],u=(w>>>0>=u>>>0&1)+w|0);q[b+(o+82)|0]=u&255;w=ye(b,y[(Pe+(o<<3)|0)>>2]);z=ve(b,w);w=(z|0)==0|e?z:(dd(y[w>>2])|0)!=2?z:0;B=Qe+(o<<3)|0;z=ye(b,y[B>>2]);B=ve(b,z);z=(B|0)==0|e?B:(dd(y[z>>2])|0)!=2?B:0;Re(k,l,c,f,g,o);if(u==0){if((D|0)==0){s=1;break}v=j;D=n;C=q[D];u=q[D+1|0];q[v+12|0]=C;q[v+8|0]=C;q[v+4|0]=C;q[v]=C;q[v+13|0]=u;q[v+9|0]=u;q[v+5|0]=u;q[v+1|0]=u;C=q[D+2|0];D=q[D+3|0];q[v+14|0]=C;q[v+10|0]=C;q[v+6|0]=C;q[v+2|0]=C;q[v+15|0]=D;q[v+11|0]=D;q[v+7|0]=D;q[v+3|0]=D}else{if(u==1){if(!C){s=1;break}v=j;C=h;u=q[C+1|0];kc(v,q[C],4);D=C+2|0;kc(v+4|0,u,4);C=q[C+3|0];kc(v+8|0,q[D],4);kc(v+12|0,C,4)}else{if(u==2){Se(j,n,h,v,D)}else{if(u==3){if((D|0)==0){s=1;break}(w|0)==0&&kc(r,q[p],4);Te(j,n)}else{if(u==4){if((D|0)==0|C^1|(z|0)==0){s=1;break}Ue(j,n,h)}else{if(u==5){if((D|0)==0|C^1|(z|0)==0){s=1;break}Ve(j,n,h)}else{if(u==6){if((D|0)==0|C^1|(z|0)==0){s=1;break}We(j,n,h)}else{if(u==7){if((D|0)==0){s=1;break}(w|0)==0&&kc(r,q[p],4);Xe(j,n)}else{if(!C){s=1;break}Ye(j,h)}}}}}}}}v=c;u=j;D=(y[Ze+(o<<2)>>2]<<4)+y[$e+(o<<2)>>2]|0;w=u+4|0;y[(v+D|0)>>2]=y[u>>2];C=u+8|0;y[(D+(v+16)|0)>>2]=y[w>>2];u=u+12|0;y[(D+(v+32)|0)>>2]=y[C>>2];y[(D+(v+48)|0)>>2]=y[u>>2];Oe(c,t,o);o=o+1|0}m=i;return s}xd.X=1;function yd(b,c,d,f,g,e,i){for(var h=y[b+200>>2],k=ve(b,h),l=(i|0)==0,h=(k|0)==0|l?k:(dd(y[h>>2])|0)!=2?k:0,k=y[b+204>>2],i=ve(b,k),k=(i|0)==0|l?i:(dd(y[k>>2])|0)!=2?i:0,j=y[b+212>>2],n=ve(b,j),b=(h|0)==0,i=(k|0)==0,l=b|i|(((n|0)==0|l?n:(dd(y[j>>2])|0)!=2?n:0)|0)==0,j=0;;){var p=j<<2,n=d+(p<<6)|0,r=d+((p|3)<<6)|0,o=d+((p|2)<<6)|0,t=d+((p|1)<<6)|0,s=p+16|0,u=p+19|0,w=p+18|0,p=p+17|0,v=g+(j<<3)|0,z=f+(j*9+1)|0,B=c+(j<<6)|0;if(j>>>0>=2){var D=0;break}if(e==0){af(B,z,v,h,k)}else{if(e==1){if(b){D=1;break}for(var C=B,z=0;;){var E=z<<3,G=C+(E|1)|0,H=C+(E|2)|0,K=C+(E|3)|0,L=C+(E|4)|0,N=C+(E|5)|0,O=C+(E|6)|0,R=C+(E|7)|0,U=v+z|0;q[C+E|0]=q[U];q[G]=q[U];q[H]=q[U];q[K]=q[U];q[L]=q[U];q[N]=q[U];q[O]=q[U];q[R]=q[U];z=z+1|0;if((z|0)==8){break}}}else{if(e==2){if(i){D=1;break}C=B;v=z;for(z=0;;){if(E=z+(C+8)|0,G=z+(C+16)|0,H=z+(C+24)|0,K=z+(C+32)|0,L=z+(C+40)|0,N=z+(C+48)|0,O=z+(C+56)|0,R=v+z|0,q[C+z|0]=q[R],q[E]=q[R],q[G]=q[R],q[H]=q[R],q[K]=q[R],q[L]=q[R],q[N]=q[R],q[O]=q[R],z=z+1|0,(z|0)==8){break}}}else{if(l){D=1;break}bf(B,z,v)}}}Oe(B,n,s);Oe(B,t,p);Oe(B,o,w);Oe(B,r,u);j=j+1|0}return D}yd.X=1;function Le(b,c){for(var d=0;;){var f=d<<4,g=c+d|0,e=b+(f|1)|0,i=b+(f|2)|0,h=b+(f|3)|0,k=b+(f|4)|0,l=b+(f|5)|0,j=b+(f|6)|0,n=b+(f|7)|0,p=b+(f|8)|0,r=b+(f|9)|0,o=b+(f|10)|0,t=b+(f|11)|0,s=b+(f|12)|0,u=b+(f|13)|0,w=b+(f|14)|0,v=b+(f|15)|0;q[b+f|0]=q[g];q[e]=q[g];q[i]=q[g];q[h]=q[g];q[k]=q[g];q[l]=q[g];q[j]=q[g];q[n]=q[g];q[p]=q[g];q[r]=q[g];q[o]=q[g];q[t]=q[g];q[s]=q[g];q[u]=q[g];q[w]=q[g];q[v]=q[g];d=d+1|0;if((d|0)==16){break}}}Le.X=1;function Ne(b,c,d){for(var f=A[c-1|0]&255,g=A[c+15|0]&255,e=A[d+15|0]&255,c=((g-f<<3)+(((A[c+14|0]&255)-(A[c]&255))*7+(((A[c+13|0]&255)-(A[c+1|0]&255))*6+(((A[c+12|0]&255)-(A[c+2|0]&255))*5+(((A[c+11|0]&255)-(A[c+3|0]&255)<<2)+(((A[c+10|0]&255)-(A[c+4|0]&255))*3+(((A[c+9|0]&255)-(A[c+5|0]&255)<<1)+((A[c+8|0]&255)-(A[c+6|0]&255)))))))))*5+32>>6,d=((e-f<<3)+(((A[d+14|0]&255)-(A[d]&255))*7+(((A[d+13|0]&255)-(A[d+1|0]&255))*6+(((A[d+12|0]&255)-(A[d+2|0]&255))*5+(((A[d+11|0]&255)-(A[d+3|0]&255)<<2)+(((A[d+10|0]&255)-(A[d+4|0]&255))*3+(((A[d+9|0]&255)-(A[d+5|0]&255)<<1)+((A[d+8|0]&255)-(A[d+6|0]&255)))))))))*5+32>>6,g=(e+g<<4)+16+d*-7+c*-7|0,e=0;;){for(var f=e<<4,i=g+d*e|0,h=0;;){var k=i+c*h>>5;q[b+(f+h)|0]=(k|0)<0?0:(k|0)>255?-1:k&255;h=h+1|0;if((h|0)==16){break}}e=e+1|0;if((e|0)==16){break}}}Ne.X=1;function Oe(b,c,d){var f=(y[c>>2]|0)==16777215;a:do{if(!f){for(var g=d>>>0<16,e=g?d:d&3,g=g?16:8,e=y[$e+(e<<2)>>2]+g*y[Ze+(e<<2)>>2]|0,i=e+1|0,h=e+2|0,k=e+3|0,l=0;;){var j=g*l|0,n=b+(i+j)|0,p=b+(h+j)|0,r=b+(k+j)|0,o=b+(e+j)|0,t=l<<2,s=c+((t|2)<<2)|0,j=c+((t|3)<<2)|0,u=y[c+((t|1)<<2)>>2],w=A[n]&255;q[o]=q[Q.a+(y[c+(t<<2)>>2]+512+(A[o]&255))|0];o=y[s>>2];t=A[p]&255;q[n]=q[Q.a+(w+(u+512))|0];n=q[Q.a+(y[j>>2]+512+(A[r]&255))|0];q[p]=q[Q.a+(t+(o+512))|0];q[r]=n;l=l+1|0;if((l|0)==4){break a}}}}while(0)}Oe.X=1;function Re(b,c,d,f,g,e){var i=F[$e+(e<<2)>>2],h=F[Ze+(e<<2)>>2],k=(1285>>>(e>>>0)&1|0)!=0;if(k){var l=q[h+(g+1)|0];q[c+1|0]=q[g+h|0];q[c+2|0]=l;l=q[h+(g+3)|0];q[c+3|0]=q[h+(g+2)|0];q[c+4|0]=l}else{var l=(h<<4)+i|0,j=q[l+(d+15)|0];q[c+1|0]=q[d+(l-1)|0];q[c+2|0]=j;j=q[l+(d+47)|0];q[c+3|0]=q[l+(d+31)|0];q[c+4|0]=j}(51>>>(e>>>0)&1|0)==0?(f=h-1|0,i=(f<<4)+i|0,e=q[i+(d+1)|0],q[b+1|0]=q[d+i|0],q[b+2|0]=e,e=q[i+(d+3)|0],q[b+3|0]=q[i+(d+2)|0],q[b+4|0]=e,e=q[i+(d+5)|0],q[b+5|0]=q[i+(d+4)|0],q[b+6|0]=e,e=q[i+(d+7)|0],q[b+7|0]=q[i+(d+6)|0],q[b+8|0]=e,d=k?q[g+f|0]:q[d+(i-1)|0],q[b]=d,q[c]=d):(d=q[f+i|0],q[c]=d,q[b]=d,c=q[i+(f+2)|0],q[b+1|0]=q[i+(f+1)|0],q[b+2|0]=c,c=q[i+(f+4)|0],q[b+3|0]=q[i+(f+3)|0],q[b+4|0]=c,c=q[i+(f+6)|0],q[b+5|0]=q[i+(f+5)|0],q[b+6|0]=c,c=q[i+(f+8)|0],q[b+7|0]=q[i+(f+7)|0],q[b+8|0]=c)}Re.X=1;function Me(b,c,d,f,g){var f=(f|0)!=0,g=(g|0)==0,e=g|f^1;do{if(e){var i=f?((A[d+15|0]&255)+((A[d+14|0]&255)+((A[d+13|0]&255)+((A[d+12|0]&255)+((A[d+11|0]&255)+((A[d+10|0]&255)+((A[d+9|0]&255)+((A[d+8|0]&255)+((A[d+7|0]&255)+((A[d+6|0]&255)+((A[d+5|0]&255)+((A[d+4|0]&255)+((A[d+3|0]&255)+((A[d+2|0]&255)+((A[d+1|0]&255)+(A[d]&255)))))))))))))))+8|0)>>>4:g?128:((A[c+15|0]&255)+((A[c+14|0]&255)+((A[c+13|0]&255)+((A[c+12|0]&255)+((A[c+11|0]&255)+((A[c+10|0]&255)+((A[c+9|0]&255)+((A[c+8|0]&255)+((A[c+7|0]&255)+((A[c+6|0]&255)+((A[c+5|0]&255)+((A[c+4|0]&255)+((A[c+3|0]&255)+((A[c+2|0]&255)+((A[c+1|0]&255)+(A[c]&255)))))))))))))))+8|0)>>>4}else{for(var h=i=0;;){var k=(A[c+i|0]&255)+h+(A[d+i|0]&255)|0,i=i+1|0;if((i|0)==16){break}h=k}i=(k+16|0)>>>5}}while(0);kc(b,i&255,256)}Me.X=1;function Se(b,c,d,f,g){f=(f|0)!=0;g=(g|0)==0;kc(b,(g|f^1?f?(A[d]&255)+2+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)>>2:g?128:(A[c]&255)+2+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)>>2:((A[c]&255)+4+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)+(A[d]&255)+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)|0)>>>3)&255,16)}Se.X=1;function Te(b,c){var d=c+1|0,f=c+2|0;q[b]=((A[c]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;var g=c+3|0;q[b+1|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;d=c+4|0;q[b+2|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+5|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+8|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;f=c+5|0;q[b+3|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+9|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;g=c+6|0;q[b+7|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+10|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;d=c+7|0;q[b+11|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[g]&255)+2+(A[d]&255)*3|0)>>>2&255}Te.X=1;function Ue(b,c,d){var f=c-1|0;q[b]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+5|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+10|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;var g=c+1|0;q[b+1|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+11|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;f=c+2|0;q[b+2|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+7|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+3|0]=((A[g]&255)+2+(A[c+3|0]&255)+((A[f]&255)<<1)|0)>>>2&255;g=d-1|0;c=d+1|0;q[b+4|0]=((A[g]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+9|0]=((A[g]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[g]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255;g=d+2|0;q[b+8|0]=((A[d]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[d]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[c]&255)+2+(A[d+3|0]&255)+((A[g]&255)<<1)|0)>>>2&255}Ue.X=1;function Ve(b,c,d){var f=c-1|0;q[b]=((A[f]&255)+1+(A[c]&255)|0)>>>1&255;q[b+9|0]=((A[f]&255)+1+(A[c]&255)|0)>>>1&255;var g=c+1|0;q[b+5|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+1|0]=((A[c]&255)+1+(A[g]&255)|0)>>>1&255;q[b+10|0]=((A[c]&255)+1+(A[g]&255)|0)>>>1&255;f=c+2|0;q[b+6|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+2|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;q[b+11|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;c=c+3|0;q[b+7|0]=((A[g]&255)+2+(A[c]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+3|0]=((A[f]&255)+1+(A[c]&255)|0)>>>1&255;g=d+1|0;q[b+8|0]=((A[g]&255)+2+(A[d-1|0]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[d+2|0]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255}Ve.X=1;function We(b,c,d){var f=d-1|0;q[b]=((A[f]&255)+1+(A[d]&255)|0)>>>1&255;q[b+6|0]=((A[f]&255)+1+(A[d]&255)|0)>>>1&255;var g=d+1|0;q[b+5|0]=((A[f]&255)+2+(A[g]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+11|0]=((A[f]&255)+2+(A[g]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[d]&255)+1+(A[g]&255)|0)>>>1&255;q[b+10|0]=((A[d]&255)+1+(A[g]&255)|0)>>>1&255;f=d+2|0;q[b+9|0]=((A[d]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[d]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+8|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;q[b+14|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;var e=d+3|0;q[b+13|0]=((A[g]&255)+2+(A[e]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[f]&255)+1+(A[e]&255)|0)>>>1&255;g=c-1|0;q[b+1|0]=((A[c]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+7|0]=((A[c]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;d=c+1|0;q[b+2|0]=((A[d]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+3|0]=((A[c+2|0]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255}We.X=1;function Xe(b,c){var d=c+1|0;q[b]=((A[c]&255)+1+(A[d]&255)|0)>>>1&255;var f=c+2|0;q[b+1|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;var g=c+3|0;q[b+2|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;var e=c+4|0;q[b+3|0]=((A[g]&255)+1+(A[e]&255)|0)>>>1&255;q[b+4|0]=((A[c]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+5|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[f]&255)+2+(A[e]&255)+((A[g]&255)<<1)|0)>>>2&255;var i=c+5|0;q[b+7|0]=((A[g]&255)+2+(A[i]&255)+((A[e]&255)<<1)|0)>>>2&255;q[b+8|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;q[b+9|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;q[b+10|0]=((A[g]&255)+1+(A[e]&255)|0)>>>1&255;q[b+11|0]=((A[e]&255)+1+(A[i]&255)|0)>>>1&255;q[b+12|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[f]&255)+2+(A[e]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[g]&255)+2+(A[i]&255)+((A[e]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[e]&255)+2+(A[c+6|0]&255)+((A[i]&255)<<1)|0)>>>2&255}Xe.X=1;function Ye(b,c){var d=c+1|0;q[b]=((A[c]&255)+1+(A[d]&255)|0)>>>1&255;var f=c+2|0;q[b+1|0]=((A[c]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+2|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;var g=c+3|0;q[b+3|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;q[b+5|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;q[b+7|0]=((A[f]&255)+2+(A[g]&255)*3|0)>>>2&255;q[b+8|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;q[b+9|0]=((A[f]&255)+2+(A[g]&255)*3|0)>>>2&255;q[b+10|0]=q[g];q[b+11|0]=q[g];q[b+12|0]=q[g];q[b+13|0]=q[g];q[b+14|0]=q[g];q[b+15|0]=q[g]}Ye.X=1;function bf(b,c,d){for(var f=A[c+7|0]&255,g=A[d+7|0]&255,e=A[c-1|0]&255,c=((A[c+4|0]&255)-(A[c+2|0]&255)+((A[c+5|0]&255)-(A[c+1|0]&255)<<1)+((A[c+6|0]&255)-(A[c]&255))*3+(f-e<<2))*17+16|0,i=c>>5,d=((g-e<<2)+(A[d+4|0]&255)-(A[d+2|0]&255)+((A[d+5|0]&255)-(A[d+1|0]&255)<<1)+((A[d+6|0]&255)-(A[d]&255))*3)*17+16>>5,h=g+f<<4,k=d*3|0,f=h+(c>>3&-4)+16-k|0,l=i*3|0,g=l+(h+16)-k|0,j=c>>4&-2,c=j+(h+16)-k|0,e=h+(i+16)-k|0,n=h+16|0,h=n-k|0,i=n-i-k|0,k=n-j-k|0,l=h-l|0,j=0;;){var n=j<<3,p=b+(n|1)|0,r=b+(n|2)|0,o=b+(n|3)|0,t=b+(n|4)|0,s=b+(n|5)|0,u=b+(n|6)|0,w=b+(n|7)|0,v=d*j|0,z=f+v|0,B=g+v|0,D=c+v|0,C=e+v|0,E=h+v|0,G=i+v|0,H=k+v|0;q[b+n|0]=q[Q.a+((l+v>>5)+512)|0];q[p]=q[Q.a+((H>>5)+512)|0];q[r]=q[Q.a+((G>>5)+512)|0];q[o]=q[Q.a+((E>>5)+512)|0];q[t]=q[Q.a+((C>>5)+512)|0];q[s]=q[Q.a+((D>>5)+512)|0];q[u]=q[Q.a+((B>>5)+512)|0];q[w]=q[Q.a+((z>>5)+512)|0];j=j+1|0;if((j|0)==8){break}}}bf.X=1;function af(b,c,d,f,g){f=(f|0)!=0;g=(g|0)==0;if(g|f^1){if(g){if(f){var e=(A[d]&255)+2+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)>>2,i=e}else{var i=128,e=128}}else{i=(A[c+4|0]&255)+2+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)>>2,e=(A[c]&255)+2+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)>>2}}else{i=(A[c+4|0]&255)+2+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)>>2,e=((A[c]&255)+4+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)+(A[d]&255)+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)|0)>>>3}e&=255;i&=255;var h=b+4|0;kc(b,e,4);var k=b+8|0,l=b+12|0;kc(h,i,4);kc(k,e,4);k=b+16|0;h=b+20|0;kc(l,i,4);kc(k,e,4);l=b+24|0;k=b+28|0;kc(h,i,4);kc(l,e,4);kc(k,i,4);f?(f=A[d+4|0]&255,e=A[d+5|0]&255,i=A[d+6|0]&255,l=A[d+7|0]&255,d=l+(i+(e+(f+2)))>>2,g=g?d:(l+(i+(e+(f+4)))+(A[c+4|0]&255)+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)|0)>>>3,c=d):g?c=g=128:(g=(A[c+4|0]&255)+2+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)>>2,c=(A[c]&255)+2+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)>>2);c&=255;d=g&255;f=b+36|0;kc(b+32|0,c,4);e=b+40|0;g=b+44|0;kc(f,d,4);kc(e,c,4);e=b+48|0;f=b+52|0;kc(g,d,4);kc(e,c,4);g=b+56|0;b=b+60|0;kc(f,d,4);kc(g,c,4);kc(b,d,4)}af.X=1;function ud(b,c,d,f,g,e){var i=m;m+=24;var h,k=F[g+4>>2],l=Math.floor((f>>>0)/(k>>>0)),j=l<<4,l=f-l*k<<4;y[i+4>>2]=k;y[i+8>>2]=y[g+8>>2];var k=b|0,n=y[k>>2];a:do{if(n==0||n==1){if((cf(b,c+12|0,d)|0)!=0){var p=1;h=19}else{y[i>>2]=y[b+116>>2],df(e,b+132|0,i,l,j,0,0,16,16),h=15}}else{if(n==2){(ef(b,c+12|0,d)|0)!=0?(p=1,h=19):(h=i|0,y[h>>2]=y[b+116>>2],df(e,b+132|0,i,l,j,0,0,16,8),y[h>>2]=y[b+124>>2],df(e,b+164|0,i,l,j,0,8,16,8),h=15)}else{if(n==3){(ff(b,c+12|0,d)|0)!=0?(p=1,h=19):(h=i|0,y[h>>2]=y[b+116>>2],df(e,b+132|0,i,l,j,0,0,8,16),y[h>>2]=y[b+120>>2],df(e,b+148|0,i,l,j,8,0,8,16),h=15)}else{var r=b,o=c+176|0,t=d,s=0;b:for(;;){var u=o+16+(s<<2)|0;if(s>>>0>=4){var w=0;break}var v=r+116+(s<<2)|0,z=y[o+(s<<2)>>2]==0?1:y[o+(s<<2)>>2]==1||y[o+(s<<2)>>2]==2?2:4;y[(r+100+(s<<2)|0)>>2]=y[u>>2];u=gf(t,y[u>>2]);y[v>>2]=u;if((u|0)==0){w=1;break}for(v=0;;){if(v>>>0>=z>>>0){break}if((hf(r,o,s,v)|0)!=0){w=1;break b}v=v+1|0}s=s+1|0}if((w|0)!=0){p=1,h=19}else{r=i|0;for(o=0;;){var B=c+176+(o<<2)|0,v=o<<3,u=o<<2,s=b+132+((u|1)<<2)|0,z=b+132+(u<<2)|0,t=b+132+((u|2)<<2)|0;y[r>>2]=y[b+116+(o<<2)>>2];var D=y[B>>2];v&=8;B=o>>>0<2?0:8;D==0?df(e,z,i,l,j,v,B,8,8):D==1?(df(e,z,i,l,j,v,B,8,4),df(e,t,i,l,j,v,B|4,8,4)):D==2?(df(e,z,i,l,j,v,B,4,8),df(e,s,i,l,j,v|4,B,4,8)):(u=b+132+((u|3)<<2)|0,df(e,z,i,l,j,v,B,4,4),z=v|4,df(e,s,i,l,j,z,B,4,4),s=B|4,df(e,t,i,l,j,v,s,4,4),df(e,u,i,l,j,z,s,4,4));o=o+1|0;if((o|0)==4){h=15;break a}}}}}}}while(0);h==15&&(F[b+196>>2]>>>0>1||((y[k>>2]|0)==0?rd(g,e):jf(g,f,e,c+328|0)),p=0);m=i;return p}ud.X=1;function cf(b,c,d){var f=m;m+=40;var g,e=f+4,i=F[c+132>>2],h=b+4|0,k=e|0;kf(y[h>>2],y[b+200>>2],k,5);kf(y[h>>2],y[b+204>>2],e+12|0,10);g=e+8|0;var l=e+20|0;if((y[b>>2]|0)==0){if((y[e>>2]|0)==0){var j=0,n=0;g=11}else{(y[e+12>>2]|0)==0?(n=j=0,g=11):(y[e+4>>2]|0)==0&&(y[g>>2]|0)==0?(n=j=0,g=11):(y[e+16>>2]|0)!=0?g=7:(y[l>>2]|0)==0?(n=j=0,g=11):g=7}}else{g=7}if(g==7){if(g=x[c+148>>1],c=x[c+150>>1],l=e+24|0,kf(y[h>>2],y[b+208>>2],l,10),(y[e+24>>2]|0)==0&&kf(y[h>>2],y[b+212>>2],l,15),lf(f,k,i),e=x[f>>1]+g&65535,h=x[f+2>>1]+c&65535,((e<<16>>16)+8192|0)>>>0>16383){var p=1;g=13}else{((h<<16>>16)+2048|0)>>>0>4095?(p=1,g=13):(j=e,n=h,g=11)}}if(g==11){if(d=gf(d,i),(d|0)==0){p=1}else{p=b+132|0;e=b+136|0;h=b+140|0;k=b+144|0;c=b+148|0;g=b+152|0;var l=b+156|0,r=b+160|0,o=b+164|0,t=b+168|0,s=b+172|0,u=b+176|0,w=b+180|0,v=b+184|0,z=b+188|0,B=b+192|0;x[b+192>>1]=j;x[b+194>>1]=n;J=j=Gb[B>>1]+(Gb[B+2>>1]<<16);x[z>>1]=J&65535;x[z+2>>1]=J>>16;J=j;x[v>>1]=J&65535;x[v+2>>1]=J>>16;J=j;x[w>>1]=J&65535;x[w+2>>1]=J>>16;J=j;x[u>>1]=J&65535;x[u+2>>1]=J>>16;J=j;x[s>>1]=J&65535;x[s+2>>1]=J>>16;J=j;x[t>>1]=J&65535;x[t+2>>1]=J>>16;J=j;x[o>>1]=J&65535;x[o+2>>1]=J>>16;J=j;x[r>>1]=J&65535;x[r+2>>1]=J>>16;J=j;x[l>>1]=J&65535;x[l+2>>1]=J>>16;J=j;x[g>>1]=J&65535;x[g+2>>1]=J>>16;J=j;x[c>>1]=J&65535;x[c+2>>1]=J>>16;J=j;x[k>>1]=J&65535;x[k+2>>1]=J>>16;J=j;x[h>>1]=J&65535;x[h+2>>1]=J>>16;J=j;x[e>>1]=J&65535;x[e+2>>1]=J>>16;J=j;x[p>>1]=J&65535;x[p+2>>1]=J>>16;y[b+100>>2]=i;y[b+104>>2]=i;y[b+108>>2]=i;y[b+112>>2]=i;y[b+116>>2]=d;y[b+120>>2]=d;y[b+124>>2]=d;y[b+128>>2]=d;p=0}}m=f;return p}cf.X=1;function ef(b,c,d){var f=m;m+=4;var g=m;m+=36;var e=x[c+148>>1],i=x[c+150>>1],h=F[c+132>>2],k=b+4|0,l=g|0;kf(y[k>>2],y[b+204>>2],g+12|0,10);var j=g+16|0;if((y[j>>2]|0)==(h|0)){var n=F[g+20>>2];y[f>>2]=n;var p=n&65535,r=n>>>16&65535,n=f,o=f+2|0}else{kf(y[k>>2],y[b+200>>2],l,5),n=g+24|0,kf(y[k>>2],y[b+208>>2],n,10),(y[g+24>>2]|0)==0&&kf(y[k>>2],y[b+212>>2],n,15),lf(f,l,h),o=f+2|0,p=x[f>>1],r=x[o>>1],n=f}var e=p+e&65535,t=r+i&65535;if(((e<<16>>16)+8192|0)>>>0>16383){b=1}else{if(((t<<16>>16)+2048|0)>>>0>4095){b=1}else{if(p=gf(d,h),(p|0)==0){b=1}else{var i=b+132|0,r=b+136|0,s=b+140|0,u=b+144|0,w=b+148|0,v=b+152|0,z=b+156|0,B=b+160|0;x[b+160>>1]=e;x[b+162>>1]=t;J=e=Gb[B>>1]+(Gb[B+2>>1]<<16);x[z>>1]=J&65535;x[z+2>>1]=J>>16;J=e;x[v>>1]=J&65535;x[v+2>>1]=J>>16;J=e;x[w>>1]=J&65535;x[w+2>>1]=J>>16;J=e;x[u>>1]=J&65535;x[u+2>>1]=J>>16;J=e;x[s>>1]=J&65535;x[s+2>>1]=J>>16;J=e;x[r>>1]=J&65535;x[r+2>>1]=J>>16;J=e;x[i>>1]=J&65535;x[i+2>>1]=J>>16;r=b+100|0;y[r>>2]=h;y[b+104>>2]=h;y[b+116>>2]=p;y[b+120>>2]=p;e=x[c+152>>1];h=x[c+154>>1];c=F[c+136>>2];p=b+200|0;kf(y[k>>2],y[p>>2],l,13);(y[g+4>>2]|0)==(c|0)?(k=F[g+8>>2],y[f>>2]=k,g=k&65535,k=k>>>16&65535):(y[g+12>>2]=1,y[j>>2]=y[r>>2],y[g+20>>2]=Gb[i>>1]+(Gb[i+2>>1]<<16),kf(y[k>>2],y[p>>2],g+24|0,7),lf(f,l,c),g=x[n>>1],k=x[o>>1]);g=g+e&65535;k=k+h&65535;((g<<16>>16)+8192|0)>>>0>16383?b=1:((k<<16>>16)+2048|0)>>>0>4095?b=1:(d=gf(d,c),(d|0)==0?b=1:(l=b+164|0,j=b+168|0,n=b+172|0,o=b+176|0,h=b+180|0,i=b+184|0,e=b+188|0,p=b+192|0,x[b+192>>1]=g,x[b+194>>1]=k,J=g=Gb[p>>1]+(Gb[p+2>>1]<<16),x[e>>1]=J&65535,x[e+2>>1]=J>>16,J=g,x[i>>1]=J&65535,x[i+2>>1]=J>>16,J=g,x[h>>1]=J&65535,x[h+2>>1]=J>>16,J=g,x[o>>1]=J&65535,x[o+2>>1]=J>>16,J=g,x[n>>1]=J&65535,x[n+2>>1]=J>>16,J=g,x[j>>1]=J&65535,x[j+2>>1]=J>>16,J=g,x[l>>1]=J&65535,x[l+2>>1]=J>>16,y[b+108>>2]=c,y[b+112>>2]=c,y[b+124>>2]=d,y[b+128>>2]=d,b=0))}}}m=f;return b}ef.X=1;function ff(b,c,d){var f=m;m+=4;var g=m;m+=36;var e=x[c+148>>1],i=x[c+150>>1],h=F[c+132>>2],k=b+4|0,l=g|0;kf(y[k>>2],y[b+200>>2],l,5);var j=g+4|0;if((y[j>>2]|0)==(h|0)){var n=F[g+8>>2];y[f>>2]=n;var p=n&65535,r=n>>>16&65535,n=f,o=f+2|0}else{n=b+204|0,kf(y[k>>2],y[n>>2],g+12|0,10),o=g+24|0,kf(y[k>>2],y[n>>2],o,14),(y[g+24>>2]|0)==0&&kf(y[k>>2],y[b+212>>2],o,15),lf(f,l,h),o=f+2|0,p=x[f>>1],r=x[o>>1],n=f}var e=p+e&65535,t=r+i&65535;if(((e<<16>>16)+8192|0)>>>0>16383){b=1}else{if(((t<<16>>16)+2048|0)>>>0>4095){b=1}else{if(p=gf(d,h),(p|0)==0){b=1}else{var i=b+132|0,r=b+136|0,s=b+140|0,u=b+144|0,w=b+164|0,v=b+168|0,z=b+172|0,B=b+176|0;x[b+176>>1]=e;x[b+178>>1]=t;J=e=Gb[B>>1]+(Gb[B+2>>1]<<16);x[z>>1]=J&65535;x[z+2>>1]=J>>16;J=e;x[v>>1]=J&65535;x[v+2>>1]=J>>16;J=e;x[w>>1]=J&65535;x[w+2>>1]=J>>16;J=e;x[u>>1]=J&65535;x[u+2>>1]=J>>16;J=e;x[s>>1]=J&65535;x[s+2>>1]=J>>16;J=e;x[r>>1]=J&65535;x[r+2>>1]=J>>16;J=e;x[i>>1]=J&65535;x[i+2>>1]=J>>16;r=b+100|0;y[r>>2]=h;y[b+108>>2]=h;y[b+116>>2]=p;y[b+124>>2]=p;e=x[c+152>>1];h=x[c+154>>1];c=F[c+136>>2];p=g+24|0;kf(y[k>>2],y[b+208>>2],p,10);(y[g+24>>2]|0)==0&&kf(y[k>>2],y[b+204>>2],p,11);(y[g+28>>2]|0)==(c|0)?(k=F[g+32>>2],y[f>>2]=k,g=k&65535,k=k>>>16&65535):(y[g>>2]=1,y[j>>2]=y[r>>2],y[g+8>>2]=Gb[i>>1]+(Gb[i+2>>1]<<16),kf(y[k>>2],y[b+204>>2],g+12|0,14),lf(f,l,c),g=x[n>>1],k=x[o>>1]);g=g+e&65535;k=k+h&65535;((g<<16>>16)+8192|0)>>>0>16383?b=1:((k<<16>>16)+2048|0)>>>0>4095?b=1:(d=gf(d,c),(d|0)==0?b=1:(l=b+148|0,j=b+152|0,n=b+156|0,o=b+160|0,h=b+180|0,i=b+184|0,e=b+188|0,p=b+192|0,x[b+192>>1]=g,x[b+194>>1]=k,J=g=Gb[p>>1]+(Gb[p+2>>1]<<16),x[e>>1]=J&65535,x[e+2>>1]=J>>16,J=g,x[i>>1]=J&65535,x[i+2>>1]=J>>16,J=g,x[h>>1]=J&65535,x[h+2>>1]=J>>16,J=g,x[o>>1]=J&65535,x[o+2>>1]=J>>16,J=g,x[n>>1]=J&65535,x[n+2>>1]=J>>16,J=g,x[j>>1]=J&65535,x[j+2>>1]=J>>16,J=g,x[l>>1]=J&65535,x[l+2>>1]=J>>16,y[b+104>>2]=c,y[b+112>>2]=c,y[b+120>>2]=d,y[b+128>>2]=d,b=0))}}}m=f;return b}ff.X=1;function mf(b,c,d){if((c|0)>(b|0)){var f=b,b=c}else{f=(c|0)<(b|0)?c:b}return(b|0)<(d|0)?b:(f|0)>(d|0)?f:d}function kf(b,c,d,f){var g=d|0;y[g>>2]=0;var e=d+4|0;y[e>>2]=-1;var i=d+10|0;x[i>>1]=0;d=d+8|0;x[d>>1]=0;(c|0)!=0&&(y[c+4>>2]|0)==(b|0)&&(b=F[c>>2],y[g>>2]=1,b>>>0<6&&(g=x[c+132+(f<<2)>>1],b=x[c+132+(f<<2)+2>>1],y[e>>2]=y[c+100+(f>>>2<<2)>>2],x[d>>1]=g,x[i>>1]=b))}function hf(b,c,d,f){var g=m;m+=40;var e=g+4,i=x[c+32+(d<<4)+(f<<2)>>1],h=x[c+32+(d<<4)+(f<<2)+2>>1],k=y[c+(d<<2)>>2],c=y[c+16+(d<<2)>>2],l=b+4|0,j=e|0;kf(y[l>>2],ye(b,y[nf+(d<<7)+(k<<5)+(f<<3)>>2]),j,A[nf+(d<<7)+(k<<5)+(f<<3)+4|0]&255);kf(y[l>>2],ye(b,y[of+(d<<7)+(k<<5)+(f<<3)>>2]),e+12|0,A[of+(d<<7)+(k<<5)+(f<<3)+4|0]&255);var n=e+24|0;kf(y[l>>2],ye(b,y[pf+(d<<7)+(k<<5)+(f<<3)>>2]),n,A[pf+(d<<7)+(k<<5)+(f<<3)+4|0]&255);(y[e+24>>2]|0)==0&&kf(y[l>>2],ye(b,y[qf+(d<<7)+(k<<5)+(f<<3)>>2]),n,A[qf+(d<<7)+(k<<5)+(f<<3)+4|0]&255);lf(g,j,c);e=x[g>>1]+i&65535;h=x[g+2>>1]+h&65535;((e<<16>>16)+8192|0)>>>0>16383?b=1:((h<<16>>16)+2048|0)>>>0>4095?b=1:(k==0?(d<<=2,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h,f=d|1,x[b+132+(f<<2)>>1]=e,x[b+132+(f<<2)+2>>1]=h,f=d|2,x[b+132+(f<<2)>>1]=e,x[b+132+(f<<2)+2>>1]=h,d|=3,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h):k==1?(d=(f<<1)+(d<<2)|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h,d|=1,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h):k==2?(d=(d<<2)+f|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h,d=d+2|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h):k==3&&(d=(d<<2)+f|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h),b=0);m=g;return b}hf.X=1;function lf(b,c,d){var f;(y[c+12>>2]|0)==0?(y[c+24>>2]|0)!=0?f=3:(y[c>>2]|0)==0?f=3:(f=c+8|0,J=Gb[f>>1]+(Gb[f+2>>1]<<16),x[b>>1]=J&65535,x[b+2>>1]=J>>16,f=11):f=3;if(f==3){f=(y[c+4>>2]|0)==(d|0);var g=(y[c+16>>2]|0)==(d|0);((g&1)+(f&1)+((y[c+28>>2]|0)==(d|0)&1)|0)==1?(c=f?c+8|0:g?c+20|0:c+32|0,J=Gb[c>>1]+(Gb[c+2>>1]<<16),x[b>>1]=J&65535,x[b+2>>1]=J>>16):(x[b>>1]=mf(x[c+8>>1]<<16>>16,x[c+20>>1]<<16>>16,x[c+32>>1]<<16>>16)&65535,x[b+2>>1]=mf(x[c+10>>1]<<16>>16,x[c+22>>1]<<16>>16,x[c+34>>1]<<16>>16)&65535)}}lf.X=1;function rf(b,c,d,f,g,e,i,h,k){var l=m;m+=144;var j;if((d|0)<0){j=3}else{if((h+(d+1)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((k+f|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g,t=e;j=4}}}j==3&&(n=l|0,o=h+1|0,sf(b,n,d,f,g,e,o,k,o),sf(b+e*g|0,l+o*k|0,d,f,g,e,o,k,o),r=p=0,t=k);b=8-i|0;d=k>>>0<2;f=h>>>0<2;g=16-h|0;e=(o<<1)-h|0;j=o+1|0;var s=o+2|0,u=h>>>1;h&=-2;k>>>=1;t=t*o|0;p=p+r*o|0;for(r=0;;){a:do{if(!d){for(var w=n+(p+t*r)|0,v=c+(r<<6)|0,z=0;;){if(!f){for(var B=v+h|0,D=0;;){var C=D<<1,E=C|1,G=A[w+C|0]&255,H=A[w+(j+C)|0]&255,K=A[w+E|0]&255;q[C+(v+8)|0]=((H*i+(A[w+(o+C)|0]&255)*b<<3)+32|0)>>>6&255;q[v+C|0]=((K*i+G*b<<3)+32|0)>>>6&255;G=A[C+(w+2)|0]&255;q[C+(v+9)|0]=(((A[w+(s+C)|0]&255)*i+H*b<<3)+32|0)>>>6&255;q[v+E|0]=((G*i+K*b<<3)+32|0)>>>6&255;D=D+1|0;if((D|0)==(u|0)){break}}w=w+h|0;v=B}z=z+1|0;if((z|0)==(k|0)){break a}w=w+e|0;v=v+g|0}}}while(0);r=r+1|0;if((r|0)==2){break}}m=l}rf.X=1;function sf(b,c,d,f,g,e,i,h,k){var l=i+d|0,j=h+f|0,n=(d|0)<0|(l|0)>(g|0)?2:4,f=(j|0)<0?-h|0:f,d=(l|0)<0?-i|0:d,f=(f|0)>(e|0)?e:f,p=(d|0)>(g|0)?g:d,d=p+i|0,r=f+h|0,b=(p|0)>0?b+p|0:b,l=(f|0)>0?b+f*g|0:b,b=(p|0)<0?-p|0:0,d=(d|0)>(g|0)?d-g|0:0,i=i-b-d|0,p=(f|0)<0?-f|0:0,f=(r|0)>(e|0)?r-e|0:0;if((p|0)!=0){for(var r=e^-1,o=h-1-((j|0)>0?j:0)|0,r=(o|0)<(r|0)?r:o,o=r^-1,r=((o|0)>0?o:0)+(r+1)|0,o=r*k|0,t=0;;){if(lc[n](l,c+t*k|0,b,i,d),t=t+1|0,(t|0)==(r|0)){break}}c=c+o|0}if((h-p|0)!=(f|0)){p=h-1|0;r=e^-1;o=p-((j|0)>0?j:0)|0;r=(o|0)<(r|0)?r:o;p=p-r|0;o=r^-1;r=h+e-1-((p|0)<(e|0)?e:p)-r-((o|0)>0?o:0)|0;o=r*k|0;p=r*g|0;for(t=0;;){if(lc[n](l+t*g|0,c+t*k|0,b,i,d),t=t+1|0,(t|0)==(r|0)){break}}c=c+o|0;l=l+p|0}g=l+ -g|0;l=(f|0)==0;a:do{if(!l){f=h-1|0;p=e^-1;r=f-((j|0)>0?j:0)|0;f=f-((r|0)<(p|0)?p:r)|0;f=((f|0)<(e|0)?e:f)-e|0;for(p=0;;){if(lc[n](g,c+p*k|0,b,i,d),p=p+1|0,(p|0)==(f|0)){break a}}}}while(0)}sf.X=1;function tf(b,c,d,f,g,e,i,h,k){var l=m;m+=144;var j;if((d|0)<0){j=3}else{if((h+d|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((k+(f+1)|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g,t=e;j=4}}}j==3&&(n=l|0,j=k+1|0,sf(b,n,d,f,g,e,h,j,h),sf(b+e*g|0,l+j*h|0,d,f,g,e,h,j,h),r=p=0,o=h,t=j);b=8-i|0;d=k>>>0<2;f=h>>>0<2;g=16-h|0;e=o<<1;j=e-h|0;var s=o+1|0,u=h>>>1;h&=-2;var w=e|1;k>>>=1;t=t*o|0;p=p+r*o|0;for(r=0;;){a:do{if(!d){for(var v=n+(p+t*r)|0,z=c+(r<<6)|0,B=0;;){if(!f){for(var D=z+h|0,C=0;;){var E=C<<1,G=E|1,H=A[v+(o+E)|0]&255,K=A[v+E|0]&255;q[E+(z+8)|0]=((H*b+(A[v+(e+E)|0]&255)*i<<3)+32|0)>>>6&255;q[z+E|0]=((K*b+H*i<<3)+32|0)>>>6&255;H=A[v+(s+E)|0]&255;K=A[v+G|0]&255;q[E+(z+9)|0]=((H*b+(A[v+(w+E)|0]&255)*i<<3)+32|0)>>>6&255;q[z+G|0]=((K*b+H*i<<3)+32|0)>>>6&255;C=C+1|0;if((C|0)==(u|0)){break}}v=v+h|0;z=D}B=B+1|0;if((B|0)==(k|0)){break a}v=v+j|0;z=z+g|0}}}while(0);r=r+1|0;if((r|0)==2){break}}m=l}tf.X=1;function uf(b,c,d,f,g,e,i,h,k,l){var j=m;m+=164;var n;if((d|0)<0){n=3}else{if((k+(d+1)|0)>>>0>g>>>0|(f|0)<0){n=3}else{if((l+(f+1)|0)>>>0>e>>>0){n=3}else{var p=b,r=d,o=f,t=g,s=e;n=4}}}n==3&&(p=j|0,t=k+1|0,n=l+1|0,sf(b,p,d,f,g,e,t,n,t),sf(b+e*g|0,j+n*t|0,d,f,g,e,t,n,t),o=r=0,s=n);b=8-i|0;d=8-h|0;f=l>>>0<2;g=t<<1;e=k>>>0<2;n=16-k|0;var u=g-k|0,w=t+1|0,v=t+2|0,z=k>>>1;k&=-2;var B=g|1,D=g+2|0;l>>>=1;s=s*t|0;r=r+o*t|0;for(o=0;;){a:do{if(!f){for(var C=p+(r+s*o)|0,E=c+(o<<6)|0,G=0;;){var H=A[C+t|0]&255;if(!e){for(var K=E+k|0,L=H*h+(A[C]&255)*d|0,N=(A[C+g|0]&255)*h+H*d|0,H=0;;){var O=H<<1,R=O|1,U=A[C+(w+O)|0]&255,Y=U*h+(A[C+R|0]&255)*d|0,U=(A[C+(B+O)|0]&255)*h+U*d|0,L=(L*b+32+Y*i|0)>>>6;q[O+(E+8)|0]=(N*b+32+U*i|0)>>>6&255;q[E+O|0]=L&255;N=A[C+(v+O)|0]&255;L=N*h+(A[O+(C+2)|0]&255)*d|0;N=(A[C+(D+O)|0]&255)*h+N*d|0;Y=(Y*b+32+L*i|0)>>>6;q[O+(E+9)|0]=(U*b+32+N*i|0)>>>6&255;q[E+R|0]=Y&255;H=H+1|0;if((H|0)==(z|0)){break}}C=C+k|0;E=K}G=G+1|0;if((G|0)==(l|0)){break a}C=C+u|0;E=E+n|0}}}while(0);o=o+1|0;if((o|0)==2){break}}m=j}uf.X=1;function vf(b,c,d,f,g,e,i,h){var k=m;m+=444;var l;if((d|0)<0){l=3}else{if((i+d|0)>>>0>g>>>0|(f|0)<0){l=3}else{if((h+(f+5)|0)>>>0>e>>>0){l=3}else{var j=b,n=d,p=f,r=g;l=4}}}l==3&&(sf(b,k,d,f,g,e,i,h+5|0,i),j=k,p=n=0,r=i);b=n+r+p*r|0;d=h>>>0<4;a:do{if(!d){f=(i|0)==0;g=(r<<2)-i|0;e=64-i|0;l=r*-2|0;for(var n=r<<1,p=h>>>2,o=j+b|0,t=j+(b+r*5)|0,s=c,u=0;;){if(!f){for(var w=s+i|0,v=0;;){var z=v-r|0,B=r+v|0,D=n+v|0,C=A[t+(l+v)|0]&255,E=A[t+z|0]&255,G=A[t+B|0]&255,H=A[t+v|0]&255,K=G+C|0,L=A[o+D|0]&255;q[v+(s+48)|0]=q[Q.a+((16-K+(A[t+D|0]&255)-(K<<2)+L+(H+E)*20>>5)+512)|0];D=L+H|0;B=A[o+B|0]&255;q[v+(s+32)|0]=q[Q.a+((G+16-D+B-(D<<2)+(E+C)*20>>5)+512)|0];G=B+E|0;D=A[o+v|0]&255;q[v+(s+16)|0]=q[Q.a+((H+16-G+D-(G<<2)+(L+C)*20>>5)+512)|0];C=D+C|0;q[s+v|0]=q[Q.a+((E+16-C+(A[o+z|0]&255)-(C<<2)+(B+L)*20>>5)+512)|0];v=v+1|0;if((v|0)==(i|0)){break}}o=o+i|0;t=t+i|0;s=w}u=u+1|0;if((u|0)==(p|0)){break a}o=o+g|0;t=t+g|0;s=s+e|0}}}while(0);m=k}vf.X=1;function wf(b,c,d,f,g,e,i,h,k){var l=m;m+=444;var j;if((d|0)<0){j=3}else{if((i+d|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g;j=4}}}j==3&&(sf(b,l,d,f,g,e,i,h+5|0,i),n=l,r=p=0,o=i);b=p+o+r*o|0;d=h>>>0<4;a:do{if(!d){f=(i|0)==0;g=(o<<2)-i|0;e=64-i|0;j=o<<1;for(var p=o*-2|0,r=h>>>2,t=n+b|0,s=n+(b+o*5)|0,u=n+(b+o*(k+2))|0,w=c,v=0;;){if(!f){for(var z=u+i|0,B=w+i|0,D=0;;){var C=j+D|0,E=o+D|0,G=D-o|0,H=A[s+(p+D)|0]&255,K=A[s+G|0]&255,L=A[s+E|0]&255,N=A[s+D|0]&255,O=L+H|0,R=A[t+C|0]&255;q[D+(w+48)|0]=((A[Q.a+((16-O+(A[s+C|0]&255)-(O<<2)+R+(N+K)*20>>5)+512)|0]&255)+1+(A[u+C|0]&255)|0)>>>1&255;O=R+N|0;C=A[t+E|0]&255;q[D+(w+32)|0]=((A[Q.a+((L+16-O-(O<<2)+C+(K+H)*20>>5)+512)|0]&255)+1+(A[u+E|0]&255)|0)>>>1&255;E=C+K|0;L=A[t+D|0]&255;q[D+(w+16)|0]=((A[Q.a+((N+16-E-(E<<2)+L+(R+H)*20>>5)+512)|0]&255)+1+(A[u+D|0]&255)|0)>>>1&255;H=L+H|0;q[w+D|0]=((A[Q.a+((K+16-H-(H<<2)+(A[t+G|0]&255)+(C+R)*20>>5)+512)|0]&255)+1+(A[u+G|0]&255)|0)>>>1&255;D=D+1|0;if((D|0)==(i|0)){break}}t=t+i|0;s=s+i|0;u=z;w=B}v=v+1|0;if((v|0)==(r|0)){break a}t=t+g|0;s=s+g|0;u=u+g|0;w=w+e|0}}}while(0);m=l}wf.X=1;function xf(b,c,d,f,g,e,i,h){var k=m;m+=444;var l;if((d|0)<0){l=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){l=3}else{if((h+f|0)>>>0>e>>>0){l=3}else{var j=b,n=d,p=f,r=g;l=4}}}l==3&&(r=i+5|0,sf(b,k,d,f,g,e,r,h,r),j=k,p=n=0);b=(h|0)==0;a:do{if(!b){d=i>>>2;f=(d|0)==0;g=r-i|0;e=16-i|0;l=i&-4;for(var o=j+(n+5+p*r)|0,t=c,s=0;;){if(!f){for(var u=t+l|0,w=A[o-1|0]&255,v=A[o-2|0]&255,z=A[o-3|0]&255,B=A[o-4|0]&255,D=A[o-5|0]&255,C=0;;){var E=C<<2,G=E|1,H=E|2,K=E|3,L=B+w|0,N=A[o+E|0]&255;q[t+E|0]=q[Q.a+((16-L+D-(L<<2)+N+(z+v)*20>>5)+512)|0];L=N+z|0;E=A[o+G|0]&255;D=N+w|0;q[t+G|0]=q[Q.a+((B+16-L+E-(L<<2)+(v+w)*20>>5)+512)|0];L=E+v|0;B=A[o+H|0]&255;G=E+N|0;q[t+H|0]=q[Q.a+((z+16-L+B-(L<<2)+D*20>>5)+512)|0];H=B+w|0;z=A[o+K|0]&255;q[t+K|0]=q[Q.a+((v+16-H+z-(H<<2)+G*20>>5)+512)|0];C=C+1|0;if((C|0)==(d|0)){break}D=w;w=z;v=B;z=E;B=N}o=o+l|0;t=u}s=s+1|0;if((s|0)==(h|0)){break a}o=o+g|0;t=t+e|0}}}while(0);m=k}xf.X=1;function yf(b,c,d,f,g,e,i,h,k){var l=m;m+=444;var j;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+f|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g;j=4}}}j==3&&(o=i+5|0,sf(b,l,d,f,g,e,o,h,o),n=l,r=p=0);b=(h|0)==0;a:do{if(!b){d=i>>>2;f=(d|0)==0;g=o-i|0;e=16-i|0;j=(k|0)!=0;for(var t=i&-4,s=n+(p+5+r*o)|0,u=c,w=0;;){if(!f){for(var v=u+t|0,z=A[s-1|0]&255,B=A[s-2|0]&255,D=A[s-3|0]&255,C=A[s-4|0]&255,E=A[s-5|0]&255,G=0;;){var H=G<<2,K=H|1,L=H|2,N=H|3,O=C+z|0,R=A[s+H|0]&255;q[u+H|0]=((j?B:D)+1+(A[Q.a+((16-O+E-(O<<2)+R+(D+B)*20>>5)+512)|0]&255)|0)>>>1&255;E=R+D|0;H=A[s+K|0]&255;q[u+K|0]=((j?z:B)+1+(A[Q.a+((C+16-E+H-(E<<2)+(B+z)*20>>5)+512)|0]&255)|0)>>>1&255;E=H+B|0;C=A[s+L|0]&255;q[u+L|0]=((j?R:z)+1+(A[Q.a+((D+16-E+C-(E<<2)+(R+z)*20>>5)+512)|0]&255)|0)>>>1&255;E=C+z|0;D=A[s+N|0]&255;q[u+N|0]=((j?H:R)+1+(A[Q.a+((B+16-E+D-(E<<2)+(H+R)*20>>5)+512)|0]&255)|0)>>>1&255;G=G+1|0;if((G|0)==(d|0)){break}E=z;z=D;B=C;D=H;C=R}s=s+t|0;u=v}w=w+1|0;if((w|0)==(h|0)){break a}s=s+g|0;u=u+e|0}}}while(0);m=l}yf.X=1;function zf(b,c,d,f,g,e,i,h,k){var l=m;m+=444;var j;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g;j=4}}}j==3&&(o=i+5|0,sf(b,l,d,f,g,e,o,h+5|0,o),n=l,r=p=0);b=r*o+p|0;d=(k&1|2)+o+b|0;f=n+d|0;g=(h|0)==0;a:do{if(!g){p=i>>>2;r=(p|0)==0;j=o-i|0;for(var e=16-i|0,t=i&-4,s=n+(o*(k>>>1&1|2)+5+b)|0,u=c,w=0;;){if(r){var v=u}else{for(var v=u+t|0,z=A[s-2|0]&255,B=A[s-1|0]&255,D=A[s-3|0]&255,C=A[s-4|0]&255,E=A[s-5|0]&255,G=0;;){var H=G<<2,K=H|1,L=H|2,N=H|3,O=C+B|0,R=A[s+H|0]&255;q[u+H|0]=q[Q.a+((16-O+E-(O<<2)+R+(D+z)*20>>5)+512)|0];O=R+D|0;H=A[s+K|0]&255;E=R+B|0;q[u+K|0]=q[Q.a+((C+16-O+H-(O<<2)+(B+z)*20>>5)+512)|0];O=H+z|0;C=A[s+L|0]&255;K=H+R|0;q[u+L|0]=q[Q.a+((D+16-O+C-(O<<2)+E*20>>5)+512)|0];L=C+B|0;D=A[s+N|0]&255;q[u+N|0]=q[Q.a+((z+16-L+D-(L<<2)+K*20>>5)+512)|0];G=G+1|0;if((G|0)==(p|0)){break}z=C;E=B;B=D;D=H;C=R}s=s+t|0}w=w+1|0;if((w|0)==(h|0)){break}s=s+j|0;u=v+e|0}if(h>>>0>=4){p=(i|0)==0;r=(o<<2)-i|0;j=64-i|0;t=o<<1;u=o*-2|0;s=h>>>2;w=n+(d+o*5)|0;z=f;e=v+(e-(h<<4))|0;for(B=0;;){if(!p){R=e+i|0;for(G=0;;){var U=G+(e+48)|0,O=G+(e+32)|0,C=G+(e+16)|0,N=e+G|0,Y=t+G|0,X=o+G|0,D=G-o|0,E=A[w+(u+G)|0]&255,H=A[w+D|0]&255,ba=A[w+X|0]&255,K=A[w+G|0]&255,$=ba+E|0,L=A[z+Y|0]&255;q[U]=((A[Q.a+((16-$+(A[w+Y|0]&255)-($<<2)+L+(K+H)*20>>5)+512)|0]&255)+1+(A[U]&255)|0)>>>1&255;U=L+K|0;X=A[z+X|0]&255;q[O]=((A[Q.a+((ba+16-U-(U<<2)+X+(H+E)*20>>5)+512)|0]&255)+1+(A[O]&255)|0)>>>1&255;O=A[z+G|0]&255;ba=X+H|0;q[C]=((A[Q.a+((K+16-ba-(ba<<2)+O+(L+E)*20>>5)+512)|0]&255)+1+(A[C]&255)|0)>>>1&255;C=O+E|0;q[N]=((A[Q.a+((H+16-C-(C<<2)+(A[z+D|0]&255)+(X+L)*20>>5)+512)|0]&255)+1+(A[N]&255)|0)>>>1&255;G=G+1|0;if((G|0)==(i|0)){break}}w=w+i|0;z=z+i|0;e=R}B=B+1|0;if((B|0)==(s|0)){break a}w=w+r|0;z=z+r|0;e=e+j|0}}}}while(0);m=l}zf.X=1;function Af(b,c,d,f,g,e,i,h){var k=m;m+=1788;var l,j=k+444;if((d|0)<0){l=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){l=3}else{if((h+(f+5)|0)>>>0>e>>>0){l=3}else{var n=b,p=d,r=f,o=g;l=4}}}l==3&&(l=i+5|0,sf(b,k,d,f,g,e,l,h+5|0,l),n=k,r=p=0,o=l);b=(h|0)==-5;do{if(b){l=12}else{l=i>>>2;for(var d=(l|0)==0,f=o-i|0,g=i&-4,e=h+5|0,t=j|0,s=n+(p+5+r*o)|0,u=0;;){if(!d){for(var w=t+(g<<2)|0,v=A[s-5|0]&255,z=A[s-4|0]&255,B=A[s-3|0]&255,D=A[s-2|0]&255,C=A[s-1|0]&255,E=0;;){var G=E<<2,H=G|1,K=G|2,L=G|3,N=C+z|0,O=A[s+G|0]&255;y[t+(G<<2)>>2]=v-N-(N<<2)+O+(D+B)*20|0;v=O+B|0;G=A[s+H|0]&255;y[t+(H<<2)>>2]=G+z-v-(v<<2)+(C+D)*20|0;z=G+D|0;H=A[s+K|0]&255;y[t+(K<<2)>>2]=H+B-z-(z<<2)+(O+C)*20|0;B=H+C|0;K=A[s+L|0]&255;y[t+(L<<2)>>2]=K+D-B-(B<<2)+(G+O)*20|0;E=E+1|0;if((E|0)==(l|0)){break}v=C;z=O;B=G;D=H;C=K}t=w;s=s+g|0}u=u+1|0;if((u|0)==(e|0)){break}s=s+f|0}l=h>>>0<4?18:12}}while(0);a:do{if(l==12){n=(i|0)==0;p=64-i|0;r=i*3|0;o=i*-2|0;b=i<<1;d=h>>>2;f=j+(i<<2)|0;g=j+(i*6<<2)|0;e=c;for(t=0;;){if(!n){s=e+i|0;for(u=0;;){if(C=u-i|0,O=u+i|0,L=b+u|0,E=f+(O<<2)|0,w=f+(C<<2)|0,D=F[g+(o+u<<2)>>2],C=F[g+(C<<2)>>2],z=y[g+(O<<2)>>2],B=F[g+(u<<2)>>2],G=z+D|0,O=F[f+(L<<2)>>2],q[u+(e+48)|0]=q[Q.a+((512-G+y[g+(L<<2)>>2]-(G<<2)+O+(B+C)*20>>10)+512)|0],L=O+B|0,E=y[E>>2],q[u+(e+32)|0]=q[Q.a+((z+512-L+E-(L<<2)+(C+D)*20>>10)+512)|0],L=y[f+(u<<2)>>2],z=E+C|0,q[u+(e+16)|0]=q[Q.a+((B+512-z+L-(z<<2)+(O+D)*20>>10)+512)|0],D=L+D|0,q[e+u|0]=q[Q.a+((C+512-D+y[w>>2]-(D<<2)+(E+O)*20>>10)+512)|0],u=u+1|0,(u|0)==(i|0)){break}}f=f+(i<<2)|0;g=g+(i<<2)|0;e=s}t=t+1|0;if((t|0)==(d|0)){break a}f=f+(r<<2)|0;g=g+(r<<2)|0;e=e+p|0}}}while(0);m=k}Af.X=1;function Bf(b,c,d,f,g,e,i,h,k){var l=m;m+=1788;var j,n=l+444;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var p=b,r=d,o=f,t=g;j=4}}}j==3&&(j=i+5|0,sf(b,l,d,f,g,e,j,h+5|0,j),p=l,o=r=0,t=j);b=(h|0)==-5;do{if(b){j=12}else{j=i>>>2;for(var d=(j|0)==0,f=t-i|0,g=i&-4,e=h+5|0,s=n|0,u=p+(r+5+o*t)|0,w=0;;){if(!d){for(var v=s+(g<<2)|0,z=A[u-5|0]&255,B=A[u-4|0]&255,D=A[u-3|0]&255,C=A[u-2|0]&255,E=A[u-1|0]&255,G=0;;){var H=G<<2,K=H|1,L=H|2,N=H|3,O=E+B|0,R=A[u+H|0]&255;y[s+(H<<2)>>2]=z-O-(O<<2)+R+(C+D)*20|0;z=R+D|0;H=A[u+K|0]&255;y[s+(K<<2)>>2]=H+B-z-(z<<2)+(E+C)*20|0;B=H+C|0;K=A[u+L|0]&255;y[s+(L<<2)>>2]=K+D-B-(B<<2)+(R+E)*20|0;D=K+E|0;L=A[u+N|0]&255;y[s+(N<<2)>>2]=L+C-D-(D<<2)+(H+R)*20|0;G=G+1|0;if((G|0)==(j|0)){break}z=E;B=R;D=H;C=K;E=L}s=v;u=u+g|0}w=w+1|0;if((w|0)==(e|0)){break}u=u+f|0}j=h>>>0<4?18:12}}while(0);a:do{if(j==12){p=(i|0)==0;r=64-i|0;o=i*3|0;t=i<<1;b=i*-2|0;d=h>>>2;f=n+(i<<2)|0;g=n+(i*6<<2)|0;e=n+((k+2)*i+i<<2)|0;s=c;for(u=0;;){if(!p){v=e+(i<<2)|0;w=s+i|0;for(C=0;;){if(L=t+C|0,N=C+i|0,B=e+(N<<2)|0,G=C-i|0,E=e+(G<<2)|0,z=f+(N<<2)|0,R=f+(G<<2)|0,D=F[g+(b+C<<2)>>2],G=F[g+(G<<2)>>2],K=F[g+(N<<2)>>2],H=F[g+(C<<2)>>2],O=K+D|0,N=F[f+(L<<2)>>2],q[C+(s+48)|0]=((A[Q.a+((512-O+y[g+(L<<2)>>2]-(O<<2)+N+(H+G)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[e+(L<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255,L=N+H|0,z=F[z>>2],q[C+(s+32)|0]=((A[Q.a+((K+512-L-(L<<2)+z+(G+D)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[B>>2]+16>>5)+512)|0]&255)|0)>>>1&255,B=F[f+(C<<2)>>2],L=z+G|0,q[C+(s+16)|0]=((A[Q.a+((H+512-L-(L<<2)+B+(N+D)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[e+(C<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255,D=B+D|0,q[s+C|0]=((A[Q.a+((G+512-D-(D<<2)+y[R>>2]+(z+N)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[E>>2]+16>>5)+512)|0]&255)|0)>>>1&255,C=C+1|0,(C|0)==(i|0)){break}}f=f+(i<<2)|0;g=g+(i<<2)|0;e=v;s=w}u=u+1|0;if((u|0)==(d|0)){break a}f=f+(o<<2)|0;g=g+(o<<2)|0;e=e+(o<<2)|0;s=s+r|0}}}while(0);m=l}Bf.X=1;function Cf(b,c){var d=b+40|0,f=y[d>>2],g=(f|0)==0;a:do{if(!g){for(var e=b|0,i=b+32|0,h=0,k=f;;){var l=h+1|0,j=F[e>>2];(y[j+h*40+20>>2]-1|0)>>>0<2?(k=F[j+h*40+12>>2],y[j+h*40+8>>2]=k>>>0>c>>>0?k-y[i>>2]|0:k,j=y[d>>2]):j=k;if(l>>>0>=j>>>0){break a}h=l;k=j}}}while(0)}function Df(b,c,d){var d=(d|0)==0,f=F[b+24>>2];b|=0;a:do{if(d){for(var g=0,e=0;;){for(var i=e>>>0>>0;;){if(!(i&(g|0)==0)){var h=g,k=e;break a}var l=y[b>>2];if((y[l+e*40+20>>2]|0)!=3){break}if((y[l+e*40+8>>2]|0)!=(c|0)){break}g=1}e=e+1|0}}else{for(e=g=0;;){for(i=e>>>0>>0;;){if(!(i&(g|0)==0)){h=g;k=e;break a}l=F[b>>2];if((y[l+e*40+20>>2]-1|0)>>>0>=2){break}if((y[l+e*40+8>>2]|0)!=(c|0)){break}g=1}e=e+1|0}}}while(0);return(h|0)==0?-1:k}function Ef(b,c,d,f,g,e,i,h,k){var l=m;m+=1788;var j,n=l+444,p=i+5|0;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var r=b,o=d,t=f,s=g;j=4}}}j==3&&(sf(b,l,d,f,g,e,p,h+5|0,p),r=l,t=o=0,s=p);b=o+s+t*s|0;d=h>>>0<4;a:do{if(!d){f=(p|0)==0;g=(s<<2)-i-5|0;e=p*3|0;j=s*-2|0;for(var o=s<<1,t=(i<<1)+10|0,u=-5-i|0,w=h>>>2,v=n+(p<<2)|0,z=r+b|0,B=r+(b+s*5)|0,D=0;;){if(!f){for(var C=v+(p<<2)|0,E=0;;){var G=E-s|0,H=s+E|0,K=o+E|0,L=v+(p+E<<2)|0,N=v+(u+E<<2)|0,O=A[B+(j+E)|0]&255,R=A[B+G|0]&255,U=A[B+H|0]&255,Y=A[B+E|0]&255,X=U+O|0,ba=A[z+K|0]&255;y[v+(t+E<<2)>>2]=(A[B+K|0]&255)-X-(X<<2)+ba+(Y+R)*20|0;K=ba+Y|0;H=A[z+H|0]&255;y[L>>2]=H+U-K-(K<<2)+(R+O)*20|0;L=A[z+E|0]&255;U=H+R|0;y[v+(E<<2)>>2]=L+Y-U-(U<<2)+(ba+O)*20|0;O=L+O|0;y[N>>2]=(A[z+G|0]&255)+R-O-(O<<2)+(H+ba)*20|0;E=E+1|0;if((E|0)==(p|0)){break}}v=C;z=z+p|0;B=B+p|0}D=D+1|0;if((D|0)==(w|0)){break a}v=v+(e<<2)|0;z=z+g|0;B=B+g|0}}}while(0);p=(h|0)==0;a:do{if(!p){r=i>>>2;s=(r|0)==0;b=16-i|0;d=i&-4;f=n+20|0;g=n+(k+2<<2)|0;e=c;for(j=0;;){if(!s){o=g+(d<<2)|0;E=y[f-20>>2];D=y[f-16>>2];v=y[f-12>>2];t=y[f-8>>2];u=y[f-4>>2];for(z=0;;){C=z<<2;N=C|1;G=C|2;B=C|3;R=u+D|0;w=F[f+(C<<2)>>2];q[e+C|0]=((A[Q.a+((E+512-R-(R<<2)+w+(t+v)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(C<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;E=w+v|0;C=F[f+(N<<2)>>2];q[e+N|0]=((A[Q.a+((D+512-E-(E<<2)+C+(u+t)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(N<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;D=C+t|0;N=F[f+(G<<2)>>2];q[e+G|0]=((A[Q.a+((v+512-D-(D<<2)+N+(w+u)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(G<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;v=N+u|0;G=F[f+(B<<2)>>2];q[e+B|0]=((A[Q.a+((t+512-v-(v<<2)+G+(C+w)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(B<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;z=z+1|0;if((z|0)==(r|0)){break}E=u;D=w;v=C;t=N;u=G}f=f+(d<<2)|0;g=o;e=e+d|0}j=j+1|0;if((j|0)==(h|0)){break a}f=f+20|0;g=g+20|0;e=e+b|0}}}while(0);m=l}Ef.X=1;function df(b,c,d,f,g,e,i,h,k){var l=b+((i<<4)+e)|0,j=c|0,n=x[j>>1]<<16>>16,c=c+2|0,p=x[c>>1]<<16>>16,r=d+4|0,o=y[r>>2]<<4,t=d+8|0,s=y[t>>2]<<4,f=e+f|0,u=f+(n>>2)|0,g=i+g|0,w=g+(p>>2)|0,n=y[Ff+((n&3)<<4)+((p&3)<<2)>>2];n==0?sf(y[d>>2],l,u,w,o,s,h,k,16):n==1?wf(y[d>>2],l,u,w-2|0,o,s,h,k,0):n==2?vf(y[d>>2],l,u,w-2|0,o,s,h,k):n==3?wf(y[d>>2],l,u,w-2|0,o,s,h,k,1):n==4?yf(y[d>>2],l,u-2|0,w,o,s,h,k,0):n==5?zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,0):n==6?Ef(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,0):n==7?zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,2):n==8?xf(y[d>>2],l,u-2|0,w,o,s,h,k):n==9?Bf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,0):n==10?Af(y[d>>2],l,u-2|0,w-2|0,o,s,h,k):n==11?Bf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,1):n==12?yf(y[d>>2],l,u-2|0,w,o,s,h,k,1):n==13?zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,1):n==14?Ef(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,1):zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,3);b=b+(((i<<2)+256&-8)+(e>>>1))|0;d=y[d>>2];e=y[r>>2];i=y[t>>2];t=e<<3;r=i<<3;l=x[j>>1]<<16>>16;j=(l>>3)+(f>>>1)|0;f=x[c>>1]<<16>>16;c=(f>>3)+(g>>>1)|0;g=l&7;f&=7;h>>>=1;k>>>=1;e=(e<<8)*i|0;i=d+e|0;l=(g|0)!=0;n=(f|0)==0;n|l^1?l?rf(i,b,j,c,t,r,g,h,k):n?(sf(i,b,j,c,t,r,h,k,8),sf(d+(r*t+e)|0,b+64|0,j,c,t,r,h,k,8)):tf(i,b,j,c,t,r,f,h,k):uf(i,b,j,c,t,r,g,f,h,k)}df.X=1;function Gf(b,c,d,f){Cf(b,d);var g=(y[c>>2]|0)==0;a:do{if(g){var e=0}else{var i=b|0,h=b+32|0,k=b+4|0,l=f-1|0,j=0,n=d;b:for(;;){var p=j+2|0,r=j+1|0,o=f-j|0,t=c+4+j*12+4|0,s=c+4+j*12+8|0,u=F[c+4+j*12>>2];if(u>>>0>=3){e=0;break a}u>>>0<2?(s=F[t>>2],(u|0)==0?(s=n-s|0,s=(s|0)<0?y[h>>2]+s|0:s):(s=s+n|0,u=y[h>>2],s=s-((s|0)<(u|0)?0:u)|0),s>>>0>d>>>0?(u=1,t=s-y[h>>2]|0):(u=1,t=s)):(u=0,t=y[s>>2],s=n);u=Df(b,t,u);if((u|0)<0){e=1;break a}t=F[i>>2];if(F[t+u*40+20>>2]>>>0<=1){e=1;break a}if(j>>>0>>0){for(t=0;;){var w=y[k>>2];y[(w+(f-t<<2)|0)>>2]=y[w+(l-t<<2)>>2];t=t+1|0;if((t|0)==(o|0)){break}}o=y[i>>2]}else{o=t}y[(y[k>>2]+(j<<2)|0)>>2]=o+u*40|0;if(r>>>0>f>>>0){j=r,n=s}else{t=r;for(o=0;;){var w=F[k>>2],v=y[w+(r+o<<2)>>2];(v|0)!=(y[i>>2]+u*40|0)&&(y[w+(t<<2)>>2]=v,t=t+1|0);if((p+o|0)>>>0>f>>>0){j=r;n=s;continue b}o=o+1|0}}}}}while(0);return e}Gf.X=1;function Hf(b,c,d,f){var g=F[b+36>>2],g=(g|0)==65535|g>>>0>>0;do{if(g){var e=1}else{var e=b+24|0,i=F[e>>2],h=b|0,k=0;a:for(;;){if(k>>>0>=i>>>0){var l=y[b+40>>2];break}var j=F[h>>2],n=j+k*40+20|0,p=(y[n>>2]|0)==3;do{if(p&&(y[j+k*40+8>>2]|0)==(f|0)){y[n>>2]=0;i=b+40|0;l=y[i>>2]-1|0;y[i>>2]=l;if((y[y[h>>2]+k*40+24>>2]|0)!=0){break a}h=b+44|0;y[h>>2]=y[h>>2]-1|0;break a}}while(0);k=k+1|0}h=b+40|0;l>>>0>2]>>>0?(e=b+8|0,y[(y[e>>2]+12|0)>>2]=c,y[(y[e>>2]+8|0)>>2]=f,y[(y[e>>2]+16|0)>>2]=d,y[(y[e>>2]+20|0)>>2]=3,y[(y[e>>2]+24|0)>>2]=(y[b+56>>2]|0)==0&1,y[h>>2]=y[h>>2]+1|0,e=b+44|0,y[e>>2]=y[e>>2]+1|0,e=0):e=1}}while(0);return e}Hf.X=1;function If(b){var c=b+40|0,d=F[c>>2],f=d>>>0>2]>>>0;do{if(f){var g=0}else{if((d|0)==0){g=1}else{for(var g=b|0,e=F[g>>2],i=d>>>0>1?d:1,h=0,k=-1,l=0;;){if((y[e+l*40+20>>2]-1|0)>>>0<2){var j=F[e+l*40+8>>2];if((j|0)<(h|0)|(k|0)==-1){n=l,h=j}else{var n=k}}else{n=k}l=l+1|0;if((l|0)==(i|0)){break}k=n}(n|0)>-1?(y[e+n*40+20>>2]=0,y[c>>2]=y[c>>2]-1|0,(y[y[g>>2]+n*40+24>>2]|0)==0&&(g=b+44|0,y[g>>2]=y[g>>2]-1|0),g=0):g=1}}}while(0);return g}If.X=1;function gf(b,c){if(c>>>0>16){var d=0}else{d=F[y[b+4>>2]+(c<<2)>>2],d=(d|0)==0?0:F[d+20>>2]>>>0>1?y[d>>2]:0}return d}function Jf(b){var c=y[b>>2],d=y[b+28>>2];y[b+8>>2]=c+d*40|0;return y[c+d*40>>2]}function Kf(b,c,d,f,g,e,i,h){var k,l=b+8|0,j=F[l>>2];if((y[d>>2]|0)==(y[j>>2]|0)){d=b+52|0;y[d>>2]=0;var n=b+56|0,p=(y[n>>2]|0)==0&1,r=(c|0)==0;do{if(r){if(y[j+20>>2]=0,y[(y[l>>2]+12|0)>>2]=f,y[(y[l>>2]+8|0)>>2]=f,y[(y[l>>2]+16|0)>>2]=g,y[(y[l>>2]+24|0)>>2]=p,(y[n>>2]|0)!=0){var o=0}else{o=b+44|0,y[o>>2]=y[o>>2]+1|0,o=0}}else{if((e|0)==0){if((y[c+8>>2]|0)==0){var t=If(b),o=f}else{var t=o=0,s=f;a:for(;;){var u=c+12+t*20+4|0,w=c+12+t*20+12|0,v=y[c+12+t*20>>2];do{if(v==0){var z=0;break a}else{if(v==1){var B;B=b;k=Df(B,s-y[u>>2]|0,1);if((k|0)<0){B=1}else{var D=B|0;y[(y[D>>2]+k*40+20|0)>>2]=0;var C=B+40|0;y[C>>2]=y[C>>2]-1|0;(y[y[D>>2]+k*40+24>>2]|0)==0&&(B=B+44|0,y[B>>2]=y[B>>2]-1|0);B=0}k=20}else{if(v==2){B=b,k=Df(B,y[c+12+t*20+8>>2],0),(k|0)<0?B=1:(D=B|0,y[(y[D>>2]+k*40+20|0)>>2]=0,C=B+40|0,y[C>>2]=y[C>>2]-1|0,(y[y[D>>2]+k*40+24>>2]|0)==0&&(B=B+44|0,y[B>>2]=y[B>>2]-1|0),B=0),k=20}else{if(v==3){B=Lf(b,s,y[u>>2],y[w>>2]),k=20}else{if(v==4){var E=b,G=y[c+12+t*20+16>>2];k=E+36|0;y[k>>2]=G;D=E+24|0;C=(y[D>>2]|0)==0;b:do{if(!C){for(var H=E|0,K=E+40|0,L=E+44|0,N=0,O=y[H>>2];;){var R=N+1|0,U=O+N*40+20|0;if((y[U>>2]|0)==3&&(F[O+N*40+8>>2]>>>0>G>>>0||(y[k>>2]|0)==65535)){y[U>>2]=0,y[K>>2]=y[K>>2]-1|0,O=F[H>>2],(y[O+N*40+24>>2]|0)==0&&(y[L>>2]=y[L>>2]-1|0)}if(R>>>0>=F[D>>2]>>>0){break b}N=R}}}while(0);E=s;G=o;k=21}else{if(v==5){Mf(b),y[d>>2]=1,E=0,G=o,k=21}else{if(v==6){if(k=Hf(b,s,g,y[w>>2]),(k|0)==0){E=s,G=1,k=21}else{var Y=k;k=23}}else{Y=1,k=23}}}}}}}}while(0);if(k==23){z=Y;break}else{if(k==20){if((B|0)!=0){z=B;break}E=s;G=o}}o=G;t=t+1|0;s=E}if((o|0)!=0){o=z;break}o=s;t=z}s=b+40|0;F[s>>2]>>>0>2]>>>0?(y[(y[l>>2]+12|0)>>2]=o,y[(y[l>>2]+8|0)>>2]=o,y[(y[l>>2]+16|0)>>2]=g,y[(y[l>>2]+20|0)>>2]=2,y[(y[l>>2]+24|0)>>2]=p,o=b+44|0,y[o>>2]=y[o>>2]+1|0,y[s>>2]=y[s>>2]+1|0,o=t):o=1}else{o=b+20|0,y[o>>2]=0,t=b+16|0,y[t>>2]=0,Mf(b),k=(y[c>>2]|0)==0?(y[n>>2]|0)==0?8:7:7,k==7&&(y[t>>2]=0,y[o>>2]=0),o=y[l>>2]+20|0,(y[c+4>>2]|0)==0?(y[o>>2]=2,y[b+36>>2]=65535):(y[o>>2]=3,y[b+36>>2]=0),y[(y[l>>2]+12|0)>>2]=0,y[(y[l>>2]+8|0)>>2]=0,y[(y[l>>2]+16|0)>>2]=0,y[(y[l>>2]+24|0)>>2]=p,y[b+44>>2]=1,y[b+40>>2]=1,o=0}}}while(0);y[(y[l>>2]+36|0)>>2]=e;y[(y[l>>2]+28|0)>>2]=i;y[(y[l>>2]+32|0)>>2]=h;c=(y[n>>2]|0)==0;a:do{if(c){if(f=b+44|0,g=b+28|0,e=F[g>>2],F[f>>2]>>>0>e>>>0){for(;;){if(Nf(b),e=F[g>>2],F[f>>2]>>>0<=e>>>0){X=e;break a}}}else{var X=e}}else{X=b+16|0,f=b+12|0,y[(y[f>>2]+(y[X>>2]<<4)|0)>>2]=y[y[l>>2]>>2],y[(y[f>>2]+(y[X>>2]<<4)+12|0)>>2]=y[y[l>>2]+36>>2],y[(y[f>>2]+(y[X>>2]<<4)+4|0)>>2]=y[y[l>>2]+28>>2],y[(y[f>>2]+(y[X>>2]<<4)+8|0)>>2]=y[y[l>>2]+32>>2],y[X>>2]=y[X>>2]+1|0,X=y[b+28>>2]}}while(0);Of(y[b>>2],X+1|0);b=o}else{b=1}return b}Kf.X=1;function Mf(b){for(var c=b|0,d=b+44|0,f=0,g=y[c>>2];;){var e=g+f*40+20|0;(y[e>>2]|0)!=0&&(y[e>>2]=0,g=y[c>>2],(y[g+f*40+24>>2]|0)==0&&(y[d>>2]=y[d>>2]-1|0));f=f+1|0;if((f|0)==16){break}}for(;;){if((Nf(b)|0)!=0){break}}y[b+40>>2]=0;y[b+36>>2]=65535;y[b+48>>2]=0}function Lf(b,c,d,f){var g=F[b+36>>2],g=(g|0)==65535|g>>>0>>0;do{if(g){var e=1}else{var i=F[b+24>>2],e=b|0,h=0;a:for(;;){if(h>>>0>=i>>>0){break}var k=F[e>>2],l=k+h*40+20|0,j=(y[l>>2]|0)==3;do{if(j&&(y[k+h*40+8>>2]|0)==(f|0)){y[l>>2]=0;i=b+40|0;y[i>>2]=y[i>>2]-1|0;if((y[y[e>>2]+h*40+24>>2]|0)!=0){break a}h=b+44|0;y[h>>2]=y[h>>2]-1|0;break a}}while(0);h=h+1|0}h=Df(b,c-d|0,1);(h|0)<0?e=1:(i=y[e>>2]+h*40+20|0,F[i>>2]>>>0>1?(y[i>>2]=3,y[(y[e>>2]+h*40+8|0)>>2]=f,e=0):e=1)}}while(0);return e}Lf.X=1;function Nf(b){if((y[b+56>>2]|0)==0){var c;c=y[b>>2];for(var d=2147483647,f=0,g=0;;){var e=c+f*40|0,i=f+1|0;(y[c+f*40+24>>2]|0)==0?e=g:(f=y[c+f*40+16>>2],(f|0)<(d|0)?d=f:e=g);if(i>>>0>y[b+28>>2]>>>0){break}f=i;g=e}c=e;(c|0)==0?b=1:(i=b+16|0,d=b+12|0,y[(y[d>>2]+(y[i>>2]<<4)|0)>>2]=y[c>>2],y[(y[d>>2]+(y[i>>2]<<4)+12|0)>>2]=y[c+36>>2],y[(y[d>>2]+(y[i>>2]<<4)+4|0)>>2]=y[c+28>>2],y[(y[d>>2]+(y[i>>2]<<4)+8|0)>>2]=y[c+32>>2],y[i>>2]=y[i>>2]+1|0,y[(c+24|0)>>2]=0,(y[c+20>>2]|0)==0&&(b=b+44|0,y[b>>2]=y[b>>2]-1|0),b=0)}else{b=1}return b}Nf.X=1;function Of(b,c){var d=m;m+=40;for(var f=7,g=0;;){var e=f>>>0>>0;a:do{if(e){for(var i=c-f|0,h=-f|0,k=0;;){for(var l=f+k|0,j=(b+l*40|0)>>2,n=d>>2,p=j+10;j>>0>>0){break}if((Pf(j,d)|0)<=0){break}j>>=2;n=o>>2;for(p=j+10;j>2;n=o>>2;for(p=j+10;j>>=1}m=d}function Fe(b,c,d,f,g,e){y[b+36>>2]=65535;var i=f>>>0>1?f:1;y[b+24>>2]=i;f=b+28|0;y[f>>2]=(e|0)==0?d:i;y[b+32>>2]=g;y[b+56>>2]=e;y[b+44>>2]=0;y[b+40>>2]=0;y[b+48>>2]=0;d=jc(680);g=b|0;y[g>>2]=d;e=(d|0)==0;a:do{if(e){i=65535}else{Pc(d,0,680);for(var i=c*384|47,h=0;;){if(h>>>0>=(y[f>>2]+1|0)>>>0){break}var k=jc(i);y[(y[g>>2]+h*40+4|0)>>2]=k;var k=F[g>>2],l=y[k+h*40+4>>2];if((l|0)==0){i=65535;break a}y[k+h*40>>2]=l+(-l&15)|0;h=h+1|0}h=jc(68);i=b+4|0;y[i>>2]=h;h=jc((y[f>>2]<<4)+16|0);y[b+12>>2]=h;i=y[i>>2];(i|0)==0|(h|0)==0?i=65535:(Pc(i,0,68),y[b+20>>2]=0,i=y[b+16>>2]=0)}}while(0);return i}Fe.X=1;function Qf(b){var c=b+40|0,d=(y[c>>2]|0)==0;a:do{if(!d){for(var f=b|0,g=b+4|0,e=0;;){var i=e+1|0;y[(y[g>>2]+(e<<2)|0)>>2]=y[f>>2]+e*40|0;if(i>>>0>=F[c>>2]>>>0){break a}e=i}}}while(0)}function Pf(b,c){var d=F[b+20>>2],f=(d|0)==0,g=F[c+20>>2],e=(g|0)==0;a:do{if(f){if(e){var i=(y[c+24>>2]|0)==0;if((y[b+24>>2]|0)==0){if(!i){i=1;break}}else{if(i){i=-1;break}}i=0}else{i=1}}else{if(e){i=-1}else{do{if(d==0){i=1;break a}else{if((d==1||d==2)&&(g-1|0)>>>0<2){d=y[b+8>>2];f=y[c+8>>2];if((d|0)>(f|0)){i=-1;break a}i=(d|0)<(f|0)&1;break a}}}while(0);if((d-1|0)>>>0<2){i=-1}else{if((g-1|0)>>>0<2){i=1}else{var i=y[b+8>>2],h=y[c+8>>2],i=(i|0)>(h|0)?1:((i|0)<(h|0))<<31>>31}}}}}while(0);return i}Pf.X=1;function rd(b,c){for(var d=y[b+4>>2],f=y[b+12>>2],g=y[b+16>>2],e=y[b+20>>2],i=d<<4,h=0;;){var k=i*h|0,l=f+(k|4)|0,j=f+(k|8)|0,n=f+(k|12)|0,p=h<<4,r=c+(p|8)|0,o=c+(p|12)|0,t=y[c+(p|4)>>2];y[(f+k|0)>>2]=y[c+p>>2];y[l>>2]=t;k=y[o>>2];y[j>>2]=y[r>>2];y[n>>2]=k;h=h+1|0;if((h|0)==16){break}}f=d<<3;h=y[c+260>>2];y[g>>2]=y[c+256>>2];y[(g+4|0)>>2]=h;h=f|4;j=y[c+268>>2];y[(g+f|0)>>2]=y[c+264>>2];y[(g+h|0)>>2]=j;j=i|4;n=y[c+276>>2];y[(g+i|0)>>2]=y[c+272>>2];y[(g+j|0)>>2]=n;n=d*24|0;r=n|4;k=y[c+284>>2];y[(g+n|0)>>2]=y[c+280>>2];y[(g+r|0)>>2]=k;k=d<<5;l=k|4;p=y[c+292>>2];y[(g+k|0)>>2]=y[c+288>>2];y[(g+l|0)>>2]=p;p=d*40|0;o=p|4;t=y[c+300>>2];y[(g+p|0)>>2]=y[c+296>>2];y[(g+o|0)>>2]=t;var t=d*48|0,s=t|4,u=y[c+308>>2];y[(g+t|0)>>2]=y[c+304>>2];y[(g+s|0)>>2]=u;var d=d*56|0,u=d|4,w=y[c+316>>2];y[(g+d|0)>>2]=y[c+312>>2];y[(g+u|0)>>2]=w;g=y[c+324>>2];y[e>>2]=y[c+320>>2];y[(e+4|0)>>2]=g;g=y[c+332>>2];y[(e+f|0)>>2]=y[c+328>>2];y[(e+h|0)>>2]=g;g=y[c+340>>2];y[(e+i|0)>>2]=y[c+336>>2];y[(e+j|0)>>2]=g;i=y[c+348>>2];y[(e+n|0)>>2]=y[c+344>>2];y[(e+r|0)>>2]=i;i=y[c+356>>2];y[(e+k|0)>>2]=y[c+352>>2];y[(e+l|0)>>2]=i;i=y[c+364>>2];y[(e+p|0)>>2]=y[c+360>>2];y[(e+o|0)>>2]=i;i=y[c+372>>2];y[(e+t|0)>>2]=y[c+368>>2];y[(e+s|0)>>2]=i;i=y[c+380>>2];y[(e+d|0)>>2]=y[c+376>>2];y[(e+u|0)>>2]=i}rd.X=1;function Ee(b){var c=b|0,d=F[c>>2],f=(d|0)==0;a:do{if(f){var g=0}else{var e=b+28|0;if((y[e>>2]|0)==-1){g=d}else{for(var i=0,h=d;;){var k=i+1|0;Ae(y[h+i*40+4>>2]);y[(y[c>>2]+i*40+4|0)>>2]=0;h=y[c>>2];if(k>>>0>=(y[e>>2]+1|0)>>>0){g=h;break a}i=k}}}}while(0);Ae(g);y[c>>2]=0;c=b+4|0;Ae(y[c>>2]);y[c>>2]=0;b=b+12|0;Ae(y[b>>2]);y[b>>2]=0}function Rf(b,c,d,f){var g,e=b+16|0;y[e>>2]=0;y[b+20>>2]=0;f=(f|0)==0;a:do{if(f){var i=0}else{var h=b+48|0,k=F[h>>2],l=(k|0)==(c|0);do{if(l){g=17}else{var j=b+32|0,n=((k+1|0)>>>0)%(F[j>>2]>>>0);if((n|0)==(c|0)){g=17}else{g=b+28|0;for(var p=b|0,r=y[y[p>>2]+y[g>>2]*40>>2],o=b+44|0,t=b+40|0;;){Cf(b,n);if((If(b)|0)!=0){i=1;break a}var s=F[g>>2],u=F[o>>2]>>>0>>0;b:do{if(u){var w=s}else{for(;;){Nf(b);var v=F[g>>2];if(F[o>>2]>>>0>>0){w=v;break b}}}}while(0);y[(y[p>>2]+w*40+20|0)>>2]=1;y[(y[p>>2]+y[g>>2]*40+12|0)>>2]=n;y[(y[p>>2]+y[g>>2]*40+8|0)>>2]=n;y[(y[p>>2]+y[g>>2]*40+16|0)>>2]=0;y[(y[p>>2]+y[g>>2]*40+24|0)>>2]=0;y[o>>2]=y[o>>2]+1|0;y[t>>2]=y[t>>2]+1|0;Of(y[p>>2],y[g>>2]+1|0);n=((n+1|0)>>>0)%(F[j>>2]>>>0);if((n|0)==(c|0)){break}}j=F[e>>2];o=(j|0)==0;b:do{if(!o){t=b+12|0;for(n=0;;){if(n>>>0>=j>>>0){break b}var z=F[g>>2],B=F[p>>2],D=F[B+z*40>>2];if((y[y[t>>2]+(n<<4)>>2]|0)==(D|0)){var C=0;break}n=n+1|0}for(;;){if(C>>>0>=z>>>0){break b}var E=B+C*40|0;if((y[E>>2]|0)==(r|0)){break}C=C+1|0}y[E>>2]=D;y[(y[p>>2]+y[g>>2]*40|0)>>2]=r}}while(0);if((d|0)!=0){g=21}else{var G=y[h>>2];g=22}}}}while(0);do{if(g==17){if((d|0)==0){G=k,g=22}else{if(l){i=1;break a}g=21}}}while(0);g==22?((G|0)!=(c|0)&&(i=F[b+32>>2],y[h>>2]=((c-1+i|0)>>>0)%(i>>>0)),i=0):g==21&&(y[h>>2]=c,i=0)}}while(0);return i}Rf.X=1;function jf(b,c,d,f){for(var g=F[b+4>>2],e=y[b+8>>2]*g|0,i=(c>>>0)%(g>>>0),h=F[b>>2],k=c-i|0,l=e<<8,j=i<<3,n=g<<4,p=(k<<8)+(i<<4)|0,r=g<<2&1073741820,o=r<<1,t=o+r|0,s=c<<8,u=i*240|0,w=(s|1)-u|0,v=(s|2)-u|0,z=(s|3)-u|0,B=s-u|0,D=0;;){var C=y[$e+(D<<2)>>2],E=y[Ze+(D<<2)>>2],G=E<<4,H=G+C|0,K=(y[f+(D<<6)>>2]|0)==16777215;a:do{if(K){var L=h+(p+C+E*n)|0,N=y[H+(d+16)>>2],O=H+(d+32)|0;y[L>>2]=y[d+H>>2];y[(L+(r<<2)|0)>>2]=N;var R=y[H+(d+48)>>2];y[(L+(o<<2)|0)>>2]=y[O>>2];y[(L+(t<<2)|0)>>2]=R}else{for(var U=n*E|0,Y=w+C+U|0,X=v+C+U|0,ba=z+C+U|0,$=B+C+U|0,ja=G+(C+1)|0,sa=G+(C+2)|0,Ea=G+(C+3)|0,Xa=C+G|0,ea=0;;){var fa=ea<<2,va=f+(D<<6)+((fa|3)<<2)|0,ob=f+(D<<6)+((fa|2)<<2)|0,wa=n*ea|0,pb=h+(Y+wa)|0,gb=h+(X+wa)|0,Ib=h+(ba+wa)|0,Fa=ea<<4,qb=d+(sa+Fa)|0,Ya=d+(Ea+Fa)|0,Na=A[d+(ja+Fa)|0]&255,za=y[f+(D<<6)+((fa|1)<<2)>>2];q[h+($+wa)|0]=q[Q.a+(y[f+(D<<6)+(fa<<2)>>2]+512+(A[d+(Xa+Fa)|0]&255))|0];var da=A[qb]&255,Oa=y[ob>>2];q[pb]=q[Q.a+((Na|512)+za)|0];var Za=A[Ya]&255,Aa=y[va>>2];q[gb]=q[Q.a+(da+(Oa+512))|0];q[Ib]=q[Q.a+(Za+(Aa+512))|0];var hb=ea+1|0;if((hb|0)==4){break a}ea=hb}}}while(0);var Ga=D+1|0;if((Ga|0)==16){break}D=Ga}for(var Pa=e<<6,$a=g<<3&2147483640,Ab=d+256|0,cb=d+320|0,rb=l+j+(k<<6)|0,Qa=$a>>>2,pa=$a>>>1,ia=pa+Qa|0,qa=l+(c<<6)|0,Ra=i*56|0,ra=(qa|1)-Ra|0,ib=(qa|2)-Ra|0,sb=(qa|3)-Ra|0,jb=qa-Ra|0,db=0;;){var Sa=db+16|0,kb=Sa&3,ta=F[$e+(kb<<2)>>2],Bb=F[Ze+(kb<<2)>>2],Ha=Sa>>>0>19,ya=Ha?cb:Ab,xa=Ha?Pa:0,Ba=Bb<<3,Ca=Ba+ta|0,Ta=(y[f+(Sa<<6)>>2]|0)==16777215;a:do{if(Ta){var lb=h+(rb+xa+ta+Bb*$a)|0,Jb=y[Ca+(ya+8)>>2],eb=Ca+(ya+16)|0;y[lb>>2]=y[ya+Ca>>2];y[(lb+(Qa<<2)|0)>>2]=Jb;var Da=y[Ca+(ya+24)>>2];y[(lb+(pa<<2)|0)>>2]=y[eb>>2];y[(lb+(ia<<2)|0)>>2]=Da}else{for(var Ia=$a*Bb|0,mb=ra+xa+ta+Ia|0,Ua=ib+xa+ta+Ia|0,Ja=sb+xa+ta+Ia|0,Ka=jb+xa+ta+Ia|0,Cb=Ba+(ta+1)|0,Db=Ba+(ta+2)|0,Eb=Ba+(ta+3)|0,tb=ta+Ba|0,Va=0;;){var fb=Va<<2,ub=f+(Sa<<6)+((fb|3)<<2)|0,nb=f+(Sa<<6)+((fb|2)<<2)|0,Fb=$a*Va|0,Qb=h+(mb+Fb)|0,wb=h+(Ua+Fb)|0,Lb=h+(Ja+Fb)|0,Rb=Va<<3,Wb=ya+(Db+Rb)|0,Tb=ya+(Eb+Rb)|0,Xb=A[ya+(Cb+Rb)|0]&255,Vb=y[f+(Sa<<6)+((fb|1)<<2)>>2];q[h+(Ka+Fb)|0]=q[Q.a+(y[f+(Sa<<6)+(fb<<2)>>2]+512+(A[ya+(tb+Rb)|0]&255))|0];var Yb=A[Wb]&255,fc=y[nb>>2];q[Qb]=q[Q.a+((Xb|512)+Vb)|0];var ga=A[Tb]&255,pc=y[ub>>2];q[wb]=q[Q.a+(Yb+(fc+512))|0];q[Lb]=q[Q.a+(ga+(pc+512))|0];var Ub=Va+1|0;if((Ub|0)==4){break a}Va=Ub}}}while(0);var Fc=db+1|0;if((Fc|0)==8){break}db=Fc}}jf.X=1;function Sf(b,c){var d=m;m+=164;var f=d+128,g=y[b+4>>2],e=b|0,i=b+8|0,h=y[i>>2],k=h*g|0,h=(h|0)==0;a:do{if(!h){for(var l=d|0,j=f|0,n=g<<4,p=k<<8,r=k<<6,o=g<<3,t=0,s=0,u=0;;){var w=c+u*216|0,v=c+u*216+24|0,z,B=y[w+8>>2];if((B|0)==1){B=0}else{z=y[w+200>>2];z=(z|0)==0?1:(B|0)==2&&((y[w+4>>2]|0)!=(y[z+4>>2]|0)&1|0)!=0?1:5;var D=y[w+204>>2],B=(D|0)==0?z:(B|0)==2&&((y[w+4>>2]|0)!=(y[D+4>>2]|0)&1|0)!=0?z:z|2}z=B;(z|0)!=0&&(Tf(w,l,z)|0)!=0&&(Uf(j,w,z),B=t*g|0,Vf(y[e>>2]+((B<<8)+(s<<4))|0,l,j,n),Wf(j,w,z,y[v>>2]),w=y[e>>2],v=(s<<3)+p+(B<<6)|0,Xf(w+v|0,w+(v+r)|0,l,j,o));s=s+1|0;w=(s|0)==(g|0);t=(w&1)+t|0;s=w?0:s;if(t>>>0>=F[i>>2]>>>0){break a}u=u+1|0}}}while(0);m=d}Sf.X=1;function Tf(b,c,d){var f=(d&2|0)==0;a:do{if(f){y[c+24>>2]=0;y[c+16>>2]=0;y[c+8>>2]=0;var g=y[c>>2]=0}else{var e=F[b>>2]>>>0>5;do{if(!e){var g=b+204|0,i=F[g>>2];if(F[i>>2]>>>0<=5){f=Yf(b,i,0,10);y[c>>2]=f;e=Yf(b,y[g>>2],1,11);y[c+8>>2]=e;i=Yf(b,y[g>>2],4,14);y[c+16>>2]=i;g=Yf(b,y[g>>2],5,15);y[c+24>>2]=g;if((f|e|0)==0&&(i|g|0)==0){g=0;break a}g=1;break a}}}while(0);y[c+24>>2]=4;y[c+16>>2]=4;y[c+8>>2]=4;y[c>>2]=4;g=1}}while(0);e=(d&4|0)==0;a:do{if(e){y[c+100>>2]=0,y[c+68>>2]=0,y[c+36>>2]=0,y[c+4>>2]=0,d=g,f=b|0}else{f=b|0;i=F[f>>2]>>>0>5;do{if(!i){var d=b+200|0,h=F[d>>2];if(F[h>>2]>>>0<=5){e=Yf(b,h,0,5);y[c+4>>2]=e;i=Yf(b,y[d>>2],2,7);y[c+36>>2]=i;h=Yf(b,y[d>>2],8,13);y[c+68>>2]=h;d=Yf(b,y[d>>2],10,15);y[c+100>>2]=d;if((g|0)!=0){d=g;break a}if((e|i|0)==0&&(h|d|0)==0){d=g;break a}d=1;break a}}}while(0);y[c+100>>2]=4;y[c+68>>2]=4;y[c+36>>2]=4;y[c+4>>2]=4;d=1}}while(0);g=F[f>>2];f=g>>>0>5;a:do{if(f){y[c+120>>2]=3,y[c+112>>2]=3,y[c+104>>2]=3,y[c+96>>2]=3,y[c+88>>2]=3,y[c+80>>2]=3,y[c+72>>2]=3,y[c+64>>2]=3,y[c+56>>2]=3,y[c+48>>2]=3,y[c+40>>2]=3,y[c+32>>2]=3,y[c+124>>2]=3,y[c+116>>2]=3,y[c+108>>2]=3,y[c+92>>2]=3,y[c+84>>2]=3,y[c+76>>2]=3,y[c+60>>2]=3,y[c+52>>2]=3,y[c+44>>2]=3,y[c+28>>2]=3,y[c+20>>2]=3,y[c+12>>2]=3,e=1}else{if((cd(g)|0)==1){Zf(b,c)}else{if(g==2){var k=b+32|0;y[c+32>>2]=x[k>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var l=b+34|0;y[c+40>>2]=x[l>>1]<<16>>16==0?x[b+30>>1]<<16>>16!=0?2:0:2;var j=b+40|0;y[c+48>>2]=x[j>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;var n=b+42|0;y[c+56>>2]=x[n>>1]<<16>>16==0?x[b+38>>1]<<16>>16!=0?2:0:2;e=b+48|0;y[c+96>>2]=x[e>>1]<<16>>16==0?x[b+44>>1]<<16>>16!=0?2:0:2;i=b+50|0;y[c+104>>2]=x[i>>1]<<16>>16==0?x[b+46>>1]<<16>>16!=0?2:0:2;h=b+56|0;y[c+112>>2]=x[h>>1]<<16>>16==0?x[b+52>>1]<<16>>16!=0?2:0:2;var p=b+58|0;y[c+120>>2]=x[p>>1]<<16>>16==0?x[b+54>>1]<<16>>16!=0?2:0:2;var r=$f(b,8,2);y[c+64>>2]=r;r=$f(b,9,3);y[c+72>>2]=r;r=$f(b,12,6);y[c+80>>2]=r;r=$f(b,13,7);y[c+88>>2]=r;r=b+30|0;y[c+12>>2]=x[r>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var o=b+36|0;y[c+20>>2]=x[o>>1]<<16>>16==0?x[r>>1]<<16>>16!=0?2:0:2;y[c+28>>2]=x[b+38>>1]<<16>>16==0?x[o>>1]<<16>>16!=0?2:0:2;y[c+44>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+52>>2]=x[j>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;y[c+60>>2]=x[n>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;k=b+46|0;y[c+76>>2]=x[k>>1]<<16>>16==0?x[b+44>>1]<<16>>16!=0?2:0:2;l=b+52|0;y[c+84>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+92>>2]=x[b+54>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;y[c+108>>2]=x[i>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;y[c+116>>2]=x[h>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;y[c+124>>2]=x[p>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2}else{if(g==3){e=b+32|0;y[c+32>>2]=x[e>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;i=b+34|0;y[c+40>>2]=x[i>>1]<<16>>16==0?x[b+30>>1]<<16>>16!=0?2:0:2;h=b+40|0;y[c+48>>2]=x[h>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;p=b+42|0;y[c+56>>2]=x[p>>1]<<16>>16==0?x[b+38>>1]<<16>>16!=0?2:0:2;k=b+44|0;y[c+64>>2]=x[k>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;l=b+46|0;y[c+72>>2]=x[l>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;j=b+52|0;y[c+80>>2]=x[j>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;n=b+54|0;y[c+88>>2]=x[n>>1]<<16>>16==0?x[p>>1]<<16>>16!=0?2:0:2;r=b+48|0;y[c+96>>2]=x[r>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;o=b+50|0;y[c+104>>2]=x[o>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;var t=b+56|0;y[c+112>>2]=x[t>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;var s=b+58|0;y[c+120>>2]=x[s>>1]<<16>>16==0?x[n>>1]<<16>>16!=0?2:0:2;y[c+12>>2]=x[b+30>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;y[c+28>>2]=x[b+38>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;y[c+44>>2]=x[i>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;y[c+60>>2]=x[p>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;y[c+76>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+92>>2]=x[n>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;y[c+108>>2]=x[o>>1]<<16>>16==0?x[r>>1]<<16>>16!=0?2:0:2;y[c+124>>2]=x[s>>1]<<16>>16==0?x[t>>1]<<16>>16!=0?2:0:2;e=$f(b,4,1);y[c+20>>2]=e;e=$f(b,6,3);y[c+52>>2]=e;e=$f(b,12,9);y[c+84>>2]=e;e=$f(b,14,11);y[c+116>>2]=e}else{e=$f(b,2,0),y[c+32>>2]=e,e=$f(b,3,1),y[c+40>>2]=e,e=$f(b,6,4),y[c+48>>2]=e,e=$f(b,7,5),y[c+56>>2]=e,e=$f(b,8,2),y[c+64>>2]=e,e=$f(b,9,3),y[c+72>>2]=e,e=$f(b,12,6),y[c+80>>2]=e,e=$f(b,13,7),y[c+88>>2]=e,e=$f(b,10,8),y[c+96>>2]=e,e=$f(b,11,9),y[c+104>>2]=e,e=$f(b,14,12),y[c+112>>2]=e,e=$f(b,15,13),y[c+120>>2]=e,e=$f(b,1,0),y[c+12>>2]=e,e=$f(b,4,1),y[c+20>>2]=e,e=$f(b,5,4),y[c+28>>2]=e,e=$f(b,3,2),y[c+44>>2]=e,e=$f(b,6,3),y[c+52>>2]=e,e=$f(b,7,6),y[c+60>>2]=e,e=$f(b,9,8),y[c+76>>2]=e,e=$f(b,12,9),y[c+84>>2]=e,e=$f(b,13,12),y[c+92>>2]=e,e=$f(b,11,10),y[c+108>>2]=e,e=$f(b,14,11),y[c+116>>2]=e,e=$f(b,15,14),y[c+124>>2]=e}}}if((d|0)!=0){e=d}else{e=(y[c+32>>2]|0)==0;do{if(e&&(y[c+40>>2]|0)==0&&(y[c+48>>2]|0)==0&&(y[c+56>>2]|0)==0&&(y[c+64>>2]|0)==0&&(y[c+72>>2]|0)==0&&(y[c+80>>2]|0)==0&&(y[c+88>>2]|0)==0&&(y[c+96>>2]|0)==0&&(y[c+104>>2]|0)==0&&(y[c+112>>2]|0)==0&&(y[c+120>>2]|0)==0&&(y[c+12>>2]|0)==0&&(y[c+20>>2]|0)==0&&(y[c+28>>2]|0)==0&&(y[c+44>>2]|0)==0&&(y[c+52>>2]|0)==0&&(y[c+60>>2]|0)==0&&(y[c+76>>2]|0)==0&&(y[c+84>>2]|0)==0&&(y[c+92>>2]|0)==0&&(y[c+108>>2]|0)==0&&(y[c+116>>2]|0)==0&&(y[c+124>>2]|0)==0){e=d;break a}}while(0);e=1}}}while(0);return e}Tf.X=1;function Zf(b,c){var d=b+32|0;y[c+32>>2]=x[d>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var f=b+34|0;y[c+40>>2]=x[f>>1]<<16>>16==0?x[b+30>>1]<<16>>16!=0?2:0:2;var g=b+40|0;y[c+48>>2]=x[g>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;var e=b+42|0;y[c+56>>2]=x[e>>1]<<16>>16==0?x[b+38>>1]<<16>>16!=0?2:0:2;var i=b+44|0;y[c+64>>2]=x[i>>1]<<16>>16==0?x[d>>1]<<16>>16!=0?2:0:2;var h=b+46|0;y[c+72>>2]=x[h>>1]<<16>>16==0?x[f>>1]<<16>>16!=0?2:0:2;var k=b+52|0;y[c+80>>2]=x[k>>1]<<16>>16==0?x[g>>1]<<16>>16!=0?2:0:2;var l=b+54|0;y[c+88>>2]=x[l>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;var j=b+48|0;y[c+96>>2]=x[j>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;var n=b+50|0;y[c+104>>2]=x[n>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;var p=b+56|0;y[c+112>>2]=x[p>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;var r=b+58|0;y[c+120>>2]=x[r>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;var o=b+30|0;y[c+12>>2]=x[o>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var t=b+36|0;y[c+20>>2]=x[t>>1]<<16>>16==0?x[o>>1]<<16>>16!=0?2:0:2;y[c+28>>2]=x[b+38>>1]<<16>>16==0?x[t>>1]<<16>>16!=0?2:0:2;y[c+44>>2]=x[f>>1]<<16>>16==0?x[d>>1]<<16>>16!=0?2:0:2;y[c+52>>2]=x[g>>1]<<16>>16==0?x[f>>1]<<16>>16!=0?2:0:2;y[c+60>>2]=x[e>>1]<<16>>16==0?x[g>>1]<<16>>16!=0?2:0:2;y[c+76>>2]=x[h>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;y[c+84>>2]=x[k>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;y[c+92>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+108>>2]=x[n>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;y[c+116>>2]=x[p>>1]<<16>>16==0?x[n>>1]<<16>>16!=0?2:0:2;y[c+124>>2]=x[r>>1]<<16>>16==0?x[p>>1]<<16>>16!=0?2:0:2}Zf.X=1;function Uf(b,c,d){var f=F[c+20>>2],g=c+12|0,e=Cc(0,51,y[g>>2]+f|0),i=c+16|0,h=Cc(0,51,y[i>>2]+f|0),k=A[Q.f+e|0]&255;y[b+28>>2]=k;h=A[Q.g+h|0]&255;y[b+32>>2]=h;e=Q.h+e*3|0;y[b+24>>2]=e;if((d&2|0)!=0){var l=y[y[c+204>>2]+20>>2];if((l|0)==(f|0)){y[b+4>>2]=k,y[b+8>>2]=h,y[b>>2]=e}else{var j=(l+(f+1)|0)>>>1,l=Cc(0,51,y[g>>2]+j|0),j=Cc(0,51,y[i>>2]+j|0);y[b+4>>2]=A[Q.f+l|0]&255;y[b+8>>2]=A[Q.g+j|0]&255;y[b>>2]=Q.h+l*3|0}}(d&4|0)!=0&&(c=y[y[c+200>>2]+20>>2],(c|0)==(f|0)?(y[b+16>>2]=k,y[b+20>>2]=h,y[b+12>>2]=e):(f=(c+(f+1)|0)>>>1,g=Cc(0,51,y[g>>2]+f|0),i=Cc(0,51,y[i>>2]+f|0),y[b+16>>2]=A[Q.f+g|0]&255,y[b+20>>2]=A[Q.g+i|0]&255,y[b+12>>2]=Q.h+g*3|0))}Uf.X=1;function Vf(b,c,d,f){for(var g,e=d+24|0,i=d+12|0,h=f<<2,k=0,l=0;;){var j=h*l|0,n=b+j|0,p=j+(b+4)|0,r=j+(b+8)|0,j=j+(b+12)|0,o=l<<2,t=c+(o<<3)|0,s=o|1,u=c+(s<<3)+4|0,w=o|2;g=c+(w<<3)+4|0;var v=o|3,z=c+(v<<3)+4|0,s=c+(s<<3)|0,w=c+(w<<3)|0,v=c+(v<<3)|0,o=y[c+(o<<3)+4>>2];(o|0)!=0&&ag(n,o,i,f);u=y[u>>2];(u|0)!=0&&ag(p,u,e,f);g=y[g>>2];(g|0)!=0&&ag(r,g,e,f);z=y[z>>2];(z|0)!=0&&ag(j,z,e,f);t=y[t>>2];z=y[s>>2];(t|0)==(z|0)?(g=y[w>>2],(z|0)!=(g|0)?g=14:(g|0)!=(y[v>>2]|0)?g=14:((t|0)!=0&&bg(n,t,d+k*12|0,f),g=22)):g=14;g==14&&((t|0)==0?n=z:(cg(n,t,d+k*12|0,f),n=y[s>>2]),(n|0)!=0&&cg(p,n,d+k*12|0,f),p=y[w>>2],(p|0)!=0&&cg(r,p,d+k*12|0,f),r=y[v>>2],(r|0)!=0&&cg(j,r,d+k*12|0,f));l=l+1|0;if((l|0)==4){break}k=2}}Vf.X=1;function Wf(b,c,d,f){var g=c+20|0,e=F[Ad+(Cc(0,51,y[g>>2]+f|0)<<2)>>2],i=c+12|0,h=Cc(0,51,y[i>>2]+e|0),k=c+16|0,l=Cc(0,51,y[k>>2]+e|0),j=A[Q.f+h|0]&255;y[b+28>>2]=j;l=A[Q.g+l|0]&255;y[b+32>>2]=l;h=Q.h+h*3|0;y[b+24>>2]=h;if((d&2|0)!=0){var n=y[y[c+204>>2]+20>>2];if((n|0)==(y[g>>2]|0)){y[b+4>>2]=j,y[b+8>>2]=l,y[b>>2]=h}else{var p=(e+1+y[Ad+(Cc(0,51,n+f|0)<<2)>>2]|0)>>>1,n=Cc(0,51,p+y[i>>2]|0),p=Cc(0,51,y[k>>2]+p|0);y[b+4>>2]=A[Q.f+n|0]&255;y[b+8>>2]=A[Q.g+p|0]&255;y[b>>2]=Q.h+n*3|0}}(d&4|0)!=0&&(c=y[y[c+200>>2]+20>>2],(c|0)==(y[g>>2]|0)?(y[b+16>>2]=j,y[b+20>>2]=l,y[b+12>>2]=h):(f=(e+1+y[Ad+(Cc(0,51,c+f|0)<<2)>>2]|0)>>>1,i=Cc(0,51,f+y[i>>2]|0),k=Cc(0,51,y[k>>2]+f|0),y[b+16>>2]=A[Q.f+i|0]&255,y[b+20>>2]=A[Q.g+k|0]&255,y[b+12>>2]=Q.h+i*3|0))}Wf.X=1;function Xf(b,c,d,f,g){for(var e,i=f+24|0,h=f+12|0,k=g<<2,l=g<<1,j=l+4|0,n=0,p=0;;){var r=k*n|0,o=b+r|0,t=l+r|0,s=b+t|0,u=r+4|0,w=b+u|0,v=r|2,z=b+v|0,B=r+6|0,D=b+B|0,C=j+r|0,E=b+C|0,r=c+r|0;e=c+t|0;var u=c+u|0,v=c+v|0,B=c+B|0,G=c+C|0,C=n<<3,H=d+(C<<3)+4|0,K=d+(C<<3)|0,L=d+((C|4)<<3)+4|0,t=C|2,N=d+(t<<3)+4|0,O=d+((C|6)<<3)+4|0,R=d+((C|1)<<3)|0,t=d+(t<<3)|0,C=d+((C|3)<<3)|0,U=y[H>>2];(U|0)!=0&&(dg(o,U,h,g),dg(r,y[H>>2],h,g));H=y[L>>2];(H|0)!=0&&(dg(s,H,h,g),dg(e,y[L>>2],h,g));s=y[N>>2];(s|0)!=0&&(dg(w,s,i,g),dg(u,y[N>>2],i,g));s=y[O>>2];(s|0)!=0&&(dg(E,s,i,g),dg(G,y[O>>2],i,g));E=y[K>>2];s=y[R>>2];(E|0)==(s|0)?(e=y[t>>2],(s|0)!=(e|0)?e=14:(e|0)!=(y[C>>2]|0)?e=14:((E|0)!=0&&(e=f+p*12|0,eg(o,E,e,g),eg(r,y[K>>2],e,g)),e=22)):e=14;e==14&&((E|0)==0?o=s:(s=f+p*12|0,fg(o,E,s,g),fg(r,y[K>>2],s,g),o=y[R>>2]),(o|0)!=0&&(r=f+p*12|0,fg(z,o,r,g),fg(v,y[R>>2],r,g)),z=y[t>>2],(z|0)!=0&&(o=f+p*12|0,fg(w,z,o,g),fg(u,y[t>>2],o,g)),w=y[C>>2],(w|0)!=0&&(p=f+p*12|0,fg(D,w,p,g),fg(B,y[C>>2],p,g)));n=n+1|0;if((n|0)==2){break}p=2}}Xf.X=1;function dg(b,c,d,f){var g=b-1|0,e=A[b+1|0],i=A[g]&255,h=A[b]&255,k=Bc(i-h|0),l=d+4|0;if(k>>>0>2]>>>0){var k=A[b-2|0]&255,j=Bc(k-i|0),n=F[d+8>>2];j>>>0>>0&&(e&=255,Bc(e-h|0)>>>0>>0&&(c>>>0<4?(n=A[y[d>>2]+(c-1)|0]&255,k=Cc(n^-1,n+1|0,4-e+(h-i<<2)+k>>3),h=q[Q.a+((h|512)-k)|0],q[g]=q[Q.a+((i|512)+k)|0],q[b]=h):(q[g]=(e+(i+2)+(k<<1)|0)>>>2&255,q[b]=(h+2+(e<<1)+k|0)>>>2&255)))}g=b+f|0;i=b+(f-1)|0;e=A[f+(b+1)|0];h=A[i]&255;k=A[g]&255;Bc(h-k|0)>>>0>2]>>>0&&(b=A[b+(f-2)|0]&255,l=Bc(b-h|0),f=F[d+8>>2],l>>>0>>0&&(l=e&255,Bc(l-k|0)>>>0>>0&&(c>>>0<4?(c=A[y[d>>2]+(c-1)|0]&255,c=Cc(c^-1,c+1|0,4-l+(k-h<<2)+b>>3),d=q[Q.a+((k|512)-c)|0],q[i]=q[Q.a+((h|512)+c)|0],q[g]=d):(q[i]=(l+(h+2)+(b<<1)|0)>>>2&255,q[g]=(k+2+(l<<1)+b|0)>>>2&255))))}dg.X=1;function eg(b,c,d,f){var g=c>>>0<4;a:do{if(g){var e=A[y[d>>2]+(c-1)|0]&255,i=e+1|0,h=d+4|0,k=d+8|0;e^=-1;for(var l=f*-2|0,j=0;;){var n=b+(j-f)|0,p=b+j|0,r=A[b+(j+f)|0],o=A[n]&255,t=A[p]&255;if(Bc(o-t|0)>>>0>2]>>>0){var s=A[b+(l+j)|0]&255,u=Bc(s-o|0),w=F[k>>2];u>>>0>>0&&(r&=255,Bc(r-t|0)>>>0>>0&&(s=Cc(e,i,4-r+(t-o<<2)+s>>3),t=q[Q.a+((t|512)-s)|0],q[n]=q[Q.a+((o|512)+s)|0],q[p]=t))}j=j+1|0;if((j|0)==8){break a}}}else{i=d+4|0;h=d+8|0;k=f*-2|0;for(e=0;;){if(l=b+(e-f)|0,j=b+e|0,s=A[b+(e+f)|0],n=A[l]&255,p=A[j]&255,Bc(n-p|0)>>>0>2]>>>0&&(o=A[b+(k+e)|0]&255,w=Bc(o-n|0),t=F[h>>2],w>>>0>>0&&(s&=255,Bc(s-p|0)>>>0>>0&&(q[l]=(s+(n+2)+(o<<1)|0)>>>2&255,q[j]=(p+2+(s<<1)+o|0)>>>2&255))),e=e+1|0,(e|0)==8){break a}}}}while(0)}eg.X=1;function fg(b,c,d,f){var g=A[y[d>>2]+(c-1)|0]&255,c=g+1|0,e=d+4|0,i=d+8|0,d=g^-1,g=f*-2|0,h=b+ -f|0,k=A[b+f|0],l=A[h]&255,j=A[b]&255,n=Bc(l-j|0),p=F[e>>2];if(n>>>0

>>0){var n=A[b+g|0]&255,r=Bc(n-l|0),o=F[i>>2];r>>>0>>0&&(k&=255,Bc(k-j|0)>>>0>>0&&(p=Cc(d,c,4-k+(j-l<<2)+n>>3),j=q[Q.a+((j|512)-p)|0],q[h]=q[Q.a+((l|512)+p)|0],q[b]=j,p=y[e>>2]))}e=b+(1-f)|0;h=b+1|0;j=A[f+(b+1)|0];f=A[e]&255;l=A[h]&255;Bc(f-l|0)>>>0

>>0&&(b=A[b+(g|1)|0]&255,g=Bc(b-f|0),i=F[i>>2],g>>>0>>0&&(g=j&255,Bc(g-l|0)>>>0>>0&&(c=Cc(d,c,4-g+(l-f<<2)+b>>3),d=q[Q.a+((l|512)-c)|0],q[e]=q[Q.a+((f|512)+c)|0],q[h]=d)))}fg.X=1;function ag(b,c,d,f){var g=F[d+4>>2],e=F[d+8>>2],i=c>>>0<4;a:do{if(i){for(var h=A[y[d>>2]+(c-1)|0]&255,k=-h|0,l=h+1|0,j=0;;){var n=j*f|0,p=b+(n-2)|0,r=b+(n-1)|0,o=n+(b+1)|0,t=b+(n-3)|0,s=n+(b+2)|0,n=b+n|0,u=A[p]&255,w=A[r]&255,v=A[n]&255,z=A[o]&255;Bc(w-v|0)>>>0>>0&&Bc(u-w|0)>>>0>>0&&Bc(z-v|0)>>>0>>0&&(t=A[t]&255,s=A[s]&255,Bc(t-w|0)>>>0>>0?(q[p]=Cc(k,h,(v+(w+1)>>1)-(u<<1)+t>>1)+u&255,p=l):p=h,Bc(s-v|0)>>>0>>0?(q[o]=Cc(k,h,(v+(w+1)>>1)-(z<<1)+s>>1)+z&255,o=p+1|0):o=p,o=Cc(-o|0,o,u+4-z+(v-w<<2)>>3),v=q[Q.a+((v|512)-o)|0],q[r]=q[Q.a+((w|512)+o)|0],q[n]=v);j=j+1|0;if((j|0)==4){break a}}}else{h=(g>>>2)+2|0;for(k=0;;){var u=k*f|0,n=b+(u-2)|0,w=b+(u-1)|0,l=u+(b+1)|0,v=b+(u-3)|0,j=u+(b+2)|0,o=b+(u-4)|0,r=u+(b+3)|0,u=b+u|0,z=A[n]&255,s=A[w]&255,t=A[u]&255,B=A[l]&255,D=Bc(s-t|0),C=D>>>0>>0;b:do{if(C&&Bc(z-s|0)>>>0>>0&&Bc(B-t|0)>>>0>>0){var E=D>>>0>>0,G=A[v]&255,p=A[j]&255;do{if(E){if(Bc(G-s|0)>>>0>>0){E=s+z+t|0,q[w]=(B+4+(E<<1)+G|0)>>>3&255,q[n]=(G+(E+2)|0)>>>2&255,q[v]=(E+4+G*3+((A[o]&255)<<1)|0)>>>3&255}else{if(q[w]=(s+2+(z<<1)+B|0)>>>2&255,!E){break}}if(Bc(p-t|0)>>>0>=e>>>0){break}n=t+s+B|0;q[u]=(z+4+(n<<1)+p|0)>>>3&255;q[l]=(p+(n+2)|0)>>>2&255;q[j]=(n+4+p*3+((A[r]&255)<<1)|0)>>>3&255;break b}q[w]=(s+2+(z<<1)+B|0)>>>2&255}while(0);q[u]=(t+(z+2)+(B<<1)|0)>>>2&255}}while(0);k=k+1|0;if((k|0)==4){break a}}}}while(0)}ag.X=1;function bg(b,c,d,f){var g=F[d+4>>2],e=F[d+8>>2],i=c>>>0<4;a:do{if(i){for(var h=A[y[d>>2]+(c-1)|0]&255,k=-h|0,l=h+1|0,j=f*-2|0,n=f*-3|0,p=f<<1,r=0;;){var o=b+(j+r)|0,t=b+(r-f)|0,s=b+(r+f)|0,u=b+(n+r)|0,w=b+(p+r)|0,v=b+r|0,z=A[o]&255,B=A[t]&255,D=A[v]&255,C=A[s]&255;Bc(B-D|0)>>>0>>0&&Bc(z-B|0)>>>0>>0&&Bc(C-D|0)>>>0>>0&&(u=A[u]&255,Bc(u-B|0)>>>0>>0?(q[o]=Cc(k,h,(D+(B+1)>>1)-(z<<1)+u>>1)+z&255,o=l):o=h,w=A[w]&255,Bc(w-D|0)>>>0>>0?(q[s]=Cc(k,h,(D+(B+1)>>1)-(C<<1)+w>>1)+C&255,s=o+1|0):s=o,z=Cc(-s|0,s,z+4-C+(D-B<<2)>>3),D=q[Q.a+((D|512)-z)|0],q[t]=q[Q.a+((B|512)+z)|0],q[v]=D);r=r+1|0;if((r|0)==16){break a}}}else{h=(g>>>2)+2|0;k=f*-3|0;l=f*3|0;j=f*-2|0;n=f<<1;p=f*-4|0;for(r=0;;){var s=b+(j+r)|0,w=b+(r-f)|0,t=b+(r+f)|0,o=b+(k+r)|0,v=b+(n+r)|0,u=b+(p+r)|0,B=b+(l+r)|0,D=b+r|0,z=A[s]&255,E=A[w]&255,G=A[D]&255,H=A[t]&255,K=Bc(E-G|0),L=K>>>0>>0;b:do{if(L&&Bc(z-E|0)>>>0>>0&&Bc(H-G|0)>>>0>>0){var N=K>>>0>>0,O=A[o]&255,C=A[v]&255;do{if(N){if(Bc(O-E|0)>>>0>>0){N=E+z+G|0,q[w]=(H+4+(N<<1)+O|0)>>>3&255,q[s]=(O+(N+2)|0)>>>2&255,q[o]=(N+4+O*3+((A[u]&255)<<1)|0)>>>3&255}else{if(q[w]=(E+2+(z<<1)+H|0)>>>2&255,!N){break}}if(Bc(C-G|0)>>>0>=e>>>0){break}s=G+E+H|0;q[D]=(z+4+(s<<1)+C|0)>>>3&255;q[t]=(C+(s+2)|0)>>>2&255;q[v]=(s+4+C*3+((A[B]&255)<<1)|0)>>>3&255;break b}q[w]=(E+2+(z<<1)+H|0)>>>2&255}while(0);q[D]=(G+(z+2)+(H<<1)|0)>>>2&255}}while(0);r=r+1|0;if((r|0)==16){break a}}}}while(0)}bg.X=1;function cg(b,c,d,f){for(var c=A[y[d>>2]+(c-1)|0]&255,g=d+4|0,d=d+8|0,e=-c|0,i=c+1|0,h=f*-2|0,k=f*-3|0,l=f<<1,j=0;;){var n=b+(h+j)|0,p=b+(j-f)|0,r=b+(j+f)|0,o=b+(k+j)|0,t=b+(l+j)|0,s=b+j|0,u=A[r],w=A[p]&255,v=A[s]&255;if(Bc(w-v|0)>>>0>2]>>>0){var z=A[n]&255,B=Bc(z-w|0),D=F[d>>2];B>>>0>>0&&(u&=255,Bc(u-v|0)>>>0>>0&&(o=A[o]&255,Bc(o-w|0)>>>0>>0?(q[n]=Cc(e,c,(v+(w+1)>>1)-(z<<1)+o>>1)+z&255,n=i,D=y[d>>2]):n=c,t=A[t]&255,Bc(t-v|0)>>>0>>0?(q[r]=Cc(e,c,(v+(w+1)>>1)-(u<<1)+t>>1)+u&255,r=n+1|0):r=n,z=Cc(-r|0,r,4-u+(v-w<<2)+z>>3),v=q[Q.a+((v|512)-z)|0],q[p]=q[Q.a+((w|512)+z)|0],q[s]=v))}j=j+1|0;if((j|0)==4){break}}}cg.X=1;function Yf(b,c,d,f){return x[b+28+(d<<1)>>1]<<16>>16==0?x[c+28+(f<<1)>>1]<<16>>16!=0?2:(y[b+116+(d>>>2<<2)>>2]|0)!=(y[c+116+(f>>>2<<2)>>2]|0)?1:(Bc((x[b+132+(d<<2)>>1]<<16>>16)-(x[c+132+(f<<2)>>1]<<16>>16)|0)|0)>3?1:(Bc((x[b+132+(d<<2)+2>>1]<<16>>16)-(x[c+132+(f<<2)+2>>1]<<16>>16)|0)|0)>3?1:0:2}function $f(b,c,d){var f=x[b+132+(c<<2)>>1]<<16>>16,g=x[b+132+(d<<2)>>1]<<16>>16,e=x[b+132+(c<<2)+2>>1]<<16>>16,i=x[b+132+(d<<2)+2>>1]<<16>>16;return x[b+28+(c<<1)>>1]<<16>>16==0?x[b+28+(d<<1)>>1]<<16>>16!=0?2:(Bc(f-g|0)|0)>3?1:(Bc(e-i|0)|0)>3?1:(y[b+116+(c>>>2<<2)>>2]|0)!=(y[b+116+(d>>>2<<2)>>2]|0)?1:0:2}function gg(b,c,d){var f,g=F[c+4>>2],e=F[c+8>>2];if(d==5||d==0){f=2}else{if((y[b+3384>>2]|0)==0){var i=0;f=4}else{f=2}}a:do{if(f==2){for(var h=b+1220|0,k=0;;){var l=k+1|0,k=gf(h,k);if(!(l>>>0<16&(k|0)==0)){i=k;break a}k=l}}}while(0);for(var h=b+1212|0,l=b+1176|0,j=F[l>>2],n=0,k=f=0;;){if(f>>>0>=j>>>0){break}if((y[y[h>>2]+f*216+196>>2]|0)!=0){break}f=f+1|0;var n=n+1|0,p=(n|0)==(g|0),k=(p&1)+k|0,n=p?0:n}j=(f|0)==(j|0);a:do{if(j){do{if(d==7||d==2){if((y[b+3384>>2]|0)==0|(i|0)==0){f=13;break}}else{if((i|0)==0){f=13;break}}f=14}while(0);f==13?Pc(y[c>>2],128,g*384*e|0):f==14&&sd(y[c>>2],i,g*384*e|0);f=y[l>>2];y[b+1204>>2]=f;if((f|0)!=0){for(f=0;;){p=f+1|0;y[(y[h>>2]+f*216+8|0)>>2]=1;if(p>>>0>=F[l>>2]>>>0){break a}f=p}}}else{f=F[h>>2];p=(n|0)==0;b:do{if(!p){for(var r=b+1204|0,o=g*k|0,t=n+o|0,s=n-1|0,o=s+o|0,u=0;;){var w=f+(t-u)*216-20|0;hg(f+(o-u)*216|0,c,k,s-u|0,d,i);y[w>>2]=1;y[r>>2]=y[r>>2]+1|0;u=u+1|0;if((u|0)==(n|0)){break b}}}}while(0);p=n+1|0;r=p>>>0>>0;b:do{if(r){t=b+1204|0;s=g-1-n|0;o=p+g*k|0;for(u=0;;){var w=o+u|0,v=f+w*216+196|0;(y[v>>2]|0)==0&&(hg(f+w*216|0,c,k,p+u|0,d,i),y[v>>2]=1,y[t>>2]=y[t>>2]+1|0);u=u+1|0;if((u|0)==(s|0)){break b}}}}while(0);f=(k|0)==0;b:do{if(f){var z=0}else{if((g|0)==0){z=k}else{p=k-1|0;r=b+1204|0;t=-g|0;s=g*p|0;for(o=0;;){u=y[h>>2]+(s+o)*216|0;for(w=0;;){hg(u,c,p-w|0,o,d,i);y[u+196>>2]=1;y[r>>2]=y[r>>2]+1|0;w=w+1|0;if((w|0)==(k|0)){break}u=u+t*216|0}o=o+1|0;if((o|0)==(g|0)){z=k;break b}}}}}while(0);f=z+1|0;if(f>>>0>>0){p=(g|0)==0;r=b+1204|0;t=e-1-z|0;for(s=0;;){o=f+s|0;u=g*o|0;w=y[h>>2];b:do{if(!p){for(v=0;;){var B=u+v|0,D=w+B*216+196|0;(y[D>>2]|0)==0&&(hg(w+B*216|0,c,o,v,d,i),y[D>>2]=1,y[r>>2]=y[r>>2]+1|0);v=v+1|0;if((v|0)==(g|0)){break b}}}}while(0);s=s+1|0;if((s|0)==(t|0)){break a}}}}}while(0);return 0}gg.X=1;function hg(b,c,d,f,g,e){var i=m;m+=452;var h,k=i+384,l=i+448,j=m;m+=24;var n=F[c+4>>2],p=F[c+8>>2];Lc(c,n*d+f|0);var r=c|0,o=F[r>>2],t=d<<4,s=f<<4,u=(d<<8)*n+s|0;y[b+20>>2]=40;y[b+8>>2]=0;y[b>>2]=6;y[b+12>>2]=0;y[b+16>>2]=0;y[b+24>>2]=0;if(g==7||g==2){Pc(i|0,0,384),h=5}else{y[l>>2]=0;y[j+4>>2]=n;y[j+8>>2]=p;y[j>>2]=e;var w=i|0;(e|0)==0?(Pc(w,0,384),h=5):(df(w,l,j,s,t,0,0,16,16),rd(c,w),h=70)}if(h==5){var v=k|0;Pc(k,0,64);if((d|0)==0){var z=0,B=I,D=I,C=I,E=I}else{if((y[b+ -n*216+196>>2]|0)==0){z=0,E=C=D=B=I}else{var G=u-(n<<4)|0,H=G|1,K=G|3,L=(A[o+H|0]&255)+(A[o+G|0]&255)+(A[H+(o+1)|0]&255)+(A[o+K|0]&255)|0,N=G|7,O=(A[K+(o+2)|0]&255)+(A[K+(o+1)|0]&255)+(A[K+(o+3)|0]&255)+(A[o+N|0]&255)|0,R=(A[N+(o+2)|0]&255)+(A[N+(o+1)|0]&255)+(A[N+(o+3)|0]&255)+(A[N+(o+4)|0]&255)|0,U=(A[N+(o+6)|0]&255)+(A[N+(o+5)|0]&255)+(A[N+(o+7)|0]&255)+(A[o+(G|15)|0]&255)|0,Y=O+L|0;y[v>>2]=R+Y+y[v>>2]+U|0;var X=k+4|0;y[X>>2]=Y-R+y[X>>2]-U|0;z=1;B=L;D=O;C=R;E=U}}if((p-1|0)==(d|0)){var ba=0,$=z,ja=I,sa=I,Ea=I,Xa=I}else{if((y[b+n*216+196>>2]|0)==0){ba=0,$=z,Xa=Ea=sa=ja=I}else{var ea=u+(n<<8)|0,fa=ea|1,va=ea|3,ob=(A[o+fa|0]&255)+(A[o+ea|0]&255)+(A[fa+(o+1)|0]&255)+(A[o+va|0]&255)|0,wa=ea|7,pb=(A[va+(o+2)|0]&255)+(A[va+(o+1)|0]&255)+(A[va+(o+3)|0]&255)+(A[o+wa|0]&255)|0,gb=(A[wa+(o+2)|0]&255)+(A[wa+(o+1)|0]&255)+(A[wa+(o+3)|0]&255)+(A[wa+(o+4)|0]&255)|0,Ib=(A[wa+(o+6)|0]&255)+(A[wa+(o+5)|0]&255)+(A[wa+(o+7)|0]&255)+(A[o+(ea|15)|0]&255)|0,Fa=pb+ob|0;y[v>>2]=gb+Fa+y[v>>2]+Ib|0;var qb=k+4|0;y[qb>>2]=Fa-gb+y[qb>>2]-Ib|0;ba=1;$=z+1|0;ja=ob;sa=pb;Ea=gb;Xa=Ib}}if((f|0)==0){var Ya=$,Na=0,za=I,da=I,Oa=I,Za=I}else{if((y[b-216+196>>2]|0)==0){Ya=$,Na=0,Za=Oa=da=za=I}else{var Aa=u-1|0,hb=n<<4,Ga=n<<5,Pa=n*48|0,$a=(A[o+(Aa+hb)|0]&255)+(A[o+Aa|0]&255)+(A[o+(Aa+Ga)|0]&255)+(A[o+(Aa+Pa)|0]&255)|0,Ab=n<<6,cb=Aa+Ab|0,rb=(A[o+(cb+hb)|0]&255)+(A[o+cb|0]&255)+(A[o+(cb+Ga)|0]&255)+(A[o+(cb+Pa)|0]&255)|0,Qa=cb+Ab|0,pa=(A[o+(Qa+hb)|0]&255)+(A[o+Qa|0]&255)+(A[o+(Qa+Ga)|0]&255)+(A[o+(Qa+Pa)|0]&255)|0,ia=Qa+Ab|0,qa=(A[o+(ia+hb)|0]&255)+(A[o+ia|0]&255)+(A[o+(ia+Ga)|0]&255)+(A[o+(ia+Pa)|0]&255)|0,Ra=rb+$a|0;y[v>>2]=pa+Ra+y[v>>2]+qa|0;var ra=k+16|0;y[ra>>2]=Ra-pa+y[ra>>2]-qa|0;Ya=$+1|0;Na=1;za=$a;da=rb;Oa=pa;Za=qa}}if((n-1|0)==(f|0)){h=16}else{if((y[b+412>>2]|0)==0){h=16}else{var ib=u+16|0,sb=n<<4,jb=n<<5,db=n*48|0,Sa=(A[o+(ib+sb)|0]&255)+(A[o+ib|0]&255)+(A[o+(ib+jb)|0]&255)+(A[o+(ib+db)|0]&255)|0,kb=n<<6,ta=ib+kb|0,Bb=(A[o+(ta+sb)|0]&255)+(A[o+ta|0]&255)+(A[o+(ta+jb)|0]&255)+(A[o+(ta+db)|0]&255)|0,Ha=ta+kb|0,ya=(A[o+(Ha+sb)|0]&255)+(A[o+Ha|0]&255)+(A[o+(Ha+jb)|0]&255)+(A[o+(Ha+db)|0]&255)|0,xa=Ha+kb|0,Ba=(A[o+(xa+sb)|0]&255)+(A[o+xa|0]&255)+(A[o+(xa+jb)|0]&255)+(A[o+(xa+db)|0]&255)|0,Ca=Ya+1|0,Ta=Na+1|0,lb=Bb+Sa|0;y[v>>2]=ya+lb+y[v>>2]+Ba|0;var Jb=k+16|0,eb=lb-ya+y[Jb>>2]-Ba|0;y[Jb>>2]=eb;var Da=($|0)!=0;if(Da|(Na|0)==0){if(Da){var Ia=1,mb=Ca,Ua=Ta;h=20}else{Ja=Ta,Ka=Ca,Cb=1,Db=eb,h=25}}else{y[k+4>>2]=Oa+Za+da+za-Sa-Bb-ya-Ba>>5;var Ja=Ta,Ka=Ca,Cb=1,Db=eb;h=25}}}if(h==16){if(($|0)==0){var Eb=Na,tb=Ya,Va=0;h=21}else{Ia=0,mb=Ya,Ua=Na,h=20}}h==20&&(y[(k+4|0)>>2]>>=$+3,Eb=Ua,tb=mb,Va=Ia,h=21);if(h==21){var fb=(Eb|0)!=0;if(fb|(z|0)==0|(ba|0)==0){if(fb){Ja=Eb,Ka=tb,Cb=Va,Db=y[k+16>>2],h=25}else{var ub=Va,nb=tb;h=26}}else{y[k+16>>2]=C+E+D+B-Xa-Ea-sa-ja>>5,ub=Va,nb=tb,h=26}}h==25&&(y[k+16>>2]=Db>>Ja+3,ub=Cb,nb=Ka);nb==1?y[v>>2]>>=4:nb==2?y[v>>2]>>=5:nb==3?y[v>>2]=y[v>>2]*21>>10:y[v>>2]>>=6;ig(v);var Fb=i|0,Qb=0,wb=Fb,Lb=0;a:for(;;){for(var Rb=Lb<<2,Wb=Qb+1|0,Tb=0;;){var Xb=Tb+1|0,Vb=Wb+Tb|0,Yb=Qb+Tb|0;if(Yb>>>0>=256){break a}var fc=F[k+((Rb|Yb>>>2&3)<<2)>>2];q[wb+Tb|0]=(fc|0)<0?0:(fc|0)>255?-1:fc&255;if((Vb&63|0)==0){break}Tb=Xb}Qb=Vb;wb=wb+Xb|0;Lb=Lb+1|0}for(var ga=F[r>>2],pc=(z|0)!=0,Ub=k+4|0,Fc=(ba|0)!=0,Fg=(Na|0)!=0,qc=k+16|0,Gg=(ub|0)!=0,Yh=Fg^1,Zh=Gg^1,$h=pc^1,ai=Fc^1,bi=p*n<<6,Zb=(p<<8)+(d<<6)|0,$b=f<<3,hc=n*(Zb-8)+$b|0,ic=n*(Zb+64)+$b|0,Hg=n*Zb+$b|0,ci=Hg-1|0,di=Hg+8|0,Ig=n*(Zb|8)+$b|0,ei=Ig+8|0,Jg=n*(Zb|16)+$b|0,fi=Jg+8|0,Kg=n*(Zb|24)+$b|0,gi=Kg+8|0,Lg=n*(Zb|32)+$b|0,hi=Lg+8|0,Mg=n*(Zb|40)+$b|0,ii=Mg+8|0,Ng=n*(Zb|48)+$b|0,ji=Ng+8|0,Og=n*(Zb|56)+$b|0,ki=Og+8|0,li=Ig-1|0,mi=Jg-1|0,ni=Kg-1|0,oi=Lg-1|0,pi=Mg-1|0,qi=Ng-1|0,ri=Og-1|0,si=ic|1,ti=ic|2,ui=ic|3,vi=ic|4,wi=ic|5,xi=ic|6,yi=ic|7,zi=hc|1,Ai=hc|2,Bi=hc|3,Ci=hc|4,Di=hc|5,Ei=hc|6,Fi=hc|7,Pg=Za,Qg=Oa,Rg=da,Sg=za,Tg=Xa,Ug=Ea,Vg=sa,Wg=ja,Xg=E,Yg=C,Zg=D,$g=B,Yc=0;;){var Gi=i+((Yc<<6)+256)|0,la=bi*Yc|0,Hi=ga+(ic+la)|0,Ii=ga+(ci+la)|0,Ji=ga+(di+la)|0,Ki=ga+(ei+la)|0,Li=ga+(fi+la)|0,Mi=ga+(gi+la)|0,Ni=ga+(hi+la)|0,Oi=ga+(ii+la)|0,Pi=ga+(ji+la)|0,Qi=ga+(ki+la)|0,Ri=ga+(li+la)|0,Si=ga+(mi+la)|0,Ti=ga+(ni+la)|0,Ui=ga+(oi+la)|0,Vi=ga+(pi+la)|0,Wi=ga+(qi+la)|0,Xi=ga+(ri+la)|0,Yi=ga+(si+la)|0,Zi=ga+(ti+la)|0,$i=ga+(ui+la)|0,aj=ga+(vi+la)|0,bj=ga+(wi+la)|0,cj=ga+(xi+la)|0,dj=ga+(yi+la)|0;Pc(k,0,64);if(pc){var ah=(A[ga+(zi+la)|0]&255)+(A[ga+(hc+la)|0]&255)|0,bh=(A[ga+(Bi+la)|0]&255)+(A[ga+(Ai+la)|0]&255)|0,Ed=(A[ga+(Di+la)|0]&255)+(A[ga+(Ci+la)|0]&255)|0,Fd=(A[ga+(Fi+la)|0]&255)+(A[ga+(Ei+la)|0]&255)|0,ch=bh+ah|0;y[v>>2]=Ed+ch+y[v>>2]+Fd|0;y[Ub>>2]=ch-Ed+y[Ub>>2]-Fd|0;var Gd=1,Hd=ah,Id=bh,Jd=Ed,Kd=Fd}else{Gd=0,Hd=$g,Id=Zg,Jd=Yg,Kd=Xg}if(Fc){var dh=(A[Yi]&255)+(A[Hi]&255)|0,eh=(A[$i]&255)+(A[Zi]&255)|0,Ld=(A[bj]&255)+(A[aj]&255)|0,Md=(A[dj]&255)+(A[cj]&255)|0,fh=eh+dh|0;y[v>>2]=Ld+fh+y[v>>2]+Md|0;y[Ub>>2]=fh-Ld+y[Ub>>2]-Md|0;var yc=Gd+1|0,Nd=dh,Od=eh,Pd=Ld,Qd=Md}else{yc=Gd,Nd=Wg,Od=Vg,Pd=Ug,Qd=Tg}if(Fg){var gh=(A[Ri]&255)+(A[Ii]&255)|0,hh=(A[Ti]&255)+(A[Si]&255)|0,Rd=(A[Vi]&255)+(A[Ui]&255)|0,Sd=(A[Xi]&255)+(A[Wi]&255)|0,ih=hh+gh|0;y[v>>2]=Rd+ih+y[v>>2]+Sd|0;y[qc>>2]=ih-Rd+y[qc>>2]-Sd|0;var Zc=yc+1|0,$c=1,Td=gh,Ud=hh,Vd=Rd,Wd=Sd}else{Zc=yc,$c=0,Td=Sg,Ud=Rg,Vd=Qg,Wd=Pg}if(Gg){var jh=(A[Ki]&255)+(A[Ji]&255)|0,kh=(A[Mi]&255)+(A[Li]&255)|0,Xd=(A[Oi]&255)+(A[Ni]&255)|0,Yd=(A[Qi]&255)+(A[Pi]&255)|0,Zd=Zc+1|0,$d=$c+1|0,lh=kh+jh|0;y[v>>2]=Xd+lh+y[v>>2]+Yd|0;var ae=lh-Xd+y[qc>>2]-Yd|0;y[qc>>2]=ae;var mh=(yc|0)!=0;if(mh|Yh|Zh){if(mh){var nh=Zd,oh=$d;h=50}else{be=$d,ce=Zd,de=ae,h=55}}else{y[Ub>>2]=Vd+Wd+Ud+Td-jh-kh-Xd-Yd>>4;var be=$d,ce=Zd,de=ae;h=55}}else{if((yc|0)==0){var ee=$c,ad=Zc;h=51}else{nh=Zc,oh=$c,h=50}}h==50&&(y[Ub>>2]>>=yc+2,ee=oh,ad=nh,h=51);if(h==51){var ph=(ee|0)!=0;if(ph|$h|ai){if(ph){be=ee,ce=ad,de=y[qc>>2],h=55}else{var Jc=ad;h=56}}else{y[qc>>2]=Jd+Kd+Id+Hd-Qd-Pd-Od-Nd>>4,Jc=ad,h=56}}h==55&&(y[qc>>2]=de>>be+2,Jc=ce);Jc==1?y[v>>2]>>=3:Jc==2?y[v>>2]>>=4:Jc==3?y[v>>2]=y[v>>2]*21>>9:y[v>>2]>>=5;ig(v);var fe=0,ge=Gi,he=0;a:for(;;){for(var ej=he<<2,fj=fe+1|0,Kc=0;;){var qh=Kc+1|0,rh=fj+Kc|0,sh=fe+Kc|0;if(sh>>>0>=64){break a}var ie=F[k+((ej|sh>>>1&3)<<2)>>2];q[ge+Kc|0]=(ie|0)<0?0:(ie|0)>255?-1:ie&255;if((rh&15|0)==0){break}Kc=qh}fe=rh;ge=ge+qh|0;he=he+1|0}var th=Yc+1|0;if((th|0)==2){break}Pg=Wd;Qg=Vd;Rg=Ud;Sg=Td;Tg=Qd;Ug=Pd;Vg=Od;Wg=Nd;Xg=Kd;Yg=Jd;Zg=Id;$g=Hd;Yc=th}rd(c,Fb)}m=i}hg.X=1;function ig(b){var c=b+4|0,d=y[c>>2],f=b+16|0,g=y[f>>2],e=y[b>>2];if((d|g|0)==0){y[b+60>>2]=e,y[b+56>>2]=e,y[b+52>>2]=e,y[b+48>>2]=e,y[b+44>>2]=e,y[b+40>>2]=e,y[b+36>>2]=e,y[b+32>>2]=e,y[b+28>>2]=e,y[b+24>>2]=e,y[b+20>>2]=e,y[f>>2]=e,y[b+12>>2]=e,y[b+8>>2]=e,y[c>>2]=e}else{var i=d+e|0,h=d>>1,k=h+e|0,h=e-h|0,d=e-d|0;y[b>>2]=g+i|0;e=g>>1;y[f>>2]=e+i|0;y[(b+32|0)>>2]=i-e|0;y[(b+48|0)>>2]=i-g|0;y[c>>2]=g+k|0;y[(b+20|0)>>2]=e+k|0;y[(b+36|0)>>2]=k-e|0;y[(b+52|0)>>2]=k-g|0;y[(b+8|0)>>2]=g+h|0;y[(b+24|0)>>2]=e+h|0;y[(b+40|0)>>2]=h-e|0;y[(b+56|0)>>2]=h-g|0;y[(b+12|0)>>2]=g+d|0;y[(b+28|0)>>2]=e+d|0;y[(b+44|0)>>2]=d-e|0;y[(b+60|0)>>2]=d-g|0}}ig.X=1;function jg(b,c,d,f){var g,e=(y[d+284>>2]|0)==0;a:do{if(e){var i=0}else{for(i=0;;){var h=y[d+288+i*20>>2];if(h==0){i=0;break a}else{if(h==5){break}}i=i+1|0}i=1}}while(0);e=y[c+16>>2];do{if(e==0){if((y[f>>2]|0)==5){y[b+4>>2]=0;var k=y[b>>2]=0}else{k=y[b>>2]}var l=d+20|0,j=F[l>>2],h=b|0;if(j>>>0>>0){if(g=F[c+20>>2],(k-j|0)>>>0>>1>>>0){g=11}else{var n=y[b+4>>2]+g|0;g=15}}else{g=11}a:do{if(g==11){n=j>>>0>k>>>0;do{if(n){var p=F[c+20>>2];if((j-k|0)>>>0>p>>>1>>>0){n=y[b+4>>2]-p|0;break a}}}while(0);n=y[b+4>>2]}}while(0);k=f+4|0;(y[k>>2]|0)==0?(h=y[d+24>>2],h=j+n+((h|0)<0?h:0)|0):(j=b+4|0,y[j>>2]=n,l=y[l>>2],g=d+24|0,p=y[g>>2],p=l+n+((p|0)<0?p:0)|0,(y[k>>2]|0)==0?h=p:(i|0)==0?(y[h>>2]=l,h=p):(y[j>>2]=0,l=y[g>>2],y[h>>2]=(l|0)<0?-l|0:0,h=0))}else{if(e==1){(y[f>>2]|0)==5?h=0:(h=y[b+12>>2],h=F[b+8>>2]>>>0>F[d+12>>2]>>>0?y[c+12>>2]+h|0:h);var p=F[c+36>>2],r=(p|0)==0,j=r?0:y[d+12>>2]+h|0,k=(l=(y[f+4>>2]|0)==0)?(((j|0)!=0)<<31>>31)+j|0:j;(j=(k|0)!=0)?(g=k-1|0,k=(g>>>0)%(p>>>0),g=Math.floor((g>>>0)/(p>>>0))):g=k=I;a:do{if(r){var o=0}else{for(var t=y[c+40>>2],s=p>>>0>1?p:1,u=0,w=0;;){if(w=y[t+(u<<2)>>2]+w|0,u=u+1|0,(u|0)==(s|0)){o=w;break a}}}}while(0);a:do{if(j){p=y[c+40>>2];t=o*g|0;for(s=0;;){r=s+1|0;t=y[p+(s<<2)>>2]+t|0;if(r>>>0>k>>>0){var v=t;break a}s=r}}else{v=0}}while(0);j=l?y[c+28>>2]+v|0:v;k=y[d+32>>2]+y[c+32>>2]|0;l=b+12|0;(i|0)==0?(j=((k|0)<0?k:0)+j+y[d+28>>2]|0,y[l>>2]=h,y[b+8>>2]=y[d+12>>2],h=j):(y[l>>2]=0,h=y[b+8>>2]=0)}else{(y[f>>2]|0)==5?(j=l=0,h=b+12|0):(l=F[d+12>>2],h=b+12|0,j=y[h>>2],j=F[b+8>>2]>>>0>l>>>0?y[c+12>>2]+j|0:j,l=l+j<<1,l=(y[f+4>>2]|0)!=0?l:l-1|0),(i|0)==0?(y[h>>2]=j,y[b+8>>2]=y[d+12>>2],h=l):(y[h>>2]=0,h=y[b+8>>2]=0)}}}while(0);return h}jg.X=1;function Rc(b,c){var d;Pc(c,0,952);var f=S(b,1),g=(f|0)==-1;a:do{if(g){d=1}else{d=(f|0)==1;y[c>>2]=d&1;do{if(d){var e=S(b,8);if((e|0)==-1){d=1;break a}y[c+4>>2]=e;if((e|0)==255){e=S(b,16);if((e|0)==-1){d=1;break a}y[c+8>>2]=e;e=S(b,16);if((e|0)==-1){d=1;break a}y[c+12>>2]=e}}}while(0);d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+16>>2]=d&1;if(d){d=S(b,1);if((d|0)==-1){d=1;break}y[c+20>>2]=(d|0)==1&1}d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+24>>2]=d&1;if(d){d=S(b,3);if((d|0)==-1){d=1;break}y[c+28>>2]=d;d=S(b,1);if((d|0)==-1){d=1;break}y[c+32>>2]=(d|0)==1&1;d=S(b,1);if((d|0)==-1){d=1;break}d=(d|0)==1;y[c+36>>2]=d&1;if(d){d=S(b,8);if((d|0)==-1){d=1;break}y[c+40>>2]=d;d=S(b,8);if((d|0)==-1){d=1;break}y[c+44>>2]=d;d=S(b,8);if((d|0)==-1){d=1;break}y[c+48>>2]=d}else{y[c+40>>2]=2,y[c+44>>2]=2,y[c+48>>2]=2}}else{y[c+28>>2]=5,y[c+40>>2]=2,y[c+44>>2]=2,y[c+48>>2]=2}d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+52>>2]=d&1;if(d){d=c+56|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>5){d=1;break}d=c+60|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>5){d=1;break}}d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+64>>2]=d&1;if(d){d=id(b);if((od(b,32)|0)==-1|(d|0)==0){d=1;break}y[c+68>>2]=d;d=id(b);if((od(b,32)|0)==-1|(d|0)==0){d=1;break}y[c+72>>2]=d;d=S(b,1);if((d|0)==-1){d=1;break}y[c+76>>2]=(d|0)==1&1}d=S(b,1);if((d|0)==-1){d=1}else{e=(d|0)==1;d=c+80|0;y[d>>2]=e&1;if(e){if(e=kg(b,c+84|0),(e|0)!=0){d=e;break}}else{y[c+84>>2]=1,y[c+96>>2]=288000001,y[c+224>>2]=288000001,y[c+480>>2]=24,y[c+484>>2]=24,y[c+488>>2]=24,y[c+492>>2]=24}e=S(b,1);if((e|0)==-1){d=1}else{var i=(e|0)==1,e=c+496|0;y[e>>2]=i&1;if(i){if(i=kg(b,c+500|0),(i|0)!=0){d=i;break}}else{y[c+500>>2]=1,y[c+512>>2]=240000001,y[c+640>>2]=240000001,y[c+896>>2]=24,y[c+900>>2]=24,y[c+904>>2]=24,y[c+908>>2]=24}d=(y[d>>2]|0)==0?(y[e>>2]|0)==0?47:45:45;if(d==45){d=S(b,1);if((d|0)==-1){d=1;break}y[c+912>>2]=(d|0)==1&1}d=S(b,1);if((d|0)==-1){d=1}else{if(y[c+916>>2]=(d|0)==1&1,d=S(b,1),(d|0)==-1){d=1}else{d=(d|0)==1;y[c+920>>2]=d&1;if(d){d=S(b,1);if((d|0)==-1){d=1;break}y[c+924>>2]=(d|0)==1&1;d=c+928|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=c+932|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=c+936|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=c+940|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=T(b,c+944|0);if((d|0)!=0){break}d=T(b,c+948|0);if((d|0)!=0){break}}else{y[c+924>>2]=1,y[c+928>>2]=2,y[c+932>>2]=1,y[c+936>>2]=16,y[c+940>>2]=16,y[c+944>>2]=16,y[c+948>>2]=16}d=0}}}}}}}}}}while(0);return d}Rc.X=1;function kg(b,c){var d=c|0,f=T(b,d),g=(f|0)==0;a:do{if(g){var e=y[d>>2]+1|0;y[d>>2]=e;if(e>>>0>32){e=1}else{var i=S(b,4);if((i|0)==-1){e=1}else{e=c+4|0;y[e>>2]=i;var h=S(b,4);if((h|0)==-1){e=1}else{i=c+8|0;y[i>>2]=h;for(h=0;;){var k=c+268+(h<<2)|0,l=c+140+(h<<2)|0,j=c+12+(h<<2)|0;if(h>>>0>=F[d>>2]>>>0){break}var n=T(b,j);if((n|0)!=0){e=n;break a}n=y[j>>2];if((n|0)==-1){e=1;break a}n=n+1|0;y[j>>2]=n;y[j>>2]=n<>2]+6;j=T(b,l);if((j|0)!=0){e=j;break a}j=y[l>>2];if((j|0)==-1){e=1;break a}j=j+1|0;y[l>>2]=j;y[l>>2]=j<>2]+4;l=S(b,1);if((l|0)==-1){e=1;break a}y[k>>2]=(l|0)==1&1;h=h+1|0}e=S(b,5);(e|0)==-1?e=1:(y[c+396>>2]=e+1|0,e=S(b,5),(e|0)==-1?e=1:(y[c+400>>2]=e+1|0,e=S(b,5),(e|0)==-1?e=1:(y[c+404>>2]=e+1|0,e=S(b,5),(e|0)==-1?e=1:(y[c+408>>2]=e,e=0))))}}}}else{e=f}}while(0);return e}kg.X=1;function lg(b,c,d,f,g,e){var b=b+16|0,i=y[b>>2];if((i|0)==0){b=3}else{if((y[i+60>>2]|0)==0){b=3}else{y[c>>2]=1;y[d>>2]=y[y[b>>2]+64>>2]<<1;var h=y[b>>2];y[f>>2]=(y[h+52>>2]<<4)-(y[h+68>>2]+y[h+64>>2]<<1)|0;y[g>>2]=y[y[b>>2]+72>>2]<<1;h=y[b>>2];h=(y[h+56>>2]<<4)-(y[h+76>>2]+y[h+72>>2]<<1)|0;b=4}}b==3&&(y[c>>2]=0,y[d>>2]=0,y[f>>2]=0,h=y[g>>2]=0);y[e>>2]=h}lg.X=1;function mg(b,c,d,f,g){var e=m;m+=204;var i,h=e+4,k=e+12,l=e+104,j=e+176,n=e+196,p=e+200;y[n>>2]=0;var r=b+3344|0;(y[r>>2]|0)==0?i=3:(y[b+3348>>2]|0)!=(c|0)?i=3:(i=b+3356|0,y[j>>2]=y[i>>2],y[j+4>>2]=y[i+4>>2],y[j+8>>2]=y[i+8>>2],y[j+12>>2]=y[i+12>>2],y[j+16>>2]=y[i+16>>2],y[j+4>>2]=y[j>>2],y[j+8>>2]=0,y[j+16>>2]=0,y[g>>2]=y[b+3352>>2],i=5);if(i==3){if((Mc(c,d,j,g)|0)!=0){var o=3;i=58}else{i=b+3356|0,y[i>>2]=y[j>>2],y[i+4>>2]=y[j+4>>2],y[i+8>>2]=y[j+8>>2],y[i+12>>2]=y[j+12>>2],y[i+16>>2]=y[j+16>>2],y[b+3352>>2]=y[g>>2],y[b+3348>>2]=c,i=5}}a:do{if(i==5){y[r>>2]=0;d=j;c=h;if((S(d,1)|0)==-1){c=1}else{var t=S(d,2),o=c+4|0;y[o>>2]=t;d=S(d,5);y[c>>2]=d;c=(d-2|0)>>>0<3?1:(d-7|0)>>>0<2|(d|0)==5&&(y[o>>2]|0)==0?1:(d==12||d==11||d==10||d==9||d==6)&&(y[o>>2]|0)!=0?1:0}if((c|0)!=0){o=3}else{if(c=h|0,o=F[c>>2],(o|0)==0|o>>>0>12){o=0}else{if(o=Ie(j,h,b,n),o==0){o=(y[n>>2]|0)==0;b:do{if(!o){i=(y[b+1184>>2]|0)==0;do{if(!i&&(y[b+16>>2]|0)!=0){if((y[b+3380>>2]|0)!=0){o=3;break a}if((y[b+1188>>2]|0)==0){i=b+1220|0;var s=Jf(i),u=b+1336|0;y[b+1336>>2]=s;Qf(i);gg(b,u,0)}else{gg(b,b+1336|0,y[b+1372>>2])}y[g>>2]=0;y[r>>2]=1;y[b+1180>>2]=0;var s=b+1336|0,u=b+1368|0,w=b+1360|0;i=53;break b}}while(0);y[b+1188>>2]=0;y[b+1180>>2]=0}i=18}while(0);if(i==18){if(w=F[c>>2],w==7){if((Oc(j,k)|0)==0){ze(b,k);o=0;break}b=k+40|0;Ae(y[b>>2]);y[b>>2]=0;b=k+84|0;Ae(y[b>>2]);y[b>>2]=0;o=3;break}else{if(w==8){if((Sc(j,l)|0)==0){Be(b,l);o=0;break}b=l+20|0;Ae(y[b>>2]);y[b>>2]=0;b=l+24|0;Ae(y[b>>2]);y[b>>2]=0;b=l+28|0;Ae(y[b>>2]);y[b>>2]=0;b=l+44|0;Ae(y[b>>2]);y[b>>2]=0;o=3;break}else{if(w==5||w==1){s=b+1180|0;if((y[s>>2]|0)!=0){o=0;break}y[b+1184>>2]=1;u=((y[b+1188>>2]|0)==0&1|0)==0;do{if(!u){y[b+1204>>2]=0;y[b+1208>>2]=f;Wc(j,e);u=b+8|0;o=y[u>>2];w=(w|0)==5;d=Ce(b,y[e>>2],w&1);if((d|0)==0){if((o|0)==(y[u>>2]|0)){break}k=F[b+16>>2];y[p>>2]=1;l=b|0;f=F[l>>2];f=f>>>0<32?y[b+20+(f<<2)>>2]:0;y[g>>2]=0;y[r>>2]=1;if(w){if(g=ed(p,j,k,y[b+12>>2]),(y[p>>2]|g|0)!=0){i=38}else{if(p=b+1220|0,(y[b+1276>>2]|0)!=0|(f|0)==0){i=38}else{if((y[f+52>>2]|0)!=(y[k+52>>2]|0)){i=38}else{if((y[f+56>>2]|0)!=(y[k+56>>2]|0)){i=38}else{if((y[f+88>>2]|0)!=(y[k+88>>2]|0)){i=38}else{g=(y[p>>2]|0)==0;b:do{if(!g){for(y[p+60>>2]=1;;){if((Nf(p)|0)!=0){break b}}}}while(0);i=40}}}}}}else{i=38}i==38&&(y[b+1280>>2]=0);y[l>>2]=y[u>>2];o=2;break a}y[b+4>>2]=256;y[b+12>>2]=0;y[u>>2]=32;y[b+16>>2]=0;y[b+3380>>2]=0;o=(d|0)==65535?5:4;break a}}while(0);if((y[b+3380>>2]|0)!=0){o=3;break}u=b+1368|0;w=b+2356|0;d=b+16|0;if((Uc(j,w,y[d>>2],y[b+12>>2],h)|0)!=0){o=3;break}if(((y[b+1188>>2]|0)==0&1|0)==0){c=b+1220|0}else{o=b+1220|0;if((y[c>>2]|0)!=5&&(Rf(o,y[b+2368>>2],(y[h+4>>2]|0)!=0&1,y[y[d>>2]+48>>2])|0)!=0){o=3;break}c=Jf(o);y[b+1336>>2]=c;c=o}w>>=2;o=u>>2;for(d=w+247;w>2]=1;w=b+1360|0;o=h;d=w;t=y[o+4>>2];y[d>>2]=y[o>>2];y[d+4>>2]=t;o=y[b+16>>2];Je(y[b+1172>>2],y[b+12>>2],y[b+1432>>2],y[o+52>>2],y[o+56>>2]);Qf(c);if((Gf(c,b+1436|0,y[b+1380>>2],y[b+1412>>2])|0)!=0){o=3;break}c=b+1336|0;if((fd(j,b,c,u)|0)!=0){jd(b,y[b+1368>>2]);o=3;break}d=aa;o=(y[b+1404>>2]|0)==0;do{if(o){if((y[b+1196>>2]|0)==(y[b+1176>>2]|0)){var v=1,d=7;break}}else{d=F[b+1176>>2];t=(d|0)==0;b:do{if(t){var z=0}else{for(var B=y[b+1212>>2],D=d>>>0>1?d:1,C=0,E=0;;){if(E=((y[B+C*216+196>>2]|0)!=0&1)+E|0,C=C+1|0,(C|0)==(D|0)){z=E;break b}}}}while(0);if((z|0)==(d|0)){v=1;d=7;break}}d=6}while(0);d==6&&(v=0);if((v|0)==0){o=0;break}y[s>>2]=1;s=c}else{o=0;break}}}}Sf(s,y[b+1212>>2]);c=b;y[c+1196>>2]=0;y[c+1192>>2]=0;o=c+1176|0;d=(y[o>>2]|0)==0;b:do{if(!d){t=c+1212|0;for(B=0;;){D=B+1|0;y[(y[t>>2]+B*216+4|0)>>2]=0;y[(y[t>>2]+B*216+196|0)>>2]=0;if(D>>>0>=F[o>>2]>>>0){break b}B=D}}}while(0);c=jg(b+1284|0,y[b+16>>2],u,w);o=b+1188|0;(y[o>>2]|0)!=0&&(d=b+1220|0,(y[b+1364>>2]|0)==0?Kf(d,0,s,y[b+1380>>2],c,(y[b+1360>>2]|0)==5&1,y[b+1208>>2],y[b+1204>>2]):Kf(d,b+1644|0,s,y[b+1380>>2],c,(y[b+1360>>2]|0)==5&1,y[b+1208>>2],y[b+1204>>2]));y[b+1184>>2]=0;y[o>>2]=0;o=1}else{o=o==65520?4:3}}}}}while(0);m=e;return o}mg.X=1;function ng(b){for(var c=0;;){var d=b+20+(c<<2)|0,f=y[d>>2];(f|0)!=0&&(Ae(y[f+40>>2]),y[(y[d>>2]+40|0)>>2]=0,Ae(y[y[d>>2]+84>>2]),y[(y[d>>2]+84|0)>>2]=0,Ae(y[d>>2]),y[d>>2]=0);c=c+1|0;if((c|0)==32){var g=0;break}}for(;;){if(c=b+148+(g<<2)|0,d=y[c>>2],(d|0)!=0&&(Ae(y[d+20>>2]),y[(y[c>>2]+20|0)>>2]=0,Ae(y[y[c>>2]+24>>2]),y[(y[c>>2]+24|0)>>2]=0,Ae(y[y[c>>2]+28>>2]),y[(y[c>>2]+28|0)>>2]=0,Ae(y[y[c>>2]+44>>2]),y[(y[c>>2]+44|0)>>2]=0,Ae(y[c>>2]),y[c>>2]=0),g=g+1|0,(g|0)==256){break}}g=b+3376|0;Ae(y[g>>2]);y[g>>2]=0;g=b+1212|0;Ae(y[g>>2]);y[g>>2]=0;g=b+1172|0;Ae(y[g>>2]);y[g>>2]=0;Ee(b+1220|0)}ng.X=1;Module._broadwaySetStreamLength=(function(b){y[og>>2]=b});function pg(b,c,d){var f=m;m+=4;var g=(c|0)==0|(d|0)==0;a:do{if(g){var e=-1}else{var i=c|0;if((y[i>>2]|0)==0){e=-1}else{var h=c+4|0;if((y[h>>2]|0)==0){e=-1}else{if((b|0)==0){e=-3}else{if(e=b,(y[e>>2]|0)==0){e=-3}else{var k=d|0;y[k>>2]=0;y[f>>2]=0;var l=y[h>>2],j=y[i>>2],i=b+8|0;y[b+3392>>2]=y[c+12>>2];var h=c+8|0,n=1,p=j,r=l,l=0;b:for(;;){if((y[e>>2]|0)==2){y[e>>2]=1;y[k>>2]=p+l|0;break}l=mg(i,p,r,y[h>>2],f);j=y[f>>2];p=p+j|0;r=r-j|0;r=(r|0)<0?0:r;y[k>>2]=p;do{if(l==2){break b}else{if(l==1){b=b+4|0;y[b>>2]=y[b>>2]+1|0;e=(r|0)==0?2:3;break a}else{if(l==4){var o=0;c:for(;;){if(o>>>0>=256){var t=1;break}var s=F[i+148+(o<<2)>>2],u=(s|0)==0;do{if(!u){var w=y[i+20+(y[s+4>>2]<<2)>>2];if((w|0)!=0&&(De(s,y[w+52>>2],y[w+56>>2])|0)==0){t=0;break c}}}while(0);o=o+1|0}o=((t|0)==0&1|r|0)!=0?n:-2}else{if(l==5){e=-4;break a}else{o=n}}}}}while(0);if((r|0)==0){e=o;break a}n=o;l=j}k=b+1288|0;(y[k>>2]|0)==0?e=4:(y[b+1244>>2]|0)==(y[b+1248>>2]|0)?e=4:(y[k>>2]=0,y[e>>2]=2,e=3)}}}}}}while(0);m=f;return e}pg.X=1;function qg(){var b=y[rg>>2],c=sg,d=m;m+=12;var f=d+4,g=d+8;if((b|0)==0|(c|0)==0){c=-1}else{var e=(b+8|0)+1220|0,b=e+20|0,i=F[b>>2];i>>>0>2]>>>0?(e=y[e+12>>2],y[b>>2]=i+1|0,b=e+(i<<4)|0):b=0;(b|0)==0?b=0:(y[g>>2]=y[b+4>>2],y[f>>2]=y[b+12>>2],y[d>>2]=y[b+8>>2],b=y[b>>2]);(b|0)==0?c=0:(y[c>>2]=b,y[c+4>>2]=y[g>>2],y[c+8>>2]=y[f>>2],y[c+12>>2]=y[d>>2],c=2)}m=d;return c}Module._broadwayCreateStream=(function(b){var c=og,d=jc(b);y[c+8>>2]=d;y[c+4>>2]=d;y[c>>2]=b;y[c+12>>2]=d+b|0;return y[og+4>>2]});Module._broadwayPlayStream=(function(){var b=og;y[tg>>2]=y[b+4>>2];for(y[tg+4>>2]=y[b>>2];;){if(ug(),(y[tg+4>>2]|0)==0){break}}});Module._broadwayInit=(function(){var b=rg;if((b|0)==0){b=-1}else{var c=jc(3396);if((c|0)==0){b=-4}else{var d=c+8|0;Pc(d,0,3388);y[d+8>>2]=32;y[d+4>>2]=256;y[d+1332>>2]=1;var f=jc(2112);y[d+3376>>2]=f;(((f|0)==0?1:0)|0)==0?(y[c>>2]=1,y[c+4>>2]=0,y[b>>2]=c,b=0):((c|0)!=0&&(ng(c+8|0),Ae(c)),b=-4)}}(b|0)==0?(y[vg>>2]=1,y[wg>>2]=1):(xg(Q.aa|0),yg());return-1});function ug(){var b;y[tg+8>>2]=y[wg>>2];var c=pg(y[rg>>2],tg,zg);if(c==4){var d=y[rg>>2],f=Ag;if((d|0)==0|(f|0)==0){f=-1}else{if(b=d+8|0,(y[d+24>>2]|0)==0){f=-6}else{if((y[d+20>>2]|0)==0){f=-6}else{d=y[b+16>>2];y[f+4>>2]=((d|0)==0?0:y[d+52>>2])<<4;d=y[b+16>>2];y[f+8>>2]=((d|0)==0?0:y[d+56>>2])<<4;d=y[b+16>>2];if((d|0)==0){d=5}else{if((y[d+80>>2]|0)==0){d=5}else{if(d=y[d+84>>2],(d|0)==0){d=5}else{if((y[d+24>>2]|0)==0){d=5}else{if((y[d+32>>2]|0)==0){d=5}else{var g=1,d=6}}}}}d==5&&(g=0);y[f+12>>2]=g;g=y[b+16>>2];(g|0)==0?g=2:(y[g+80>>2]|0)==0?g=2:(g=y[g+84>>2],g=(g|0)==0?2:(y[g+24>>2]|0)==0?2:(y[g+36>>2]|0)==0?2:y[g+48>>2]);y[f+16>>2]=g;lg(b,f+28|0,f+32|0,f+36|0,f+40|0,f+44|0);g=y[b+16>>2];(g|0)==0?g=d=1:(y[g+80>>2]|0)==0?g=d=1:(d=y[g+84>>2],(d|0)==0?g=d=1:(y[d>>2]|0)==0?g=d=1:(g=y[d+4>>2],g==255?(g=y[d+8>>2],d=y[d+12>>2],(g|0)==0|(d|0)==0&&(g=d=0)):g==1?g=d=1:g==2?(d=11,g=12):g==3?(d=11,g=10):g==4?(d=11,g=16):g==5?(d=33,g=40):g==6?(d=11,g=24):g==7?(d=11,g=20):g==8?(d=11,g=32):g==9?(d=33,g=80):g==10?(d=11,g=18):g==11?(d=11,g=15):g==12?(d=33,g=64):g==13?(d=99,g=160):g=d=0));y[(f+20|0)>>2]=g;y[(f+24|0)>>2]=d;b=y[b+16>>2];y[f>>2]=(b|0)==0?0:y[b>>2];f=0}}}(f|0)!=0?f=-1:(y[Bg>>2]=(y[Ag+4>>2]*3*y[Ag+8>>2]|0)>>>1,Cg((Pb=m,m+=1,m=m+3>>2<<2,y[Pb>>2]=0,Pb)),f=F[zg>>2],y[tg+4>>2]=y[tg+4>>2]-f+y[tg>>2]|0,y[tg>>2]=f,f=0);b=8}else{c==3?(b=y[zg>>2],y[tg+4>>2]=y[tg+4>>2]-b+y[tg>>2]|0,y[tg>>2]=b,b=5):c==-2||c==1?(y[tg+4>>2]=0,f=c,b=8):c==2?(y[tg+4>>2]=0,b=5):(f=c,b=8)}a:do{if(b==5){if(y[wg>>2]=y[wg>>2]+1|0,(qg()|0)!=2){f=c}else{for(;;){if(y[vg>>2]=y[vg>>2]+1|0,Dg(y[sg>>2],y[Ag+4>>2],y[Ag+8>>2]),(qg()|0)!=2){f=c;break a}}}}}while(0);return f}ug.X=1;function yg(){var b=y[Eg>>2];(b|0)!=0&&Ae(b)}Module._broadwayExit=yg;Module._broadwayGetMajorVersion=(function(){var b=m;m+=8;y[b>>2]=2;y[b+4>>2]=3;var c=y[b>>2];m=b;return c});Module._broadwayGetMinorVersion=(function(){var b=m;m+=8;y[b>>2]=2;y[b+4>>2]=3;var c=y[b+4>>2];m=b;return c});function Pc(b,c,d){kc(b,c&255,d)}function jc(b){var c,d=b>>>0<245;do{if(d){var f=b>>>0<11?16:b+11&-8,g=f>>>3;c=F[V>>2];var e=c>>>(g>>>0);if((e&3|0)!=0){var i=(e&1^1)+g|0,f=i<<1,h=V+40+(f<<2)|0,d=V+40+(f+2<<2)|0,f=F[d>>2],b=f+8|0,k=F[b>>2];(h|0)==(k|0)?y[V>>2]=c&(1<>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[d>>2]=k,y[k+12>>2]=h);i<<=3;y[f+4>>2]=i|3;y[(f+(i|4)|0)>>2]|=1;k=b;c=37;break}if(f>>>0<=F[V+8>>2]>>>0){var l=f;c=29;break}if((e|0)!=0){b=1<>>12&16;k=d>>>(b>>>0);d=k>>>5&8;g=k>>>(d>>>0);k=g>>>2&4;e=g>>>(k>>>0);g=e>>>1&2;e>>>=g>>>0;var j=e>>>1&1,k=(d|b|k|g|j)+(e>>>(j>>>0))|0,b=k<<1,g=V+40+(b<<2)|0,e=V+40+(b+2<<2)|0,d=F[e>>2],b=d+8|0,j=F[b>>2];(g|0)==(j|0)?y[V>>2]=c&(1<>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[e>>2]=j,y[j+12>>2]=g);k<<=3;c=k-f|0;y[d+4>>2]=f|3;g=d;d=g+f|0;y[g+(f|4)>>2]=c|1;y[g+k>>2]=c;j=F[V+8>>2];(j|0)!=0&&(f=y[V+20>>2],g=j>>>2&1073741822,k=V+40+(g<<2)|0,e=F[V>>2],j=1<<(j>>>3),(e&j|0)==0?(y[V>>2]=e|j,i=k,h=V+40+(g+2<<2)|0):(g=V+40+(g+2<<2)|0,e=F[g>>2],e>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(i=e,h=g)),y[h>>2]=f,y[i+12>>2]=f,y[(f+8|0)>>2]=i,y[(f+12|0)>>2]=k);y[V+8>>2]=c;y[V+20>>2]=d;k=b;c=37;break}if((y[V+4>>2]|0)==0){l=f;c=29;break}c=uh(f);if((c|0)==0){l=f;c=29;break}k=c}else{if(b>>>0>4294967231){l=-1;c=29;break}c=b+11&-8;if((y[V+4>>2]|0)==0){l=c;c=29;break}f=vh(c);if((f|0)==0){l=c;c=29;break}k=f}c=37}while(0);c==29&&(i=F[V+8>>2],l>>>0>i>>>0?(i=F[V+12>>2],l>>>0>>0?(i=i-l|0,y[V+12>>2]=i,h=F[V+24>>2],y[V+24>>2]=h+l|0,y[l+(h+4)>>2]=i|1,y[h+4>>2]=l|3,k=h+8|0):k=wh(l)):(h=i-l|0,c=F[V+20>>2],h>>>0>15?(y[V+20>>2]=c+l|0,y[V+8>>2]=h,y[l+(c+4)>>2]=h|1,y[c+i>>2]=h,y[c+4>>2]=l|3):(y[V+8>>2]=0,y[V+20>>2]=0,y[c+4>>2]=i|3,y[(i+(c+4)|0)>>2]|=1),k=c+8|0));return k}jc.X=1;function uh(b){var c=y[V+4>>2],d=(c&-c)-1|0,c=d>>>12&16,f=d>>>(c>>>0),d=f>>>5&8,g=f>>>(d>>>0),f=g>>>2&4,e=g>>>(f>>>0),g=e>>>1&2;e>>>=g>>>0;var i=e>>>1&1,c=d=F[V+304+((d|c|f|g|i)+(e>>>(i>>>0))<<2)>>2],d=(y[d+4>>2]&-8)-b|0;a:for(;;){for(f=c;;){g=y[f+16>>2];if((g|0)==0){if(f=y[f+20>>2],(f|0)==0){break a}}else{f=g}g=(y[f+4>>2]&-8)-b|0;if(g>>>0>>0){c=f;d=g;continue a}}}g=c;i=F[V+16>>2];e=g>>>0>>0;do{if(!e){var h=g+b|0,f=h;if(g>>>0>>0){var e=F[c+24>>2],h=F[c+12>>2],k=(h|0)==(c|0);do{if(k){var l=c+20|0,j=y[l>>2];if((j|0)==0&&(l=c+16|0,j=y[l>>2],(j|0)==0)){var n=0;break}for(;;){var p=j+20|0,r=y[p>>2];if((r|0)==0&&(p=j+16|0,r=F[p>>2],(r|0)==0)){break}l=p;j=r}l>>>0>>0?(W(),a("Reached an unreachable!")):(y[l>>2]=0,n=j)}else{l=F[c+8>>2],l>>>0>>0?(W(),a("Reached an unreachable!")):(y[l+12>>2]=h,y[h+8>>2]=l,n=h)}}while(0);i=(e|0)==0;a:do{if(!i){h=c+28|0;k=V+304+(y[h>>2]<<2)|0;l=(c|0)==(y[k>>2]|0);do{if(l){y[k>>2]=n;if((n|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break a}if(e>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{if(j=e+16|0,(y[j>>2]|0)==(c|0)?y[j>>2]=n:y[e+20>>2]=n,(n|0)==0){break a}}}while(0);n>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[n+24>>2]=e,h=F[c+16>>2],(h|0)!=0&&(h>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[n+16>>2]=h,y[h+24>>2]=n)),h=F[c+20>>2],(h|0)!=0&&(h>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[n+20>>2]=h,y[h+24>>2]=n)))}}while(0);if(d>>>0<16){var o=d+b|0;y[c+4>>2]=o|3;y[(o+(g+4)|0)>>2]|=1}else{y[c+4>>2]=b|3;y[b+(g+4)>>2]=d|1;y[g+(d+b)>>2]=d;i=F[V+8>>2];if((i|0)!=0){b=F[V+20>>2];g=i>>>2&1073741822;n=V+40+(g<<2)|0;e=F[V>>2];i=1<<(i>>>3);if((e&i|0)==0){y[V>>2]=e|i;var o=n,t=V+40+(g+2<<2)|0}else{g=V+40+(g+2<<2)|0,e=F[g>>2],e>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(o=e,t=g)}y[t>>2]=b;y[o+12>>2]=b;y[b+8>>2]=o;y[b+12>>2]=n}y[V+8>>2]=d;y[V+20>>2]=f}return c+8|0}}}while(0);W();a("Reached an unreachable!")}uh.X=1;function vh(b){var c=-b|0,d=b>>>8;if((d|0)==0){var f=0}else{if(b>>>0>16777215){f=31}else{var g=(d+1048320|0)>>>16&8,e=d<>>16&4,h=e<>>16&2,l=14-(i|g|k)+(h<>>15)|0,f=b>>>((l+7|0)>>>0)&1|l<<1}}var j=F[V+304+(f<<2)>>2],n=(j|0)==0;a:do{if(n){var p=0,r=c,o=0}else{for(var t=0,s=c,u=j,w=b<<((f|0)==31?0:25-(f>>>1)|0),v=0;;){var z=y[u+4>>2]&-8,B=z-b|0;if(B>>>0>>0){if((z|0)==(b|0)){p=u;r=B;o=u;break a}var D=u,C=B}else{D=t,C=s}var E=F[u+20>>2],G=F[u+16+(w>>>31<<2)>>2],H=(E|0)==0|(E|0)==(G|0)?v:E;if((G|0)==0){p=D;r=C;o=H;break a}t=D;s=C;u=G;w<<=1;v=H}}}while(0);if((o|0)==0&(p|0)==0){var K=1<>2]&(K|-K);if((L|0)==0){var N=o}else{var O=(L&-L)-1|0,R=O>>>12&16,U=O>>>(R>>>0),Y=U>>>5&8,X=U>>>(Y>>>0),ba=X>>>2&4,$=X>>>(ba>>>0),ja=$>>>1&2,sa=$>>>(ja>>>0),Ea=sa>>>1&1,N=y[V+304+((Y|R|ba|ja|Ea)+(sa>>>(Ea>>>0))<<2)>>2]}}else{N=o}var Xa=(N|0)==0;a:do{if(Xa){var ea=r,fa=p}else{for(var va=N,ob=r,wa=p;;){var pb=(y[va+4>>2]&-8)-b|0,gb=pb>>>0>>0,Ib=gb?pb:ob,Fa=gb?va:wa,qb=F[va+16>>2];if((qb|0)!=0){va=qb}else{var Ya=F[va+20>>2];if((Ya|0)==0){ea=Ib;fa=Fa;break a}va=Ya}ob=Ib;wa=Fa}}}while(0);var Na=(fa|0)==0;a:do{if(Na){var za=0}else{if(ea>>>0<(y[V+8>>2]-b|0)>>>0){var da=fa,Oa=F[V+16>>2],Za=da>>>0>>0;do{if(!Za){var Aa=da+b|0,hb=Aa;if(da>>>0>>0){var Ga=F[fa+24>>2],Pa=F[fa+12>>2],$a=(Pa|0)==(fa|0);do{if($a){var Ab=fa+20|0,cb=y[Ab>>2];if((cb|0)==0){var rb=fa+16|0,Qa=y[rb>>2];if((Qa|0)==0){var pa=0;break}var ia=rb,qa=Qa}else{ia=Ab,qa=cb}for(;;){var Ra=qa+20|0,ra=y[Ra>>2];if((ra|0)!=0){ia=Ra,qa=ra}else{var ib=qa+16|0,sb=F[ib>>2];if((sb|0)==0){break}ia=ib;qa=sb}}ia>>>0>>0?(W(),a("Reached an unreachable!")):(y[ia>>2]=0,pa=qa)}else{var jb=F[fa+8>>2];jb>>>0>>0?(W(),a("Reached an unreachable!")):(y[jb+12>>2]=Pa,y[Pa+8>>2]=jb,pa=Pa)}}while(0);var db=(Ga|0)==0;b:do{if(!db){var Sa=fa+28|0,kb=V+304+(y[Sa>>2]<<2)|0,ta=(fa|0)==(y[kb>>2]|0);do{if(ta){y[kb>>2]=pa;if((pa|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break b}if(Ga>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{var Bb=Ga+16|0;(y[Bb>>2]|0)==(fa|0)?y[Bb>>2]=pa:y[Ga+20>>2]=pa;if((pa|0)==0){break b}}}while(0);if(pa>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{y[pa+24>>2]=Ga;var Ha=F[fa+16>>2];(Ha|0)!=0&&(Ha>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[pa+16>>2]=Ha,y[Ha+24>>2]=pa));var ya=F[fa+20>>2];(ya|0)!=0&&(ya>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[pa+20>>2]=ya,y[ya+24>>2]=pa))}}}while(0);var xa=ea>>>0<16;b:do{if(xa){var Ba=ea+b|0;y[fa+4>>2]=Ba|3;y[(Ba+(da+4)|0)>>2]|=1}else{if(y[fa+4>>2]=b|3,y[b+(da+4)>>2]=ea|1,y[da+(ea+b)>>2]=ea,ea>>>0<256){var Ca=ea>>>2&1073741822,Ta=V+40+(Ca<<2)|0,lb=F[V>>2],Jb=1<<(ea>>>3);if((lb&Jb|0)==0){y[V>>2]=lb|Jb;var eb=Ta,Da=V+40+(Ca+2<<2)|0}else{var Ia=V+40+(Ca+2<<2)|0,mb=F[Ia>>2];mb>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(eb=mb,Da=Ia)}y[Da>>2]=hb;y[eb+12>>2]=hb;y[b+(da+8)>>2]=eb;y[b+(da+12)>>2]=Ta}else{var Ua=Aa,Ja=ea>>>8;if((Ja|0)==0){var Ka=0}else{if(ea>>>0>16777215){Ka=31}else{var Cb=(Ja+1048320|0)>>>16&8,Db=Ja<>>16&4,tb=Db<>>16&2,fb=14-(Eb|Cb|Va)+(tb<>>15)|0,Ka=ea>>>((fb+7|0)>>>0)&1|fb<<1}}var ub=V+304+(Ka<<2)|0;y[b+(da+28)>>2]=Ka;var nb=b+(da+16)|0;y[b+(da+20)>>2]=0;y[nb>>2]=0;var Fb=y[V+4>>2],Qb=1<>2]=Fb|Qb,y[ub>>2]=Ua,y[b+(da+24)>>2]=ub,y[b+(da+12)>>2]=Ua,y[b+(da+8)>>2]=Ua}else{for(var wb=ea<<((Ka|0)==31?0:25-(Ka>>>1)|0),Lb=y[ub>>2];;){if((y[Lb+4>>2]&-8|0)==(ea|0)){var Rb=Lb+8|0,Wb=F[Rb>>2],Tb=F[V+16>>2],Xb=Lb>>>0>>0;do{if(!Xb&&Wb>>>0>=Tb>>>0){y[Wb+12>>2]=Ua;y[Rb>>2]=Ua;y[b+(da+8)>>2]=Wb;y[b+(da+12)>>2]=Lb;y[b+(da+24)>>2]=0;break b}}while(0);W();a("Reached an unreachable!")}else{var Vb=Lb+16+(wb>>>31<<2)|0,Yb=F[Vb>>2];if((Yb|0)==0){if(Vb>>>0>=F[V+16>>2]>>>0){y[Vb>>2]=Ua;y[b+(da+24)>>2]=Lb;y[b+(da+12)>>2]=Ua;y[b+(da+8)>>2]=Ua;break b}W();a("Reached an unreachable!")}else{wb<<=1,Lb=Yb}}}}}}}while(0);za=fa+8|0;break a}}}while(0);W();a("Reached an unreachable!")}else{za=0}}}while(0);return za}vh.X=1;function wh(b){var c;(y[xh>>2]|0)==0&&yh();var d=(y[V+440>>2]&4|0)==0;do{if(d){c=y[V+24>>2];if((c|0)==0){c=5}else{if(c=zh(c),(c|0)==0){c=5}else{var f=y[xh+8>>2],f=b+47-y[V+12>>2]+f&-f;if(f>>>0<2147483647){var g=Ah(f);if((g|0)==(y[c>>2]+y[c+4>>2]|0)){var e=g,i=f,h=g;c=12}else{var k=g,l=f;c=14}}else{c=13}}}if(c==5){if(c=Ah(0),(c|0)==-1){c=13}else{var f=y[xh+8>>2],f=f+(b+47)&-f,g=c,j=y[xh+4>>2],n=j-1|0,f=(n&g|0)==0?f:f-g+(n+g&-j)|0;f>>>0<2147483647?(g=Ah(f),(g|0)==(c|0)?(e=c,i=f,h=g,c=12):(k=g,l=f,c=14)):c=13}}if(c==13){y[V+440>>2]|=4,c=22}else{if(c==12){if((e|0)!=-1){var p=i,r=e;c=25;break}k=h;l=i}c=-l|0;if((k|0)!=-1&l>>>0<2147483647){if(l>>>0<(b+48|0)>>>0){f=y[xh+8>>2],f=b+47-l+f&-f,f>>>0<2147483647?(Ah(f)|0)==-1?(Ah(c),c=21):(o=f+l|0,c=20):(o=l,c=20)}else{var o=l;c=20}}else{o=l,c=20}c==20&&(k|0)!=-1?(p=o,r=k,c=25):(y[V+440>>2]|=4,c=22)}}else{c=22}}while(0);c==22&&(d=y[xh+8>>2],d=d+(b+47)&-d,d>>>0<2147483647?(d=Ah(d),e=Ah(0),(e|0)!=-1&(d|0)!=-1&d>>>0>>0?(e=e-d|0,e>>>0<=(b+40|0)>>>0|(d|0)==-1?c=48:(p=e,r=d,c=25)):c=48):c=48);a:do{if(c==25){d=y[V+432>>2]+p|0;y[V+432>>2]=d;d>>>0>F[V+436>>2]>>>0&&(y[V+436>>2]=d);d=F[V+24>>2];e=(d|0)==0;b:do{if(e){i=F[V+16>>2];(i|0)==0|r>>>0>>0&&(y[V+16>>2]=r);y[V+444>>2]=r;y[V+448>>2]=p;y[V+456>>2]=0;y[V+36>>2]=y[xh>>2];y[V+32>>2]=-1;for(i=0;;){if(h=i<<1,k=V+40+(h+2<<2)|0,l=V+40+(h<<2)|0,y[V+40+(h+3<<2)>>2]=l,y[k>>2]=l,i=i+1|0,(i|0)==32){break}}Bh(r,p-40|0)}else{for(o=V+444|0;;){if((o|0)==0){break}i=F[o>>2];h=o+4|0;k=F[h>>2];l=i+k|0;if((r|0)==(l|0)){if((y[o+12>>2]&8|0)!=0){break}o=d;if(!(o>>>0>=i>>>0&o>>>0>>0)){break}y[h>>2]=k+p|0;Bh(y[V+24>>2],y[V+12>>2]+p|0);break b}o=y[o+8>>2]}r>>>0>2]>>>0&&(y[V+16>>2]=r);h=r+p|0;for(k=V+444|0;;){if((k|0)==0){break}l=k|0;i=F[l>>2];if((i|0)==(h|0)){if((y[k+12>>2]&8|0)!=0){break}y[l>>2]=r;var t=k+4|0;y[t>>2]=y[t>>2]+p|0;t=Ch(r,i,b);c=49;break a}k=y[k+8>>2]}Dh(r,p)}}while(0);d=F[V+12>>2];d>>>0>b>>>0?(t=d-b|0,y[V+12>>2]=t,e=d=F[V+24>>2],y[V+24>>2]=e+b|0,y[b+(e+4)>>2]=t|1,y[d+4>>2]=b|3,t=d+8|0,c=49):c=48}}while(0);c==48&&(y[Eh>>2]=12,t=0);return t}wh.X=1;function Ae(b){var c,d=(b|0)==0;a:do{if(!d){var f=b-8|0,g=f,e=F[V+16>>2],i=f>>>0>>0;b:do{if(!i){var h=F[b-4>>2],k=h&3;if((k|0)!=1){var l=h&-8,j=b+(l-8)|0,n=j,p=(h&1|0)==0;c:do{if(p){var r=F[f>>2];if((k|0)==0){break a}var o=-8-r|0,t=b+o|0,s=t,u=r+l|0;if(t>>>0>>0){break b}if((s|0)==(y[V+20>>2]|0)){var w=b+(l-4)|0;if((y[w>>2]&3|0)!=3){var v=s,z=u;break}y[V+8>>2]=u;y[w>>2]&=-2;y[o+(b+4)>>2]=u|1;y[j>>2]=u;break a}if(r>>>0<256){var B=F[o+(b+8)>>2],D=F[o+(b+12)>>2];if((B|0)==(D|0)){y[V>>2]&=1<<(r>>>3)^-1,v=s,z=u}else{var C=V+40+((r>>>2&1073741822)<<2)|0,E=(B|0)!=(C|0)&B>>>0>>0;do{if(!E&&!((D|0)!=(C|0)&D>>>0>>0)){y[B+12>>2]=D;y[D+8>>2]=B;v=s;z=u;break c}}while(0);W();a("Reached an unreachable!")}}else{var G=t,H=F[o+(b+24)>>2],K=F[o+(b+12)>>2],L=(K|0)==(G|0);do{if(L){var N=o+(b+20)|0,O=y[N>>2];if((O|0)==0){var R=o+(b+16)|0,U=y[R>>2];if((U|0)==0){var Y=0;break}var X=R,ba=U}else{X=N,ba=O,c=20}for(;;){var $=ba+20|0,ja=y[$>>2];if((ja|0)!=0){X=$,ba=ja}else{var sa=ba+16|0,Ea=F[sa>>2];if((Ea|0)==0){break}X=sa;ba=Ea}}X>>>0>>0?(W(),a("Reached an unreachable!")):(y[X>>2]=0,Y=ba)}else{var Xa=F[o+(b+8)>>2];Xa>>>0>>0?(W(),a("Reached an unreachable!")):(y[Xa+12>>2]=K,y[K+8>>2]=Xa,Y=K)}}while(0);if((H|0)==0){v=s,z=u}else{var ea=o+(b+28)|0,fa=V+304+(y[ea>>2]<<2)|0,va=(G|0)==(y[fa>>2]|0);do{if(va){y[fa>>2]=Y;if((Y|0)!=0){break}y[V+4>>2]&=1<>2]^-1;v=s;z=u;break c}if(H>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{var ob=H+16|0;(y[ob>>2]|0)==(G|0)?y[ob>>2]=Y:y[H+20>>2]=Y;if((Y|0)==0){v=s;z=u;break c}}}while(0);if(Y>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{y[Y+24>>2]=H;var wa=F[o+(b+16)>>2];(wa|0)!=0&&(wa>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[Y+16>>2]=wa,y[wa+24>>2]=Y));var pb=F[o+(b+20)>>2];(pb|0)==0?(v=s,z=u):pb>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[Y+20>>2]=pb,y[pb+24>>2]=Y,v=s,z=u)}}}}else{v=g,z=l}}while(0);var gb=v;if(gb>>>0>>0){var Ib=b+(l-4)|0,Fa=F[Ib>>2];if((Fa&1|0)!=0){var qb=(Fa&2|0)==0;do{if(qb){if((n|0)==(y[V+24>>2]|0)){var Ya=y[V+12>>2]+z|0;y[V+12>>2]=Ya;y[V+24>>2]=v;y[v+4>>2]=Ya|1;(v|0)==(y[V+20>>2]|0)&&(y[V+20>>2]=0,y[V+8>>2]=0);if(Ya>>>0<=F[V+28>>2]>>>0){break a}Fh(0);break a}if((n|0)==(y[V+20>>2]|0)){var Na=y[V+8>>2]+z|0;y[V+8>>2]=Na;y[V+20>>2]=v;y[v+4>>2]=Na|1;y[(gb+Na|0)>>2]=Na;break a}var za=(Fa&-8)+z|0,da=Fa>>>3,Oa=Fa>>>0<256;c:do{if(Oa){var Za=F[b+l>>2],Aa=F[b+(l|4)>>2];if((Za|0)==(Aa|0)){y[V>>2]&=1<>>2&1073741822)<<2)|0;c=(Za|0)==(hb|0)?62:Za>>>0>2]>>>0?65:62;do{if(c==62&&!((Aa|0)!=(hb|0)&&Aa>>>0>2]>>>0)){y[Za+12>>2]=Aa;y[Aa+8>>2]=Za;break c}}while(0);W();a("Reached an unreachable!")}}else{var Ga=j,Pa=F[l+(b+16)>>2],$a=F[b+(l|4)>>2],Ab=($a|0)==(Ga|0);do{if(Ab){var cb=l+(b+12)|0,rb=y[cb>>2];if((rb|0)==0){var Qa=l+(b+8)|0,pa=y[Qa>>2];if((pa|0)==0){var ia=0;break}var qa=Qa,Ra=pa}else{qa=cb,Ra=rb,c=72}for(;;){var ra=Ra+20|0,ib=y[ra>>2];if((ib|0)!=0){qa=ra,Ra=ib}else{var sb=Ra+16|0,jb=F[sb>>2];if((jb|0)==0){break}qa=sb;Ra=jb}}qa>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[qa>>2]=0,ia=Ra)}else{var db=F[b+l>>2];db>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[db+12>>2]=$a,y[$a+8>>2]=db,ia=$a)}}while(0);if((Pa|0)!=0){var Sa=l+(b+20)|0,kb=V+304+(y[Sa>>2]<<2)|0,ta=(Ga|0)==(y[kb>>2]|0);do{if(ta){y[kb>>2]=ia;if((ia|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break c}if(Pa>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{var Bb=Pa+16|0;(y[Bb>>2]|0)==(Ga|0)?y[Bb>>2]=ia:y[Pa+20>>2]=ia;if((ia|0)==0){break c}}}while(0);if(ia>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{y[ia+24>>2]=Pa;var Ha=F[l+(b+8)>>2];(Ha|0)!=0&&(Ha>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[ia+16>>2]=Ha,y[Ha+24>>2]=ia));var ya=F[l+(b+12)>>2];(ya|0)!=0&&(ya>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[ia+20>>2]=ya,y[ya+24>>2]=ia))}}}}while(0);y[v+4>>2]=za|1;y[gb+za>>2]=za;if((v|0)!=(y[V+20>>2]|0)){var xa=za}else{y[V+8>>2]=za;break a}}else{y[Ib>>2]=Fa&-2,y[v+4>>2]=z|1,xa=y[gb+z>>2]=z}}while(0);if(xa>>>0<256){var Ba=xa>>>2&1073741822,Ca=V+40+(Ba<<2)|0,Ta=F[V>>2],lb=1<<(xa>>>3);if((Ta&lb|0)==0){y[V>>2]=Ta|lb;var Jb=Ca,eb=V+40+(Ba+2<<2)|0}else{var Da=V+40+(Ba+2<<2)|0,Ia=F[Da>>2];Ia>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(Jb=Ia,eb=Da)}y[eb>>2]=v;y[Jb+12>>2]=v;y[v+8>>2]=Jb;y[v+12>>2]=Ca;break a}var mb=v,Ua=xa>>>8;if((Ua|0)==0){var Ja=0}else{if(xa>>>0>16777215){Ja=31}else{var Ka=(Ua+1048320|0)>>>16&8,Cb=Ua<>>16&4,Eb=Cb<>>16&2,Va=14-(Db|Ka|tb)+(Eb<>>15)|0,Ja=xa>>>((Va+7|0)>>>0)&1|Va<<1}}var fb=V+304+(Ja<<2)|0;y[v+28>>2]=Ja;y[v+20>>2]=0;y[v+16>>2]=0;var ub=y[V+4>>2],nb=1<>2]=ub|nb,y[fb>>2]=mb,y[v+24>>2]=fb,y[v+12>>2]=v,y[v+8>>2]=v}else{for(var Qb=xa<<((Ja|0)==31?0:25-(Ja>>>1)|0),wb=y[fb>>2];;){if((y[wb+4>>2]&-8|0)==(xa|0)){var Lb=wb+8|0,Rb=F[Lb>>2],Wb=F[V+16>>2],Tb=wb>>>0>>0;do{if(!Tb&&Rb>>>0>=Wb>>>0){y[Rb+12>>2]=mb;y[Lb>>2]=mb;y[v+8>>2]=Rb;y[v+12>>2]=wb;y[v+24>>2]=0;break c}}while(0);W();a("Reached an unreachable!")}else{var Xb=wb+16+(Qb>>>31<<2)|0,Vb=F[Xb>>2];if((Vb|0)==0){if(Xb>>>0>=F[V+16>>2]>>>0){y[Xb>>2]=mb;y[v+24>>2]=wb;y[v+12>>2]=v;y[v+8>>2]=v;break c}W();a("Reached an unreachable!")}else{Qb<<=1,wb=Vb}}}}}while(0);var Yb=y[V+32>>2]-1|0;y[V+32>>2]=Yb;if((Yb|0)!=0){break a}var fc=y[V+452>>2],ga=(fc|0)==0;c:do{if(!ga){for(var pc=fc;;){var Ub=y[pc+8>>2];if((Ub|0)==0){break c}pc=Ub}}}while(0);y[V+32>>2]=-1;break a}}}}}while(0);W();a("Reached an unreachable!")}}while(0)}Ae.X=1;function Fh(b){(y[xh>>2]|0)==0&&yh();var c=b>>>0<4294967232;a:do{if(c){var d=F[V+24>>2];if((d|0)==0){d=0;break}var f=F[V+12>>2],g=f>>>0>(b+40|0)>>>0;do{if(g){var e=F[xh+8>>2],i=(Math.floor(((-40-b-1+f+e|0)>>>0)/(e>>>0))-1)*e|0,h=zh(d);if((y[h+12>>2]&8|0)==0){var k=Ah(0),l=h+4|0;if((k|0)==(y[h>>2]+y[l>>2]|0)&&(i=Ah(-(i>>>0>2147483646?-2147483648-e|0:i)|0),e=Ah(0),(i|0)!=-1&e>>>0>>0&&(i=k-e|0,(k|0)!=(e|0)))){y[l>>2]=y[l>>2]-i|0;y[V+432>>2]=y[V+432>>2]-i|0;Bh(y[V+24>>2],y[V+12>>2]-i|0);d=(k|0)!=(e|0);break a}}}}while(0);if(F[V+12>>2]>>>0<=F[V+28>>2]>>>0){d=0;break}y[V+28>>2]=-1}d=0}while(0);return d&1}Fh.X=1;function yh(){if((y[xh>>2]|0)==0){var b=Gh();(b-1&b|0)==0?(y[xh+8>>2]=b,y[xh+4>>2]=b,y[xh+12>>2]=-1,y[xh+16>>2]=2097152,y[xh+20>>2]=0,y[V+440>>2]=0,y[xh>>2]=Math.floor(Date.now()/1e3)&-16^1431655768):(W(),a("Reached an unreachable!"))}}function zh(b){for(var c=V+444|0;;){var d=F[c>>2];if(d>>>0<=b>>>0&&(d+y[c+4>>2]|0)>>>0>b>>>0){var f=c;break}c=F[c+8>>2];if((c|0)==0){f=0;break}}return f}function Bh(b,c){var d=b+8|0,d=(d&7|0)==0?0:-d&7,f=c-d|0;y[V+24>>2]=b+d|0;y[V+12>>2]=f;y[d+(b+4)>>2]=f|1;y[c+(b+4)>>2]=40;y[V+28>>2]=y[xh+16>>2]}function Ch(b,c,d){var f,g=b+8|0,g=(g&7|0)==0?0:-g&7,e=c+8|0,e=(e&7|0)==0?0:-e&7,i=c+e|0,h=g+d|0,k=b+h|0,l=i-(b+g)-d|0;y[g+(b+4)>>2]=d|3;d=(i|0)==(y[V+24>>2]|0);a:do{if(d){var j=y[V+12>>2]+l|0;y[V+12>>2]=j;y[V+24>>2]=k;y[h+(b+4)>>2]=j|1}else{if((i|0)==(y[V+20>>2]|0)){j=y[V+8>>2]+l|0,y[V+8>>2]=j,y[V+20>>2]=k,y[h+(b+4)>>2]=j|1,y[(b+(j+h)|0)>>2]=j}else{var n=F[e+(c+4)>>2];if((n&3|0)==1){var j=n&-8,p=n>>>3,r=n>>>0<256;b:do{if(r){var o=F[c+(e|8)>>2],t=F[e+(c+12)>>2];if((o|0)==(t|0)){y[V>>2]&=1<>>2&1073741822)<<2)|0;f=(o|0)==(s|0)?14:o>>>0>2]>>>0?17:14;do{if(f==14&&!((t|0)!=(s|0)&&t>>>0>2]>>>0)){y[o+12>>2]=t;y[t+8>>2]=o;break b}}while(0);W();a("Reached an unreachable!")}}else{f=i;o=F[c+(e|24)>>2];t=F[e+(c+12)>>2];s=(t|0)==(f|0);do{if(s){var u=e|16,w=u+(c+4)|0,v=y[w>>2];if((v|0)==0){if(u=c+u|0,v=y[u>>2],(v|0)==0){var z=0;break}}else{u=w}for(;;){var w=v+20|0,B=y[w>>2];if((B|0)==0&&(w=v+16|0,B=F[w>>2],(B|0)==0)){break}u=w;v=B}u>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[u>>2]=0,z=v)}else{u=F[c+(e|8)>>2],u>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[u+12>>2]=t,y[t+8>>2]=u,z=t)}}while(0);if((o|0)!=0){t=e+(c+28)|0;s=V+304+(y[t>>2]<<2)|0;u=(f|0)==(y[s>>2]|0);do{if(u){y[s>>2]=z;if((z|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break b}if(o>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{if(v=o+16|0,(y[v>>2]|0)==(f|0)?y[v>>2]=z:y[o+20>>2]=z,(z|0)==0){break b}}}while(0);z>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[z+24>>2]=o,f=e|16,o=F[c+f>>2],(o|0)!=0&&(o>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[z+16>>2]=o,y[o+24>>2]=z)),f=F[f+(c+4)>>2],(f|0)!=0&&(f>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[z+20>>2]=f,y[f+24>>2]=z)))}}}while(0);n=c+(j|e)|0;j=j+l|0}else{n=i,j=l}y[(n+4|0)>>2]&=-2;y[h+(b+4)>>2]=j|1;y[b+(j+h)>>2]=j;if(j>>>0<256){p=j>>>2&1073741822;n=V+40+(p<<2)|0;r=F[V>>2];j=1<<(j>>>3);if((r&j|0)==0){y[V>>2]=r|j;var D=n,C=V+40+(p+2<<2)|0}else{j=V+40+(p+2<<2)|0,p=F[j>>2],p>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(D=p,C=j)}y[C>>2]=k;y[D+12>>2]=k;y[h+(b+8)>>2]=D;y[h+(b+12)>>2]=n}else{if(n=k,r=j>>>8,(r|0)==0?p=0:j>>>0>16777215?p=31:(p=(r+1048320|0)>>>16&8,f=r<>>16&4,f<<=r,o=(f+245760|0)>>>16&2,p=14-(r|p|o)+(f<>>15)|0,p=j>>>((p+7|0)>>>0)&1|p<<1),r=V+304+(p<<2)|0,y[h+(b+28)>>2]=p,f=h+(b+16)|0,y[h+(b+20)>>2]=0,y[f>>2]=0,f=y[V+4>>2],o=1<>2]=f|o,y[r>>2]=n,y[h+(b+24)>>2]=r,y[h+(b+12)>>2]=n,y[h+(b+8)>>2]=n}else{p=j<<((p|0)==31?0:25-(p>>>1)|0);for(r=y[r>>2];;){if((y[r+4>>2]&-8|0)==(j|0)){f=r+8|0;o=F[f>>2];t=F[V+16>>2];s=r>>>0>>0;do{if(!s&&o>>>0>=t>>>0){y[o+12>>2]=n;y[f>>2]=n;y[h+(b+8)>>2]=o;y[h+(b+12)>>2]=r;y[h+(b+24)>>2]=0;break a}}while(0);W();a("Reached an unreachable!")}else{if(f=r+16+(p>>>31<<2)|0,o=F[f>>2],(o|0)==0){if(f>>>0>=F[V+16>>2]>>>0){y[f>>2]=n;y[h+(b+24)>>2]=r;y[h+(b+12)>>2]=n;y[h+(b+8)>>2]=n;break a}W();a("Reached an unreachable!")}else{p<<=1,r=o}}}}}}}}while(0);return b+(g|8)|0}Ch.X=1;function Dh(b,c){var d=F[V+24>>2],f=zh(d),g=y[f>>2],e=y[f+4>>2],f=g+e|0,i=g+(e-39)|0,g=g+(e-47+((i&7|0)==0?0:-i&7))|0,g=g>>>0<(d+16|0)>>>0?d:g,e=g+8|0;Bh(b,c-40|0);y[(g+4|0)>>2]=27;y[e>>2]=y[V+444>>2];y[e+4>>2]=y[V+448>>2];y[e+8>>2]=y[V+452>>2];y[e+12>>2]=y[V+456>>2];y[V+444>>2]=b;y[V+448>>2]=c;y[V+456>>2]=0;y[V+452>>2]=e;y[(g+28|0)>>2]=7;e=(g+32|0)>>>0>>0;a:do{if(e){for(i=0;;){var h=i<<2,k=h+(g+36)|0;y[(h+(g+32)|0)>>2]=7;if(k>>>0>=f>>>0){break a}i=i+1|0}}}while(0);f=(g|0)==(d|0);a:do{if(!f){if(e=g-d|0,i=d+e|0,y[(e+(d+4)|0)>>2]&=-2,y[d+4>>2]=e|1,y[i>>2]=e,e>>>0<256){h=e>>>2&1073741822;i=V+40+(h<<2)|0;k=F[V>>2];e=1<<(e>>>3);if((k&e|0)==0){y[V>>2]=k|e;var l=i,j=V+40+(h+2<<2)|0}else{e=V+40+(h+2<<2)|0,h=F[e>>2],h>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(l=h,j=e)}y[j>>2]=d;y[l+12>>2]=d;y[d+8>>2]=l;y[d+12>>2]=i}else{i=d;k=e>>>8;if((k|0)==0){h=0}else{if(e>>>0>16777215){h=31}else{var h=(k+1048320|0)>>>16&8,n=k<>>16&4;n<<=k;var p=(n+245760|0)>>>16&2,h=14-(k|h|p)+(n<

>>15)|0,h=e>>>((h+7|0)>>>0)&1|h<<1}}k=V+304+(h<<2)|0;y[d+28>>2]=h;y[d+20>>2]=0;y[d+16>>2]=0;n=y[V+4>>2];p=1<>2]=n|p,y[k>>2]=i,y[d+24>>2]=k,y[d+12>>2]=d,y[d+8>>2]=d}else{h=e<<((h|0)==31?0:25-(h>>>1)|0);for(k=y[k>>2];;){if((y[k+4>>2]&-8|0)==(e|0)){var n=k+8|0,p=F[n>>2],r=F[V+16>>2],o=k>>>0>>0;do{if(!o&&p>>>0>=r>>>0){y[p+12>>2]=i;y[n>>2]=i;y[d+8>>2]=p;y[d+12>>2]=k;y[d+24>>2]=0;break a}}while(0);W();a("Reached an unreachable!")}else{if(n=k+16+(h>>>31<<2)|0,p=F[n>>2],(p|0)==0){if(n>>>0>=F[V+16>>2]>>>0){y[n>>2]=i;y[d+24>>2]=k;y[d+12>>2]=d;y[d+8>>2]=d;break a}W();a("Reached an unreachable!")}else{h<<=1,k=p}}}}}}}while(0)}Dh.X=1;function Hh(b){y[b>>2]=Ih+8|0;Jh(b)}function sd(b,c,d){if(d>=20&&c%2==b%2){if(c%4==b%4){for(d=c+d;c%4;){q[b++]=q[c++]}c>>=2;b>>=2;for(var f=d>>2;c>=1;b>>=1;for(f=d>>1;c=20){for(d=b+d;b%4;){q[b++]=c}c<0&&(c+=256);b>>=2;for(var f=d>>2,g=c|c<<8|c<<16|c<<24;b>2]=b}var Eh,Rh=0,Sh=0,Th=0,Z={va:"/",ya:2,b:[ha],D:ca,t:(function(b,c){if(typeof b!=="string"){return ha}if(c===aa){c=Z.va}b&&b[0]=="/"&&(c="");for(var d=(c+"/"+b).split("/").reverse(),f=[""];d.length;){var g=d.pop();g==""||g=="."||(g==".."?f.length>1&&f.pop():f.push(g))}return f.length==1?"/":f.join("/")}),u:(function(b,c,d){var f={xa:ka,r:ka,error:0,name:ha,path:ha,object:ha,H:ka,J:ha,I:ha},b=Z.t(b);if(b=="/"){f.xa=ca,f.r=f.H=ca,f.name="/",f.path=f.J="/",f.object=f.I=Z.root}else{if(b!==ha){for(var d=d||0,b=b.slice(1).split("/"),g=Z.root,e=[""];b.length;){if(b.length==1&&g.e){f.H=ca,f.J=e.length==1?"/":e.join("/"),f.I=g,f.name=b[0]}var i=b.shift();if(g.e){if(g.L){if(!g.c.hasOwnProperty(i)){f.error=2;break}}else{f.error=Kh;break}}else{f.error=20;break}g=g.c[i];if(g.link&&!(c&&b.length==0)){if(d>40){f.error=40;break}f=Z.t(g.link,e.join("/"));return Z.u([f].concat(b).join("/"),c,d+1)}e.push(i);if(b.length==0){f.r=ca,f.path=e.join("/"),f.object=g}}}}return f}),B:(function(b,c){Z.z();var d=Z.u(b,c);return d.r?d.object:(Qh(d.error),ha)}),w:(function(b,c,d,f,g){b||(b="/");typeof b==="string"&&(b=Z.B(b));b||(Qh(Kh),a(Error("Parent path must exist.")));b.e||(Qh(20),a(Error("Parent must be a folder.")));!b.write&&!Z.D&&(Qh(Kh),a(Error("Parent folder must be writeable.")));if(!c||c=="."||c==".."){Qh(2),a(Error("Name must not be empty."))}b.c.hasOwnProperty(c)&&(Qh(17),a(Error("Can't overwrite object.")));b.c[c]={L:f===aa?ca:f,write:g===aa?ka:g,timestamp:Date.now(),wa:Z.ya++};for(var e in d){d.hasOwnProperty(e)&&(b.c[c][e]=d[e])}return b.c[c]}),q:(function(b,c,d,f){return Z.w(b,c,{e:ca,d:ka,c:{}},d,f)}),ua:(function(b,c,d,f){b=Z.B(b);b===ha&&a(Error("Invalid parent."));for(c=c.split("/").reverse();c.length;){var g=c.pop();g&&(b.c.hasOwnProperty(g)||Z.q(b,g,d,f),b=b.c[g])}return b}),l:(function(b,c,d,f,g){d.e=ka;return Z.w(b,c,d,f,g)}),ta:(function(b,c,d,f,g){if(typeof d==="string"){for(var e=[],i=0;i0&&Z.b[2].object.i("\n".charCodeAt(0)),Z.b[3].object.i.buffer.length>0&&Z.b[3].object.i("\n".charCodeAt(0)))})};function Uh(b,c,d){var f=Z.b[b];if(f){if(f.m){if(d<0){return Qh(Mh),-1}else{if(f.object.d){if(f.object.i){for(var g=0;g>2];if(Uh(c,b,Ac(b))>=0&&(b="\n".charCodeAt(0)&255,q[Wh]=b>=0?b:Math.pow(2,aa)+b,Uh(c,Wh,1)==-1&&c in Z.b)){Z.b[c].error=ca}}wc.unshift({C:(function(){Z.D=ka;Z.j.s||Z.j()})});xc.push({C:(function(){Z.za()})});Qh(0);P(12,"void*",M);var Wh=P([0],"i8",M);Module.sa=(function(b){function c(){for(var b=0;b<3;b++){f.push(0)}}var d=b.length+1,f=[P(rc("/bin/this.program"),"i8",M)];c();for(var g=0;g>2]=hj;y[Xh+4>>2]=ij;gj=P([2,0,0,0,0],["i8*",0,0,0,0],M);y[hj>>2]=gj+8|0;y[hj+4>>2]=Q.P|0;y[hj+8>>2]=aa;y[ij>>2]=gj+8|0;y[ij+4>>2]=Q.O|0;y[ij+8>>2]=hj;lc=[0,0,(function(b,c,d,f,g){(d|0)!=0&&(kc(c,q[b],d),c=c+d|0);if((f|0)!=0){for(d=0;;){if(q[c+d|0]=q[b+d|0],d=d+1|0,(d|0)==(f|0)){break}}c=c+f|0;b=b+f|0}(g|0)!=0&&kc(c,q[b-1|0],g)}),0,(function(b,c,d,f){sd(c,b,f)}),0,(function(){}),0,(function(b){Hh(b)}),0,(function(b){Hh(b);b|=0;(b|0)!=0&&Ae(b)}),0,(function(){return Q.R|0}),0,(function(b){y[b>>2]=Xh+8|0;Hh(b)}),0,(function(b){y[b>>2]=Xh+8|0;Hh(b);b|=0;(b|0)!=0&&Ae(b)}),0,(function(){return Q.Q|0}),0];Module.FUNCTION_TABLE=lc;function jj(b){b=b||Module.arguments;vc(wc);var c=ha;Module._main&&(c=Module.sa(b),vc(xc),Ob.print());return c}Module.run=jj;Module.preRun&&Module.preRun();Module.noInitialRun=ca;Module.noInitialRun||jj();Module.postRun&&Module.postRun();Z&&(Module.FS=Z);Module.HEAPU8=A;Module.CorrectionsMonitor=Ob;Z.createDataFile=Z.ta;var kj=ka;_runMainLoop=(function(){window.addEventListener("message",(function(){_mainLoopIteration();kj||window.postMessage(0,"*")}),ka)});Module.play=(function(){kj=ka;window.postMessage(0,"*")});Module.stop=(function(){kj=ca});Module.onFrameDecoded=(function(){});_broadwayOnFrameDecoded=(function(){Module.onFrameDecoded()});Module.createStreamBuffer=(function(b){b=jc(b);(b|0)==0&&xg(Q.ba|0);return b});var lj=Module.patches={};function mj(){return(function(){return this}).call(ha)}Sb=(function(b,c){b||a("Assertion: "+c)});Module.patch=(function(b,c,d){Sb(typeof d=="function");b||(b=mj());Module.CC_VARIABLE_MAP&&(c=Module.CC_VARIABLE_MAP[c]);Sb(c in b&&(typeof b[c]==="function"||typeof b[c]==="undefined"),"Can only patch functions.");lj[c]=b[c];b[c]=d;return lj[c]});Module.unpatch=(function(b,c){b||(b=mj());Module.CC_VARIABLE_MAP&&(c=Module.CC_VARIABLE_MAP[c]);Sb(c in b&&typeof b[c]=="function");c in lj&&(b[c]=lj[c])});Bc=Math.abs;Cc=(function(b,c,d){return dc?c:d});Module.CC_VARIABLE_MAP={"___setErrNo":"Qh","_Mmcop3":"Lf","_h264bsdCheckDeltaPicOrderCntBottom":"bd","_h264bsdFilterPicture":"Sf","_h264bsdReorderRefPicList":"Gf","_sbrk":"Ah","_CheckPps":"De","_Intra4x4VerticalLeftPrediction":"Xe","_coeffToken4_0":"oe","_DecRefPicMarking":"Vc","_coeffToken4_1":"pe","_h264bsdStoreSeqParamSet":"ze","_Mmcop6":"Hf","_Mmcop5":"Mf","intArrayFromString":"rc","_add_segment":"Dh","_init_top":"Bh","_h264bsdFillBlock":"sf","ENVIRONMENT_IS_WORKER":"ua","_decInfo":"Ag","_h264bsdCroppingParams":"lg","_h264bsdGetRefPicData":"gf","_EdgeBoundaryStrength":"Yf","e$$5":"ab","_Intra4x4DiagonalDownLeftPrediction":"Te","_sys_alloc":"wh","_h264bsdConceal":"gg","_DecodeCoeffToken":"Bd","FS":"Z","_clip":"Cc","_h264bsdQpC":"Ad","_h264bsdMarkSliceCorrupted":"jd","_OutputPicture":"Nf","i":"tc","_FilterHorChromaEdge":"fg","_sbrk$called":"Vh","base":"sc","_h264bsdNextMbAddress":"Ic","_DecodeTotalZeros":"we","_h264bsdDecodePicOrderCnt":"jg","_DecodeHrdParameters":"kg","_N_B_SUB_PART":"of","_init_mparams":"yh","_N_D_SUB_PART":"qf","_decPicture":"sg","_MvPrediction16x16":"cf","_coeffToken0_1":"Dd","_coeffToken0_0":"Cd","_levelScale":"Ec","_coeffToken0_3":"ke","_h264bsdDecodeExpGolombUnsigned":"T","_coeffToken0_2":"je","_tmalloc_small":"uh","Array_copy":"zc","PAGE_SIZE":"zb","Runtime":"Mb","_decInput":"tg","_h264bsdCheckPicOrderCntLsb":"Xc","TOTAL_MEMORY":"yb","__ATEXIT__":"xc","_h264bsdInterPrediction":"ud","_decOutput":"zg","_N_C_SUB_PART":"pf","__ZTVN10__cxxabiv120__si_class_type_infoE":"gj","_h264bsdIntra4x4Prediction":"xd","_h264bsdDecodeExpGolombTruncated":"nd","_h264bsdFlushBits":"od","_GetLumaEdgeThresholds":"Uf","Pointer_stringify":"cc","_broadwayOnHeadersDecoded":"Cg","_h264bsdInterpolateHorQuarter":"yf","_h264bsdInterpolateHorHalf":"xf","JSCompiler_alias_NULL":"ha","_stdout":"Sh","_h264bsdMbPartPredMode":"dd","HEAPU32":"F","HEAP8":"q","_mparams":"xh","Runtime$QUANTUM_SIZE":"Kb","_h264bsdPredictSamples":"df","_h264bsdProcessChromaDc":"Hc","_h264bsdDecodeSliceData":"fd","_h264bsdInterpolateVerHalf":"vf","_broadwayDecode":"ug","CorrectionsMonitor":"Ob","_stdin":"Rh","JSCompiler_alias_FALSE":"ka","_h264bsdDecodeMacroblockLayer":"gd","_Intra16x16PlanePrediction":"Ne","_N_B_4x4B":"ue","_lumaFracPos":"Ff","_DetermineNc":"qd","_free":"Ae","_h264bsdInterpolateChromaHorVer":"uf","_h264bsdGetNeighbourPels":"vd","__ZTISt9bad_alloc":"hj","_Intra4x4HorizontalUpPrediction":"Ye","_sys_trim":"Fh","globalScope":"ac","_h264bsdDecodeExpGolombSigned":"Qc","patches":"lj","Runtime$staticAlloc":"vb","_memcpy":"sd","_Intra16x16DcPrediction":"Me","_broadwayOnPictureDecoded":"Dg","ENVIRONMENT_IS_SHELL":"La","_broadwayExit":"yg","_MvPrediction":"hf","__ZTVSt9bad_alloc":"Ih","_h264bsdIntra16x16Prediction":"wd","_InnerBoundaryStrength":"$f","_h264bsdCheckAccessUnitBoundary":"Ie","String_len":"Ac","_ShellSort":"Of","_h264bsdDecodeResidualBlockCavlc":"pd","_H264SwDecNextPicture":"qg","JSCompiler_alias_TRUE":"ca","_DecodeSubMbPred":"kd","buffer":"oc","_Intra16x16VerticalPrediction":"Ke","STACK_MAX":"mc","_Intra4x4VerticalRightPrediction":"Ve","_DecodeForegroundLeftOverMap":"Ge","ALLOC_STATIC":"M","__ATINIT__":"wc","_CeilLog2NumSliceGroups":"Tc","_MvPrediction16x8":"ef","_GetBoundaryStrengths":"Tf","_dcCoeffIndex":"zd","_segment_holding":"zh","_Intra4x4DcPrediction":"Se","__ZTISt20bad_array_new_length":"ij","_Intra16x16HorizontalPrediction":"Le","tempInt":"Pb","_ProcessResidual":"td","_picDecodeNumber":"wg","globalEval":"Wa","_N_C_4x4B":"Pe","___setErrNo$ret":"Eh","_streamBuffer":"Eg","_prepend_alloc":"Ch","_coeffToken8":"qe","_h264bsdInterpolateMidHorQuarter":"Ef","_h264bsdGetBits":"S","_h264bsdFreeDpb":"Ee","_H264SwDecMemset":"Pc","ERRNO_CODES$EACCES":"Kh","_h264bsdMarkDecRefPic":"Kf","_h264bsdInterpolateChromaVer":"tf","_ComparePictures":"Pf","ERRNO_CODES$EIO":"Nh","_h264bsdInterpolateHorVerQuarter":"zf","_h264bsdNumMbPart":"cd","_sysconf":"Gh","arguments_":"ma","_DecodeMbPred":"ld","ERRNO_CODES$EINVAL":"Mh","_GetInterNeighbour":"kf","_N_D_4x4B":"Qe","STACKTOP":"m","_DecodeBoxOutMap":"He","_write":"Uh","undef":"I","_memset":"kc","_IntraChromaPlanePrediction":"bf","_h264bsdCheckPpsId":"Wc","_h264bsdInterpolateMidHalf":"Af","_N_A_4x4B":"te","_h264bsdIntraChromaPrediction":"yd","_h264bsdCompareSeqParamSets":"Nc","run":"jj","_GetBoundaryStrengthsA":"Zf","_h264bsdAddResidual":"Oe","_abs":"Bc","_h264bsdActivateParamSets":"Ce","allocate":"P","_fputc$ret":"Wh","assert":"Sb","abort":"Nb","_ConcealMb":"hg","_h264bsdBlockY":"Ze","_FilterLuma":"Vf","_h264bsdBlockX":"$e","_h264bsdShowBits32":"id","_FindDpbPic":"Df","_coeffTokenMinus1_0":"re","HEAPF32":"Hb","_Intra4x4DiagonalDownRightPrediction":"Ue","_coeffTokenMinus1_1":"se","breakLoop":"kj","_h264bsdDecodeSliceGroupMap":"Je","__ZNSt9bad_allocD2Ev":"Hh","__ZNSt9exceptionD2Ev":"Jh","_h264bsdInitRefPicList":"Qf","_h264bsdGetNeighbourMb":"ye","JSCompiler_alias_VOID":"aa","__gm_":"V","_h264bsdInterpolateMidVerQuarter":"Bf","_IntraChromaDcPrediction":"af","_abort":"W","_Transform":"ig","TOTAL_STACK":"nc","_h264bsdWriteMacroblock":"rd","_MedianFilter":"mf","setValue":"dc","_decInst":"rg","_FilterHorChroma":"eg","_FilterChroma":"Xf","_FilterVerLumaEdge":"ag","JSCompiler_alias_THROW":"a","_h264bsdAllocateDpbImage":"Jf","HEAP16":"x","ERRNO_CODES$ENXIO":"Ph","_puts":"xg","_DecodeResidual":"md","_h264bsdInterpolateVerQuarter":"wf","FUNCTION_TABLE":"lc","_h264bsdProcessBlock":"Dc","_h264bsdInterpolateChromaHor":"rf","tempDoublePtr":"uc","callRuntimeCallbacks":"vc","_picSize":"Bg","_h264bsdSetCurrImageMbPointers":"Lc","_FilterVerChromaEdge":"dg","_h264bsdShutdown":"ng","STRING_TABLE":"Q","STATICTOP":"xb","HEAPU8":"A","_FilterHorLuma":"bg","_picDisplayNumber":"vg","HEAP32":"y","_h264bsdCheckPriorPicsFlag":"ed","getGlobalScope":"mj","_malloc":"jc","_coeffToken2_2":"ne","_N_A_SUB_PART":"nf","_h264bsdExtractNalUnit":"Mc","_coeffToken2_0":"le","_coeffToken2_1":"me","_GetChromaEdgeThresholds":"Wf","nodeFS":"Ma","ERRNO_CODES$EBADF":"Lh","_MvPrediction8x16":"ff","_h264bsdWriteOutputBlocks":"jf","_h264bsdDecodePicParamSet":"Sc","ERRNO_CODES$EISDIR":"Oh","_h264bsdDecodeMacroblock":"hd","ENVIRONMENT_IS_NODE":"na","_h264bsdDecode":"mg","_SlidingWindowRefPicMarking":"If","_FilterHorLumaEdge":"cg","_stderr":"Th","_h264bsdIsNeighbourAvailable":"ve","__ZTVSt20bad_array_new_length":"Xh","_tmalloc_large":"vh","tempBigInt":"J","tempDoubleF64":"ec","tempDoubleI32":"gc","_SetPicNums":"Cf","_Get4x4NeighbourPels":"Re","_h264bsdProcessLumaDc":"Gc","_h264bsdStorePicParamSet":"Be","Runtime$stackAlloc":"bb","_H264SwDecDecode":"pg","_DecodeRunBefore":"xe","writeStringToMemory":"bc","_h264bsdDecodeVuiParameters":"Rc","_Intra4x4HorizontalDownPrediction":"We","_h264bsdCheckGapsInFrameNum":"Rf","_h264bsdInitDpb":"Fe","_broadwayStream":"og","_GetPredictionMv":"lf","ENVIRONMENT_IS_WEB":"oa","HEAPU16":"Gb","_h264bsdDecodeSliceHeader":"Uc","_h264bsdDecodeSeqParamSet":"Oc"} + +"use strict";function mht(a){var b="";if(16==a.length)for(var c=0;4>c;c++)b+="["+a[4*c+0].toFixed(4)+","+a[4*c+1].toFixed(4)+","+a[4*c+2].toFixed(4)+","+a[4*c+3].toFixed(4)+"]
";else{if(9!=a.length)return a.toString();for(var c=0;3>c;c++)b+="["+a[3*c+0].toFixed(4)+","+a[3*c+1].toFixed(4)+","+a[3*c+2].toFixed(4)+"]
"}return b}function makeLookAt(a,b,c,d,e,f,g,h,i){var j=$V([a,b,c]),k=$V([d,e,f]),l=$V([g,h,i]),m=j.subtract(k).toUnitVector(),n=l.cross(m).toUnitVector(),o=m.cross(n).toUnitVector(),p=$M([[n.e(1),n.e(2),n.e(3),0],[o.e(1),o.e(2),o.e(3),0],[m.e(1),m.e(2),m.e(3),0],[0,0,0,1]]),q=$M([[1,0,0,-a],[0,1,0,-b],[0,0,1,-c],[0,0,0,1]]);return p.x(q)}function makeOrtho(a,b,c,d,e,f){var g=-(b+a)/(b-a),h=-(d+c)/(d-c),i=-(f+e)/(f-e);return $M([[2/(b-a),0,0,g],[0,2/(d-c),0,h],[0,0,-2/(f-e),i],[0,0,0,1]])}function makePerspective(a,b,c,d){var e=c*Math.tan(a*Math.PI/360),f=-e,g=f*b,h=e*b;return makeFrustum(g,h,f,e,c,d)}function makeFrustum(a,b,c,d,e,f){var g=2*e/(b-a),h=2*e/(d-c),i=(b+a)/(b-a),j=(d+c)/(d-c),k=-(f+e)/(f-e),l=-2*f*e/(f-e);return $M([[g,0,i,0],[0,h,j,0],[0,0,k,l],[0,0,-1,0]])}function makeOrtho(a,b,c,d,e,f){var g=-(b+a)/(b-a),h=-(d+c)/(d-c),i=-(f+e)/(f-e);return $M([[2/(b-a),0,0,g],[0,2/(d-c),0,h],[0,0,-2/(f-e),i],[0,0,0,1]])}function error(a){console.error(a),console.trace()}function assert(a,b){a||error(b)}function isPowerOfTwo(a){return 0==(a&a-1)}function text(a){return a.join("\n")}function nextHighestPowerOfTwo(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1}function inherit(a,b){var c=Object.create(a.prototype);for(var d in b)c[d]=b[d];return c}function patchOptimizations(a,b){var c=getGlobalScope();for(var d in b){var e=b[d];if(e){var f=a[d];f||(f="original"),console.info(d+": "+f),assert(f in e.options);var g=e.options[f].fn;g&&(c[e.original]=Module.patch(null,e.name,g),console.info("Patching: "+e.name+", with: "+f))}}}function getGlobalScope(){return function(){return this}.call(null)}function clip(a,b,c){return a>c?a:c>b?b:c}function OptimizedGetBoundaryStrengthsA(a,b){var c=a+28,d=HEAP16[c+0>>1],e=HEAP16[c+2>>1],f=HEAP16[c+4>>1],g=HEAP16[c+6>>1],h=HEAP16[c+8>>1],i=HEAP16[c+10>>1],j=HEAP16[c+12>>1],k=HEAP16[c+14>>1],l=HEAP16[c+16>>1],m=HEAP16[c+18>>1],n=HEAP16[c+20>>1],o=HEAP16[c+22>>1],p=HEAP16[c+24>>1],q=HEAP16[c+26>>1],r=HEAP16[c+28>>1],s=HEAP16[c+30>>1];HEAP32[b+32>>2]=f||d?2:0,HEAP32[b+40>>2]=g||e?2:0,HEAP32[b+48>>2]=j||h?2:0,HEAP32[b+56>>2]=k||i?2:0,HEAP32[b+64>>2]=l||f?2:0,HEAP32[b+72>>2]=m||g?2:0,HEAP32[b+80>>2]=p||j?2:0,HEAP32[b+88>>2]=q||k?2:0,HEAP32[b+96>>2]=n||l?2:0,HEAP32[b+104>>2]=o||m?2:0,HEAP32[b+112>>2]=r||p?2:0,HEAP32[b+120>>2]=s||q?2:0,HEAP32[b+12>>2]=e||d?2:0,HEAP32[b+20>>2]=h||e?2:0,HEAP32[b+28>>2]=i||h?2:0,HEAP32[b+44>>2]=g||f?2:0,HEAP32[b+52>>2]=j||g?2:0,HEAP32[b+60>>2]=k||j?2:0,HEAP32[b+76>>2]=m||l?2:0,HEAP32[b+84>>2]=p||m?2:0,HEAP32[b+92>>2]=q||p?2:0,HEAP32[b+108>>2]=o||n?2:0,HEAP32[b+116>>2]=r||o?2:0,HEAP32[b+124>>2]=s||r?2:0}function OptimizedFilterVerLumaEdge(a,b,c,d){var e,f,g,h,i,j,k,l,m,n,o=_h264bsdClip+512,p=HEAP32[c+4>>2],q=HEAP32[c+8>>2];if(4>b){g=f=255&HEAPU8[HEAP32[c>>2]+(b-1)];for(var r=4;r>0;r--)j=255&HEAPU8[a+-2],h=255&HEAPU8[a+-1],i=255&HEAPU8[a],k=255&HEAPU8[a+1],Math.abs(h-i)>1)-(j<<1)>>1,HEAP8[a-2]=j+clip(-f,f,n),g++),m=255&HEAPU8[a+2],Math.abs(m-i)>1)-(k<<1)>>1,HEAP8[a+1]=k+clip(-f,f,n),g++),n=(i-h<<2)+(j-k)+4>>3,e=clip(-g,g,n),h=255&HEAPU8[o+(h+e)],i=255&HEAPU8[o+(i-e)],g=f,HEAP8[a-1]=h,HEAP8[a]=i,a+=d)}else OriginalFilterVerLumaEdge(a,b,c,d)}function OptimizedFilterHorLuma(a,b,c,d){var e,f,g,h,i,j,k,l,m,n,o=_h264bsdClip+512,p=HEAP32[c+4>>2],q=HEAP32[c+8>>2];if(4>b){g=f=255&HEAPU8[HEAP32[c>>2]+(b-1)];for(var r=16;r>0;r--)j=255&HEAPU8[a+(-d<<1)],h=255&HEAPU8[a+-d],i=255&HEAPU8[a],k=255&HEAPU8[a+d],Math.abs(h-i)>1)-(j<<1)>>1,HEAP8[a+(-d<<1)]=j+clip(-f,f,n),g++),m=255&HEAPU8[a+(d<<2)],Math.abs(m-i)>1)-(k<<1)>>1,HEAP8[a+d]=k+clip(-f,f,n),g++),n=(i-h<<2)+(j-k)+4>>3,e=clip(-g,g,n),h=255&HEAPU8[o+(h+e)],i=255&HEAPU8[o+(i-e)],g=f,HEAP8[a-d]=h,HEAP8[a]=i,a++)}else OriginalFilterHorLuma(a,b,c,d)}Matrix.Translation=function(a){if(2==a.elements.length){var b=Matrix.I(3);return b.elements[2][0]=a.elements[0],b.elements[2][1]=a.elements[1],b}if(3==a.elements.length){var b=Matrix.I(4);return b.elements[0][3]=a.elements[0],b.elements[1][3]=a.elements[1],b.elements[2][3]=a.elements[2],b}throw"Invalid length for Translation"},Matrix.prototype.flatten=function(){var a=[];if(0==this.elements.length)return[];for(var b=0;b4||this.elements[0].length>4)return null;for(var a=0;ab;b++)a==b?this.elements[a].push(1):this.elements[a].push(0);for(var a=this.elements.length;4>a;a++)0==a?this.elements.push([1,0,0,0]):1==a?this.elements.push([0,1,0,0]):2==a?this.elements.push([0,0,1,0]):3==a&&this.elements.push([0,0,0,1]);return this},Matrix.prototype.make3x3=function(){return 4!=this.elements.length||4!=this.elements[0].length?null:Matrix.create([[this.elements[0][0],this.elements[0][1],this.elements[0][2]],[this.elements[1][0],this.elements[1][1],this.elements[1][2]],[this.elements[2][0],this.elements[2][1],this.elements[2][2]]])},Vector.prototype.flatten=function(){return this.elements};var Size=function(){function a(a,b){this.w=a,this.h=b}return a.prototype={toString:function(){return"("+this.w+", "+this.h+")"},getHalfSize:function(){return new Size(this.w>>>1,this.h>>>1)},length:function(){return this.w*this.h}},a}();assert(Module),HEAP8=Module.HEAP8,HEAPU8=Module.HEAPU8,HEAP16=Module.HEAP16,HEAP32=Module.HEAP32,_h264bsdClip=Module._get_h264bsdClip();var Avc=function(){function a(){Module._broadwayInit(),this.streamBuffer=b(Module._broadwayCreateStream(c),c),this.pictureBuffers={},this.onPictureDecoded=function(){},Module.patch(null,"_broadwayOnHeadersDecoded",function(){}),Module.patch(null,"_broadwayOnPictureDecoded",function(a,c,d){var e=this.pictureBuffers[a];e||(e=this.pictureBuffers[a]=b(a,3*c*d/2)),this.onPictureDecoded(e,c,d)}.bind(this))}function b(a,b){return HEAPU8.subarray(a,a+b)}var c=1048576;return a.prototype={decode:function(a){this.streamBuffer.set(a),Module._broadwaySetStreamLength(a.length),Module._broadwayPlayStream()},configure:function(a){patchOptimizations(a,patches),console.info("Broadway Configured: "+JSON.stringify(a))}},a}(),patches={filter:{name:"_h264bsdFilterPicture",display:"Filter Picture",original:"Original_h264bsdFilterPicture",options:{none:{display:"None",fn:function(){}},original:{display:"Original",fn:null}}},filterHorLuma:{name:"_FilterHorLuma",display:"Filter Hor Luma",original:"OriginalFilterHorLuma",options:{none:{display:"None",fn:function(){}},original:{display:"Original",fn:null},optimized:{display:"Optimized",fn:OptimizedFilterHorLuma}}},filterVerLumaEdge:{name:"_FilterVerLumaEdge",display:"Filter Ver Luma Edge",original:"OriginalFilterVerLumaEdge",options:{none:{display:"None",fn:function(){}},original:{display:"Original",fn:null},optimized:{display:"Optimized",fn:OptimizedFilterVerLumaEdge}}},getBoundaryStrengthsA:{name:"_GetBoundaryStrengthsA",display:"Get Boundary Strengths",original:"OriginalGetBoundaryStrengthsA",options:{none:{display:"None",fn:function(){}},original:{display:"Original",fn:null},optimized:{display:"Optimized",fn:OptimizedGetBoundaryStrengthsA}}}},Script=function(){function a(){}return a.createFromElementId=function(b){var c=document.getElementById(b);assert(c,"Could not find shader with ID: "+b);for(var d="",e=c.firstChild;e;)3==e.nodeType&&(d+=e.textContent),e=e.nextSibling;var f=new a;return f.type=c.type,f.source=d,f},a.createFromSource=function(b,c){var d=new a;return d.type=b,d.source=c,d},a}(),Shader=function(){function a(a,b){if("x-shader/x-fragment"==b.type)this.shader=a.createShader(a.FRAGMENT_SHADER);else{if("x-shader/x-vertex"!=b.type)return error("Unknown shader type: "+b.type),void 0;this.shader=a.createShader(a.VERTEX_SHADER)}return a.shaderSource(this.shader,b.source),a.compileShader(this.shader),a.getShaderParameter(this.shader,a.COMPILE_STATUS)?void 0:(error("An error occurred compiling the shaders: "+a.getShaderInfoLog(this.shader)),void 0)}return a}(),Program=function(){function a(a){this.gl=a,this.program=this.gl.createProgram()}return a.prototype={attach:function(a){this.gl.attachShader(this.program,a.shader)},link:function(){this.gl.linkProgram(this.program),assert(this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS),"Unable to initialize the shader program.")},use:function(){this.gl.useProgram(this.program)},getAttributeLocation:function(a){return this.gl.getAttribLocation(this.program,a)},setMatrixUniform:function(a,b){var c=this.gl.getUniformLocation(this.program,a);this.gl.uniformMatrix4fv(c,!1,b)}},a}(),Texture=function(){function a(a,b,c){this.gl=a,this.size=b,this.texture=a.createTexture(),a.bindTexture(a.TEXTURE_2D,this.texture),this.format=c?c:a.LUMINANCE,a.texImage2D(a.TEXTURE_2D,0,this.format,b.w,b.h,0,this.format,a.UNSIGNED_BYTE,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE)}var b=null;return a.prototype={fill:function(a,b){var c=this.gl;assert(a.length>=this.size.w*this.size.h,"Texture size mismatch, data:"+a.length+", texture: "+this.size.w*this.size.h),c.bindTexture(c.TEXTURE_2D,this.texture),b?c.texSubImage2D(c.TEXTURE_2D,0,0,0,this.size.w,this.size.h,this.format,c.UNSIGNED_BYTE,a):c.texImage2D(c.TEXTURE_2D,0,this.format,this.size.w,this.size.h,0,this.format,c.UNSIGNED_BYTE,a)},bind:function(a,c,d){var e=this.gl;b||(b=[e.TEXTURE0,e.TEXTURE1,e.TEXTURE2]),e.activeTexture(b[a]),e.bindTexture(e.TEXTURE_2D,this.texture),e.uniform1i(e.getUniformLocation(c.program,d),a)}},a}(),WebGLCanvas=function(){function a(a,d,e){this.canvas=a,this.size=d,this.canvas.width=d.w,this.canvas.height=d.h,this.onInitWebGL(),this.onInitShaders(),c.call(this),e&&b.call(this),this.onInitTextures(),h.call(this)}function b(){var a=this.gl;this.framebuffer=a.createFramebuffer(),a.bindFramebuffer(a.FRAMEBUFFER,this.framebuffer),this.framebufferTexture=new Texture(this.gl,this.size,a.RGBA);var b=a.createRenderbuffer();a.bindRenderbuffer(a.RENDERBUFFER,b),a.renderbufferStorage(a.RENDERBUFFER,a.DEPTH_COMPONENT16,this.size.w,this.size.h),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.framebufferTexture.texture,0),a.framebufferRenderbuffer(a.FRAMEBUFFER,a.DEPTH_ATTACHMENT,a.RENDERBUFFER,b)}function c(){var a,b=this.gl;this.quadVPBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,this.quadVPBuffer),a=[1,1,0,-1,1,0,1,-1,0,-1,-1,0],b.bufferData(b.ARRAY_BUFFER,new Float32Array(a),b.STATIC_DRAW),this.quadVPBuffer.itemSize=3,this.quadVPBuffer.numItems=4;var c=1,d=1;this.quadVTCBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,this.quadVTCBuffer),a=[c,0,0,0,c,d,0,d],b.bufferData(b.ARRAY_BUFFER,new Float32Array(a),b.STATIC_DRAW)}function d(){this.mvMatrix=Matrix.I(4)}function e(a){this.mvMatrix=this.mvMatrix.x(a)}function f(a){e.call(this,Matrix.Translation($V([a[0],a[1],a[2]])).ensure4x4())}function g(){this.program.setMatrixUniform("uPMatrix",new Float32Array(this.perspectiveMatrix.flatten())),this.program.setMatrixUniform("uMVMatrix",new Float32Array(this.mvMatrix.flatten()))}function h(){var a=this.gl;this.perspectiveMatrix=makePerspective(45,1,.1,100),d.call(this),f.call(this,[0,0,-2.4]),a.bindBuffer(a.ARRAY_BUFFER,this.quadVPBuffer),a.vertexAttribPointer(this.vertexPositionAttribute,3,a.FLOAT,!1,0,0),a.bindBuffer(a.ARRAY_BUFFER,this.quadVTCBuffer),a.vertexAttribPointer(this.textureCoordAttribute,2,a.FLOAT,!1,0,0),this.onInitSceneTextures(),g.call(this),this.framebuffer&&(console.log("Bound Frame Buffer"),a.bindFramebuffer(a.FRAMEBUFFER,this.framebuffer))}var i=Script.createFromSource("x-shader/x-vertex",text(["attribute vec3 aVertexPosition;","attribute vec2 aTextureCoord;","uniform mat4 uMVMatrix;","uniform mat4 uPMatrix;","varying highp vec2 vTextureCoord;","void main(void) {"," gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);"," vTextureCoord = aTextureCoord;","}"])),j=Script.createFromSource("x-shader/x-fragment",text(["precision highp float;","varying highp vec2 vTextureCoord;","uniform sampler2D texture;","void main(void) {"," gl_FragColor = texture2D(texture, vTextureCoord);","}"]));return a.prototype={toString:function(){return"WebGLCanvas Size: "+this.size},checkLastError:function(a){var b=this.gl.getError();if(b!=this.gl.NO_ERROR){var c=this.glNames[b];c=void 0!==c?c+"("+b+")":"Unknown WebGL ENUM (0x"+value.toString(16)+")",a?console.log("WebGL Error: %s, %s",a,c):console.log("WebGL Error: %s",c),console.trace()}},onInitWebGL:function(){try{this.gl=this.canvas.getContext("experimental-webgl")}catch(a){}if(this.gl||error("Unable to initialize WebGL. Your browser may not support it."),!this.glNames){this.glNames={};for(var b in this.gl)"number"==typeof this.gl[b]&&(this.glNames[this.gl[b]]=b)}},onInitShaders:function(){this.program=new Program(this.gl),this.program.attach(new Shader(this.gl,i)),this.program.attach(new Shader(this.gl,j)),this.program.link(),this.program.use(),this.vertexPositionAttribute=this.program.getAttributeLocation("aVertexPosition"),this.gl.enableVertexAttribArray(this.vertexPositionAttribute),this.textureCoordAttribute=this.program.getAttributeLocation("aTextureCoord"),this.gl.enableVertexAttribArray(this.textureCoordAttribute)},onInitTextures:function(){var a=this.gl;this.texture=new Texture(a,this.size,a.RGBA)},onInitSceneTextures:function(){this.texture.bind(0,this.program,"texture")},drawScene:function(){this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)},readPixels:function(a){var b=this.gl;b.readPixels(0,0,this.size.w,this.size.h,b.RGBA,b.UNSIGNED_BYTE,a)}},a}(),YUVWebGLCanvas=function(){function a(a,b){WebGLCanvas.call(this,a,b)}var b=Script.createFromSource("x-shader/x-vertex",text(["attribute vec3 aVertexPosition;","attribute vec2 aTextureCoord;","uniform mat4 uMVMatrix;","uniform mat4 uPMatrix;","varying highp vec2 vTextureCoord;","void main(void) {"," gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);"," vTextureCoord = aTextureCoord;","}"]));Script.createFromSource("x-shader/x-fragment",text(["precision highp float;","varying highp vec2 vTextureCoord;","uniform sampler2D YTexture;","uniform sampler2D UTexture;","uniform sampler2D VTexture;","void main(void) {"," vec3 YUV = vec3"," ("," texture2D(YTexture, vTextureCoord).x * 1.1643828125, // premultiply Y"," texture2D(UTexture, vTextureCoord).x,"," texture2D(VTexture, vTextureCoord).x"," );"," gl_FragColor = vec4"," ("," YUV.x + 1.59602734375 * YUV.z - 0.87078515625,"," YUV.x - 0.39176171875 * YUV.y - 0.81296875 * YUV.z + 0.52959375,"," YUV.x + 2.017234375 * YUV.y - 1.081390625,"," 1"," );","}"])),Script.createFromSource("x-shader/x-fragment",text(["precision highp float;","varying highp vec2 vTextureCoord;","uniform sampler2D YTexture;","uniform sampler2D UTexture;","uniform sampler2D VTexture;","void main(void) {"," gl_FragColor = texture2D(YTexture, vTextureCoord);","}"]));var c=Script.createFromSource("x-shader/x-fragment",text(["precision highp float;","varying highp vec2 vTextureCoord;","uniform sampler2D YTexture;","uniform sampler2D UTexture;","uniform sampler2D VTexture;","const mat4 YUV2RGB = mat4","("," 1.1643828125, 0, 1.59602734375, -.87078515625,"," 1.1643828125, -.39176171875, -.81296875, .52959375,"," 1.1643828125, 2.017234375, 0, -1.081390625,"," 0, 0, 0, 1",");","void main(void) {"," gl_FragColor = vec4( texture2D(YTexture, vTextureCoord).x, texture2D(UTexture, vTextureCoord).x, texture2D(VTexture, vTextureCoord).x, 1) * YUV2RGB;","}"]));return a.prototype=inherit(WebGLCanvas,{onInitShaders:function(){this.program=new Program(this.gl),this.program.attach(new Shader(this.gl,b)),this.program.attach(new Shader(this.gl,c)),this.program.link(),this.program.use(),this.vertexPositionAttribute=this.program.getAttributeLocation("aVertexPosition"),this.gl.enableVertexAttribArray(this.vertexPositionAttribute),this.textureCoordAttribute=this.program.getAttributeLocation("aTextureCoord"),this.gl.enableVertexAttribArray(this.textureCoordAttribute)},onInitTextures:function(){console.log("creatingTextures: size: "+this.size),this.YTexture=new Texture(this.gl,this.size),this.UTexture=new Texture(this.gl,this.size.getHalfSize()),this.VTexture=new Texture(this.gl,this.size.getHalfSize())},onInitSceneTextures:function(){this.YTexture.bind(0,this.program,"YTexture"),this.UTexture.bind(1,this.program,"UTexture"),this.VTexture.bind(2,this.program,"VTexture")},fillYUVTextures:function(a,b,c){this.YTexture.fill(a),this.UTexture.fill(b),this.VTexture.fill(c)},toString:function(){return"YUVCanvas Size: "+this.size}}),a}(),FilterWebGLCanvas=function(){function a(a,b,c){WebGLCanvas.call(this,a,b,c)}var b=Script.createFromSource("x-shader/x-vertex",text(["attribute vec3 aVertexPosition;","attribute vec2 aTextureCoord;","uniform mat4 uMVMatrix;","uniform mat4 uPMatrix;","varying highp vec2 vTextureCoord;","void main(void) {"," gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);"," vTextureCoord = aTextureCoord;","}"])),c=Script.createFromSource("x-shader/x-fragment",text(["precision highp float;","varying highp vec2 vTextureCoord;","uniform sampler2D FTexture;","void main(void) {"," gl_FragColor = texture2D(FTexture, vTextureCoord);","}"]));return a.prototype=inherit(WebGLCanvas,{onInitShaders:function(){this.program=new Program(this.gl),this.program.attach(new Shader(this.gl,b)),this.program.attach(new Shader(this.gl,c)),this.program.link(),this.program.use(),this.vertexPositionAttribute=this.program.getAttributeLocation("aVertexPosition"),this.gl.enableVertexAttribArray(this.vertexPositionAttribute),this.textureCoordAttribute=this.program.getAttributeLocation("aTextureCoord"),this.gl.enableVertexAttribArray(this.textureCoordAttribute)},onInitTextures:function(){console.log("creatingTextures: size: "+this.size),this.FTexture=new Texture(this.gl,this.size,this.gl.RGBA)},onInitSceneTextures:function(){this.FTexture.bind(0,this.program,"FTexture")},process:function(a,b){this.FTexture.fill(a),this.drawScene(),this.readPixels(b)},toString:function(){return"FilterWebGLCanvas Size: "+this.size}}),a}();!function(a){var b,c,d,e,f=0,g=["ms","moz","webkit","o"];for(b=0,c=g.length;c>b&&!a.requestAnimationFrame;++b)a.requestAnimationFrame=a[g[b]+"RequestAnimationFrame"],a.cancelAnimationFrame=a[g[b]+"CancelAnimationFrame"]||a[g[b]+"CancelRequestAnimationFrame"];a.requestAnimationFrame||(a.requestAnimationFrame=function(b){return d=(new Date).getTime(),e=Math.max(0,16-(d-f)),f=d+e,a.setTimeout(function(){b(d+e)},e)}),a.cancelAnimationFrame||(a.cancelAnimationFrame=function(a){clearTimeout(a)})}(window),function(a,b){function c(){i=new Avc,i.configure({filter:"original",filterHorLuma:"optimized",filterVerLumaEdge:"optimized",getBoundaryStrengthsA:"optimized"}),i.onPictureDecoded=e}function d(a){i.decode(new Uint8Array(a.data))}function e(a,b,c){var d;requestAnimationFrame(function(){var d=b*c,e=d>>2;j.YTexture.fill(a.subarray(0,d)),j.UTexture.fill(a.subarray(d,d+e)),j.VTexture.fill(a.subarray(d+e,d+2*e)),j.drawScene()}),null!==m&&k&&(d=m,m=null,d(a.subarray(0,k*l)))}function f(a){var c=b.createElement("canvas");k=a.attributes.width?a.attributes.width.value:640,l=a.attributes.height?a.attributes.height.value:360,c.width=k,c.height=l,c.style.backgroundColor="#333333",a.appendChild(c),j=new YUVWebGLCanvas(c,new Size(k,l))}var g,h,i,j,k,l,m=null;g=function(b,e){var g,i;e=e||{},g=e.hostname||a.document.location.hostname,i=e.port||a.document.location.port,f(b),c(),h=new WebSocket("ws://"+g+":"+i+"/dronestream"),h.binaryType="arraybuffer",h.onmessage=d},g.prototype.onNextFrame=function(a){m=a},a.NodecopterStream=g}(window,document,void 0); \ No newline at end of file diff --git a/node_modules/dronestream/dist/nodecopter-stream.js b/node_modules/dronestream/dist/nodecopter-stream.js new file mode 100644 index 0000000..2bb9090 --- /dev/null +++ b/node_modules/dronestream/dist/nodecopter-stream.js @@ -0,0 +1,129 @@ +/*jshint browser:true */ +/*global Avc:true, YUVWebGLCanvas: true, Size: true, requestAnimationFrame:true */ + +/* requestAnimationFrame polyfill: */ +(function (window) { + 'use strict'; + var lastTime = 0, + vendors = ['ms', 'moz', 'webkit', 'o'], + x, + length, + currTime, + timeToCall; + + for (x = 0, length = vendors.length; x < length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[ + vendors[x] + 'RequestAnimationFrame' + ]; + window.cancelAnimationFrame = window[ + vendors[x] + 'CancelAnimationFrame' + ] || window[vendors[x] + 'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) { + window.requestAnimationFrame = function (callback, element) { + currTime = new Date().getTime(); + timeToCall = Math.max(0, 16 - (currTime - lastTime)); + lastTime = currTime + timeToCall; + return window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + }; + } + + if (!window.cancelAnimationFrame) { + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + } +}(window)); + + +/* NodeCopterStream: */ +(function (window, document, undefined) { + 'use strict'; + var NS, + socket, + avc, + webGLCanvas, + width, + height, + callbackOnce = null; + + function setupAvc() { + avc = new Avc(); + avc.configure({ + filter: 'original', + filterHorLuma: 'optimized', + filterVerLumaEdge: 'optimized', + getBoundaryStrengthsA: 'optimized' + }); + avc.onPictureDecoded = handleDecodedFrame; + } + + function handleNalUnits(message) { + avc.decode(new Uint8Array(message.data)); + } + + function handleDecodedFrame(buffer, bufWidth, bufHeight) { + var callback; + + requestAnimationFrame(function () { + var lumaSize = bufWidth * bufHeight, + chromaSize = lumaSize >> 2; + + webGLCanvas.YTexture.fill(buffer.subarray(0, lumaSize)); + webGLCanvas.UTexture.fill(buffer.subarray(lumaSize, lumaSize + chromaSize)); + webGLCanvas.VTexture.fill(buffer.subarray(lumaSize + chromaSize, lumaSize + 2 * chromaSize)); + webGLCanvas.drawScene(); + }); + + // call callback with Y portion (grayscale image) + if (null !== callbackOnce && width) { + callback = callbackOnce; + callbackOnce = null; + // decoded buffer size may be larger, + // so use subarray with actual dimensions + callback(buffer.subarray(0, width * height)); + } + } + + function setupCanvas(div) { + var canvas = document.createElement('canvas'); + + width = div.attributes.width ? div.attributes.width.value : 640; + height = div.attributes.height ? div.attributes.height.value : 360; + + canvas.width = width; + canvas.height = height; + canvas.style.backgroundColor = "#333333"; + div.appendChild(canvas); + + webGLCanvas = new YUVWebGLCanvas(canvas, new Size(width, height)); + } + + + NS = function (div, options) { + var hostname, port; + options = options || {}; + hostname = options.hostname || window.document.location.hostname; + port = options.port || window.document.location.port; + + setupCanvas(div); + setupAvc(); + + socket = new WebSocket( + 'ws://' + hostname + ':' + port + '/dronestream' + ); + socket.binaryType = 'arraybuffer'; + socket.onmessage = handleNalUnits; + }; + + // enqueue callback oto be called with next (black&white) frame + NS.prototype.onNextFrame = function (callback) { + callbackOnce = callback; + }; + + window.NodecopterStream = NS; + +}(window, document, undefined)); diff --git a/node_modules/dronestream/dist/vendor/broadway/AUTHORS b/node_modules/dronestream/dist/vendor/broadway/AUTHORS new file mode 100644 index 0000000..f4eb7bd --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/AUTHORS @@ -0,0 +1,7 @@ +The following authors have all licensed their contributions to the project +under the licensing terms detailed in LICENSE. + +Michael Bebenita +Alon Zakai +Andreas Gal +Mathieu 'p01' Henri diff --git a/node_modules/dronestream/dist/vendor/broadway/LICENSE b/node_modules/dronestream/dist/vendor/broadway/LICENSE new file mode 100644 index 0000000..7d6da32 --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/LICENSE @@ -0,0 +1,17 @@ +Copyright (c) 2011, Project Authors (see AUTHORS file) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the names of the Project Authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-- + +The 3-clause BSD above applies to all code except for code originating +from the Android project (the .cpp files in Avc/). Those files are under +the Android project's Apache 2.0 license. + diff --git a/node_modules/dronestream/dist/vendor/broadway/avc-codec.js b/node_modules/dronestream/dist/vendor/broadway/avc-codec.js new file mode 100644 index 0000000..563af38 --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/avc-codec.js @@ -0,0 +1 @@ +function a(b){throw b}var aa=void 0,ca=true,ha=null,ka=false,ma=[],na=typeof process==="object",oa=typeof window==="object",ua=typeof importScripts==="function",La=!oa&&!na&&!ua;if(na){print=(function(b){process.stdout.write(b+"\n")});printErr=(function(b){process.stderr.write(b+"\n")});var Ma=require("fs");read=(function(b){var c=Ma.readFileSync(b).toString();!c&&b[0]!="/"&&(b=__dirname.split("/").slice(0,-1).join("/")+"/src/"+b,c=Ma.readFileSync(b).toString());return c});ma=process.argv.slice(2)}else{La?(this.read||(read=(function(b){snarf(b)})),ma=this.arguments?arguments:scriptArgs):oa?(print=printErr=(function(b){console.log(b)}),read=(function(b){var c=new XMLHttpRequest;c.open("GET",b,ka);c.send(ha);return c.responseText}),this.arguments&&(ma=arguments)):ua?load=importScripts:a("Unknown runtime environment. Where are we?")}function Wa(b){eval.call(ha,b)}typeof load=="undefined"&&typeof read!="undefined"&&(load=(function(b){Wa(read(b))}));typeof printErr==="undefined"&&(printErr=(function(){}));typeof print==="undefined"&&(print=printErr);try{this.Module=Module}catch(ab){this.Module=Module={}}if(!Module.arguments){Module.arguments=ma}if(Module.print){print=Module.print}function bb(b){var c=m;m+=b;m=m+3>>2<<2;return c}function vb(b){var c=xb;xb+=b;xb=xb+3>>2<<2;if(xb>=yb){for(;yb<=xb;){yb=Math.ceil(2*yb/zb)*zb}var b=q,d=new ArrayBuffer(yb);q=new Int8Array(d);x=new Int16Array(d);y=new Int32Array(d);A=new Uint8Array(d);Gb=new Uint16Array(d);F=new Uint32Array(d);Hb=new Float32Array(d);q.set(b)}return c}var Kb=4,Mb={},Ob={N:0,v:0,Ma:{},La:(function(b,c){c||(this.v++,this.v>=this.N&&Nb("\n\nToo many corrections!"))}),print:(function(){})},I=0,Pb,J;function Nb(b){print(b+":\n"+Error().stack);a("Assertion: "+b)}function Sb(b,c){b||Nb("Assertion failed: "+c)}var ac=this;Module.ccall=(function(b,c,d,f){try{var g=eval("_"+b)}catch(e){try{g=ac.Module["_"+b]}catch(i){}}Sb(g,"Cannot call unknown function "+b+" (perhaps LLVM optimizations or closure removed it?)");var h=0,b=f?f.map((function(b){if(d[h++]=="string"){var c=m;bb(b.length+1);bc(b,c);b=c}return b})):[];return(function(b,c){return c=="string"?cc(b):b})(g.apply(ha,b),c)});function dc(b,c,d){d=d||"i8";d[d.length-1]==="*"&&(d="i32");switch(d){case"i1":q[b]=c;break;case"i8":q[b]=c;break;case"i16":x[b>>1]=c;break;case"i32":y[b>>2]=c;break;case"i64":y[b>>2]=c;break;case"float":Hb[b>>2]=c;break;case"double":ec[0]=c;y[b>>2]=gc[0];y[b+4>>2]=gc[1];break;default:Nb("invalid type for setValue: "+d)}}Module.setValue=dc;Module.getValue=(function(b,c){c=c||"i8";c[c.length-1]==="*"&&(c="i32");switch(c){case"i1":return q[b];case"i8":return q[b];case"i16":return x[b>>1];case"i32":return y[b>>2];case"i64":return y[b>>2];case"float":return Hb[b>>2];case"double":return gc[0]=y[b>>2],gc[1]=y[b+4>>2],ec[0];default:Nb("invalid type for setValue: "+c)}return ha});var M=2;Module.ALLOC_NORMAL=0;Module.ALLOC_STACK=1;Module.ALLOC_STATIC=M;function P(b,c,d){var f,g;typeof b==="number"?(f=ca,g=b):(f=ka,g=b.length);var e=typeof c==="string"?c:ha,d=[jc,bb,vb][d===aa?M:d](Math.max(g,e?1:c.length));if(f){return kc(d,0,g),d}for(var i=0;i>2);Hb.subarray(uc>>2);var ec=(new Float64Array(q.buffer)).subarray(uc>>3);mc=uc+8;xb=Math.ceil(mc/zb)*zb;function vc(b){for(;b.length>0;){var c=b.shift(),d=c.C;typeof d==="number"&&(d=lc[d]);d(c.ra===aa?ha:c.ra)}}var wc=[],xc=[];function zc(b,c){return Array.prototype.slice.call(q.subarray(b,b+c))}Module.Array_copy=zc;Module.TypedArray_copy=(function(b,c){for(var d=new Uint8Array(c),f=0;f255&&(g&=255);d.push(g);f+=1}c||d.push(0);return d}Module.intArrayFromString=rc;Module.intArrayToString=(function(b){for(var c=[],d=0;d255&&(f&=255);c.push(String.fromCharCode(f))}return c.join("")});function bc(b,c,d){for(var f=0;f255&&(g&=255);q[c+f]=g;f+=1}d||(q[c+f]=0)}Module.writeStringToMemory=bc;var Q=[];function Bc(b){return(b|0)<0?-b|0:b}function Cc(b,c,d){return(d|0)<(b|0)?b:(d|0)>(c|0)?c:d}function Dc(b,c,d,f){var g,e=A[Q.n+c|0]&255,i=A[Q.o+c|0]&255,c=y[Ec+i*12>>2]<>2]<>2]<>2]=y[b>>2]*c|0);d=(f&65436|0)==0;a:do{if(d){if((f&98|0)==0){if(g=y[b>>2]+32>>6,(g+512|0)>>>0>1023){var k=1;g=18}else{y[b+60>>2]=g,y[b+56>>2]=g,y[b+52>>2]=g,y[b+48>>2]=g,y[b+44>>2]=g,y[b+40>>2]=g,y[b+36>>2]=g,y[b+32>>2]=g,y[b+28>>2]=g,y[b+24>>2]=g,y[b+20>>2]=g,y[b+16>>2]=g,y[b+12>>2]=g,y[b+8>>2]=g,y[b+4>>2]=g,y[b>>2]=g,g=17}}else{var l=b+4|0,j=y[l>>2]*h|0;g=b+20|0;var n=y[g>>2]*c|0,p=b+8|0,i=b+24|0,r=y[i>>2]*h|0,o=b+12|0,t=y[b>>2],s=t-n|0,u=(j>>1)-r|0,j=j+(r>>1)|0,t=t+(n+32)|0,n=t+j>>6;y[b>>2]=n;r=s+32|0;s=r+u>>6;y[l>>2]=s;l=r-u>>6;y[p>>2]=l;p=t-j>>6;y[o>>2]=p;y[b+48>>2]=n;y[b+32>>2]=n;y[b+16>>2]=n;y[b+52>>2]=s;y[b+36>>2]=s;y[g>>2]=s;y[b+56>>2]=l;y[b+40>>2]=l;y[i>>2]=l;y[b+60>>2]=p;y[b+44>>2]=p;y[b+28>>2]=p;(n+512|0)>>>0>1023?(k=1,g=18):(s+512|0)>>>0>1023?(k=1,g=18):(l+512|0)>>>0>1023?(k=1,g=18):(p+512|0)>>>0>1023?(k=1,g=18):g=17}}else{var w=b+4|0,i=b+56|0,s=y[i>>2],o=b+60|0,v=y[w>>2]*h|0,u=y[o>>2]*e|0,z=b+8|0,B=y[z>>2],D=b+20|0,C=b+16|0,E=y[D>>2]*c|0,G=y[C>>2]*e|0,t=b+32|0,H=b+12|0,K=y[H>>2],L=b+24|0,N=y[t>>2]*h|0,O=y[L>>2]*h|0,R=b+28|0,U=y[R>>2],p=b+48|0,r=b+36|0,n=y[r>>2],Y=y[p>>2]*e|0,X=b+40|0,ba=b+44|0,$=y[ba>>2],l=b+52|0,j=y[X>>2]*e|0,ja=y[l>>2]*h|0,sa=y[b>>2],Ea=E+sa|0,E=sa-E|0,sa=(v>>1)-O|0,v=(O>>1)+v|0;y[b>>2]=v+Ea|0;y[w>>2]=sa+E|0;y[z>>2]=E-sa|0;y[H>>2]=Ea-v|0;w=h*(U+B)|0;B=(B-U)*h|0;U=(G>>1)-Y|0;G=(Y>>1)+G|0;y[C>>2]=G+w|0;y[D>>2]=U+B|0;y[L>>2]=B-U|0;y[R>>2]=w-G|0;D=c*($+K)|0;K=(K-$)*c|0;$=(N>>1)-ja|0;N=(ja>>1)+N|0;y[t>>2]=N+D|0;y[r>>2]=$+K|0;y[X>>2]=K-$|0;y[ba>>2]=D-N|0;t=h*(s+n)|0;s=(n-s)*h|0;n=(j>>1)-u|0;u=(u>>1)+j|0;y[p>>2]=u+t|0;y[l>>2]=n+s|0;y[i>>2]=s-n|0;y[o>>2]=t-u|0;for(i=0;;){s=b+(i<<2)|0;o=b+(i+12<<2)|0;l=b+(i+4<<2)|0;p=b+(i+8<<2)|0;if((i|0)==4){g=17;break a}t=y[s>>2];r=y[p>>2];n=t-r|0;j=y[l>>2];X=y[o>>2];u=(j>>1)-X|0;j=(X>>1)+j|0;r=t+(r+32)|0;t=r+j>>6;y[s>>2]=t;n=n+32|0;s=n+u>>6;y[l>>2]=s;l=n-u>>6;y[p>>2]=l;p=r-j>>6;y[o>>2]=p;if((t+512|0)>>>0>1023){k=1;g=18;break a}if((s+512|0)>>>0>1023){k=1;g=18;break a}if((l+512|0)>>>0>1023){k=1;g=18;break a}if((p+512|0)>>>0>1023){k=1;g=18;break a}i=i+1|0}}}while(0);g==17&&(k=0);return k}Dc.X=1;function Gc(b,c){var d=A[Q.o+c|0],f=A[Q.n+c|0],g=b+8|0,e=y[g>>2],i=b+20|0,h=y[i>>2],k=b+16|0,l=y[k>>2],j=b+32|0,n=y[j>>2],p=b+12|0,r=y[p>>2],o=b+24|0,t=y[o>>2],s=b+28|0,u=y[s>>2],w=b+48|0,v=y[w>>2],z=b+36|0,B=y[z>>2],D=b+40|0,C=y[D>>2],E=b+44|0,G=y[E>>2],H=b+52|0,K=y[H>>2],L=b+4|0,N=y[b>>2],O=h+N|0,R=N-h|0,U=y[L>>2],Y=U-t|0,X=t+U|0,ba=X+O|0;y[b>>2]=ba;var $=Y+R|0;y[L>>2]=$;var ja=R-Y|0;y[g>>2]=ja;var sa=O-X|0;y[p>>2]=sa;var Ea=u+e|0,Xa=e-u|0,ea=l-v|0,fa=v+l|0,va=fa+Ea|0;y[k>>2]=va;var ob=ea+Xa|0;y[i>>2]=ob;var wa=Xa-ea|0;y[o>>2]=wa;var pb=Ea-fa|0;y[s>>2]=pb;var gb=G+r|0,Ib=r-G|0,Fa=n-K|0,qb=K+n|0,Ya=qb+gb|0;y[j>>2]=Ya;var Na=Fa+Ib|0;y[z>>2]=Na;var za=Ib-Fa|0;y[D>>2]=za;var da=gb-qb|0;y[E>>2]=da;var Oa=b+56|0,Za=b+60|0,Aa=y[Oa>>2],hb=Aa+B|0,Ga=B-Aa|0,Pa=y[Za>>2],$a=C-Pa|0,Ab=Pa+C|0,cb=Ab+hb|0;y[w>>2]=cb;var rb=$a+Ga|0;y[H>>2]=rb;var Qa=Ga-$a|0;y[Oa>>2]=Qa;var pa=hb-Ab|0;y[Za>>2]=pa;var ia=f&255,qa=F[Ec+(d&255)*12>>2],Ra=c>>>0>11;a:do{if(Ra){var ra=qa<>2]=(db+ib)*ra|0;y[k>>2]=(jb+sb)*ra|0;y[j>>2]=(sb-jb)*ra|0;y[w>>2]=(ib-db)*ra|0;var Sa=Na+$|0,kb=$-Na|0,ta=ob-rb|0,Bb=rb+ob|0;y[L>>2]=(Bb+Sa)*ra|0;y[i>>2]=(ta+kb)*ra|0;y[z>>2]=(kb-ta)*ra|0;y[H>>2]=(Sa-Bb)*ra|0;var Ha=za+ja|0,ya=ja-za|0,xa=wa-Qa|0,Ba=Qa+wa|0;y[g>>2]=(Ba+Ha)*ra|0;y[o>>2]=(xa+ya)*ra|0;y[D>>2]=(ya-xa)*ra|0;y[Oa>>2]=(Ha-Ba)*ra|0;var Ca=da+sa|0,Ta=sa-da|0,lb=pb-pa|0,Jb=pa+pb|0;y[p>>2]=(Jb+Ca)*ra|0;y[s>>2]=(lb+Ta)*ra|0;y[E>>2]=(Ta-lb)*ra|0;y[Za>>2]=(Ca-Jb)*ra|0}else{for(var eb=(c-6|0)>>>0<6?1:2,Da=2-ia|0,Ia=0,mb=ba;;){var Ua=b+(Ia+8<<2)|0,Ja=b+(Ia+4<<2)|0,Ka=b+(Ia+12<<2)|0,Cb=y[Ua>>2],Db=Cb+mb|0,Eb=mb-Cb|0,tb=y[Ja>>2],Va=y[Ka>>2],fb=tb-Va|0,ub=Va+tb|0;y[b+(Ia<<2)>>2]=(ub+Db)*qa+eb>>Da;y[Ja>>2]=(fb+Eb)*qa+eb>>Da;y[Ua>>2]=(Eb-fb)*qa+eb>>Da;y[Ka>>2]=(Db-ub)*qa+eb>>Da;var nb=Ia+1|0;if((nb|0)==4){break a}var Fb=y[b+(nb<<2)>>2],Ia=nb,mb=Fb}}}while(0)}Gc.X=1;function Hc(b,c){var d=y[Ec+(A[Q.o+c|0]&255)*12>>2];if(c>>>0>5){var f=0;d<<=(A[Q.n+c|0]&255)-1}else{f=1}var g=y[b>>2],e=b+8|0,i=y[e>>2],h=i+g|0,g=g-i|0,i=b+4|0,k=y[i>>2],l=b+12|0,j=y[l>>2],n=k-j|0,k=j+k|0;y[b>>2]=(k+h)*d>>f;y[i>>2]=(h-k)*d>>f;y[e>>2]=(n+g)*d>>f;y[l>>2]=(g-n)*d>>f;var e=b+16|0,i=y[e>>2],h=b+24|0,l=y[h>>2],g=l+i|0,i=i-l|0,l=b+20|0,j=y[l>>2],n=b+28|0,p=y[n>>2],k=j-p|0,j=p+j|0;y[e>>2]=(j+g)*d>>f;y[l>>2]=(g-j)*d>>f;y[h>>2]=(k+i)*d>>f;y[n>>2]=(i-k)*d>>f}Hc.X=1;function Ic(b,c,d){var f=F[b+(d<<2)>>2],g=d+1|0,e=g>>>0>>0&(y[b+(g<<2)>>2]|0)!=(f|0);a:do{if(e){for(var i=d+2|0,h=0;;){var k=i+h|0;if(!(k>>>0>>0&(y[b+(k<<2)>>2]|0)!=(f|0))){var l=k;break a}h=h+1|0}}else{l=g}}while(0);return(l|0)==(c|0)?0:l}function Lc(b,c){var d=F[b+4>>2],f=(c>>>0)%(d>>>0),g=c-f|0,d=y[b+8>>2]*d|0,e=y[b>>2];y[b+12>>2]=e+((g<<8)+(f<<4))|0;f=(d<<8)+(f<<3)+(g<<6)|0;y[b+16>>2]=e+f|0;y[b+20>>2]=e+(f+(d<<6))|0}function Mc(b,c,d,f){var g,e=c>>>0>3;a:do{if(e){if(q[b]<<24>>24!=0){g=17}else{if(q[b+1|0]<<24>>24!=0){g=17}else{if((A[b+2|0]&254|0)!=0){g=17}else{for(var i=2,h=0;;){var k=h+3|0;if((k|0)==(c|0)){y[f>>2]=c;var l=1;g=30;break a}var j=q[h+(b+2)|0];if(j==0){i=i+1|0}else{if(j==1&&i>>>0>1){break}i=0}h=h+1|0}for(var h=h+4|0,n=i=0,p=0,j=0;;){var r=h+j|0,o=A[b+(k+j)|0],t=o<<24>>24!=0,p=(t&1^1)+p|0,n=o<<24>>24==3&(p|0)==2?1:n;if(o<<24>>24==1&p>>>0>1){g=j-p|0;y[d+12>>2]=g;var s=i,u=n,w=k,v=p-(p>>>0<3?p:3)|0,z=g;g=18;break a}t&&(i=p>>>0>2?1:i,p=0);if((r|0)!=(c|0)){j=j+1|0}else{g=r-k-p|0;y[d+12>>2]=g;s=i;u=n;w=k;v=p;z=g;g=18;break a}}}}}}else{g=17}}while(0);g==17&&(y[d+12>>2]=c,s=0,u=1,v=w=0,z=c,g=18);a:do{if(g==18){if(c=b+w|0,k=d|0,y[k>>2]=c,y[d+4>>2]=c,y[d+8>>2]=0,y[d+16>>2]=0,c=d+12|0,y[f>>2]=w+v+z|0,(s|0)!=0){l=1}else{if((u|0)!=0){l=k=y[k>>2];e=y[c>>2];h=j=0;b:for(;;){for(var B=k+h|0,i=e-1|0,r=j,j=0;;){var D=l+j|0,n=j+1|0,C=l+n|0;if((e|0)==(j|0)){break b}var E=A[D];if((r|0)!=2){break}if(E<<24>>24==3){if((i|0)==(j|0)){l=1;break a}if((A[C]&255)>3){l=1;break a}r=0;j=n}else{if((E&255)<3){l=1;break a}break}}r=E<<24>>24==0?r+1|0:0;q[B]=E;l=C;e=i-j|0;j=r;h=h+1|0}y[c>>2]=B-D+y[c>>2]|0}l=0}}}while(0);return l}Mc.X=1;function Nc(b,c){var d=(y[b>>2]|0)==(y[c>>2]|0);a:do{if(d){if((y[b+4>>2]|0)!=(y[c+4>>2]|0)){var f=1}else{if((y[b+12>>2]|0)!=(y[c+12>>2]|0)){f=1}else{if(f=y[b+16>>2],(f|0)!=(y[c+16>>2]|0)){f=1}else{if((y[b+44>>2]|0)!=(y[c+44>>2]|0)){f=1}else{if((y[b+48>>2]|0)!=(y[c+48>>2]|0)){f=1}else{if((y[b+52>>2]|0)!=(y[c+52>>2]|0)){f=1}else{if((y[b+56>>2]|0)!=(y[c+56>>2]|0)){f=1}else{var g=F[b+60>>2];if((g|0)!=(y[c+60>>2]|0)){f=1}else{if((y[b+80>>2]|0)!=(y[c+80>>2]|0)){f=1}else{b:do{if(f==0){if((y[b+20>>2]|0)!=(y[c+20>>2]|0)){f=1;break a}}else{if(f==1){if((y[b+24>>2]|0)!=(y[c+24>>2]|0)){f=1;break a}if((y[b+28>>2]|0)!=(y[c+28>>2]|0)){f=1;break a}if((y[b+32>>2]|0)!=(y[c+32>>2]|0)){f=1;break a}var e=F[b+36>>2];if((e|0)!=(y[c+36>>2]|0)){f=1;break a}for(var i=b+40|0,h=c+40|0,k=0;;){if(k>>>0>=e>>>0){break b}if((y[y[i>>2]+(k<<2)>>2]|0)!=(y[y[h>>2]+(k<<2)>>2]|0)){f=1;break a}k=k+1|0}}}}while(0);if((g|0)!=0){if((y[b+64>>2]|0)!=(y[c+64>>2]|0)){f=1;break}if((y[b+68>>2]|0)!=(y[c+68>>2]|0)){f=1;break}if((y[b+72>>2]|0)!=(y[c+72>>2]|0)){f=1;break}if((y[b+76>>2]|0)!=(y[c+76>>2]|0)){f=1;break}}f=0}}}}}}}}}}else{f=1}}while(0);return f}Nc.X=1;function Oc(b,c){var d=m;m+=4;Pc(c,0,92);var f=S(b,8),g=(f|0)==-1;a:do{if(g){var e=1}else{if(y[c>>2]=f,S(b,1),S(b,1),(S(b,1)|0)==-1){e=1}else{if((S(b,5)|0)==-1){e=1}else{var i=S(b,8);if((i|0)==-1){e=1}else{e=c+4|0;y[e>>2]=i;var i=c+8|0,h=T(b,i);if((h|0)!=0){e=h}else{if(F[i>>2]>>>0>31){e=1}else{if(i=T(b,d),(i|0)!=0){e=i}else{if(i=F[d>>2],i>>>0>12){e=1}else{if(y[c+12>>2]=1<>2],i>>>0>2){e=1}else{y[c+16>>2]=i;b:do{if(i==0){h=T(b,d);if((h|0)!=0){e=h;break a}h=F[d>>2];if(h>>>0>12){e=1;break a}y[c+20>>2]=1<>2]=(h|0)==1&1;h=Qc(b,c+28|0);if((h|0)!=0){e=h;break a}h=Qc(b,c+32|0);if((h|0)!=0){e=h;break a}var h=c+36|0,k=T(b,h);if((k|0)!=0){e=k;break a}k=F[h>>2];if(k>>>0>255){e=1;break a}if((k|0)==0){y[c+40>>2]=0}else{var l=jc(k<<2),k=c+40|0;y[k>>2]=l;if((l|0)==0){e=65535;break a}for(l=0;;){if(l>>>0>=F[h>>2]>>>0){break b}var j=Qc(b,y[k>>2]+(l<<2)|0);if((j|0)!=0){e=j;break a}l=l+1|0}}}}}while(0);i=c+44|0;h=T(b,i);if((h|0)!=0){e=h}else{if(F[i>>2]>>>0>16){e=1}else{if(h=S(b,1),(h|0)==-1){e=1}else{if(y[c+48>>2]=(h|0)==1&1,h=T(b,d),(h|0)!=0){e=h}else{if(k=c+52|0,y[k>>2]=y[d>>2]+1|0,h=T(b,d),(h|0)!=0){e=h}else{if(h=c+56|0,y[h>>2]=y[d>>2]+1|0,l=S(b,1),l==-1||l==0){e=1}else{if((S(b,1)|0)==-1){e=1}else{if(l=S(b,1),(l|0)==-1){e=1}else{l=(l|0)==1;y[c+60>>2]=l&1;if(l){l=c+64|0;j=T(b,l);if((j|0)!=0){e=j;break}var j=c+68|0,n=T(b,j);if((n|0)!=0){e=n;break}var n=c+72|0,p=T(b,n);if((p|0)!=0){e=p;break}var p=c+76|0,r=T(b,p);if((r|0)!=0){e=r;break}k=y[k>>2];if((y[l>>2]|0)>((k<<3)-1-y[j>>2]|0)){e=1;break}h=y[h>>2];if((y[n>>2]|0)>((h<<3)-1-y[p>>2]|0)){e=1;break}}else{k=y[k>>2],h=y[h>>2]}h=h*k|0;e=y[e>>2];k=aa;if(e==10){var o=99,t=152064,k=15}else{if(e==11){o=396,t=345600,k=15}else{if(e==12){o=396,t=912384,k=15}else{if(e==13){o=396,t=912384,k=15}else{if(e==20){o=396,t=912384,k=15}else{if(e==21){o=792,t=1824768,k=15}else{if(e==22){o=1620,t=3110400,k=15}else{if(e==30){o=1620,t=3110400,k=15}else{if(e==31){o=3600,t=6912e3,k=15}else{if(e==32){o=5120,t=7864320,k=15}else{if(e==40){o=8192,t=12582912,k=15}else{if(e==41){o=8192,t=12582912,k=15}else{if(e==42){o=8704,t=13369344,k=15}else{if(e==50){o=22080,t=42393600,k=15}else{if(e==51){o=36864,t=70778880,k=15}else{var s=2147483647,k=17}}}}}}}}}}}}}}}k==15&&(o>>>0>>0?s=2147483647:(s=Math.floor((t>>>0)/((h*384|0)>>>0)),s=s>>>0<16?s:16));e=s;y[d>>2]=e;h=F[i>>2];(e|0)==2147483647|h>>>0>e>>>0?y[d>>2]=h:h=e;e=c+88|0;y[e>>2]=h;h=S(b,1);if((h|0)==-1){e=1}else{h=(h|0)==1;y[c+80>>2]=h&1;do{if(h){j=l=jc(952);k=c+84|0;y[k>>2]=j;if((l|0)==0){e=65535;break a}l=Rc(b,j);if((l|0)!=0){e=l;break a}k=y[k>>2];if((y[k+920>>2]|0)!=0){l=F[k+948>>2];if(F[k+944>>2]>>>0>l>>>0){e=1;break a}if(l>>>0>2]>>>0){e=1;break a}if(l>>>0>F[e>>2]>>>0){e=1;break a}y[e>>2]=(l|0)==0?1:l}}}while(0);S(b,8-y[b+8>>2]|0);e=0}}}}}}}}}}}}}}}}}}}}while(0);m=d;return e}Oc.X=1;function Sc(b,c){var d=m;m+=8;var f=d+4;Pc(c,0,72);var g=c|0,e=T(b,g),i=(e|0)==0;a:do{if(i){if(F[g>>2]>>>0>255){var h=1}else{var h=c+4|0,k=T(b,h);if((k|0)!=0){h=k}else{if(F[h>>2]>>>0>31){h=1}else{if((S(b,1)|0)!=0){h=1}else{if(h=S(b,1),(h|0)==-1){h=1}else{if(y[c+8>>2]=(h|0)==1&1,h=T(b,d),(h|0)==0){if(k=y[d>>2]+1|0,h=c+12|0,y[h>>2]=k,k>>>0>8){h=1}else{k=k>>>0>1;b:do{if(k){var l=c+16|0,j=T(b,l);if((j|0)!=0){h=j;break a}l=F[l>>2];if(l>>>0>6){h=1;break a}if(l==0){j=jc(y[h>>2]<<2);l=c+20|0;y[l>>2]=j;if((j|0)==0){h=65535;break a}for(j=0;;){if(j>>>0>=F[h>>2]>>>0){break b}var n=T(b,d);if((n|0)!=0){h=n;break a}y[(y[l>>2]+(j<<2)|0)>>2]=y[d>>2]+1|0;j=j+1|0}}else{if(l==2){j=jc((y[h>>2]<<2)-4|0);l=c+24|0;y[l>>2]=j;n=jc((y[h>>2]<<2)-4|0);j=c+28|0;y[j>>2]=n;if((y[l>>2]|0)==0|(n|0)==0){h=65535;break a}for(n=0;;){if(n>>>0>=(y[h>>2]-1|0)>>>0){break b}var p=T(b,d);if((p|0)!=0){h=p;break a}y[(y[l>>2]+(n<<2)|0)>>2]=y[d>>2];p=T(b,d);if((p|0)!=0){h=p;break a}y[(y[j>>2]+(n<<2)|0)>>2]=y[d>>2];n=n+1|0}}else{if(l==3||l==4||l==5){l=S(b,1);if((l|0)==-1){h=1;break a}y[c+32>>2]=(l|0)==1&1;l=T(b,d);if((l|0)!=0){h=l;break a}y[c+36>>2]=y[d>>2]+1|0}else{if(l==6){l=T(b,d);if((l|0)!=0){h=l;break a}j=y[d>>2]+1|0;l=c+40|0;y[l>>2]=j;n=jc(j<<2);j=c+44|0;y[j>>2]=n;if((n|0)==0){h=65535;break a}n=y[Tc+(y[h>>2]-1<<2)>>2];for(p=0;;){if(p>>>0>=F[l>>2]>>>0){break b}var r=S(b,n);y[(y[j>>2]+(p<<2)|0)>>2]=r;if(F[y[j>>2]+(p<<2)>>2]>>>0>=F[h>>2]>>>0){h=1;break a}p=p+1|0}}}}}}}while(0);h=T(b,d);(h|0)==0&&(h=F[d>>2],h>>>0>31?h=1:(y[c+48>>2]=h+1|0,h=T(b,d),(h|0)==0&&(F[d>>2]>>>0>31?h=1:(S(b,1)|0)!=0?h=1:S(b,2)>>>0>2?h=1:(h=Qc(b,f),(h|0)==0&&(h=y[f>>2]+26|0,h>>>0>51?h=1:(y[c+52>>2]=h,h=Qc(b,f),(h|0)==0&&((y[f>>2]+26|0)>>>0>51?h=1:(h=Qc(b,f),(h|0)==0&&(h=F[f>>2],(h+12|0)>>>0>24?h=1:(y[c+56>>2]=h,h=S(b,1),(h|0)==-1?h=1:(y[c+60>>2]=(h|0)==1&1,h=S(b,1),(h|0)==-1?h=1:(y[c+64>>2]=(h|0)==1&1,h=S(b,1),(h|0)==-1?h=1:(y[c+68>>2]=(h|0)==1&1,S(b,8-y[b+8>>2]|0),h=0)))))))))))))}}}}}}}}else{h=e}}while(0);m=d;return h}Sc.X=1;function Uc(b,c,d,f,g){var e=m;m+=8;var i=e+4;Pc(c,0,988);var h=y[d+56>>2]*y[d+52>>2]|0,k=T(b,e),l=(k|0)==0;a:do{if(l){var j=F[e>>2];y[c>>2]=j;if(j>>>0>>0){if(j=T(b,e),(j|0)==0){var j=y[e>>2],n=c+4|0;y[n>>2]=j;if(!(j==2||j==7)){if(j==0||j==5){if((y[g>>2]|0)==5){j=1;break}if((y[d+44>>2]|0)==0){j=1;break}}else{j=1;break}}j=T(b,e);if((j|0)==0){if(j=y[e>>2],y[c+8>>2]=j,(j|0)!=(y[f>>2]|0)){j=1}else{var p=d+12|0,j=F[p>>2],r=(j|0)==0;b:do{if(r){var o=-1}else{for(var t=0;;){var s=t+1|0;if((j>>>(s>>>0)|0)==0){o=t;break b}t=s}}}while(0);r=S(b,o);if((r|0)==-1){j=1}else{if(j=g|0,(y[j>>2]|0)!=5|(r|0)==0){y[c+12>>2]=r;if((y[j>>2]|0)==5){r=T(b,e);if((r|0)!=0){j=r;break}r=F[e>>2];y[c+16>>2]=r;if(r>>>0>65535){j=1;break}}r=d+16|0;t=F[r>>2];if((t|0)==0){var t=d+20|0,s=F[t>>2],u=(s|0)==0;b:do{if(u){var w=-1}else{for(var v=0;;){var z=v+1|0;if((s>>>(z>>>0)|0)==0){w=v;break b}v=z}}}while(0);u=S(b,w);if((u|0)==-1){j=1;break}s=c+20|0;y[s>>2]=u;if((y[f+8>>2]|0)!=0){u=Qc(b,i);if((u|0)!=0){j=u;break}y[c+24>>2]=y[i>>2]}if((y[j>>2]|0)==5){s=F[s>>2];if(s>>>0>F[t>>2]>>>1>>>0){j=1;break}t=y[c+24>>2];if((s|0)!=(((t|0)>0?0:-t|0)|0)){j=1;break}}r=y[r>>2]}else{r=t}r=(r|0)==1;do{if(r&&(y[d+24>>2]|0)==0){t=Qc(b,i);if((t|0)!=0){j=t;break a}t=c+28|0;y[t>>2]=y[i>>2];if((y[f+8>>2]|0)!=0){s=Qc(b,i);if((s|0)!=0){j=s;break a}y[c+32>>2]=y[i>>2]}if((y[j>>2]|0)==5&&(t=y[t>>2],s=y[d+32>>2]+t+y[c+32>>2]|0,(((t|0)<(s|0)?t:s)|0)!=0)){j=1;break a}}}while(0);if((y[f+68>>2]|0)!=0){r=T(b,e);if((r|0)!=0){j=r;break}r=F[e>>2];y[c+36>>2]=r;if(r>>>0>127){j=1;break}}r=F[n>>2];if(r==0||r==5){r=S(b,1);if((r|0)==-1){j=1;break}y[c+40>>2]=r;if((r|0)==0){r=F[f+48>>2];if(r>>>0>16){j=1;break}y[c+44>>2]=r}else{r=T(b,e);if((r|0)!=0){j=r;break}r=F[e>>2];if(r>>>0>15){j=1;break}y[c+44>>2]=r+1|0}n=y[n>>2]}else{n=r}if(n==0||n==5){n=b;r=c+68|0;t=y[c+44>>2];p=y[p>>2];s=m;m+=8;u=s+4;v=S(n,1);z=(v|0)==-1;b:do{if(z){var B=1}else{y[r>>2]=v;if((v|0)!=0){for(B=0;;){var D=r+4+B*12+4|0,C=r+4+B*12+8|0,E=r+4+B*12|0;if(B>>>0>t>>>0){B=1;break b}var G=T(n,u);if((G|0)!=0){B=G;break b}G=F[u>>2];if(G>>>0>3){B=1;break b}y[E>>2]=G;E=G>>>0<2;do{if(E){var H=T(n,s);if((H|0)!=0){B=H;break b}H=F[s>>2];if(H>>>0>=p>>>0){B=1;break b}y[D>>2]=H+1|0}else{if((G|0)==2){H=T(n,s);if((H|0)!=0){B=H;break b}y[C>>2]=y[s>>2]}}}while(0);if((G|0)==3){break}B=B+1|0}if((B|0)==0){B=1;break}}B=0}}while(0);m=s;p=B;if((p|0)!=0){j=p;break}}if((y[g+4>>2]|0)!=0&&(j=Vc(b,c+276|0,y[j>>2],y[d+44>>2]),(j|0)!=0)){break}j=Qc(b,i);if((j|0)==0){if(j=y[i>>2],y[c+48>>2]=j,j=j+y[f+52>>2]|0,y[i>>2]=j,j>>>0>51){j=1}else{j=(y[f+60>>2]|0)==0;do{if(!j){p=T(b,e);if((p|0)!=0){j=p;break a}p=F[e>>2];y[c+52>>2]=p;if(p>>>0>2){j=1;break a}if((p|0)!=1){p=Qc(b,i);if((p|0)!=0){j=p;break a}p=F[i>>2];if((p+6|0)>>>0>12){j=1;break a}y[c+56>>2]=p<<1;p=Qc(b,i);if((p|0)!=0){j=p;break a}p=F[i>>2];if((p+6|0)>>>0>12){j=1;break a}y[c+60>>2]=p<<1}}}while(0);j=F[f+12>>2]>>>0>1;do{if(j&&(y[f+16>>2]-3|0)>>>0<3){p=f+36|0;n=y[p>>2];n=(((h>>>0)%(n>>>0)|0)==0?1:2)+Math.floor((h>>>0)/(n>>>0))|0;for(r=0;;){var K=r+1|0;if((-1<>2]=n;if((n|0)==-1){j=1;break a}y[c+64>>2]=n;p=F[p>>2];if(n>>>0>Math.floor(((h-1+p|0)>>>0)/(p>>>0))>>>0){j=1;break a}}}while(0);j=0}}}else{j=1}}}}}}else{j=1}}else{j=k}}while(0);m=e;return j}Uc.X=1;function Vc(b,c,d,f){var g=m;m+=8;var e,i=g+4,d=(d|0)==5,h=S(b,1),k=(h|0)==-1;a:do{if(d){if(k){var l=1;e=24;break}y[c>>2]=h;var j=S(b,1);if((j|0)==-1){l=1;e=24;break}y[c+4>>2]=j;if((f|0)!=0|(j|0)==0){e=23;break}}else{if(k){l=1;e=24;break}y[c+8>>2]=h;if((h|0)==0){e=23;break}for(var j=(f<<1)+2|0,n=0,p=0,r=0,o=0,t=0;;){var s=c+12+t*20+4|0,u=c+12+t*20+8|0,w=c+12+t*20+12|0,v=c+12+t*20+16|0;e=c+12+t*20|0;if(t>>>0>j>>>0){l=1;e=24;break a}var z=T(b,i);if((z|0)!=0){l=z;e=24;break a}z=F[i>>2];if(z>>>0>6){l=1;e=24;break a}y[e>>2]=z;do{if(z==3||z==1){e=T(b,g);if((e|0)!=0){l=e;e=24;break a}y[s>>2]=y[g>>2]+1|0;if(z==2){e=13}else{if(z==6||z==3){e=15}else{if(z==4){e=17}else{var B=o;e=20}}}}else{z==2?e=13:z==6?e=15:z==4?e=17:(B=o,e=20)}}while(0);do{if(e==13){B=T(b,g);if((B|0)!=0){l=B;e=24;break a}y[u>>2]=y[g>>2];B=o;e=20}else{if(e==15){e=T(b,g);if((e|0)!=0){l=e;e=24;break a}y[w>>2]=y[g>>2];(z|0)==4?e=17:(B=o,e=20)}}}while(0);if(e==17){B=T(b,g);if((B|0)!=0){l=B;e=24;break a}B=F[g>>2];if(B>>>0>f>>>0){l=1;e=24;break a}y[v>>2]=(B|0)==0?65535:B-1|0;B=o+1|0}v=((z|0)==5&1)+r|0;u=((z|0)!=0&z>>>0<4&1)+n|0;w=((z|0)==6&1)+p|0;if((z|0)==0){break}n=u;p=w;r=v;o=B;t=t+1|0}if(B>>>0>1|v>>>0>1|w>>>0>1){l=1;e=24;break}if((u|0)==0|(v|0)==0){e=23;break}}l=1;e=24}while(0);e==23&&(l=0);m=g;return l}Vc.X=1;function Wc(b,c){var d=m;m+=24;var f=d+4,g=f|0;y[f>>2]=y[b>>2];y[f+4>>2]=y[b+4>>2];y[f+8>>2]=y[b+8>>2];y[f+12>>2]=y[b+12>>2];y[f+16>>2]=y[b+16>>2];f=T(g,d);(f|0)==0?(f=T(g,d),(f|0)!=0?g=f:(g=T(g,d),(g|0)==0&&(g=F[d>>2],g>>>0>255?g=1:(y[c>>2]=g,g=0)))):g=f;m=d;return g}function Xc(b,c,d,f){var g=m;m+=24;var e=g+4,i=e|0;y[e>>2]=y[b>>2];y[e+4>>2]=y[b+4>>2];y[e+8>>2]=y[b+8>>2];y[e+12>>2]=y[b+12>>2];y[e+16>>2]=y[b+16>>2];b=T(i,g);e=(b|0)==0;do{if(e){var h=T(i,g);if((h|0)==0&&(h=T(i,g),(h|0)==0)){var h=F[c+12>>2],k=(h|0)==0;a:do{if(k){var l=-1}else{for(var j=0;;){var n=j+1|0;if((h>>>(n>>>0)|0)==0){l=j;break a}j=n}}}while(0);if((S(i,l)|0)==-1){h=1}else{if((d|0)==5&&(h=T(i,g),(h|0)!=0)){break}h=F[c+20>>2];k=(h|0)==0;a:do{if(k){var p=-1}else{for(j=0;;){n=j+1|0;if((h>>>(n>>>0)|0)==0){p=j;break a}j=n}}}while(0);h=S(i,p);(h|0)==-1?h=1:(y[f>>2]=h,h=0)}}}else{h=b}}while(0);m=g;return h}Xc.X=1;function bd(b,c,d,f){var g=m;m+=24;var e=g+4,i=e|0;y[e>>2]=y[b>>2];y[e+4>>2]=y[b+4>>2];y[e+8>>2]=y[b+8>>2];y[e+12>>2]=y[b+12>>2];y[e+16>>2]=y[b+16>>2];b=T(i,g);e=(b|0)==0;do{if(e){var h=T(i,g);if((h|0)==0&&(h=T(i,g),(h|0)==0)){var h=F[c+12>>2],k=(h|0)==0;a:do{if(k){var l=-1}else{for(var j=0;;){var n=j+1|0;if((h>>>(n>>>0)|0)==0){l=j;break a}j=n}}}while(0);if((S(i,l)|0)==-1){h=1}else{if((d|0)==5&&(h=T(i,g),(h|0)!=0)){break}h=F[c+20>>2];k=(h|0)==0;a:do{if(k){var p=-1}else{for(j=0;;){n=j+1|0;if((h>>>(n>>>0)|0)==0){p=j;break a}j=n}}}while(0);h=(S(i,p)|0)==-1?1:Qc(i,f)}}}else{h=b}}while(0);m=g;return h}bd.X=1;function cd(b){return b==1||b==0?1:b==2||b==3?2:4}function dd(b){return b>>>0<6?2:(b|0)!=6&1}function ed(b,c,d,f){var g=m;m+=28;var e=g+4,i=g+8,h=i|0;y[i>>2]=y[c>>2];y[i+4>>2]=y[c+4>>2];y[i+8>>2]=y[c+8>>2];y[i+12>>2]=y[c+12>>2];y[i+16>>2]=y[c+16>>2];c=T(h,g);i=(c|0)==0;a:do{if(i){var k=T(h,g);if((k|0)==0&&(k=T(h,g),(k|0)==0)){var k=F[d+12>>2],l=(k|0)==0;b:do{if(l){var j=-1}else{for(var n=0;;){var p=n+1|0;if((k>>>(p>>>0)|0)==0){j=n;break b}n=p}}}while(0);if((S(h,j)|0)==-1){k=1}else{if(k=T(h,g),(k|0)==0){k=d+16|0;l=F[k>>2];if((l|0)==0){l=F[d+20>>2];n=(l|0)==0;b:do{if(n){var r=-1}else{for(p=0;;){var o=p+1|0;if((l>>>(o>>>0)|0)==0){r=p;break b}p=o}}}while(0);if((S(h,r)|0)==-1){k=1;break}if((y[f+8>>2]|0)!=0&&(l=Qc(h,e),(l|0)!=0)){k=l;break}k=y[k>>2]}else{k=l}k=(k|0)==1;do{if(k&&(y[d+24>>2]|0)==0){l=Qc(h,e);if((l|0)!=0){k=l;break a}if((y[f+8>>2]|0)!=0&&(l=Qc(h,e),(l|0)!=0)){k=l;break a}}}while(0);if((y[f+68>>2]|0)!=0&&(k=T(h,g),(k|0)!=0)){break}k=S(h,1);y[b>>2]=k;k=(k|0)==-1&1}}}}else{k=c}}while(0);m=g;return k}ed.X=1;function fd(b,c,d,f){var g=m;m+=440;var e,i=g+432,h=g+436,k=g+(-g&15)|0,l=F[c+3376>>2],j=y[f>>2];y[i>>2]=0;var n=c+1192|0;y[n>>2]=y[n>>2]+1|0;var p=c+1200|0;y[p>>2]=0;var r=c+12|0;y[h>>2]=y[f+48>>2]+y[y[r>>2]+52>>2]|0;var o=f+36|0,t=c+1212|0,s=f+4|0,u=c+1176|0,w=l+12|0,v=l|0,z=f+44|0,B=c+1220|0,D=c+1172|0,C=f+52|0,E=f+56|0,f=f+60|0,G=0,H=0,K=0,L=y[t>>2];a:for(;;){if((y[o>>2]|0)==0&&(y[L+j*216+196>>2]|0)!=0){var N=1;break}L=L+j*216|0;e=y[C>>2];var O=y[E>>2],R=y[f>>2],U=y[y[r>>2]+56>>2];y[L+4>>2]=y[n>>2];y[L+8>>2]=e;y[L+12>>2]=O;y[L+16>>2]=R;y[L+24>>2]=U;L=F[s>>2];do{if(L==2||L==7){e=10}else{if((H|0)!=0){e=10}else{e=T(b,i);if((e|0)!=0){N=e;break a}e=F[i>>2];if(e>>>0>(y[u>>2]-j|0)>>>0){N=1;break a}if((e|0)==0){var Y=y[s>>2];e=12}else{Pc(w,0,164);y[v>>2]=0;var X=e,ba=1;e=11}}}}while(0);e==10&&((K|0)==0?(Y=L,e=12):(X=K,ba=H,e=11));if(e==12){var $=gd(b,l,y[t>>2]+j*216|0,Y,y[z>>2]);if(($|0)!=0){N=$;break}var ja=$=0}else{e==11&&(ja=X-1|0,y[i>>2]=ja,$=ba)}H=hd(y[t>>2]+j*216|0,l,d,B,h,j,y[y[r>>2]+64>>2],k);if((H|0)!=0){N=H;break}L=F[t>>2];G=((y[L+j*216+196>>2]|0)==1&1)+G|0;H=y[b+12>>2]<<3;K=y[b+16>>2];e=H-K|0;K=(ja|((H|0)==(K|0)?0:e>>>0>8?1:(id(b)>>>((32-e|0)>>>0)|0)!=(1<>2];if(H==2||H==7){y[p>>2]=j}H=F[u>>2];j=Ic(y[D>>2],H,j);if(K&(j|0)==0){N=1;break}if(K){H=$,K=ja}else{b=c+1196|0;c=y[b>>2]+G|0;if(c>>>0>H>>>0){N=1;break}y[b>>2]=c;N=0;break}}m=g;return N}fd.X=1;function jd(b,c){var d=F[b+1192>>2],f=y[b+1200>>2],g=(f|0)==0,e=b+1212|0;a:do{if(g){var i=c}else{for(var h=b+16|0,k=f,l=0;;){for(var l=l+1|0,j=k-1|0,n=0;;){var p=j-n|0;if(p>>>0<=c>>>0){i=p;break a}if((y[y[e>>2]+(k-n)*216-212>>2]|0)==(d|0)){break}n=n+1|0}k=F[y[h>>2]+52>>2];if(l>>>0>=(k>>>0>10?k:10)>>>0){i=p;break a}k=p}}}while(0);f=b+1172|0;for(g=b+1176|0;;){h=y[e>>2];if((y[h+i*216+4>>2]|0)!=(d|0)){break}h=h+i*216+196|0;p=y[h>>2];if((p|0)==0){break}y[h>>2]=p-1|0;i=Ic(y[f>>2],y[g>>2],i);if((i|0)==0){break}}}jd.X=1;function gd(b,c,d,f,g){var e=m;m+=8;var i,h=e+4;Pc(c,0,2088);i=T(b,e);var k=F[e>>2];if(f==7||f==2){if(f=k+6|0,f>>>0<32&(i|0)==0){var l=y[c>>2]=f;i=5}else{var j=1;i=24}}else{f=k+1|0,f>>>0<32&(i|0)==0?(l=y[c>>2]=f,i=5):(j=1,i=24)}a:do{if(i==5){j=c|0;f=(l|0)==31;b:do{if(f){for(;;){if(((y[b+8>>2]|0)==0&1|0)!=0){var n=0;break}if((S(b,1)|0)!=0){j=1;break a}}for(;;){k=c+328+(n<<2)|0;if(n>>>0>=384){break b}var p=S(b,8);y[e>>2]=p;if((p|0)==-1){j=1;break a}y[k>>2]=p;n=n+1|0}}else{var r=dd(l);if((r|0)==2){if((cd(l)|0)!=4){i=14}else{var o=kd(b,c+176|0,l,g);i=15}}else{i=14}i==14&&(o=ld(b,c+12|0,l,g));if((o|0)!=0){j=o;break a}if(k=(r|0)==1){k=y[j>>2],p=k-7|0,r=p>>>2,y[c+4>>2]=(p>>>0>11?r+268435453|0:r)<<4|(k>>>0>18?15:0)}else{var t=b,p=e,s=(r|0)==0&1,r=m;m+=4;(T(t,r)|0)==0?(t=F[r>>2],t>>>0>47?p=1:(y[p>>2]=A[((s|0)==0?Q.S:Q.T)+t|0]&255,p=0)):p=1;m=r;if((p|0)!=0){j=p;break a}p=y[e>>2];y[c+4>>2]=p;if(!((p|0)!=0|k)){break}}k=c+4|0;if((Qc(b,h)|0)!=0){j=1;break a}p=F[h>>2];if((p+26|0)>>>0>51){j=1;break a}y[c+8>>2]=p;k=md(b,c+272|0,d,y[j>>2],y[k>>2]);y[b+16>>2]=(y[b+4>>2]-y[b>>2]<<3)+y[b+8>>2]|0;if((k|0)!=0){j=k;break a}}}while(0);j=0}}while(0);m=e;return j}gd.X=1;function kd(b,c,d,f){var g=m;m+=8;for(var e,i=g+4,h=0;;){var k=c+(h<<2)|0;if(h>>>0>=4){e=5;break}if((T(b,g)|0)!=0){var l=1;e=19;break}var j=F[g>>2];if(j>>>0>3){l=1;e=19;break}y[k>>2]=j;h=h+1|0}a:do{if(e==5){h=f>>>0<2|(d|0)==5;b:do{if(h){var n=0;e=11}else{k=f>>>0>2&1;for(l=0;;){j=c+16+(l<<2)|0;if(l>>>0>=4){n=0;break b}if((nd(b,g,k)|0)!=0){l=1;break a}var p=F[g>>2];if(p>>>0>=f>>>0){l=1;break a}y[j>>2]=p;l=l+1|0}}}while(0);b:for(;;){if(n>>>0>=4){l=0;break a}h=y[c+(n<<2)>>2]==0?1:y[c+(n<<2)>>2]==1||y[c+(n<<2)>>2]==2?2:4;y[g>>2]=h;for(var r=h-1|0,o=0;;){l=c+32+(n<<4)+(o<<2)|0;k=c+32+(n<<4)+(o<<2)+2|0;if((h|0)==(o|0)){break}j=Qc(b,i);if((j|0)!=0){var t=j;break b}x[l>>1]=y[i>>2]&65535;l=Qc(b,i);if((l|0)!=0){t=l;break b}x[k>>1]=y[i>>2]&65535;o=o+1|0}y[g>>2]=r-o|0;n=n+1|0}y[g>>2]=r-o|0;l=t}}while(0);m=g;return l}kd.X=1;function ld(b,c,d,f){var g=m;m+=8;var e,i=g+4,h=dd(d);a:do{if(h==2){var k=f>>>0>1,l=cd(d);b:do{if(k){for(var j=f>>>0>2&1,n=0;;){var p=c+132+(n<<2)|0;if((l|0)==(n|0)){var r=0;break b}if((nd(b,g,j)|0)!=0){var o=1;e=21;break a}var t=F[g>>2];if(t>>>0>=f>>>0){o=1;e=21;break a}y[p>>2]=t;n=n+1|0}}else{r=0,e=7}}while(0);for(;;){k=c+148+(r<<2)+2|0;j=c+148+(r<<2)|0;if((l|0)==(r|0)){o=0;e=21;break a}n=Qc(b,i);if((n|0)!=0){o=n;e=21;break a}x[j>>1]=y[i>>2]&65535;j=Qc(b,i);if((j|0)!=0){o=j;e=21;break a}x[k>>1]=y[i>>2]&65535;r=r+1|0}}else{if(h==0){for(var l=0,s=I;;){var u=l<<3,w=c+64+(u<<2)|0,j=u|7,k=c+64+(j<<2)|0,j=c+(j<<2)|0,p=u|6,n=c+64+(p<<2)|0,p=c+(p<<2)|0,v=u|5,t=c+64+(v<<2)|0,v=c+(v<<2)|0,z=u|4,B=c+64+(z<<2)|0,z=c+(z<<2)|0,D=u|3,C=c+64+(D<<2)|0,D=c+(D<<2)|0,E=u|2,G=c+64+(E<<2)|0,E=c+(E<<2)|0,H=u|1,K=c+64+(H<<2)|0,H=c+(H<<2)|0;if((l|0)>=2){y[i>>2]=l;y[g>>2]=s;e=17;break a}var s=id(b),L=s>>>31;y[(c+(u<<2)|0)>>2]=L;u=s<<1;(L|0)==0?(y[w>>2]=s>>>28&7,w=1,u=s<<4):w=0;s=u>>>31;y[H>>2]=s;(s|0)==0?(y[K>>2]=u>>>28&7,w=w+1|0,u<<=4):u<<=1;s=u>>>31;y[E>>2]=s;(s|0)==0?(y[G>>2]=u>>>28&7,G=w+1|0,w=u<<4):(G=w,w=u<<1);E=w>>>31;y[D>>2]=E;(E|0)==0?(y[C>>2]=w>>>28&7,C=G+1|0,D=w<<4):(C=G,D=w<<1);G=D>>>31;y[z>>2]=G;(G|0)==0?(y[B>>2]=D>>>28&7,B=C+1|0,z=D<<4):(B=C,z=D<<1);C=z>>>31;y[v>>2]=C;(C|0)==0?(y[t>>2]=z>>>28&7,t=B+1|0,v=z<<4):(t=B,v=z<<1);B=v>>>31;y[p>>2]=B;(B|0)==0?(y[n>>2]=v>>>28&7,n=t+1|0,p=v<<4):(n=t,p=v<<1);t=p>>>31;y[j>>2]=t;(t|0)==0?(y[k>>2]=p>>>28&7,k=n+1|0,j=p<<4):(k=n,j=p<<1);if((od(b,k*3+8|0)|0)==-1){y[i>>2]=l;y[g>>2]=j;o=1;e=21;break a}l=l+1|0;s=j}}else{h==1?e=17:(o=0,e=21)}}}while(0);e==17&&((T(b,g)|0)!=0?o=1:(b=F[g>>2],b>>>0>3?o=1:(y[c+128>>2]=b,o=0)));m=g;return o}ld.X=1;function md(b,c,d,f,g){var e=c|0;if((dd(f)|0)==1){if(f=pd(b,c+1592|0,qd(d,0,e),16),(f&15|0)!=0){var i=f,f=22}else{x[c+48>>1]=f>>>4&255;var h=0,f=3}}else{h=1,f=3}a:do{if(f==3){for(var k=0,l=g,j=0;;){if((j|0)==4){break}var n=l>>>1,l=(l&1|0)==0;b:do{if(l){var p=k+4|0}else{for(var r=0;;){var o=k+r|0,t=c+1720+(o<<2)|0,s=c+56+(o<<6)+4|0,u=c+(o<<1)|0,w=c+56+(o<<6)|0;if((r|0)==4){p=o;break b}o=qd(d,o,e);h?(s=w=pd(b,w,o,16),w>>>=16):(s=w=pd(b,s,o,15),w>>>=15);y[t>>2]=w;if((s&15|0)!=0){i=s;break a}x[u>>1]=s>>>4&255;r=r+1|0}}}while(0);k=p;l=n;j=j+1|0}if((l&3|0)!=0){j=pd(b,c+1656|0,-1,4);if((j&15|0)!=0){i=j;break}x[c+50>>1]=j>>>4&255;j=pd(b,c+1672|0,-1,4);if((j&15|0)!=0){i=j;break}x[c+52>>1]=j>>>4&255}if((l&2|0)==0){i=0}else{for(j=0;;){r=k+j|0;n=c+1720+(r<<2)|0;l=c+(r<<1)|0;if((j|0)==8){i=0;break a}r=pd(b,c+56+(r<<6)+4|0,qd(d,r,e),15);if((r&15|0)!=0){i=r;break a}x[l>>1]=r>>>4&255;y[n>>2]=r>>>15;j=j+1|0}}}}while(0);return i}md.X=1;function hd(b,c,d,f,g,e,i,h){var k=F[c>>2];y[b>>2]=k;var l=b+196|0;y[l>>2]=y[l>>2]+1|0;Lc(d,e);var j=(k|0)==31;do{if(j){if(y[b+20>>2]=0,F[l>>2]>>>0>1){x[b+28>>1]=16;x[b+30>>1]=16;x[b+32>>1]=16;x[b+34>>1]=16;x[b+36>>1]=16;x[b+38>>1]=16;x[b+40>>1]=16;x[b+42>>1]=16;x[b+44>>1]=16;x[b+46>>1]=16;x[b+48>>1]=16;x[b+50>>1]=16;x[b+52>>1]=16;x[b+54>>1]=16;x[b+56>>1]=16;x[b+58>>1]=16;x[b+60>>1]=16;x[b+62>>1]=16;x[b+64>>1]=16;x[b+66>>1]=16;x[b+68>>1]=16;x[b+70>>1]=16;x[b+72>>1]=16;x[b+74>>1]=16;var n=0}else{for(n=0;;){var p=n<<4;x[b+28+(n<<1)>>1]=16;var r=h+(p|1)|0,o=h+(p|2)|0,t=h+(p|3)|0,s=h+(p|4)|0,u=h+(p|5)|0,w=h+(p|6)|0,v=h+(p|7)|0,z=h+(p|8)|0,B=h+(p|9)|0,D=h+(p|10)|0,C=h+(p|11)|0,E=h+(p|12)|0,G=h+(p|13)|0,H=h+(p|14)|0,K=h+(p|15)|0,L=c+328+(n<<6)+4|0,N=c+328+(n<<6)+8|0,O=c+328+(n<<6)+12|0,R=c+328+(n<<6)+16|0,U=c+328+(n<<6)+20|0,Y=c+328+(n<<6)+24|0,X=c+328+(n<<6)+28|0,ba=c+328+(n<<6)+32|0,$=c+328+(n<<6)+36|0,ja=c+328+(n<<6)+40|0,sa=c+328+(n<<6)+44|0,Ea=c+328+(n<<6)+48|0,Xa=c+328+(n<<6)+52|0,ea=c+328+(n<<6)+56|0,fa=c+328+(n<<6)+60|0;q[h+p|0]=y[c+328+(n<<6)>>2]&255;q[r]=y[L>>2]&255;q[o]=y[N>>2]&255;q[t]=y[O>>2]&255;q[s]=y[R>>2]&255;q[u]=y[U>>2]&255;q[w]=y[Y>>2]&255;q[v]=y[X>>2]&255;q[z]=y[ba>>2]&255;q[B]=y[$>>2]&255;q[D]=y[ja>>2]&255;q[C]=y[sa>>2]&255;q[E]=y[Ea>>2]&255;q[G]=y[Xa>>2]&255;q[H]=y[ea>>2]&255;q[K]=y[fa>>2]&255;n=n+1|0;if((n|0)==24){break}}rd(d,h);n=0}}else{n=b+28|0;if((k|0)==0){Pc(n,0,54),y[b+20>>2]=y[g>>2]}else{if(sd(n,c+272|0,54),n=y[c+8>>2],p=y[g>>2],(n|0)==0?n=p:(n=p+n|0,y[g>>2]=n,(n|0)<0?(n=n+52|0,y[g>>2]=n):(n|0)>51&&(n=n-52|0,y[g>>2]=n)),y[b+20>>2]=n,n=td(b,c+328|0,c+1992|0),(n|0)!=0){break}}if((dd(k)|0)==2){n=ud(b,c,f,e,d,h)}else{n=b;t=c;p=d;z=e;s=i;r=h;o=m;m+=72;B=aa;u=o+40;w=o|0;v=u|0;vd(p,w,v,z);z=(dd(y[n>>2])|0)==1;do{if(z){B=wd(n,r,t+328|0,w,v,s);if((B|0)==0){B=3;break}var va=B}else{B=xd(n,r,t,w,v,s);if((B|0)==0){B=3;break}va=B}B=6}while(0);B==3&&(va=yd(n,r+256|0,t+1352|0,o+21|0,u+16|0,y[t+140>>2],s),(va|0)==0&&(F[n+196>>2]>>>0>1||rd(p,r),va=0));m=o;n=va}if((n|0)!=0){break}n=0}}while(0);return n}hd.X=1;function td(b,c,d){var f,g=(dd(y[b>>2])|0)==1;a:do{if(g){if(x[b+76>>1]<<16>>16==0){var e=b+20|0}else{f=b+20|0,Gc(c+1536|0,y[f>>2]),e=f}for(var i=0;;){var h=c+(i<<6)|0,k=b+28+(i<<1)|0,l=d+(i<<2)|0;if((i|0)==16){break}f=y[c+1536+(y[zd+(i<<2)>>2]<<2)>>2];y[h>>2]=f;(f|0)==0?x[k>>1]<<16>>16!=0?f=9:(y[h>>2]=16777215,f=11):f=9;if(f==9&&(Dc(h,y[e>>2],1,y[l>>2])|0)!=0){var j=1;f=27;break a}i=i+1|0}var n=l,p=k,r=h,o=b+20|0;f=18}else{e=b+20|0;for(i=0;;){var t=c+(i<<6)|0,s=b+28+(i<<1)|0,u=d+(i<<2)|0;if((i|0)==16){n=u;p=s;r=t;o=e;f=18;break a}if(x[s>>1]<<16>>16==0){y[t>>2]=16777215}else{if((Dc(t,y[e>>2],0,y[u>>2])|0)!=0){j=1;f=27;break a}}i=i+1|0}}}while(0);a:do{if(f==18){d=r;g=y[Ad+(Cc(0,51,y[b+24>>2]+y[o>>2]|0)<<2)>>2];if(x[b+78>>1]<<16>>16==0){if(x[b+80>>1]<<16>>16==0){var w=0;f=21}else{f=20}}else{f=20}f==20&&(Hc(c+1600|0,g),w=0);for(;;){h=d+(w<<6)|0;f=p+(w<<1)|0;k=n+(w<<2)|0;if((w|0)==8){j=0;break a}l=y[c+1600+(w<<2)>>2];y[h>>2]=l;(l|0)==0?x[f>>1]<<16>>16!=0?f=24:(y[h>>2]=16777215,f=26):f=24;if(f==24&&(Dc(h,g,1,y[k>>2])|0)!=0){j=1;break a}w=w+1|0}}}while(0);return j}td.X=1;function id(b){var c=F[b+4>>2],d=y[b+12>>2]<<3,f=F[b+16>>2],g=d-f|0,e=(g|0)>31;a:do{if(e){var i=F[b+8>>2],h=(A[c+1|0]&255)<<16|(A[c]&255)<<24|A[c+3|0]&255|(A[c+2|0]&255)<<8,i=(i|0)==0?h:(A[c+4|0]&255)>>>((8-i|0)>>>0)|h<0){var k=F[b+8>>2],l=(A[c]&255)<0){for(var h=k+d-16-f|0,k=k+16|0,j=l,n=0;;){l=n+1|0;n=n*-8|0;j|=(A[c+l|0]&255)<>2]+c|0;y[d>>2]=f;y[b+8>>2]=f&7;f>>>0>y[b+12>>2]<<3>>>0?d=-1:(y[b+4>>2]=y[b>>2]+(f>>>3)|0,d=0);return d}function Bd(b,c){if(c>>>0<2){var d=b>>>0>32767?1:b>>>0>3071?Gb[Cd+(b>>>10<<1)>>1]&65535:b>>>0>255?Gb[Dd+(b>>>6<<1)>>1]&65535:b>>>0>31?Gb[je+((b>>>2)-8<<1)>>1]&65535:Gb[ke+(b<<1)>>1]&65535}else{c>>>0<4?d=b>>>0>32767?(b&16384|0)!=0?2:2082:b>>>0>4095?Gb[le+(b>>>10<<1)>>1]&65535:b>>>0>511?Gb[me+(b>>>7<<1)>>1]&65535:Gb[ne+(b>>>2<<1)>>1]&65535:c>>>0<8?(d=b>>>10,d=(d-8|0)>>>0<56?Gb[oe+(d<<1)>>1]&65535:Gb[pe+(b>>>6<<1)>>1]&65535):c>>>0<17?d=Gb[qe+(b>>>10<<1)>>1]&65535:(d=b>>>13,d=(d|0)!=0?Gb[re+(d<<1)>>1]&65535:Gb[se+(b>>>8<<1)>>1]&65535)}return d}Bd.X=1;function qd(b,c,d){var f=te+(c<<3)|0,g=ue+(c<<3)|0,e=A[f+4|0],c=A[g+4|0],g=(y[g>>2]|0)==4;(y[f>>2]|0)==4?(e=x[d+((e&255)<<1)>>1]<<16>>16,g?b=e+1+(x[d+((c&255)<<1)>>1]<<16>>16)>>1:(d=F[b+204>>2],b=(ve(b,d)|0)==0?e:e+1+(x[d+28+((c&255)<<1)>>1]<<16>>16)>>1)):g?(c=x[d+((c&255)<<1)>>1]<<16>>16,d=F[b+200>>2],b=(ve(b,d)|0)==0?c:c+1+(x[d+28+((e&255)<<1)>>1]<<16>>16)>>1):(d=F[b+200>>2],(ve(b,d)|0)==0?d=e=0:(e=x[d+28+((e&255)<<1)>>1]<<16>>16,d=1),f=F[b+204>>2],(ve(b,f)|0)==0?b=e:(b=x[f+28+((c&255)<<1)>>1]<<16>>16,b=(d|0)==0?b:b+(e+1)>>1));return b}qd.X=1;function S(b,c){var d=id(b);return(od(b,c)|0)==0?d>>>((32-c|0)>>>0):-1}function T(b,c){var d=id(b);if((d|0)<0){od(b,1),d=y[c>>2]=0}else{if(d>>>0>1073741823){(od(b,3)|0)==-1?d=1:(y[c>>2]=(d>>>29&1)+1|0,d=0)}else{if(d>>>0>536870911){(od(b,5)|0)==-1?d=1:(y[c>>2]=(d>>>27&3)+3|0,d=0)}else{if(d>>>0>268435455){(od(b,7)|0)==-1?d=1:(y[c>>2]=(d>>>25&7)+7|0,d=0)}else{var f;f=134217728;for(var g=0;;){if((f|0)==0){break}if((f&d|0)!=0){break}f>>>=1;g=g+1|0}f=g;d=f+4|0;(d|0)==32?(y[c>>2]=0,od(b,32),(S(b,1)|0)!=1?d=1:(d=id(b),(od(b,32)|0)==-1?d=1:d==0?(y[c>>2]=-1,d=0):(d==1&&(y[c>>2]=-1),d=1))):(od(b,f+5|0),f=S(b,d),(f|0)==-1?d=1:(y[c>>2]=(1<>2]=0;var f=T(b,d),g=y[d>>2],e=(g|0)==-1,f=(f|0)==0;do{if(e){if(f){var i=1;break}y[c>>2]=-2147483648}else{if(!f){i=1;break}i=(g+1|0)>>>1;y[c>>2]=(g&1|0)!=0?i:-i|0}i=0}while(0);m=d;return i}function nd(b,c,d){(d|0)==0?(b=S(b,1),y[c>>2]=b,(b|0)==-1?c=1:(y[c>>2]=b^1,c=0)):c=T(b,c);return c}function pd(b,c,d,f){var g=m;m+=128;var e,i=g+64,h=id(b),d=Bd(h>>>16,d),k=(d|0)==0;a:do{if(k){var l=1}else{var l=d&31,j=h<>>11&31;if(p>>>0>f>>>0){l=1}else{var r=d>>>5&63,o=(p|0)==0;b:do{if(o){var t=n,s=0}else{if((r|0)==0){var u=n,w=j,v=0}else{if(n>>>0>>0){if((od(b,l)|0)==-1){l=1;break a}v=32;w=id(b)}else{v=n,w=j}var z=w>>>((32-r|0)>>>0);w<<=r;for(var B=1<>2]=(B&z|0)!=0?-1:1;B>>>=1;var D=u+1|0;if((B|0)==0){break}u=D}u=v-r|0;v=D}z=r>>>0<3;if(p>>>0>10&z){var C=u,E=w,G=1}else{C=u,E=w,G=0}for(w=0;;){B=v+w|0;u=g+(B<<2)|0;if(B>>>0>=p>>>0){break}if(C>>>0<16){if((od(b,32-C|0)|0)==-1){l=1;break a}var H=32,E=id(b)}else{H=C}C=E>>>16;e=aa;if(C>>>0>32767){var K=0;e=16}else{if(C>>>0>16383){K=1,e=16}else{if(C>>>0>8191){K=2,e=16}else{if(C>>>0>4095){K=3,e=16}else{if(C>>>0>2047){K=4,e=16}else{if(C>>>0>1023){K=5,e=16}else{if(C>>>0>511){K=6,e=16}else{if(C>>>0>255){K=7,e=16}else{if(C>>>0>127){K=8,e=16}else{if(C>>>0>63){K=9,e=16}else{if(C>>>0>31){K=10,e=16}else{if(C>>>0>15){K=11,e=16}else{if(C>>>0>7){K=12,e=16}else{if(C>>>0>3){K=13,e=16}else{if(C>>>0>1){K=14,e=16}else{if((C|0)==0){var L=-2;e=17}else{K=15,e=16}}}}}}}}}}}}}}}}e==16&&(L=K);C=L;if((C|0)==-2){l=1;break a}e=C+1|0;E<<=e;H=H-e|0;if(C>>>0<14){var N=G;e=21}else{if(e=(G|0)!=0,(C|0)==14){N=e?G:4,e=21}else{var O=e?G:1,R=O,U=12,Y=(O|0)==0,O=C<>>0>>0){if((od(b,32-H|0)|0)==-1){l=1;break a}X=32;$=id(b)}else{X=H,$=E}X=X-U|0;ba=$<>>((32-U|0)>>>0))+O|0;ja=R;sa=Y}G=(B|0)==(r|0)&z?$+2|0:$;E=(G+2|0)>>>1;y[u>>2]=E;B=sa?1:ja;B=(E|0)>(3<>>0<6&1)+B|0:B;(G&1|0)!=0&&(y[u>>2]=-E|0);C=X;E=ba;G=B;w=w+1|0}if(p>>>0>>0){if(C>>>0<9){if((od(b,32-C|0)|0)==-1){l=1;break a}z=32;w=id(b)}else{z=C,w=E}v=we(w>>>23,p,(f|0)==4&1);if((v|0)==0){l=1;break a}u=v&15;z=z-u|0;w<<=u;u=v>>>4&15}else{z=C,w=E,u=0}v=p-1|0;G=w;w=u;for(u=0;;){B=i+(u<<2)|0;if(u>>>0>=v>>>0){break}if((w|0)==0){y[B>>2]=1,B=z,E=G,w=0}else{if(z>>>0<11){if((od(b,32-z|0)|0)==-1){l=1;break a}E=32;z=id(b)}else{E=z,z=G}G=xe(z>>>21,w);if((G|0)==0){l=1;break a}C=G&15;z<<=C;E=E-C|0;G=G>>>4&15;y[B>>2]=G+1|0;B=E;E=z;w=w-G|0}z=B;G=E;u=u+1|0}y[c+(w<<2)>>2]=y[g+(v<<2)>>2];B=1<>2]+E|0,B|=1<>2]=y[g+(G<<2)>>2],w=w+1|0,(w|0)==(v|0)){t=z;s=B;break b}}}}}while(0);l=(od(b,32-t|0)|0)!=0?1:s<<16|p<<4}}}while(0);m=g;return l}pd.X=1;function we(b,c,d){(d|0)==0?c==1?(c=Q.ha+(b>>>4)|0,b=b>>>0>31?A[c]&255:A[Q.ia+b|0]&255):b=c==2?A[Q.ja+(b>>>3)|0]&255:c==3?A[Q.ka+(b>>>3)|0]&255:c==4?A[Q.la+(b>>>4)|0]&255:c==5?A[Q.ma+(b>>>4)|0]&255:c==6?A[Q.na+(b>>>3)|0]&255:c==7?A[Q.oa+(b>>>3)|0]&255:c==8?A[Q.pa+(b>>>3)|0]&255:c==9?A[Q.qa+(b>>>3)|0]&255:c==10?A[Q.ca+(b>>>4)|0]&255:c==11?A[Q.da+(b>>>5)|0]&255:c==12?A[Q.ea+(b>>>5)|0]&255:c==13?A[Q.fa+(b>>>6)|0]&255:c==14?A[Q.ga+(b>>>7)|0]&255:b>>>0>255?17:1:b=b>>>0>255?1:(c|0)==3?17:b>>>0>127?18:(c|0)==2?34:b>>>0>63?35:51;return b}we.X=1;function xe(b,c){if(c==1){var d=A[Q.U+(b>>>10)|0]&255}else{c==2?d=A[Q.V+(b>>>9)|0]&255:c==3?d=A[Q.W+(b>>>9)|0]&255:c==4?d=A[Q.Y+(b>>>8)|0]&255:c==5?d=A[Q.Z+(b>>>8)|0]&255:c==6?d=A[Q.$+(b>>>8)|0]&255:(d=b>>>0>255?7-(b>>>8)<<4|3:b>>>0>127?116:b>>>0>63?133:b>>>0>31?150:b>>>0>15?167:b>>>0>7?184:b>>>0>3?201:b>>>0>1?218:(b|0)==0?0:235,d=(d>>>4&15)>>>0>c>>>0?0:d)}return d}xe.X=1;function ye(b,c){return c==0?y[b+200>>2]:c==1?y[b+204>>2]:c==2?y[b+208>>2]:c==3?y[b+212>>2]:c==4?b:0}function ve(b,c){return(c|0)==0?0:(y[b+4>>2]|0)!=(y[c+4>>2]|0)?0:1}function ze(b,c){var d,f=y[c+8>>2],g=b+20+(f<<2)|0,e=y[g>>2],i=(e|0)==0;do{if(i){if(d=jc(92),y[g>>2]=d,(d|0)==0){var h=65535;d=8;break}}else{d=b+8|0;if((f|0)!=(y[d>>2]|0)){Ae(y[e+40>>2]);y[(y[g>>2]+40|0)>>2]=0;Ae(y[y[g>>2]+84>>2]);y[(y[g>>2]+84|0)>>2]=0;d=7;break}var k=b+16|0;if((Nc(c,y[k>>2])|0)==0){f=c+40|0;Ae(y[f>>2]);y[f>>2]=0;f=c+84|0;Ae(y[f>>2]);h=y[f>>2]=0;d=8;break}Ae(y[e+40>>2]);y[(y[g>>2]+40|0)>>2]=0;Ae(y[y[g>>2]+84>>2]);y[(y[g>>2]+84|0)>>2]=0;y[d>>2]=33;y[b+4>>2]=257;y[k>>2]=0;y[b+12>>2]=0}d=7}while(0);if(d==7){f=c>>2;g=y[g>>2]>>2;for(e=f+23;f>2],g=b+148+(f<<2)|0,e=y[g>>2],i=(e|0)==0;do{if(i){if(d=jc(72),y[g>>2]=d,(d|0)==0){var h=65535;d=8;break}}else{d=b+4|0;if((f|0)==(y[d>>2]|0)){(y[c+4>>2]|0)==(y[b+8>>2]|0)?f=e:(y[d>>2]=257,f=y[g>>2]);Ae(y[f+20>>2]);y[(y[g>>2]+20|0)>>2]=0;Ae(y[y[g>>2]+24>>2]);y[(y[g>>2]+24|0)>>2]=0;Ae(y[y[g>>2]+28>>2]);y[(y[g>>2]+28|0)>>2]=0;Ae(y[y[g>>2]+44>>2]);y[(y[g>>2]+44|0)>>2]=0;d=7;break}Ae(y[e+20>>2]);y[(y[g>>2]+20|0)>>2]=0;Ae(y[y[g>>2]+24>>2]);y[(y[g>>2]+24|0)>>2]=0;Ae(y[y[g>>2]+28>>2]);y[(y[g>>2]+28|0)>>2]=0;Ae(y[y[g>>2]+44>>2]);y[(y[g>>2]+44|0)>>2]=0}d=7}while(0);if(d==7){h=c>>2;g=y[g>>2]>>2;for(f=h+18;h>2],e=(g|0)==0;a:do{if(e){var i=1}else{var i=y[g+4>>2],h=y[b+20+(i<<2)>>2];if((h|0)==0){i=1}else{if(h=De(g,y[h+52>>2],y[h+56>>2]),(h|0)!=0){i=h}else{var h=b+4|0,k=y[h>>2],l=(k|0)==256;do{if(l){y[h>>2]=c;var j=y[f>>2];y[b+12>>2]=j;j=y[j+4>>2];y[b+8>>2]=j;var n=y[b+20+(j<<2)>>2];y[b+16>>2]=n;j=n+52|0;n=n+56|0;y[b+1176>>2]=y[n>>2]*y[j>>2]|0;y[b+1340>>2]=y[j>>2];y[b+1344>>2]=y[n>>2];y[b+3380>>2]=1}else{if(j=b+3380|0,(y[j>>2]|0)==0){if((k|0)!=(c|0)){if(n=b+8|0,(i|0)==(y[n>>2]|0)){y[h>>2]=c,y[b+12>>2]=y[f>>2]}else{if((d|0)==0){i=1;break a}y[h>>2]=c;var p=y[f>>2];y[b+12>>2]=p;p=y[p+4>>2];y[n>>2]=p;p=y[b+20+(p<<2)>>2];y[b+16>>2]=p;n=p+52|0;p=p+56|0;y[b+1176>>2]=y[p>>2]*y[n>>2]|0;y[b+1340>>2]=y[n>>2];y[b+1344>>2]=y[p>>2];y[j>>2]=1}}}else{y[j>>2]=0;n=b+1212|0;Ae(y[n>>2]);y[n>>2]=0;j=b+1172|0;Ae(y[j>>2]);y[j>>2]=0;var r=b+1176|0,p=jc(y[r>>2]*216|0);y[n>>2]=p;p=jc(y[r>>2]<<2);y[j>>2]=p;j=y[n>>2];if((j|0)==0|(p|0)==0){i=65535;break a}Pc(j,0,y[r>>2]*216|0);var j=b+16|0,n=y[n>>2],p=y[y[j>>2]+52>>2],r=y[r>>2],o=aa,t=(r|0)==0;b:do{if(!t){for(var s=p-1|0,u=1-p|0,w=p^-1,v=0,z=0,B=0;;){var o=n+v*216+204|0,D=n+v*216+208|0,C=n+v*216+212|0,E=n+(v-p)*216|0,G=n+(u+v)*216|0,H=n+(v+w)*216|0,K=(B|0)!=0;y[n+v*216+200>>2]=K?n+(v-1)*216|0:0;var L=(z|0)!=0;if(L){if(y[o>>2]=E,B>>>0>>0){var N=G,o=8}else{o=7}}else{y[o>>2]=0,o=7}o==7&&(N=0);y[D>>2]=N;y[C>>2]=L&K?H:0;D=B+1|0;D=(B=(D|0)==(p|0))?0:D;v=v+1|0;if((v|0)==(r|0)){break b}z=(B&1)+z|0;B=D}}}while(0);p=(y[b+1216>>2]|0)==0;j=y[j>>2];b:do{if(p){if((y[j+16>>2]|0)==2){n=1}else{n=(y[j+80>>2]|0)==0;do{if(!n&&(r=y[j+84>>2],(y[r+920>>2]|0)!=0&&(y[r+944>>2]|0)==0)){n=1;break b}}while(0);n=0}}else{n=1}}while(0);p=b+1220|0;r=y[j+56>>2]*y[j+52>>2]|0;t=y[j+88>>2];s=y[j+44>>2];j=y[j+12>>2];Ee(p);j=Fe(p,r,t,s,j,n);if((j|0)!=0){i=j;break a}}}}while(0);i=0}}}}while(0);return i}Ce.X=1;Module._get_h264bsdClip=(function(){return Q.a|0});function De(b,c,d){var f,d=d*c|0,g=F[b+12>>2],e=g>>>0>1;a:do{if(e){var i=F[b+16>>2];if(i==0){for(var i=b+20|0,h=0;;){if(h>>>0>=g>>>0){f=15;break a}if(F[y[i>>2]+(h<<2)>>2]>>>0>d>>>0){var k=1;f=16;break a}h=h+1|0}}else{if(i==2){for(var i=g-1|0,h=b+24|0,l=b+28|0,j=0;;){if(j>>>0>=i>>>0){f=15;break a}var n=F[y[h>>2]+(j<<2)>>2],p=F[y[l>>2]+(j<<2)>>2];if(!(n>>>0<=p>>>0&p>>>0>>0)){k=1;f=16;break a}if((n>>>0)%(c>>>0)>>>0>(p>>>0)%(c>>>0)>>>0){k=1;f=16;break a}j=j+1|0}}else{if((i-3|0)>>>0<3){if(F[b+36>>2]>>>0>d>>>0){k=1;f=16;break}}else{if((i|0)!=6){f=15;break}if(F[b+40>>2]>>>0>>0){k=1;f=16;break}}f=15}}}else{f=15}}while(0);f==15&&(k=0);return k}De.X=1;function Ge(b,c,d,f,g,e){var i=e*g|0,h=(i|0)==0,e=c-1|0;a:do{if(!h){for(var k=0;;){if(y[b+(k<<2)>>2]=e,k=k+1|0,(k|0)==(i|0)){break a}}}}while(0);i=(e|0)==0;a:do{if(!i){h=c-2|0;for(k=0;;){var l=h-k|0,j=F[d+(l<<2)>>2],n=Math.floor((j>>>0)/(g>>>0)),j=(j>>>0)%(g>>>0),p=F[(f+(l<<2)|0)>>2],r=Math.floor((p>>>0)/(g>>>0)),p=(p>>>0)%(g>>>0),o=n>>>0>r>>>0;b:do{if(!o){for(var t=j>>>0>p>>>0,s=j+n*g|0,u=j+1|0,w=n+1|0,v=0;;){var z=s+v*g|0,B=w+v|0;c:do{if(!t){for(var D=0;;){var C=u+D|0;y[b+(z+D<<2)>>2]=l;if(C>>>0>p>>>0){break c}D=D+1|0}}}while(0);if(B>>>0>r>>>0){break b}v=v+1|0}}}while(0);k=k+1|0;if((k|0)==(e|0)){break a}}}}while(0)}Ge.X=1;function He(b,c,d,f,g){var e=g*f|0,i=(e|0)==0;a:do{if(!i){for(var h=0;;){if(y[b+(h<<2)>>2]=1,h=h+1|0,(h|0)==(e|0)){break a}}}}while(0);e=(f-c|0)>>>1;i=(g-c|0)>>>1;h=(d|0)==0;a:do{if(!h){for(var k=c<<1,l=k-1|0,j=f-1|0,k=1-k|0,n=g-1|0,p=i,r=e,o=c-1|0,t=0,s=c,u=e,w=i,v=e,z=i;;){var B=b+(p*f+r<<2)|0,D=(y[B>>2]|0)==1,C=D&1;D&&(y[B>>2]=0);(o|0)==-1&(r|0)==(u|0)?(r=u-1|0,u=r=(r|0)>0?r:0,B=l,D=0):(o|0)==1&(r|0)==(v|0)?(r=v+1|0,v=r=(r|0)<(j|0)?r:j,B=k,D=0):(s|0)==-1&(p|0)==(w|0)?(p=w-1|0,w=p=(p|0)>0?p:0,B=0,D=k):(s|0)==1&(p|0)==(z|0)?(p=z+1|0,z=p=(p|0)<(n|0)?p:n,B=0,D=l):(B=s,D=o,r=o+r|0,p=s+p|0);t=C+t|0;if(t>>>0>=d>>>0){break a}o=D;s=B}}}while(0)}He.X=1;function Ie(b,c,d,f){var g=m;m+=28;var e,i=g+4,h=g+8,k=g+12,l=g+16,j=g+20;y[f>>2]=0;var n=c|0,p=F[n>>2],r=(p-6|0)>>>0<6|(p-13|0)>>>0<6;a:do{if(r){y[f>>2]=1;var o=0}else{if(p==1||p==5){var t=d+1332|0;(y[t>>2]|0)!=0&&(y[f>>2]=1,y[t>>2]=0);var s=Wc(b,g);if((s|0)!=0){o=s}else{var u=F[d+148+(y[g>>2]<<2)>>2];if((u|0)==0){o=65520}else{var w=y[u+4>>2],v=F[d+20+(w<<2)>>2];if((v|0)==0){o=65520}else{var z=y[d+8>>2];if(!((z|0)==32|(w|0)==(z|0))&&(y[n>>2]|0)!=5){o=65520}else{var B=d+1300|0,D=y[d+1304>>2],C=y[c+4>>2];(D|0)!=(C|0)&&(D|0)==0|(C|0)==0&&(y[f>>2]=1);var E=d+1300|0,G=(y[n>>2]|0)==5;e=(y[E>>2]|0)==5?G?17:16:G?16:17;e==16&&(y[f>>2]=1);var H=v+12|0,K=b,L=y[H>>2],N=i,O=m;m+=24;var R=O+4,U=R|0;y[R>>2]=y[K>>2];y[R+4>>2]=y[K+4>>2];y[R+8>>2]=y[K+8>>2];y[R+12>>2]=y[K+12>>2];y[R+16>>2]=y[K+16>>2];var Y=T(U,O),X=(Y|0)==0;do{if(X){var ba=T(U,O);if((ba|0)!=0){var $=ba}else{var ja=T(U,O);if((ja|0)!=0){$=ja}else{var sa=(L|0)==0;b:do{if(sa){var Ea=-1}else{for(var Xa=0;;){var ea=Xa+1|0;if((L>>>(ea>>>0)|0)==0){Ea=Xa;break b}Xa=ea}}}while(0);var fa=S(U,Ea);(fa|0)==-1?$=1:(y[N>>2]=fa,$=0)}}}else{$=Y}}while(0);m=O;if(($|0)!=0){o=1}else{var va=d+1308|0,ob=y[i>>2];(y[va>>2]|0)!=(ob|0)&&(y[va>>2]=ob,y[f>>2]=1);var wa=y[n>>2];if((wa|0)==5){var pb=b,gb=y[H>>2],Ib=wa,Fa=h,qb=m;m+=24;var Ya=qb+4,Na=(Ib|0)==5;do{if(Na){var za=Ya|0,da=Ya,Oa=pb;y[da>>2]=y[Oa>>2];y[da+4>>2]=y[Oa+4>>2];y[da+8>>2]=y[Oa+8>>2];y[da+12>>2]=y[Oa+12>>2];y[da+16>>2]=y[Oa+16>>2];var Za=T(za,qb);if((Za|0)!=0){var Aa=Za}else{var hb=T(za,qb);if((hb|0)!=0){Aa=hb}else{var Ga=T(za,qb);if((Ga|0)!=0){Aa=Ga}else{var Pa=(gb|0)==0;b:do{if(Pa){var $a=-1}else{for(var Ab=0;;){var cb=Ab+1|0;if((gb>>>(cb>>>0)|0)==0){$a=Ab;break b}Ab=cb}}}while(0);Aa=(S(za,$a)|0)==-1?1:T(za,Fa)}}}}else{Aa=1}}while(0);m=qb;if((Aa|0)!=0){o=1;break}if((y[E>>2]|0)==5){var rb=d+1312|0,Qa=y[h>>2];if((y[rb>>2]|0)==(Qa|0)){var pa=Qa,ia=rb}else{y[f>>2]=1,pa=Qa,ia=rb}}else{pa=y[h>>2],ia=d+1312|0}y[ia>>2]=pa}var qa=y[v+16>>2];do{if(qa==0){if((Xc(b,v,y[n>>2],k)|0)!=0){o=1;break a}var Ra=d+1316|0,ra=y[k>>2];(y[Ra>>2]|0)!=(ra|0)&&(y[Ra>>2]=ra,y[f>>2]=1);if((y[u+8>>2]|0)!=0){var ib=bd(b,v,y[n>>2],l);if((ib|0)!=0){o=ib;break a}var sb=d+1320|0,jb=y[l>>2];(y[sb>>2]|0)!=(jb|0)&&(y[sb>>2]=jb,y[f>>2]=1)}}else{if(qa==1&&(y[v+24>>2]|0)==0){var db=u+8|0,Sa=j|0,kb,ta=b,Bb=v,Ha=y[n>>2],ya=y[db>>2],xa=Sa,Ba=m;m+=24;var Ca=Ba+4,Ta=Ca|0;y[Ca>>2]=y[ta>>2];y[Ca+4>>2]=y[ta+4>>2];y[Ca+8>>2]=y[ta+8>>2];y[Ca+12>>2]=y[ta+12>>2];y[Ca+16>>2]=y[ta+16>>2];var lb=T(Ta,Ba),Jb=(lb|0)==0;do{if(Jb){var eb=T(Ta,Ba);if((eb|0)!=0){var Da=eb}else{var Ia=T(Ta,Ba);if((Ia|0)!=0){Da=Ia}else{var mb=F[Bb+12>>2],Ua=(mb|0)==0;b:do{if(Ua){var Ja=-1}else{for(var Ka=0;;){var Cb=Ka+1|0;if((mb>>>(Cb>>>0)|0)==0){Ja=Ka;break b}Ka=Cb}}}while(0);if((S(Ta,Ja)|0)==-1){Da=1}else{if((Ha|0)==5){var Db=T(Ta,Ba);if((Db|0)!=0){Da=Db;break}}var Eb=Qc(Ta,xa);if((Eb|0)!=0){Da=Eb}else{if((ya|0)!=0){var tb=Qc(Ta,xa+4|0);if((tb|0)!=0){Da=tb;break}}Da=0}}}}}else{Da=lb}}while(0);m=Ba;kb=Da;if((kb|0)!=0){o=kb;break a}var Va=d+1324|0,fb=y[Sa>>2];(y[Va>>2]|0)!=(fb|0)&&(y[Va>>2]=fb,y[f>>2]=1);if((y[db>>2]|0)!=0){var ub=d+1328|0,nb=y[j+4>>2];(y[ub>>2]|0)!=(nb|0)&&(y[ub>>2]=nb,y[f>>2]=1)}}}}while(0);var Fb=c,Qb=B,wb=y[Fb+4>>2];y[Qb>>2]=y[Fb>>2];y[Qb+4>>2]=wb;o=0}}}}}}else{o=0}}}while(0);m=g;return o}Ie.X=1;function Je(b,c,d,f,g){var e=g*f|0,i=F[c+12>>2],h=(i|0)==1;a:do{if(h){Pc(b,0,e<<2)}else{var k=F[c+16>>2];if((k-3|0)>>>0<3){var l=y[c+36>>2]*d|0,l=l>>>0>>0?l:e,j=(k-4|0)>>>0<2?(y[c+32>>2]|0)==0?l:e-l|0:0}else{l=j=0}if(k==0){var k=b,l=i,j=y[c+20>>2],n=e,p=0,r=0;b:for(;;){for(var o=r>>>0>>0;;){if(p>>>0>>0&o){break}if(!o){break b}p=0}for(var o=j+(p<<2)|0,t=0;;){var s=r+t|0,u=F[o>>2];if(!(t>>>0>>0&s>>>0>>0)){break}y[k+(s<<2)>>2]=p;t=t+1|0}p=p+1|0;r=u+r|0}}else{if(k==1){k=b;l=i;j=f;n=g*j|0;r=(n|0)==0;b:do{if(!r){for(p=0;;){if(y[(k+(p<<2)|0)>>2]=((((Math.floor((p>>>0)/(j>>>0))*l|0)>>>1)+(p>>>0)%(j>>>0)|0)>>>0)%(l>>>0),p=p+1|0,(p|0)==(n|0)){break b}}}}while(0)}else{if(k==2){Ge(b,i,y[c+24>>2],y[c+28>>2],f,g)}else{if(k==3){He(b,y[c+32>>2],l,f,g)}else{if(k==4){k=b;l=y[c+32>>2];n=e;r=(n|0)==0;b:do{if(!r){p=1-l|0;for(o=0;;){if(y[k+(o<<2)>>2]=o>>>0>>0?l:p,o=o+1|0,(o|0)==(n|0)){break b}}}}while(0)}else{if(k==5){k=b;l=y[c+32>>2];n=f;r=g;p=(n|0)==0;b:do{if(!p){for(var o=(r|0)==0,t=1-l|0,w=s=0;;){if(!o){for(var v=0;;){if(y[k+(s+v*n<<2)>>2]=(w+v|0)>>>0>>0?l:t,v=v+1|0,(v|0)==(r|0)){break}}w=w+r|0}s=s+1|0;if((s|0)==(n|0)){break b}}}}while(0)}else{if((e|0)!=0){k=c+44|0;for(l=0;;){if(y[b+(l<<2)>>2]=y[y[k>>2]+(l<<2)>>2],l=l+1|0,(l|0)==(e|0)){break a}}}}}}}}}}}while(0)}Je.X=1;function vd(b,c,d,f){var g=(f|0)==0;do{if(!g){var e=F[b+4>>2],i=y[b+8>>2],h=Math.floor((f>>>0)/(e>>>0)),k=b|0,l=F[k>>2],j=(h|0)!=0;if(j){for(var n=e*(h*240-16)+(f<<4)-1|0,p=0;;){if(q[c+p|0]=q[l+(n+p)|0],p=p+1|0,(p|0)==21){break}}n=c+21|0}else{n=c}if(p=(h*e|0)!=(f|0)){var r=(f-(f>>>0)%(e>>>0))*240+(f<<4)-1|0,o=e<<4;q[d]=q[l+r|0];q[d+1|0]=q[l+(r+o)|0];q[d+2|0]=q[l+(r+(e<<5))|0];q[d+3|0]=q[l+(r+e*48)|0];q[d+4|0]=q[l+(r+(e<<6))|0];q[d+5|0]=q[l+(r+e*80)|0];q[d+6|0]=q[l+(r+e*96)|0];q[d+7|0]=q[l+(r+e*112)|0];q[d+8|0]=q[l+(r+(e<<7))|0];q[d+9|0]=q[l+(r+e*144)|0];q[d+10|0]=q[l+(r+e*160)|0];q[d+11|0]=q[l+(r+e*176)|0];q[d+12|0]=q[l+(r+e*192)|0];q[d+13|0]=q[l+(r+e*208)|0];q[d+14|0]=q[l+(r+e*224)|0];q[d+15|0]=q[l+(r+e*240)|0];l=d+16|0}else{l=d}k=F[k>>2];if(j){var j=h*56|0,r=f<<3,o=e<<3&2147483640,t=e*((i<<8)+j)+r-1-o|0;q[n]=q[k+t|0];q[n+1|0]=q[t+(k+1)|0];q[n+2|0]=q[t+(k+2)|0];q[n+3|0]=q[t+(k+3)|0];q[n+4|0]=q[t+(k+4)|0];q[n+5|0]=q[t+(k+5)|0];q[n+6|0]=q[t+(k+6)|0];q[n+7|0]=q[t+(k+7)|0];q[n+8|0]=q[t+(k+8)|0];j=e*(i*320+j)+r-9-o|0;q[n+9|0]=q[j+(k+8)|0];q[n+10|0]=q[j+(k+9)|0];q[n+11|0]=q[j+(k+10)|0];q[n+12|0]=q[j+(k+11)|0];q[n+13|0]=q[j+(k+12)|0];q[n+14|0]=q[j+(k+13)|0];q[n+15|0]=q[j+(k+14)|0];q[n+16|0]=q[j+(k+15)|0];q[n+17|0]=q[j+(k+16)|0]}if(p){var n=e<<3&2147483640,s=h*56|0,u=f<<3,w=e*((i<<8)+s)+u-1|0;q[l]=q[k+w|0];q[l+1|0]=q[k+(w+n)|0];h=e<<4;q[l+2|0]=q[k+(w+h)|0];p=n*3|0;q[l+3|0]=q[k+(w+p)|0];j=e<<5;q[l+4|0]=q[k+(w+j)|0];r=n*5|0;q[l+5|0]=q[k+(w+r)|0];o=n*6|0;q[l+6|0]=q[k+(w+o)|0];t=n*7|0;q[l+7|0]=q[k+(w+t)|0];e=t+(e*(i*320+s-64)+u+n-1)|0;q[l+8|0]=q[k+e|0];q[l+9|0]=q[k+(e+n)|0];q[l+10|0]=q[k+(e+h)|0];q[l+11|0]=q[k+(e+p)|0];q[l+12|0]=q[k+(e+j)|0];q[l+13|0]=q[k+(e+r)|0];q[l+14|0]=q[k+(e+o)|0];q[l+15|0]=q[k+(e+t)|0]}}}while(0)}vd.X=1;function Ke(b,c){for(var d=c+1|0,f=c+2|0,g=c+3|0,e=c+4|0,i=c+5|0,h=c+6|0,k=c+7|0,l=c+8|0,j=c+9|0,n=c+10|0,p=c+11|0,r=c+12|0,o=c+13|0,t=c+14|0,s=c+15|0,u=0;;){var w=u<<4,v=b+(w|1)|0,z=b+(w|2)|0,B=b+(w|3)|0,D=b+(w|4)|0,C=b+(w|5)|0,E=b+(w|6)|0,G=b+(w|7)|0,H=b+(w|8)|0,K=b+(w|9)|0,L=b+(w|10)|0,N=b+(w|11)|0,O=b+(w|12)|0,R=b+(w|13)|0,U=b+(w|14)|0,Y=b+(w|15)|0;q[b+w|0]=q[c];q[v]=q[d];q[z]=q[f];q[B]=q[g];q[D]=q[e];q[C]=q[i];q[E]=q[h];q[G]=q[k];q[H]=q[l];q[K]=q[j];q[L]=q[n];q[N]=q[p];q[O]=q[r];q[R]=q[o];q[U]=q[t];q[Y]=q[s];u=u+1|0;if((u|0)==16){break}}}Ke.X=1;function wd(b,c,d,f,g,e){var i=y[b+200>>2],h=ve(b,i),e=(e|0)==0,i=(h|0)==0|e?h:(dd(y[i>>2])|0)!=2?h:0,h=y[b+204>>2],k=ve(b,h),h=(k|0)==0|e?k:(dd(y[h>>2])|0)!=2?k:0,k=y[b+212>>2],l=ve(b,k),e=(l|0)==0|e?l:(dd(y[k>>2])|0)!=2?l:0,k=y[b>>2]+1&3;do{if(k==0){if((h|0)==0){var j=1,b=18;break}Ke(c,f+1|0)}else{if(k==1){if((i|0)==0){j=1;b=18;break}Le(c,g)}else{if(k==2){Me(c,f+1|0,g,i,h)}else{if((i|0)==0|(h|0)==0|(e|0)==0){j=1;b=18;break}Ne(c,f+1|0,g)}}}b=17}while(0);b==17&&(Oe(c,d|0,0),Oe(c,d+64|0,1),Oe(c,d+128|0,2),Oe(c,d+192|0,3),Oe(c,d+256|0,4),Oe(c,d+320|0,5),Oe(c,d+384|0,6),Oe(c,d+448|0,7),Oe(c,d+512|0,8),Oe(c,d+576|0,9),Oe(c,d+640|0,10),Oe(c,d+704|0,11),Oe(c,d+768|0,12),Oe(c,d+832|0,13),Oe(c,d+896|0,14),Oe(c,d+960|0,15),j=0);return j}wd.X=1;function xd(b,c,d,f,g,e){var i=m;m+=36;for(var h=i+12,e=(e|0)==0,k=i|0,l=h|0,j=i+20,h=h+1|0,n=i+1|0,p=i+4|0,r=i+5|0,o=0;;){var t=d+328+(o<<6)|0;if(o>>>0>=16){var s=0;break}var u=te+(o<<3)|0,w=ye(b,y[u>>2]),v=ve(b,w),v=(v|0)==0|e?v:(dd(y[w>>2])|0)!=2?v:0,z=ue+(o<<3)|0,B=z|0,B=ye(b,y[B>>2]),D=ve(b,B),D=(D|0)==0|e?D:(dd(y[B>>2])|0)!=2?D:0,C=(v|0)!=0;(C&(D|0)!=0&1|0)==0?u=2:(u=(dd(y[w>>2])|0)==0?A[w+82+(y[u+4>>2]&255)|0]&255:2,w=(dd(y[B>>2])|0)==0?A[B+82+(y[(z+4|0)>>2]&255)|0]&255:2,u=u>>>0>>0?u:w);(y[d+12+(o<<2)>>2]|0)==0&&(w=F[d+76+(o<<2)>>2],u=(w>>>0>=u>>>0&1)+w|0);q[b+(o+82)|0]=u&255;w=ye(b,y[(Pe+(o<<3)|0)>>2]);z=ve(b,w);w=(z|0)==0|e?z:(dd(y[w>>2])|0)!=2?z:0;B=Qe+(o<<3)|0;z=ye(b,y[B>>2]);B=ve(b,z);z=(B|0)==0|e?B:(dd(y[z>>2])|0)!=2?B:0;Re(k,l,c,f,g,o);if(u==0){if((D|0)==0){s=1;break}v=j;D=n;C=q[D];u=q[D+1|0];q[v+12|0]=C;q[v+8|0]=C;q[v+4|0]=C;q[v]=C;q[v+13|0]=u;q[v+9|0]=u;q[v+5|0]=u;q[v+1|0]=u;C=q[D+2|0];D=q[D+3|0];q[v+14|0]=C;q[v+10|0]=C;q[v+6|0]=C;q[v+2|0]=C;q[v+15|0]=D;q[v+11|0]=D;q[v+7|0]=D;q[v+3|0]=D}else{if(u==1){if(!C){s=1;break}v=j;C=h;u=q[C+1|0];kc(v,q[C],4);D=C+2|0;kc(v+4|0,u,4);C=q[C+3|0];kc(v+8|0,q[D],4);kc(v+12|0,C,4)}else{if(u==2){Se(j,n,h,v,D)}else{if(u==3){if((D|0)==0){s=1;break}(w|0)==0&&kc(r,q[p],4);Te(j,n)}else{if(u==4){if((D|0)==0|C^1|(z|0)==0){s=1;break}Ue(j,n,h)}else{if(u==5){if((D|0)==0|C^1|(z|0)==0){s=1;break}Ve(j,n,h)}else{if(u==6){if((D|0)==0|C^1|(z|0)==0){s=1;break}We(j,n,h)}else{if(u==7){if((D|0)==0){s=1;break}(w|0)==0&&kc(r,q[p],4);Xe(j,n)}else{if(!C){s=1;break}Ye(j,h)}}}}}}}}v=c;u=j;D=(y[Ze+(o<<2)>>2]<<4)+y[$e+(o<<2)>>2]|0;w=u+4|0;y[(v+D|0)>>2]=y[u>>2];C=u+8|0;y[(D+(v+16)|0)>>2]=y[w>>2];u=u+12|0;y[(D+(v+32)|0)>>2]=y[C>>2];y[(D+(v+48)|0)>>2]=y[u>>2];Oe(c,t,o);o=o+1|0}m=i;return s}xd.X=1;function yd(b,c,d,f,g,e,i){for(var h=y[b+200>>2],k=ve(b,h),l=(i|0)==0,h=(k|0)==0|l?k:(dd(y[h>>2])|0)!=2?k:0,k=y[b+204>>2],i=ve(b,k),k=(i|0)==0|l?i:(dd(y[k>>2])|0)!=2?i:0,j=y[b+212>>2],n=ve(b,j),b=(h|0)==0,i=(k|0)==0,l=b|i|(((n|0)==0|l?n:(dd(y[j>>2])|0)!=2?n:0)|0)==0,j=0;;){var p=j<<2,n=d+(p<<6)|0,r=d+((p|3)<<6)|0,o=d+((p|2)<<6)|0,t=d+((p|1)<<6)|0,s=p+16|0,u=p+19|0,w=p+18|0,p=p+17|0,v=g+(j<<3)|0,z=f+(j*9+1)|0,B=c+(j<<6)|0;if(j>>>0>=2){var D=0;break}if(e==0){af(B,z,v,h,k)}else{if(e==1){if(b){D=1;break}for(var C=B,z=0;;){var E=z<<3,G=C+(E|1)|0,H=C+(E|2)|0,K=C+(E|3)|0,L=C+(E|4)|0,N=C+(E|5)|0,O=C+(E|6)|0,R=C+(E|7)|0,U=v+z|0;q[C+E|0]=q[U];q[G]=q[U];q[H]=q[U];q[K]=q[U];q[L]=q[U];q[N]=q[U];q[O]=q[U];q[R]=q[U];z=z+1|0;if((z|0)==8){break}}}else{if(e==2){if(i){D=1;break}C=B;v=z;for(z=0;;){if(E=z+(C+8)|0,G=z+(C+16)|0,H=z+(C+24)|0,K=z+(C+32)|0,L=z+(C+40)|0,N=z+(C+48)|0,O=z+(C+56)|0,R=v+z|0,q[C+z|0]=q[R],q[E]=q[R],q[G]=q[R],q[H]=q[R],q[K]=q[R],q[L]=q[R],q[N]=q[R],q[O]=q[R],z=z+1|0,(z|0)==8){break}}}else{if(l){D=1;break}bf(B,z,v)}}}Oe(B,n,s);Oe(B,t,p);Oe(B,o,w);Oe(B,r,u);j=j+1|0}return D}yd.X=1;function Le(b,c){for(var d=0;;){var f=d<<4,g=c+d|0,e=b+(f|1)|0,i=b+(f|2)|0,h=b+(f|3)|0,k=b+(f|4)|0,l=b+(f|5)|0,j=b+(f|6)|0,n=b+(f|7)|0,p=b+(f|8)|0,r=b+(f|9)|0,o=b+(f|10)|0,t=b+(f|11)|0,s=b+(f|12)|0,u=b+(f|13)|0,w=b+(f|14)|0,v=b+(f|15)|0;q[b+f|0]=q[g];q[e]=q[g];q[i]=q[g];q[h]=q[g];q[k]=q[g];q[l]=q[g];q[j]=q[g];q[n]=q[g];q[p]=q[g];q[r]=q[g];q[o]=q[g];q[t]=q[g];q[s]=q[g];q[u]=q[g];q[w]=q[g];q[v]=q[g];d=d+1|0;if((d|0)==16){break}}}Le.X=1;function Ne(b,c,d){for(var f=A[c-1|0]&255,g=A[c+15|0]&255,e=A[d+15|0]&255,c=((g-f<<3)+(((A[c+14|0]&255)-(A[c]&255))*7+(((A[c+13|0]&255)-(A[c+1|0]&255))*6+(((A[c+12|0]&255)-(A[c+2|0]&255))*5+(((A[c+11|0]&255)-(A[c+3|0]&255)<<2)+(((A[c+10|0]&255)-(A[c+4|0]&255))*3+(((A[c+9|0]&255)-(A[c+5|0]&255)<<1)+((A[c+8|0]&255)-(A[c+6|0]&255)))))))))*5+32>>6,d=((e-f<<3)+(((A[d+14|0]&255)-(A[d]&255))*7+(((A[d+13|0]&255)-(A[d+1|0]&255))*6+(((A[d+12|0]&255)-(A[d+2|0]&255))*5+(((A[d+11|0]&255)-(A[d+3|0]&255)<<2)+(((A[d+10|0]&255)-(A[d+4|0]&255))*3+(((A[d+9|0]&255)-(A[d+5|0]&255)<<1)+((A[d+8|0]&255)-(A[d+6|0]&255)))))))))*5+32>>6,g=(e+g<<4)+16+d*-7+c*-7|0,e=0;;){for(var f=e<<4,i=g+d*e|0,h=0;;){var k=i+c*h>>5;q[b+(f+h)|0]=(k|0)<0?0:(k|0)>255?-1:k&255;h=h+1|0;if((h|0)==16){break}}e=e+1|0;if((e|0)==16){break}}}Ne.X=1;function Oe(b,c,d){var f=(y[c>>2]|0)==16777215;a:do{if(!f){for(var g=d>>>0<16,e=g?d:d&3,g=g?16:8,e=y[$e+(e<<2)>>2]+g*y[Ze+(e<<2)>>2]|0,i=e+1|0,h=e+2|0,k=e+3|0,l=0;;){var j=g*l|0,n=b+(i+j)|0,p=b+(h+j)|0,r=b+(k+j)|0,o=b+(e+j)|0,t=l<<2,s=c+((t|2)<<2)|0,j=c+((t|3)<<2)|0,u=y[c+((t|1)<<2)>>2],w=A[n]&255;q[o]=q[Q.a+(y[c+(t<<2)>>2]+512+(A[o]&255))|0];o=y[s>>2];t=A[p]&255;q[n]=q[Q.a+(w+(u+512))|0];n=q[Q.a+(y[j>>2]+512+(A[r]&255))|0];q[p]=q[Q.a+(t+(o+512))|0];q[r]=n;l=l+1|0;if((l|0)==4){break a}}}}while(0)}Oe.X=1;function Re(b,c,d,f,g,e){var i=F[$e+(e<<2)>>2],h=F[Ze+(e<<2)>>2],k=(1285>>>(e>>>0)&1|0)!=0;if(k){var l=q[h+(g+1)|0];q[c+1|0]=q[g+h|0];q[c+2|0]=l;l=q[h+(g+3)|0];q[c+3|0]=q[h+(g+2)|0];q[c+4|0]=l}else{var l=(h<<4)+i|0,j=q[l+(d+15)|0];q[c+1|0]=q[d+(l-1)|0];q[c+2|0]=j;j=q[l+(d+47)|0];q[c+3|0]=q[l+(d+31)|0];q[c+4|0]=j}(51>>>(e>>>0)&1|0)==0?(f=h-1|0,i=(f<<4)+i|0,e=q[i+(d+1)|0],q[b+1|0]=q[d+i|0],q[b+2|0]=e,e=q[i+(d+3)|0],q[b+3|0]=q[i+(d+2)|0],q[b+4|0]=e,e=q[i+(d+5)|0],q[b+5|0]=q[i+(d+4)|0],q[b+6|0]=e,e=q[i+(d+7)|0],q[b+7|0]=q[i+(d+6)|0],q[b+8|0]=e,d=k?q[g+f|0]:q[d+(i-1)|0],q[b]=d,q[c]=d):(d=q[f+i|0],q[c]=d,q[b]=d,c=q[i+(f+2)|0],q[b+1|0]=q[i+(f+1)|0],q[b+2|0]=c,c=q[i+(f+4)|0],q[b+3|0]=q[i+(f+3)|0],q[b+4|0]=c,c=q[i+(f+6)|0],q[b+5|0]=q[i+(f+5)|0],q[b+6|0]=c,c=q[i+(f+8)|0],q[b+7|0]=q[i+(f+7)|0],q[b+8|0]=c)}Re.X=1;function Me(b,c,d,f,g){var f=(f|0)!=0,g=(g|0)==0,e=g|f^1;do{if(e){var i=f?((A[d+15|0]&255)+((A[d+14|0]&255)+((A[d+13|0]&255)+((A[d+12|0]&255)+((A[d+11|0]&255)+((A[d+10|0]&255)+((A[d+9|0]&255)+((A[d+8|0]&255)+((A[d+7|0]&255)+((A[d+6|0]&255)+((A[d+5|0]&255)+((A[d+4|0]&255)+((A[d+3|0]&255)+((A[d+2|0]&255)+((A[d+1|0]&255)+(A[d]&255)))))))))))))))+8|0)>>>4:g?128:((A[c+15|0]&255)+((A[c+14|0]&255)+((A[c+13|0]&255)+((A[c+12|0]&255)+((A[c+11|0]&255)+((A[c+10|0]&255)+((A[c+9|0]&255)+((A[c+8|0]&255)+((A[c+7|0]&255)+((A[c+6|0]&255)+((A[c+5|0]&255)+((A[c+4|0]&255)+((A[c+3|0]&255)+((A[c+2|0]&255)+((A[c+1|0]&255)+(A[c]&255)))))))))))))))+8|0)>>>4}else{for(var h=i=0;;){var k=(A[c+i|0]&255)+h+(A[d+i|0]&255)|0,i=i+1|0;if((i|0)==16){break}h=k}i=(k+16|0)>>>5}}while(0);kc(b,i&255,256)}Me.X=1;function Se(b,c,d,f,g){f=(f|0)!=0;g=(g|0)==0;kc(b,(g|f^1?f?(A[d]&255)+2+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)>>2:g?128:(A[c]&255)+2+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)>>2:((A[c]&255)+4+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)+(A[d]&255)+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)|0)>>>3)&255,16)}Se.X=1;function Te(b,c){var d=c+1|0,f=c+2|0;q[b]=((A[c]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;var g=c+3|0;q[b+1|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;d=c+4|0;q[b+2|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+5|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+8|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;f=c+5|0;q[b+3|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+9|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[g]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;g=c+6|0;q[b+7|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+10|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;d=c+7|0;q[b+11|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[f]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[g]&255)+2+(A[d]&255)*3|0)>>>2&255}Te.X=1;function Ue(b,c,d){var f=c-1|0;q[b]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+5|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+10|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;var g=c+1|0;q[b+1|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+11|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;f=c+2|0;q[b+2|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+7|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+3|0]=((A[g]&255)+2+(A[c+3|0]&255)+((A[f]&255)<<1)|0)>>>2&255;g=d-1|0;c=d+1|0;q[b+4|0]=((A[g]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+9|0]=((A[g]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[g]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255;g=d+2|0;q[b+8|0]=((A[d]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[d]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[c]&255)+2+(A[d+3|0]&255)+((A[g]&255)<<1)|0)>>>2&255}Ue.X=1;function Ve(b,c,d){var f=c-1|0;q[b]=((A[f]&255)+1+(A[c]&255)|0)>>>1&255;q[b+9|0]=((A[f]&255)+1+(A[c]&255)|0)>>>1&255;var g=c+1|0;q[b+5|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[f]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[c]&255)+2+(A[d]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+1|0]=((A[c]&255)+1+(A[g]&255)|0)>>>1&255;q[b+10|0]=((A[c]&255)+1+(A[g]&255)|0)>>>1&255;f=c+2|0;q[b+6|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[c]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+2|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;q[b+11|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;c=c+3|0;q[b+7|0]=((A[g]&255)+2+(A[c]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+3|0]=((A[f]&255)+1+(A[c]&255)|0)>>>1&255;g=d+1|0;q[b+8|0]=((A[g]&255)+2+(A[d-1|0]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[d+2|0]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255}Ve.X=1;function We(b,c,d){var f=d-1|0;q[b]=((A[f]&255)+1+(A[d]&255)|0)>>>1&255;q[b+6|0]=((A[f]&255)+1+(A[d]&255)|0)>>>1&255;var g=d+1|0;q[b+5|0]=((A[f]&255)+2+(A[g]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+11|0]=((A[f]&255)+2+(A[g]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[d]&255)+1+(A[g]&255)|0)>>>1&255;q[b+10|0]=((A[d]&255)+1+(A[g]&255)|0)>>>1&255;f=d+2|0;q[b+9|0]=((A[d]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[d]&255)+2+(A[f]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+8|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;q[b+14|0]=((A[g]&255)+1+(A[f]&255)|0)>>>1&255;var e=d+3|0;q[b+13|0]=((A[g]&255)+2+(A[e]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+12|0]=((A[f]&255)+1+(A[e]&255)|0)>>>1&255;g=c-1|0;q[b+1|0]=((A[c]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+7|0]=((A[c]&255)+2+(A[d]&255)+((A[g]&255)<<1)|0)>>>2&255;d=c+1|0;q[b+2|0]=((A[d]&255)+2+(A[g]&255)+((A[c]&255)<<1)|0)>>>2&255;q[b+3|0]=((A[c+2|0]&255)+2+(A[c]&255)+((A[d]&255)<<1)|0)>>>2&255}We.X=1;function Xe(b,c){var d=c+1|0;q[b]=((A[c]&255)+1+(A[d]&255)|0)>>>1&255;var f=c+2|0;q[b+1|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;var g=c+3|0;q[b+2|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;var e=c+4|0;q[b+3|0]=((A[g]&255)+1+(A[e]&255)|0)>>>1&255;q[b+4|0]=((A[c]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+5|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[f]&255)+2+(A[e]&255)+((A[g]&255)<<1)|0)>>>2&255;var i=c+5|0;q[b+7|0]=((A[g]&255)+2+(A[i]&255)+((A[e]&255)<<1)|0)>>>2&255;q[b+8|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;q[b+9|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;q[b+10|0]=((A[g]&255)+1+(A[e]&255)|0)>>>1&255;q[b+11|0]=((A[e]&255)+1+(A[i]&255)|0)>>>1&255;q[b+12|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+13|0]=((A[f]&255)+2+(A[e]&255)+((A[g]&255)<<1)|0)>>>2&255;q[b+14|0]=((A[g]&255)+2+(A[i]&255)+((A[e]&255)<<1)|0)>>>2&255;q[b+15|0]=((A[e]&255)+2+(A[c+6|0]&255)+((A[i]&255)<<1)|0)>>>2&255}Xe.X=1;function Ye(b,c){var d=c+1|0;q[b]=((A[c]&255)+1+(A[d]&255)|0)>>>1&255;var f=c+2|0;q[b+1|0]=((A[c]&255)+2+(A[f]&255)+((A[d]&255)<<1)|0)>>>2&255;q[b+2|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;var g=c+3|0;q[b+3|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+4|0]=((A[d]&255)+1+(A[f]&255)|0)>>>1&255;q[b+5|0]=((A[d]&255)+2+(A[g]&255)+((A[f]&255)<<1)|0)>>>2&255;q[b+6|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;q[b+7|0]=((A[f]&255)+2+(A[g]&255)*3|0)>>>2&255;q[b+8|0]=((A[f]&255)+1+(A[g]&255)|0)>>>1&255;q[b+9|0]=((A[f]&255)+2+(A[g]&255)*3|0)>>>2&255;q[b+10|0]=q[g];q[b+11|0]=q[g];q[b+12|0]=q[g];q[b+13|0]=q[g];q[b+14|0]=q[g];q[b+15|0]=q[g]}Ye.X=1;function bf(b,c,d){for(var f=A[c+7|0]&255,g=A[d+7|0]&255,e=A[c-1|0]&255,c=((A[c+4|0]&255)-(A[c+2|0]&255)+((A[c+5|0]&255)-(A[c+1|0]&255)<<1)+((A[c+6|0]&255)-(A[c]&255))*3+(f-e<<2))*17+16|0,i=c>>5,d=((g-e<<2)+(A[d+4|0]&255)-(A[d+2|0]&255)+((A[d+5|0]&255)-(A[d+1|0]&255)<<1)+((A[d+6|0]&255)-(A[d]&255))*3)*17+16>>5,h=g+f<<4,k=d*3|0,f=h+(c>>3&-4)+16-k|0,l=i*3|0,g=l+(h+16)-k|0,j=c>>4&-2,c=j+(h+16)-k|0,e=h+(i+16)-k|0,n=h+16|0,h=n-k|0,i=n-i-k|0,k=n-j-k|0,l=h-l|0,j=0;;){var n=j<<3,p=b+(n|1)|0,r=b+(n|2)|0,o=b+(n|3)|0,t=b+(n|4)|0,s=b+(n|5)|0,u=b+(n|6)|0,w=b+(n|7)|0,v=d*j|0,z=f+v|0,B=g+v|0,D=c+v|0,C=e+v|0,E=h+v|0,G=i+v|0,H=k+v|0;q[b+n|0]=q[Q.a+((l+v>>5)+512)|0];q[p]=q[Q.a+((H>>5)+512)|0];q[r]=q[Q.a+((G>>5)+512)|0];q[o]=q[Q.a+((E>>5)+512)|0];q[t]=q[Q.a+((C>>5)+512)|0];q[s]=q[Q.a+((D>>5)+512)|0];q[u]=q[Q.a+((B>>5)+512)|0];q[w]=q[Q.a+((z>>5)+512)|0];j=j+1|0;if((j|0)==8){break}}}bf.X=1;function af(b,c,d,f,g){f=(f|0)!=0;g=(g|0)==0;if(g|f^1){if(g){if(f){var e=(A[d]&255)+2+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)>>2,i=e}else{var i=128,e=128}}else{i=(A[c+4|0]&255)+2+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)>>2,e=(A[c]&255)+2+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)>>2}}else{i=(A[c+4|0]&255)+2+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)>>2,e=((A[c]&255)+4+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)+(A[d]&255)+(A[d+1|0]&255)+(A[d+2|0]&255)+(A[d+3|0]&255)|0)>>>3}e&=255;i&=255;var h=b+4|0;kc(b,e,4);var k=b+8|0,l=b+12|0;kc(h,i,4);kc(k,e,4);k=b+16|0;h=b+20|0;kc(l,i,4);kc(k,e,4);l=b+24|0;k=b+28|0;kc(h,i,4);kc(l,e,4);kc(k,i,4);f?(f=A[d+4|0]&255,e=A[d+5|0]&255,i=A[d+6|0]&255,l=A[d+7|0]&255,d=l+(i+(e+(f+2)))>>2,g=g?d:(l+(i+(e+(f+4)))+(A[c+4|0]&255)+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)|0)>>>3,c=d):g?c=g=128:(g=(A[c+4|0]&255)+2+(A[c+5|0]&255)+(A[c+6|0]&255)+(A[c+7|0]&255)>>2,c=(A[c]&255)+2+(A[c+1|0]&255)+(A[c+2|0]&255)+(A[c+3|0]&255)>>2);c&=255;d=g&255;f=b+36|0;kc(b+32|0,c,4);e=b+40|0;g=b+44|0;kc(f,d,4);kc(e,c,4);e=b+48|0;f=b+52|0;kc(g,d,4);kc(e,c,4);g=b+56|0;b=b+60|0;kc(f,d,4);kc(g,c,4);kc(b,d,4)}af.X=1;function ud(b,c,d,f,g,e){var i=m;m+=24;var h,k=F[g+4>>2],l=Math.floor((f>>>0)/(k>>>0)),j=l<<4,l=f-l*k<<4;y[i+4>>2]=k;y[i+8>>2]=y[g+8>>2];var k=b|0,n=y[k>>2];a:do{if(n==0||n==1){if((cf(b,c+12|0,d)|0)!=0){var p=1;h=19}else{y[i>>2]=y[b+116>>2],df(e,b+132|0,i,l,j,0,0,16,16),h=15}}else{if(n==2){(ef(b,c+12|0,d)|0)!=0?(p=1,h=19):(h=i|0,y[h>>2]=y[b+116>>2],df(e,b+132|0,i,l,j,0,0,16,8),y[h>>2]=y[b+124>>2],df(e,b+164|0,i,l,j,0,8,16,8),h=15)}else{if(n==3){(ff(b,c+12|0,d)|0)!=0?(p=1,h=19):(h=i|0,y[h>>2]=y[b+116>>2],df(e,b+132|0,i,l,j,0,0,8,16),y[h>>2]=y[b+120>>2],df(e,b+148|0,i,l,j,8,0,8,16),h=15)}else{var r=b,o=c+176|0,t=d,s=0;b:for(;;){var u=o+16+(s<<2)|0;if(s>>>0>=4){var w=0;break}var v=r+116+(s<<2)|0,z=y[o+(s<<2)>>2]==0?1:y[o+(s<<2)>>2]==1||y[o+(s<<2)>>2]==2?2:4;y[(r+100+(s<<2)|0)>>2]=y[u>>2];u=gf(t,y[u>>2]);y[v>>2]=u;if((u|0)==0){w=1;break}for(v=0;;){if(v>>>0>=z>>>0){break}if((hf(r,o,s,v)|0)!=0){w=1;break b}v=v+1|0}s=s+1|0}if((w|0)!=0){p=1,h=19}else{r=i|0;for(o=0;;){var B=c+176+(o<<2)|0,v=o<<3,u=o<<2,s=b+132+((u|1)<<2)|0,z=b+132+(u<<2)|0,t=b+132+((u|2)<<2)|0;y[r>>2]=y[b+116+(o<<2)>>2];var D=y[B>>2];v&=8;B=o>>>0<2?0:8;D==0?df(e,z,i,l,j,v,B,8,8):D==1?(df(e,z,i,l,j,v,B,8,4),df(e,t,i,l,j,v,B|4,8,4)):D==2?(df(e,z,i,l,j,v,B,4,8),df(e,s,i,l,j,v|4,B,4,8)):(u=b+132+((u|3)<<2)|0,df(e,z,i,l,j,v,B,4,4),z=v|4,df(e,s,i,l,j,z,B,4,4),s=B|4,df(e,t,i,l,j,v,s,4,4),df(e,u,i,l,j,z,s,4,4));o=o+1|0;if((o|0)==4){h=15;break a}}}}}}}while(0);h==15&&(F[b+196>>2]>>>0>1||((y[k>>2]|0)==0?rd(g,e):jf(g,f,e,c+328|0)),p=0);m=i;return p}ud.X=1;function cf(b,c,d){var f=m;m+=40;var g,e=f+4,i=F[c+132>>2],h=b+4|0,k=e|0;kf(y[h>>2],y[b+200>>2],k,5);kf(y[h>>2],y[b+204>>2],e+12|0,10);g=e+8|0;var l=e+20|0;if((y[b>>2]|0)==0){if((y[e>>2]|0)==0){var j=0,n=0;g=11}else{(y[e+12>>2]|0)==0?(n=j=0,g=11):(y[e+4>>2]|0)==0&&(y[g>>2]|0)==0?(n=j=0,g=11):(y[e+16>>2]|0)!=0?g=7:(y[l>>2]|0)==0?(n=j=0,g=11):g=7}}else{g=7}if(g==7){if(g=x[c+148>>1],c=x[c+150>>1],l=e+24|0,kf(y[h>>2],y[b+208>>2],l,10),(y[e+24>>2]|0)==0&&kf(y[h>>2],y[b+212>>2],l,15),lf(f,k,i),e=x[f>>1]+g&65535,h=x[f+2>>1]+c&65535,((e<<16>>16)+8192|0)>>>0>16383){var p=1;g=13}else{((h<<16>>16)+2048|0)>>>0>4095?(p=1,g=13):(j=e,n=h,g=11)}}if(g==11){if(d=gf(d,i),(d|0)==0){p=1}else{p=b+132|0;e=b+136|0;h=b+140|0;k=b+144|0;c=b+148|0;g=b+152|0;var l=b+156|0,r=b+160|0,o=b+164|0,t=b+168|0,s=b+172|0,u=b+176|0,w=b+180|0,v=b+184|0,z=b+188|0,B=b+192|0;x[b+192>>1]=j;x[b+194>>1]=n;J=j=Gb[B>>1]+(Gb[B+2>>1]<<16);x[z>>1]=J&65535;x[z+2>>1]=J>>16;J=j;x[v>>1]=J&65535;x[v+2>>1]=J>>16;J=j;x[w>>1]=J&65535;x[w+2>>1]=J>>16;J=j;x[u>>1]=J&65535;x[u+2>>1]=J>>16;J=j;x[s>>1]=J&65535;x[s+2>>1]=J>>16;J=j;x[t>>1]=J&65535;x[t+2>>1]=J>>16;J=j;x[o>>1]=J&65535;x[o+2>>1]=J>>16;J=j;x[r>>1]=J&65535;x[r+2>>1]=J>>16;J=j;x[l>>1]=J&65535;x[l+2>>1]=J>>16;J=j;x[g>>1]=J&65535;x[g+2>>1]=J>>16;J=j;x[c>>1]=J&65535;x[c+2>>1]=J>>16;J=j;x[k>>1]=J&65535;x[k+2>>1]=J>>16;J=j;x[h>>1]=J&65535;x[h+2>>1]=J>>16;J=j;x[e>>1]=J&65535;x[e+2>>1]=J>>16;J=j;x[p>>1]=J&65535;x[p+2>>1]=J>>16;y[b+100>>2]=i;y[b+104>>2]=i;y[b+108>>2]=i;y[b+112>>2]=i;y[b+116>>2]=d;y[b+120>>2]=d;y[b+124>>2]=d;y[b+128>>2]=d;p=0}}m=f;return p}cf.X=1;function ef(b,c,d){var f=m;m+=4;var g=m;m+=36;var e=x[c+148>>1],i=x[c+150>>1],h=F[c+132>>2],k=b+4|0,l=g|0;kf(y[k>>2],y[b+204>>2],g+12|0,10);var j=g+16|0;if((y[j>>2]|0)==(h|0)){var n=F[g+20>>2];y[f>>2]=n;var p=n&65535,r=n>>>16&65535,n=f,o=f+2|0}else{kf(y[k>>2],y[b+200>>2],l,5),n=g+24|0,kf(y[k>>2],y[b+208>>2],n,10),(y[g+24>>2]|0)==0&&kf(y[k>>2],y[b+212>>2],n,15),lf(f,l,h),o=f+2|0,p=x[f>>1],r=x[o>>1],n=f}var e=p+e&65535,t=r+i&65535;if(((e<<16>>16)+8192|0)>>>0>16383){b=1}else{if(((t<<16>>16)+2048|0)>>>0>4095){b=1}else{if(p=gf(d,h),(p|0)==0){b=1}else{var i=b+132|0,r=b+136|0,s=b+140|0,u=b+144|0,w=b+148|0,v=b+152|0,z=b+156|0,B=b+160|0;x[b+160>>1]=e;x[b+162>>1]=t;J=e=Gb[B>>1]+(Gb[B+2>>1]<<16);x[z>>1]=J&65535;x[z+2>>1]=J>>16;J=e;x[v>>1]=J&65535;x[v+2>>1]=J>>16;J=e;x[w>>1]=J&65535;x[w+2>>1]=J>>16;J=e;x[u>>1]=J&65535;x[u+2>>1]=J>>16;J=e;x[s>>1]=J&65535;x[s+2>>1]=J>>16;J=e;x[r>>1]=J&65535;x[r+2>>1]=J>>16;J=e;x[i>>1]=J&65535;x[i+2>>1]=J>>16;r=b+100|0;y[r>>2]=h;y[b+104>>2]=h;y[b+116>>2]=p;y[b+120>>2]=p;e=x[c+152>>1];h=x[c+154>>1];c=F[c+136>>2];p=b+200|0;kf(y[k>>2],y[p>>2],l,13);(y[g+4>>2]|0)==(c|0)?(k=F[g+8>>2],y[f>>2]=k,g=k&65535,k=k>>>16&65535):(y[g+12>>2]=1,y[j>>2]=y[r>>2],y[g+20>>2]=Gb[i>>1]+(Gb[i+2>>1]<<16),kf(y[k>>2],y[p>>2],g+24|0,7),lf(f,l,c),g=x[n>>1],k=x[o>>1]);g=g+e&65535;k=k+h&65535;((g<<16>>16)+8192|0)>>>0>16383?b=1:((k<<16>>16)+2048|0)>>>0>4095?b=1:(d=gf(d,c),(d|0)==0?b=1:(l=b+164|0,j=b+168|0,n=b+172|0,o=b+176|0,h=b+180|0,i=b+184|0,e=b+188|0,p=b+192|0,x[b+192>>1]=g,x[b+194>>1]=k,J=g=Gb[p>>1]+(Gb[p+2>>1]<<16),x[e>>1]=J&65535,x[e+2>>1]=J>>16,J=g,x[i>>1]=J&65535,x[i+2>>1]=J>>16,J=g,x[h>>1]=J&65535,x[h+2>>1]=J>>16,J=g,x[o>>1]=J&65535,x[o+2>>1]=J>>16,J=g,x[n>>1]=J&65535,x[n+2>>1]=J>>16,J=g,x[j>>1]=J&65535,x[j+2>>1]=J>>16,J=g,x[l>>1]=J&65535,x[l+2>>1]=J>>16,y[b+108>>2]=c,y[b+112>>2]=c,y[b+124>>2]=d,y[b+128>>2]=d,b=0))}}}m=f;return b}ef.X=1;function ff(b,c,d){var f=m;m+=4;var g=m;m+=36;var e=x[c+148>>1],i=x[c+150>>1],h=F[c+132>>2],k=b+4|0,l=g|0;kf(y[k>>2],y[b+200>>2],l,5);var j=g+4|0;if((y[j>>2]|0)==(h|0)){var n=F[g+8>>2];y[f>>2]=n;var p=n&65535,r=n>>>16&65535,n=f,o=f+2|0}else{n=b+204|0,kf(y[k>>2],y[n>>2],g+12|0,10),o=g+24|0,kf(y[k>>2],y[n>>2],o,14),(y[g+24>>2]|0)==0&&kf(y[k>>2],y[b+212>>2],o,15),lf(f,l,h),o=f+2|0,p=x[f>>1],r=x[o>>1],n=f}var e=p+e&65535,t=r+i&65535;if(((e<<16>>16)+8192|0)>>>0>16383){b=1}else{if(((t<<16>>16)+2048|0)>>>0>4095){b=1}else{if(p=gf(d,h),(p|0)==0){b=1}else{var i=b+132|0,r=b+136|0,s=b+140|0,u=b+144|0,w=b+164|0,v=b+168|0,z=b+172|0,B=b+176|0;x[b+176>>1]=e;x[b+178>>1]=t;J=e=Gb[B>>1]+(Gb[B+2>>1]<<16);x[z>>1]=J&65535;x[z+2>>1]=J>>16;J=e;x[v>>1]=J&65535;x[v+2>>1]=J>>16;J=e;x[w>>1]=J&65535;x[w+2>>1]=J>>16;J=e;x[u>>1]=J&65535;x[u+2>>1]=J>>16;J=e;x[s>>1]=J&65535;x[s+2>>1]=J>>16;J=e;x[r>>1]=J&65535;x[r+2>>1]=J>>16;J=e;x[i>>1]=J&65535;x[i+2>>1]=J>>16;r=b+100|0;y[r>>2]=h;y[b+108>>2]=h;y[b+116>>2]=p;y[b+124>>2]=p;e=x[c+152>>1];h=x[c+154>>1];c=F[c+136>>2];p=g+24|0;kf(y[k>>2],y[b+208>>2],p,10);(y[g+24>>2]|0)==0&&kf(y[k>>2],y[b+204>>2],p,11);(y[g+28>>2]|0)==(c|0)?(k=F[g+32>>2],y[f>>2]=k,g=k&65535,k=k>>>16&65535):(y[g>>2]=1,y[j>>2]=y[r>>2],y[g+8>>2]=Gb[i>>1]+(Gb[i+2>>1]<<16),kf(y[k>>2],y[b+204>>2],g+12|0,14),lf(f,l,c),g=x[n>>1],k=x[o>>1]);g=g+e&65535;k=k+h&65535;((g<<16>>16)+8192|0)>>>0>16383?b=1:((k<<16>>16)+2048|0)>>>0>4095?b=1:(d=gf(d,c),(d|0)==0?b=1:(l=b+148|0,j=b+152|0,n=b+156|0,o=b+160|0,h=b+180|0,i=b+184|0,e=b+188|0,p=b+192|0,x[b+192>>1]=g,x[b+194>>1]=k,J=g=Gb[p>>1]+(Gb[p+2>>1]<<16),x[e>>1]=J&65535,x[e+2>>1]=J>>16,J=g,x[i>>1]=J&65535,x[i+2>>1]=J>>16,J=g,x[h>>1]=J&65535,x[h+2>>1]=J>>16,J=g,x[o>>1]=J&65535,x[o+2>>1]=J>>16,J=g,x[n>>1]=J&65535,x[n+2>>1]=J>>16,J=g,x[j>>1]=J&65535,x[j+2>>1]=J>>16,J=g,x[l>>1]=J&65535,x[l+2>>1]=J>>16,y[b+104>>2]=c,y[b+112>>2]=c,y[b+120>>2]=d,y[b+128>>2]=d,b=0))}}}m=f;return b}ff.X=1;function mf(b,c,d){if((c|0)>(b|0)){var f=b,b=c}else{f=(c|0)<(b|0)?c:b}return(b|0)<(d|0)?b:(f|0)>(d|0)?f:d}function kf(b,c,d,f){var g=d|0;y[g>>2]=0;var e=d+4|0;y[e>>2]=-1;var i=d+10|0;x[i>>1]=0;d=d+8|0;x[d>>1]=0;(c|0)!=0&&(y[c+4>>2]|0)==(b|0)&&(b=F[c>>2],y[g>>2]=1,b>>>0<6&&(g=x[c+132+(f<<2)>>1],b=x[c+132+(f<<2)+2>>1],y[e>>2]=y[c+100+(f>>>2<<2)>>2],x[d>>1]=g,x[i>>1]=b))}function hf(b,c,d,f){var g=m;m+=40;var e=g+4,i=x[c+32+(d<<4)+(f<<2)>>1],h=x[c+32+(d<<4)+(f<<2)+2>>1],k=y[c+(d<<2)>>2],c=y[c+16+(d<<2)>>2],l=b+4|0,j=e|0;kf(y[l>>2],ye(b,y[nf+(d<<7)+(k<<5)+(f<<3)>>2]),j,A[nf+(d<<7)+(k<<5)+(f<<3)+4|0]&255);kf(y[l>>2],ye(b,y[of+(d<<7)+(k<<5)+(f<<3)>>2]),e+12|0,A[of+(d<<7)+(k<<5)+(f<<3)+4|0]&255);var n=e+24|0;kf(y[l>>2],ye(b,y[pf+(d<<7)+(k<<5)+(f<<3)>>2]),n,A[pf+(d<<7)+(k<<5)+(f<<3)+4|0]&255);(y[e+24>>2]|0)==0&&kf(y[l>>2],ye(b,y[qf+(d<<7)+(k<<5)+(f<<3)>>2]),n,A[qf+(d<<7)+(k<<5)+(f<<3)+4|0]&255);lf(g,j,c);e=x[g>>1]+i&65535;h=x[g+2>>1]+h&65535;((e<<16>>16)+8192|0)>>>0>16383?b=1:((h<<16>>16)+2048|0)>>>0>4095?b=1:(k==0?(d<<=2,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h,f=d|1,x[b+132+(f<<2)>>1]=e,x[b+132+(f<<2)+2>>1]=h,f=d|2,x[b+132+(f<<2)>>1]=e,x[b+132+(f<<2)+2>>1]=h,d|=3,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h):k==1?(d=(f<<1)+(d<<2)|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h,d|=1,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h):k==2?(d=(d<<2)+f|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h,d=d+2|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h):k==3&&(d=(d<<2)+f|0,x[b+132+(d<<2)>>1]=e,x[b+132+(d<<2)+2>>1]=h),b=0);m=g;return b}hf.X=1;function lf(b,c,d){var f;(y[c+12>>2]|0)==0?(y[c+24>>2]|0)!=0?f=3:(y[c>>2]|0)==0?f=3:(f=c+8|0,J=Gb[f>>1]+(Gb[f+2>>1]<<16),x[b>>1]=J&65535,x[b+2>>1]=J>>16,f=11):f=3;if(f==3){f=(y[c+4>>2]|0)==(d|0);var g=(y[c+16>>2]|0)==(d|0);((g&1)+(f&1)+((y[c+28>>2]|0)==(d|0)&1)|0)==1?(c=f?c+8|0:g?c+20|0:c+32|0,J=Gb[c>>1]+(Gb[c+2>>1]<<16),x[b>>1]=J&65535,x[b+2>>1]=J>>16):(x[b>>1]=mf(x[c+8>>1]<<16>>16,x[c+20>>1]<<16>>16,x[c+32>>1]<<16>>16)&65535,x[b+2>>1]=mf(x[c+10>>1]<<16>>16,x[c+22>>1]<<16>>16,x[c+34>>1]<<16>>16)&65535)}}lf.X=1;function rf(b,c,d,f,g,e,i,h,k){var l=m;m+=144;var j;if((d|0)<0){j=3}else{if((h+(d+1)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((k+f|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g,t=e;j=4}}}j==3&&(n=l|0,o=h+1|0,sf(b,n,d,f,g,e,o,k,o),sf(b+e*g|0,l+o*k|0,d,f,g,e,o,k,o),r=p=0,t=k);b=8-i|0;d=k>>>0<2;f=h>>>0<2;g=16-h|0;e=(o<<1)-h|0;j=o+1|0;var s=o+2|0,u=h>>>1;h&=-2;k>>>=1;t=t*o|0;p=p+r*o|0;for(r=0;;){a:do{if(!d){for(var w=n+(p+t*r)|0,v=c+(r<<6)|0,z=0;;){if(!f){for(var B=v+h|0,D=0;;){var C=D<<1,E=C|1,G=A[w+C|0]&255,H=A[w+(j+C)|0]&255,K=A[w+E|0]&255;q[C+(v+8)|0]=((H*i+(A[w+(o+C)|0]&255)*b<<3)+32|0)>>>6&255;q[v+C|0]=((K*i+G*b<<3)+32|0)>>>6&255;G=A[C+(w+2)|0]&255;q[C+(v+9)|0]=(((A[w+(s+C)|0]&255)*i+H*b<<3)+32|0)>>>6&255;q[v+E|0]=((G*i+K*b<<3)+32|0)>>>6&255;D=D+1|0;if((D|0)==(u|0)){break}}w=w+h|0;v=B}z=z+1|0;if((z|0)==(k|0)){break a}w=w+e|0;v=v+g|0}}}while(0);r=r+1|0;if((r|0)==2){break}}m=l}rf.X=1;function sf(b,c,d,f,g,e,i,h,k){var l=i+d|0,j=h+f|0,n=(d|0)<0|(l|0)>(g|0)?2:4,f=(j|0)<0?-h|0:f,d=(l|0)<0?-i|0:d,f=(f|0)>(e|0)?e:f,p=(d|0)>(g|0)?g:d,d=p+i|0,r=f+h|0,b=(p|0)>0?b+p|0:b,l=(f|0)>0?b+f*g|0:b,b=(p|0)<0?-p|0:0,d=(d|0)>(g|0)?d-g|0:0,i=i-b-d|0,p=(f|0)<0?-f|0:0,f=(r|0)>(e|0)?r-e|0:0;if((p|0)!=0){for(var r=e^-1,o=h-1-((j|0)>0?j:0)|0,r=(o|0)<(r|0)?r:o,o=r^-1,r=((o|0)>0?o:0)+(r+1)|0,o=r*k|0,t=0;;){if(lc[n](l,c+t*k|0,b,i,d),t=t+1|0,(t|0)==(r|0)){break}}c=c+o|0}if((h-p|0)!=(f|0)){p=h-1|0;r=e^-1;o=p-((j|0)>0?j:0)|0;r=(o|0)<(r|0)?r:o;p=p-r|0;o=r^-1;r=h+e-1-((p|0)<(e|0)?e:p)-r-((o|0)>0?o:0)|0;o=r*k|0;p=r*g|0;for(t=0;;){if(lc[n](l+t*g|0,c+t*k|0,b,i,d),t=t+1|0,(t|0)==(r|0)){break}}c=c+o|0;l=l+p|0}g=l+ -g|0;l=(f|0)==0;a:do{if(!l){f=h-1|0;p=e^-1;r=f-((j|0)>0?j:0)|0;f=f-((r|0)<(p|0)?p:r)|0;f=((f|0)<(e|0)?e:f)-e|0;for(p=0;;){if(lc[n](g,c+p*k|0,b,i,d),p=p+1|0,(p|0)==(f|0)){break a}}}}while(0)}sf.X=1;function tf(b,c,d,f,g,e,i,h,k){var l=m;m+=144;var j;if((d|0)<0){j=3}else{if((h+d|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((k+(f+1)|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g,t=e;j=4}}}j==3&&(n=l|0,j=k+1|0,sf(b,n,d,f,g,e,h,j,h),sf(b+e*g|0,l+j*h|0,d,f,g,e,h,j,h),r=p=0,o=h,t=j);b=8-i|0;d=k>>>0<2;f=h>>>0<2;g=16-h|0;e=o<<1;j=e-h|0;var s=o+1|0,u=h>>>1;h&=-2;var w=e|1;k>>>=1;t=t*o|0;p=p+r*o|0;for(r=0;;){a:do{if(!d){for(var v=n+(p+t*r)|0,z=c+(r<<6)|0,B=0;;){if(!f){for(var D=z+h|0,C=0;;){var E=C<<1,G=E|1,H=A[v+(o+E)|0]&255,K=A[v+E|0]&255;q[E+(z+8)|0]=((H*b+(A[v+(e+E)|0]&255)*i<<3)+32|0)>>>6&255;q[z+E|0]=((K*b+H*i<<3)+32|0)>>>6&255;H=A[v+(s+E)|0]&255;K=A[v+G|0]&255;q[E+(z+9)|0]=((H*b+(A[v+(w+E)|0]&255)*i<<3)+32|0)>>>6&255;q[z+G|0]=((K*b+H*i<<3)+32|0)>>>6&255;C=C+1|0;if((C|0)==(u|0)){break}}v=v+h|0;z=D}B=B+1|0;if((B|0)==(k|0)){break a}v=v+j|0;z=z+g|0}}}while(0);r=r+1|0;if((r|0)==2){break}}m=l}tf.X=1;function uf(b,c,d,f,g,e,i,h,k,l){var j=m;m+=164;var n;if((d|0)<0){n=3}else{if((k+(d+1)|0)>>>0>g>>>0|(f|0)<0){n=3}else{if((l+(f+1)|0)>>>0>e>>>0){n=3}else{var p=b,r=d,o=f,t=g,s=e;n=4}}}n==3&&(p=j|0,t=k+1|0,n=l+1|0,sf(b,p,d,f,g,e,t,n,t),sf(b+e*g|0,j+n*t|0,d,f,g,e,t,n,t),o=r=0,s=n);b=8-i|0;d=8-h|0;f=l>>>0<2;g=t<<1;e=k>>>0<2;n=16-k|0;var u=g-k|0,w=t+1|0,v=t+2|0,z=k>>>1;k&=-2;var B=g|1,D=g+2|0;l>>>=1;s=s*t|0;r=r+o*t|0;for(o=0;;){a:do{if(!f){for(var C=p+(r+s*o)|0,E=c+(o<<6)|0,G=0;;){var H=A[C+t|0]&255;if(!e){for(var K=E+k|0,L=H*h+(A[C]&255)*d|0,N=(A[C+g|0]&255)*h+H*d|0,H=0;;){var O=H<<1,R=O|1,U=A[C+(w+O)|0]&255,Y=U*h+(A[C+R|0]&255)*d|0,U=(A[C+(B+O)|0]&255)*h+U*d|0,L=(L*b+32+Y*i|0)>>>6;q[O+(E+8)|0]=(N*b+32+U*i|0)>>>6&255;q[E+O|0]=L&255;N=A[C+(v+O)|0]&255;L=N*h+(A[O+(C+2)|0]&255)*d|0;N=(A[C+(D+O)|0]&255)*h+N*d|0;Y=(Y*b+32+L*i|0)>>>6;q[O+(E+9)|0]=(U*b+32+N*i|0)>>>6&255;q[E+R|0]=Y&255;H=H+1|0;if((H|0)==(z|0)){break}}C=C+k|0;E=K}G=G+1|0;if((G|0)==(l|0)){break a}C=C+u|0;E=E+n|0}}}while(0);o=o+1|0;if((o|0)==2){break}}m=j}uf.X=1;function vf(b,c,d,f,g,e,i,h){var k=m;m+=444;var l;if((d|0)<0){l=3}else{if((i+d|0)>>>0>g>>>0|(f|0)<0){l=3}else{if((h+(f+5)|0)>>>0>e>>>0){l=3}else{var j=b,n=d,p=f,r=g;l=4}}}l==3&&(sf(b,k,d,f,g,e,i,h+5|0,i),j=k,p=n=0,r=i);b=n+r+p*r|0;d=h>>>0<4;a:do{if(!d){f=(i|0)==0;g=(r<<2)-i|0;e=64-i|0;l=r*-2|0;for(var n=r<<1,p=h>>>2,o=j+b|0,t=j+(b+r*5)|0,s=c,u=0;;){if(!f){for(var w=s+i|0,v=0;;){var z=v-r|0,B=r+v|0,D=n+v|0,C=A[t+(l+v)|0]&255,E=A[t+z|0]&255,G=A[t+B|0]&255,H=A[t+v|0]&255,K=G+C|0,L=A[o+D|0]&255;q[v+(s+48)|0]=q[Q.a+((16-K+(A[t+D|0]&255)-(K<<2)+L+(H+E)*20>>5)+512)|0];D=L+H|0;B=A[o+B|0]&255;q[v+(s+32)|0]=q[Q.a+((G+16-D+B-(D<<2)+(E+C)*20>>5)+512)|0];G=B+E|0;D=A[o+v|0]&255;q[v+(s+16)|0]=q[Q.a+((H+16-G+D-(G<<2)+(L+C)*20>>5)+512)|0];C=D+C|0;q[s+v|0]=q[Q.a+((E+16-C+(A[o+z|0]&255)-(C<<2)+(B+L)*20>>5)+512)|0];v=v+1|0;if((v|0)==(i|0)){break}}o=o+i|0;t=t+i|0;s=w}u=u+1|0;if((u|0)==(p|0)){break a}o=o+g|0;t=t+g|0;s=s+e|0}}}while(0);m=k}vf.X=1;function wf(b,c,d,f,g,e,i,h,k){var l=m;m+=444;var j;if((d|0)<0){j=3}else{if((i+d|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g;j=4}}}j==3&&(sf(b,l,d,f,g,e,i,h+5|0,i),n=l,r=p=0,o=i);b=p+o+r*o|0;d=h>>>0<4;a:do{if(!d){f=(i|0)==0;g=(o<<2)-i|0;e=64-i|0;j=o<<1;for(var p=o*-2|0,r=h>>>2,t=n+b|0,s=n+(b+o*5)|0,u=n+(b+o*(k+2))|0,w=c,v=0;;){if(!f){for(var z=u+i|0,B=w+i|0,D=0;;){var C=j+D|0,E=o+D|0,G=D-o|0,H=A[s+(p+D)|0]&255,K=A[s+G|0]&255,L=A[s+E|0]&255,N=A[s+D|0]&255,O=L+H|0,R=A[t+C|0]&255;q[D+(w+48)|0]=((A[Q.a+((16-O+(A[s+C|0]&255)-(O<<2)+R+(N+K)*20>>5)+512)|0]&255)+1+(A[u+C|0]&255)|0)>>>1&255;O=R+N|0;C=A[t+E|0]&255;q[D+(w+32)|0]=((A[Q.a+((L+16-O-(O<<2)+C+(K+H)*20>>5)+512)|0]&255)+1+(A[u+E|0]&255)|0)>>>1&255;E=C+K|0;L=A[t+D|0]&255;q[D+(w+16)|0]=((A[Q.a+((N+16-E-(E<<2)+L+(R+H)*20>>5)+512)|0]&255)+1+(A[u+D|0]&255)|0)>>>1&255;H=L+H|0;q[w+D|0]=((A[Q.a+((K+16-H-(H<<2)+(A[t+G|0]&255)+(C+R)*20>>5)+512)|0]&255)+1+(A[u+G|0]&255)|0)>>>1&255;D=D+1|0;if((D|0)==(i|0)){break}}t=t+i|0;s=s+i|0;u=z;w=B}v=v+1|0;if((v|0)==(r|0)){break a}t=t+g|0;s=s+g|0;u=u+g|0;w=w+e|0}}}while(0);m=l}wf.X=1;function xf(b,c,d,f,g,e,i,h){var k=m;m+=444;var l;if((d|0)<0){l=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){l=3}else{if((h+f|0)>>>0>e>>>0){l=3}else{var j=b,n=d,p=f,r=g;l=4}}}l==3&&(r=i+5|0,sf(b,k,d,f,g,e,r,h,r),j=k,p=n=0);b=(h|0)==0;a:do{if(!b){d=i>>>2;f=(d|0)==0;g=r-i|0;e=16-i|0;l=i&-4;for(var o=j+(n+5+p*r)|0,t=c,s=0;;){if(!f){for(var u=t+l|0,w=A[o-1|0]&255,v=A[o-2|0]&255,z=A[o-3|0]&255,B=A[o-4|0]&255,D=A[o-5|0]&255,C=0;;){var E=C<<2,G=E|1,H=E|2,K=E|3,L=B+w|0,N=A[o+E|0]&255;q[t+E|0]=q[Q.a+((16-L+D-(L<<2)+N+(z+v)*20>>5)+512)|0];L=N+z|0;E=A[o+G|0]&255;D=N+w|0;q[t+G|0]=q[Q.a+((B+16-L+E-(L<<2)+(v+w)*20>>5)+512)|0];L=E+v|0;B=A[o+H|0]&255;G=E+N|0;q[t+H|0]=q[Q.a+((z+16-L+B-(L<<2)+D*20>>5)+512)|0];H=B+w|0;z=A[o+K|0]&255;q[t+K|0]=q[Q.a+((v+16-H+z-(H<<2)+G*20>>5)+512)|0];C=C+1|0;if((C|0)==(d|0)){break}D=w;w=z;v=B;z=E;B=N}o=o+l|0;t=u}s=s+1|0;if((s|0)==(h|0)){break a}o=o+g|0;t=t+e|0}}}while(0);m=k}xf.X=1;function yf(b,c,d,f,g,e,i,h,k){var l=m;m+=444;var j;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+f|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g;j=4}}}j==3&&(o=i+5|0,sf(b,l,d,f,g,e,o,h,o),n=l,r=p=0);b=(h|0)==0;a:do{if(!b){d=i>>>2;f=(d|0)==0;g=o-i|0;e=16-i|0;j=(k|0)!=0;for(var t=i&-4,s=n+(p+5+r*o)|0,u=c,w=0;;){if(!f){for(var v=u+t|0,z=A[s-1|0]&255,B=A[s-2|0]&255,D=A[s-3|0]&255,C=A[s-4|0]&255,E=A[s-5|0]&255,G=0;;){var H=G<<2,K=H|1,L=H|2,N=H|3,O=C+z|0,R=A[s+H|0]&255;q[u+H|0]=((j?B:D)+1+(A[Q.a+((16-O+E-(O<<2)+R+(D+B)*20>>5)+512)|0]&255)|0)>>>1&255;E=R+D|0;H=A[s+K|0]&255;q[u+K|0]=((j?z:B)+1+(A[Q.a+((C+16-E+H-(E<<2)+(B+z)*20>>5)+512)|0]&255)|0)>>>1&255;E=H+B|0;C=A[s+L|0]&255;q[u+L|0]=((j?R:z)+1+(A[Q.a+((D+16-E+C-(E<<2)+(R+z)*20>>5)+512)|0]&255)|0)>>>1&255;E=C+z|0;D=A[s+N|0]&255;q[u+N|0]=((j?H:R)+1+(A[Q.a+((B+16-E+D-(E<<2)+(H+R)*20>>5)+512)|0]&255)|0)>>>1&255;G=G+1|0;if((G|0)==(d|0)){break}E=z;z=D;B=C;D=H;C=R}s=s+t|0;u=v}w=w+1|0;if((w|0)==(h|0)){break a}s=s+g|0;u=u+e|0}}}while(0);m=l}yf.X=1;function zf(b,c,d,f,g,e,i,h,k){var l=m;m+=444;var j;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var n=b,p=d,r=f,o=g;j=4}}}j==3&&(o=i+5|0,sf(b,l,d,f,g,e,o,h+5|0,o),n=l,r=p=0);b=r*o+p|0;d=(k&1|2)+o+b|0;f=n+d|0;g=(h|0)==0;a:do{if(!g){p=i>>>2;r=(p|0)==0;j=o-i|0;for(var e=16-i|0,t=i&-4,s=n+(o*(k>>>1&1|2)+5+b)|0,u=c,w=0;;){if(r){var v=u}else{for(var v=u+t|0,z=A[s-2|0]&255,B=A[s-1|0]&255,D=A[s-3|0]&255,C=A[s-4|0]&255,E=A[s-5|0]&255,G=0;;){var H=G<<2,K=H|1,L=H|2,N=H|3,O=C+B|0,R=A[s+H|0]&255;q[u+H|0]=q[Q.a+((16-O+E-(O<<2)+R+(D+z)*20>>5)+512)|0];O=R+D|0;H=A[s+K|0]&255;E=R+B|0;q[u+K|0]=q[Q.a+((C+16-O+H-(O<<2)+(B+z)*20>>5)+512)|0];O=H+z|0;C=A[s+L|0]&255;K=H+R|0;q[u+L|0]=q[Q.a+((D+16-O+C-(O<<2)+E*20>>5)+512)|0];L=C+B|0;D=A[s+N|0]&255;q[u+N|0]=q[Q.a+((z+16-L+D-(L<<2)+K*20>>5)+512)|0];G=G+1|0;if((G|0)==(p|0)){break}z=C;E=B;B=D;D=H;C=R}s=s+t|0}w=w+1|0;if((w|0)==(h|0)){break}s=s+j|0;u=v+e|0}if(h>>>0>=4){p=(i|0)==0;r=(o<<2)-i|0;j=64-i|0;t=o<<1;u=o*-2|0;s=h>>>2;w=n+(d+o*5)|0;z=f;e=v+(e-(h<<4))|0;for(B=0;;){if(!p){R=e+i|0;for(G=0;;){var U=G+(e+48)|0,O=G+(e+32)|0,C=G+(e+16)|0,N=e+G|0,Y=t+G|0,X=o+G|0,D=G-o|0,E=A[w+(u+G)|0]&255,H=A[w+D|0]&255,ba=A[w+X|0]&255,K=A[w+G|0]&255,$=ba+E|0,L=A[z+Y|0]&255;q[U]=((A[Q.a+((16-$+(A[w+Y|0]&255)-($<<2)+L+(K+H)*20>>5)+512)|0]&255)+1+(A[U]&255)|0)>>>1&255;U=L+K|0;X=A[z+X|0]&255;q[O]=((A[Q.a+((ba+16-U-(U<<2)+X+(H+E)*20>>5)+512)|0]&255)+1+(A[O]&255)|0)>>>1&255;O=A[z+G|0]&255;ba=X+H|0;q[C]=((A[Q.a+((K+16-ba-(ba<<2)+O+(L+E)*20>>5)+512)|0]&255)+1+(A[C]&255)|0)>>>1&255;C=O+E|0;q[N]=((A[Q.a+((H+16-C-(C<<2)+(A[z+D|0]&255)+(X+L)*20>>5)+512)|0]&255)+1+(A[N]&255)|0)>>>1&255;G=G+1|0;if((G|0)==(i|0)){break}}w=w+i|0;z=z+i|0;e=R}B=B+1|0;if((B|0)==(s|0)){break a}w=w+r|0;z=z+r|0;e=e+j|0}}}}while(0);m=l}zf.X=1;function Af(b,c,d,f,g,e,i,h){var k=m;m+=1788;var l,j=k+444;if((d|0)<0){l=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){l=3}else{if((h+(f+5)|0)>>>0>e>>>0){l=3}else{var n=b,p=d,r=f,o=g;l=4}}}l==3&&(l=i+5|0,sf(b,k,d,f,g,e,l,h+5|0,l),n=k,r=p=0,o=l);b=(h|0)==-5;do{if(b){l=12}else{l=i>>>2;for(var d=(l|0)==0,f=o-i|0,g=i&-4,e=h+5|0,t=j|0,s=n+(p+5+r*o)|0,u=0;;){if(!d){for(var w=t+(g<<2)|0,v=A[s-5|0]&255,z=A[s-4|0]&255,B=A[s-3|0]&255,D=A[s-2|0]&255,C=A[s-1|0]&255,E=0;;){var G=E<<2,H=G|1,K=G|2,L=G|3,N=C+z|0,O=A[s+G|0]&255;y[t+(G<<2)>>2]=v-N-(N<<2)+O+(D+B)*20|0;v=O+B|0;G=A[s+H|0]&255;y[t+(H<<2)>>2]=G+z-v-(v<<2)+(C+D)*20|0;z=G+D|0;H=A[s+K|0]&255;y[t+(K<<2)>>2]=H+B-z-(z<<2)+(O+C)*20|0;B=H+C|0;K=A[s+L|0]&255;y[t+(L<<2)>>2]=K+D-B-(B<<2)+(G+O)*20|0;E=E+1|0;if((E|0)==(l|0)){break}v=C;z=O;B=G;D=H;C=K}t=w;s=s+g|0}u=u+1|0;if((u|0)==(e|0)){break}s=s+f|0}l=h>>>0<4?18:12}}while(0);a:do{if(l==12){n=(i|0)==0;p=64-i|0;r=i*3|0;o=i*-2|0;b=i<<1;d=h>>>2;f=j+(i<<2)|0;g=j+(i*6<<2)|0;e=c;for(t=0;;){if(!n){s=e+i|0;for(u=0;;){if(C=u-i|0,O=u+i|0,L=b+u|0,E=f+(O<<2)|0,w=f+(C<<2)|0,D=F[g+(o+u<<2)>>2],C=F[g+(C<<2)>>2],z=y[g+(O<<2)>>2],B=F[g+(u<<2)>>2],G=z+D|0,O=F[f+(L<<2)>>2],q[u+(e+48)|0]=q[Q.a+((512-G+y[g+(L<<2)>>2]-(G<<2)+O+(B+C)*20>>10)+512)|0],L=O+B|0,E=y[E>>2],q[u+(e+32)|0]=q[Q.a+((z+512-L+E-(L<<2)+(C+D)*20>>10)+512)|0],L=y[f+(u<<2)>>2],z=E+C|0,q[u+(e+16)|0]=q[Q.a+((B+512-z+L-(z<<2)+(O+D)*20>>10)+512)|0],D=L+D|0,q[e+u|0]=q[Q.a+((C+512-D+y[w>>2]-(D<<2)+(E+O)*20>>10)+512)|0],u=u+1|0,(u|0)==(i|0)){break}}f=f+(i<<2)|0;g=g+(i<<2)|0;e=s}t=t+1|0;if((t|0)==(d|0)){break a}f=f+(r<<2)|0;g=g+(r<<2)|0;e=e+p|0}}}while(0);m=k}Af.X=1;function Bf(b,c,d,f,g,e,i,h,k){var l=m;m+=1788;var j,n=l+444;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var p=b,r=d,o=f,t=g;j=4}}}j==3&&(j=i+5|0,sf(b,l,d,f,g,e,j,h+5|0,j),p=l,o=r=0,t=j);b=(h|0)==-5;do{if(b){j=12}else{j=i>>>2;for(var d=(j|0)==0,f=t-i|0,g=i&-4,e=h+5|0,s=n|0,u=p+(r+5+o*t)|0,w=0;;){if(!d){for(var v=s+(g<<2)|0,z=A[u-5|0]&255,B=A[u-4|0]&255,D=A[u-3|0]&255,C=A[u-2|0]&255,E=A[u-1|0]&255,G=0;;){var H=G<<2,K=H|1,L=H|2,N=H|3,O=E+B|0,R=A[u+H|0]&255;y[s+(H<<2)>>2]=z-O-(O<<2)+R+(C+D)*20|0;z=R+D|0;H=A[u+K|0]&255;y[s+(K<<2)>>2]=H+B-z-(z<<2)+(E+C)*20|0;B=H+C|0;K=A[u+L|0]&255;y[s+(L<<2)>>2]=K+D-B-(B<<2)+(R+E)*20|0;D=K+E|0;L=A[u+N|0]&255;y[s+(N<<2)>>2]=L+C-D-(D<<2)+(H+R)*20|0;G=G+1|0;if((G|0)==(j|0)){break}z=E;B=R;D=H;C=K;E=L}s=v;u=u+g|0}w=w+1|0;if((w|0)==(e|0)){break}u=u+f|0}j=h>>>0<4?18:12}}while(0);a:do{if(j==12){p=(i|0)==0;r=64-i|0;o=i*3|0;t=i<<1;b=i*-2|0;d=h>>>2;f=n+(i<<2)|0;g=n+(i*6<<2)|0;e=n+((k+2)*i+i<<2)|0;s=c;for(u=0;;){if(!p){v=e+(i<<2)|0;w=s+i|0;for(C=0;;){if(L=t+C|0,N=C+i|0,B=e+(N<<2)|0,G=C-i|0,E=e+(G<<2)|0,z=f+(N<<2)|0,R=f+(G<<2)|0,D=F[g+(b+C<<2)>>2],G=F[g+(G<<2)>>2],K=F[g+(N<<2)>>2],H=F[g+(C<<2)>>2],O=K+D|0,N=F[f+(L<<2)>>2],q[C+(s+48)|0]=((A[Q.a+((512-O+y[g+(L<<2)>>2]-(O<<2)+N+(H+G)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[e+(L<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255,L=N+H|0,z=F[z>>2],q[C+(s+32)|0]=((A[Q.a+((K+512-L-(L<<2)+z+(G+D)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[B>>2]+16>>5)+512)|0]&255)|0)>>>1&255,B=F[f+(C<<2)>>2],L=z+G|0,q[C+(s+16)|0]=((A[Q.a+((H+512-L-(L<<2)+B+(N+D)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[e+(C<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255,D=B+D|0,q[s+C|0]=((A[Q.a+((G+512-D-(D<<2)+y[R>>2]+(z+N)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[E>>2]+16>>5)+512)|0]&255)|0)>>>1&255,C=C+1|0,(C|0)==(i|0)){break}}f=f+(i<<2)|0;g=g+(i<<2)|0;e=v;s=w}u=u+1|0;if((u|0)==(d|0)){break a}f=f+(o<<2)|0;g=g+(o<<2)|0;e=e+(o<<2)|0;s=s+r|0}}}while(0);m=l}Bf.X=1;function Cf(b,c){var d=b+40|0,f=y[d>>2],g=(f|0)==0;a:do{if(!g){for(var e=b|0,i=b+32|0,h=0,k=f;;){var l=h+1|0,j=F[e>>2];(y[j+h*40+20>>2]-1|0)>>>0<2?(k=F[j+h*40+12>>2],y[j+h*40+8>>2]=k>>>0>c>>>0?k-y[i>>2]|0:k,j=y[d>>2]):j=k;if(l>>>0>=j>>>0){break a}h=l;k=j}}}while(0)}function Df(b,c,d){var d=(d|0)==0,f=F[b+24>>2];b|=0;a:do{if(d){for(var g=0,e=0;;){for(var i=e>>>0>>0;;){if(!(i&(g|0)==0)){var h=g,k=e;break a}var l=y[b>>2];if((y[l+e*40+20>>2]|0)!=3){break}if((y[l+e*40+8>>2]|0)!=(c|0)){break}g=1}e=e+1|0}}else{for(e=g=0;;){for(i=e>>>0>>0;;){if(!(i&(g|0)==0)){h=g;k=e;break a}l=F[b>>2];if((y[l+e*40+20>>2]-1|0)>>>0>=2){break}if((y[l+e*40+8>>2]|0)!=(c|0)){break}g=1}e=e+1|0}}}while(0);return(h|0)==0?-1:k}function Ef(b,c,d,f,g,e,i,h,k){var l=m;m+=1788;var j,n=l+444,p=i+5|0;if((d|0)<0){j=3}else{if((i+(d+5)|0)>>>0>g>>>0|(f|0)<0){j=3}else{if((h+(f+5)|0)>>>0>e>>>0){j=3}else{var r=b,o=d,t=f,s=g;j=4}}}j==3&&(sf(b,l,d,f,g,e,p,h+5|0,p),r=l,t=o=0,s=p);b=o+s+t*s|0;d=h>>>0<4;a:do{if(!d){f=(p|0)==0;g=(s<<2)-i-5|0;e=p*3|0;j=s*-2|0;for(var o=s<<1,t=(i<<1)+10|0,u=-5-i|0,w=h>>>2,v=n+(p<<2)|0,z=r+b|0,B=r+(b+s*5)|0,D=0;;){if(!f){for(var C=v+(p<<2)|0,E=0;;){var G=E-s|0,H=s+E|0,K=o+E|0,L=v+(p+E<<2)|0,N=v+(u+E<<2)|0,O=A[B+(j+E)|0]&255,R=A[B+G|0]&255,U=A[B+H|0]&255,Y=A[B+E|0]&255,X=U+O|0,ba=A[z+K|0]&255;y[v+(t+E<<2)>>2]=(A[B+K|0]&255)-X-(X<<2)+ba+(Y+R)*20|0;K=ba+Y|0;H=A[z+H|0]&255;y[L>>2]=H+U-K-(K<<2)+(R+O)*20|0;L=A[z+E|0]&255;U=H+R|0;y[v+(E<<2)>>2]=L+Y-U-(U<<2)+(ba+O)*20|0;O=L+O|0;y[N>>2]=(A[z+G|0]&255)+R-O-(O<<2)+(H+ba)*20|0;E=E+1|0;if((E|0)==(p|0)){break}}v=C;z=z+p|0;B=B+p|0}D=D+1|0;if((D|0)==(w|0)){break a}v=v+(e<<2)|0;z=z+g|0;B=B+g|0}}}while(0);p=(h|0)==0;a:do{if(!p){r=i>>>2;s=(r|0)==0;b=16-i|0;d=i&-4;f=n+20|0;g=n+(k+2<<2)|0;e=c;for(j=0;;){if(!s){o=g+(d<<2)|0;E=y[f-20>>2];D=y[f-16>>2];v=y[f-12>>2];t=y[f-8>>2];u=y[f-4>>2];for(z=0;;){C=z<<2;N=C|1;G=C|2;B=C|3;R=u+D|0;w=F[f+(C<<2)>>2];q[e+C|0]=((A[Q.a+((E+512-R-(R<<2)+w+(t+v)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(C<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;E=w+v|0;C=F[f+(N<<2)>>2];q[e+N|0]=((A[Q.a+((D+512-E-(E<<2)+C+(u+t)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(N<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;D=C+t|0;N=F[f+(G<<2)>>2];q[e+G|0]=((A[Q.a+((v+512-D-(D<<2)+N+(w+u)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(G<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;v=N+u|0;G=F[f+(B<<2)>>2];q[e+B|0]=((A[Q.a+((t+512-v-(v<<2)+G+(C+w)*20>>10)+512)|0]&255)+1+(A[Q.a+((y[g+(B<<2)>>2]+16>>5)+512)|0]&255)|0)>>>1&255;z=z+1|0;if((z|0)==(r|0)){break}E=u;D=w;v=C;t=N;u=G}f=f+(d<<2)|0;g=o;e=e+d|0}j=j+1|0;if((j|0)==(h|0)){break a}f=f+20|0;g=g+20|0;e=e+b|0}}}while(0);m=l}Ef.X=1;function df(b,c,d,f,g,e,i,h,k){var l=b+((i<<4)+e)|0,j=c|0,n=x[j>>1]<<16>>16,c=c+2|0,p=x[c>>1]<<16>>16,r=d+4|0,o=y[r>>2]<<4,t=d+8|0,s=y[t>>2]<<4,f=e+f|0,u=f+(n>>2)|0,g=i+g|0,w=g+(p>>2)|0,n=y[Ff+((n&3)<<4)+((p&3)<<2)>>2];n==0?sf(y[d>>2],l,u,w,o,s,h,k,16):n==1?wf(y[d>>2],l,u,w-2|0,o,s,h,k,0):n==2?vf(y[d>>2],l,u,w-2|0,o,s,h,k):n==3?wf(y[d>>2],l,u,w-2|0,o,s,h,k,1):n==4?yf(y[d>>2],l,u-2|0,w,o,s,h,k,0):n==5?zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,0):n==6?Ef(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,0):n==7?zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,2):n==8?xf(y[d>>2],l,u-2|0,w,o,s,h,k):n==9?Bf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,0):n==10?Af(y[d>>2],l,u-2|0,w-2|0,o,s,h,k):n==11?Bf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,1):n==12?yf(y[d>>2],l,u-2|0,w,o,s,h,k,1):n==13?zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,1):n==14?Ef(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,1):zf(y[d>>2],l,u-2|0,w-2|0,o,s,h,k,3);b=b+(((i<<2)+256&-8)+(e>>>1))|0;d=y[d>>2];e=y[r>>2];i=y[t>>2];t=e<<3;r=i<<3;l=x[j>>1]<<16>>16;j=(l>>3)+(f>>>1)|0;f=x[c>>1]<<16>>16;c=(f>>3)+(g>>>1)|0;g=l&7;f&=7;h>>>=1;k>>>=1;e=(e<<8)*i|0;i=d+e|0;l=(g|0)!=0;n=(f|0)==0;n|l^1?l?rf(i,b,j,c,t,r,g,h,k):n?(sf(i,b,j,c,t,r,h,k,8),sf(d+(r*t+e)|0,b+64|0,j,c,t,r,h,k,8)):tf(i,b,j,c,t,r,f,h,k):uf(i,b,j,c,t,r,g,f,h,k)}df.X=1;function Gf(b,c,d,f){Cf(b,d);var g=(y[c>>2]|0)==0;a:do{if(g){var e=0}else{var i=b|0,h=b+32|0,k=b+4|0,l=f-1|0,j=0,n=d;b:for(;;){var p=j+2|0,r=j+1|0,o=f-j|0,t=c+4+j*12+4|0,s=c+4+j*12+8|0,u=F[c+4+j*12>>2];if(u>>>0>=3){e=0;break a}u>>>0<2?(s=F[t>>2],(u|0)==0?(s=n-s|0,s=(s|0)<0?y[h>>2]+s|0:s):(s=s+n|0,u=y[h>>2],s=s-((s|0)<(u|0)?0:u)|0),s>>>0>d>>>0?(u=1,t=s-y[h>>2]|0):(u=1,t=s)):(u=0,t=y[s>>2],s=n);u=Df(b,t,u);if((u|0)<0){e=1;break a}t=F[i>>2];if(F[t+u*40+20>>2]>>>0<=1){e=1;break a}if(j>>>0>>0){for(t=0;;){var w=y[k>>2];y[(w+(f-t<<2)|0)>>2]=y[w+(l-t<<2)>>2];t=t+1|0;if((t|0)==(o|0)){break}}o=y[i>>2]}else{o=t}y[(y[k>>2]+(j<<2)|0)>>2]=o+u*40|0;if(r>>>0>f>>>0){j=r,n=s}else{t=r;for(o=0;;){var w=F[k>>2],v=y[w+(r+o<<2)>>2];(v|0)!=(y[i>>2]+u*40|0)&&(y[w+(t<<2)>>2]=v,t=t+1|0);if((p+o|0)>>>0>f>>>0){j=r;n=s;continue b}o=o+1|0}}}}}while(0);return e}Gf.X=1;function Hf(b,c,d,f){var g=F[b+36>>2],g=(g|0)==65535|g>>>0>>0;do{if(g){var e=1}else{var e=b+24|0,i=F[e>>2],h=b|0,k=0;a:for(;;){if(k>>>0>=i>>>0){var l=y[b+40>>2];break}var j=F[h>>2],n=j+k*40+20|0,p=(y[n>>2]|0)==3;do{if(p&&(y[j+k*40+8>>2]|0)==(f|0)){y[n>>2]=0;i=b+40|0;l=y[i>>2]-1|0;y[i>>2]=l;if((y[y[h>>2]+k*40+24>>2]|0)!=0){break a}h=b+44|0;y[h>>2]=y[h>>2]-1|0;break a}}while(0);k=k+1|0}h=b+40|0;l>>>0>2]>>>0?(e=b+8|0,y[(y[e>>2]+12|0)>>2]=c,y[(y[e>>2]+8|0)>>2]=f,y[(y[e>>2]+16|0)>>2]=d,y[(y[e>>2]+20|0)>>2]=3,y[(y[e>>2]+24|0)>>2]=(y[b+56>>2]|0)==0&1,y[h>>2]=y[h>>2]+1|0,e=b+44|0,y[e>>2]=y[e>>2]+1|0,e=0):e=1}}while(0);return e}Hf.X=1;function If(b){var c=b+40|0,d=F[c>>2],f=d>>>0>2]>>>0;do{if(f){var g=0}else{if((d|0)==0){g=1}else{for(var g=b|0,e=F[g>>2],i=d>>>0>1?d:1,h=0,k=-1,l=0;;){if((y[e+l*40+20>>2]-1|0)>>>0<2){var j=F[e+l*40+8>>2];if((j|0)<(h|0)|(k|0)==-1){n=l,h=j}else{var n=k}}else{n=k}l=l+1|0;if((l|0)==(i|0)){break}k=n}(n|0)>-1?(y[e+n*40+20>>2]=0,y[c>>2]=y[c>>2]-1|0,(y[y[g>>2]+n*40+24>>2]|0)==0&&(g=b+44|0,y[g>>2]=y[g>>2]-1|0),g=0):g=1}}}while(0);return g}If.X=1;function gf(b,c){if(c>>>0>16){var d=0}else{d=F[y[b+4>>2]+(c<<2)>>2],d=(d|0)==0?0:F[d+20>>2]>>>0>1?y[d>>2]:0}return d}function Jf(b){var c=y[b>>2],d=y[b+28>>2];y[b+8>>2]=c+d*40|0;return y[c+d*40>>2]}function Kf(b,c,d,f,g,e,i,h){var k,l=b+8|0,j=F[l>>2];if((y[d>>2]|0)==(y[j>>2]|0)){d=b+52|0;y[d>>2]=0;var n=b+56|0,p=(y[n>>2]|0)==0&1,r=(c|0)==0;do{if(r){if(y[j+20>>2]=0,y[(y[l>>2]+12|0)>>2]=f,y[(y[l>>2]+8|0)>>2]=f,y[(y[l>>2]+16|0)>>2]=g,y[(y[l>>2]+24|0)>>2]=p,(y[n>>2]|0)!=0){var o=0}else{o=b+44|0,y[o>>2]=y[o>>2]+1|0,o=0}}else{if((e|0)==0){if((y[c+8>>2]|0)==0){var t=If(b),o=f}else{var t=o=0,s=f;a:for(;;){var u=c+12+t*20+4|0,w=c+12+t*20+12|0,v=y[c+12+t*20>>2];do{if(v==0){var z=0;break a}else{if(v==1){var B;B=b;k=Df(B,s-y[u>>2]|0,1);if((k|0)<0){B=1}else{var D=B|0;y[(y[D>>2]+k*40+20|0)>>2]=0;var C=B+40|0;y[C>>2]=y[C>>2]-1|0;(y[y[D>>2]+k*40+24>>2]|0)==0&&(B=B+44|0,y[B>>2]=y[B>>2]-1|0);B=0}k=20}else{if(v==2){B=b,k=Df(B,y[c+12+t*20+8>>2],0),(k|0)<0?B=1:(D=B|0,y[(y[D>>2]+k*40+20|0)>>2]=0,C=B+40|0,y[C>>2]=y[C>>2]-1|0,(y[y[D>>2]+k*40+24>>2]|0)==0&&(B=B+44|0,y[B>>2]=y[B>>2]-1|0),B=0),k=20}else{if(v==3){B=Lf(b,s,y[u>>2],y[w>>2]),k=20}else{if(v==4){var E=b,G=y[c+12+t*20+16>>2];k=E+36|0;y[k>>2]=G;D=E+24|0;C=(y[D>>2]|0)==0;b:do{if(!C){for(var H=E|0,K=E+40|0,L=E+44|0,N=0,O=y[H>>2];;){var R=N+1|0,U=O+N*40+20|0;if((y[U>>2]|0)==3&&(F[O+N*40+8>>2]>>>0>G>>>0||(y[k>>2]|0)==65535)){y[U>>2]=0,y[K>>2]=y[K>>2]-1|0,O=F[H>>2],(y[O+N*40+24>>2]|0)==0&&(y[L>>2]=y[L>>2]-1|0)}if(R>>>0>=F[D>>2]>>>0){break b}N=R}}}while(0);E=s;G=o;k=21}else{if(v==5){Mf(b),y[d>>2]=1,E=0,G=o,k=21}else{if(v==6){if(k=Hf(b,s,g,y[w>>2]),(k|0)==0){E=s,G=1,k=21}else{var Y=k;k=23}}else{Y=1,k=23}}}}}}}}while(0);if(k==23){z=Y;break}else{if(k==20){if((B|0)!=0){z=B;break}E=s;G=o}}o=G;t=t+1|0;s=E}if((o|0)!=0){o=z;break}o=s;t=z}s=b+40|0;F[s>>2]>>>0>2]>>>0?(y[(y[l>>2]+12|0)>>2]=o,y[(y[l>>2]+8|0)>>2]=o,y[(y[l>>2]+16|0)>>2]=g,y[(y[l>>2]+20|0)>>2]=2,y[(y[l>>2]+24|0)>>2]=p,o=b+44|0,y[o>>2]=y[o>>2]+1|0,y[s>>2]=y[s>>2]+1|0,o=t):o=1}else{o=b+20|0,y[o>>2]=0,t=b+16|0,y[t>>2]=0,Mf(b),k=(y[c>>2]|0)==0?(y[n>>2]|0)==0?8:7:7,k==7&&(y[t>>2]=0,y[o>>2]=0),o=y[l>>2]+20|0,(y[c+4>>2]|0)==0?(y[o>>2]=2,y[b+36>>2]=65535):(y[o>>2]=3,y[b+36>>2]=0),y[(y[l>>2]+12|0)>>2]=0,y[(y[l>>2]+8|0)>>2]=0,y[(y[l>>2]+16|0)>>2]=0,y[(y[l>>2]+24|0)>>2]=p,y[b+44>>2]=1,y[b+40>>2]=1,o=0}}}while(0);y[(y[l>>2]+36|0)>>2]=e;y[(y[l>>2]+28|0)>>2]=i;y[(y[l>>2]+32|0)>>2]=h;c=(y[n>>2]|0)==0;a:do{if(c){if(f=b+44|0,g=b+28|0,e=F[g>>2],F[f>>2]>>>0>e>>>0){for(;;){if(Nf(b),e=F[g>>2],F[f>>2]>>>0<=e>>>0){X=e;break a}}}else{var X=e}}else{X=b+16|0,f=b+12|0,y[(y[f>>2]+(y[X>>2]<<4)|0)>>2]=y[y[l>>2]>>2],y[(y[f>>2]+(y[X>>2]<<4)+12|0)>>2]=y[y[l>>2]+36>>2],y[(y[f>>2]+(y[X>>2]<<4)+4|0)>>2]=y[y[l>>2]+28>>2],y[(y[f>>2]+(y[X>>2]<<4)+8|0)>>2]=y[y[l>>2]+32>>2],y[X>>2]=y[X>>2]+1|0,X=y[b+28>>2]}}while(0);Of(y[b>>2],X+1|0);b=o}else{b=1}return b}Kf.X=1;function Mf(b){for(var c=b|0,d=b+44|0,f=0,g=y[c>>2];;){var e=g+f*40+20|0;(y[e>>2]|0)!=0&&(y[e>>2]=0,g=y[c>>2],(y[g+f*40+24>>2]|0)==0&&(y[d>>2]=y[d>>2]-1|0));f=f+1|0;if((f|0)==16){break}}for(;;){if((Nf(b)|0)!=0){break}}y[b+40>>2]=0;y[b+36>>2]=65535;y[b+48>>2]=0}function Lf(b,c,d,f){var g=F[b+36>>2],g=(g|0)==65535|g>>>0>>0;do{if(g){var e=1}else{var i=F[b+24>>2],e=b|0,h=0;a:for(;;){if(h>>>0>=i>>>0){break}var k=F[e>>2],l=k+h*40+20|0,j=(y[l>>2]|0)==3;do{if(j&&(y[k+h*40+8>>2]|0)==(f|0)){y[l>>2]=0;i=b+40|0;y[i>>2]=y[i>>2]-1|0;if((y[y[e>>2]+h*40+24>>2]|0)!=0){break a}h=b+44|0;y[h>>2]=y[h>>2]-1|0;break a}}while(0);h=h+1|0}h=Df(b,c-d|0,1);(h|0)<0?e=1:(i=y[e>>2]+h*40+20|0,F[i>>2]>>>0>1?(y[i>>2]=3,y[(y[e>>2]+h*40+8|0)>>2]=f,e=0):e=1)}}while(0);return e}Lf.X=1;function Nf(b){if((y[b+56>>2]|0)==0){var c;c=y[b>>2];for(var d=2147483647,f=0,g=0;;){var e=c+f*40|0,i=f+1|0;(y[c+f*40+24>>2]|0)==0?e=g:(f=y[c+f*40+16>>2],(f|0)<(d|0)?d=f:e=g);if(i>>>0>y[b+28>>2]>>>0){break}f=i;g=e}c=e;(c|0)==0?b=1:(i=b+16|0,d=b+12|0,y[(y[d>>2]+(y[i>>2]<<4)|0)>>2]=y[c>>2],y[(y[d>>2]+(y[i>>2]<<4)+12|0)>>2]=y[c+36>>2],y[(y[d>>2]+(y[i>>2]<<4)+4|0)>>2]=y[c+28>>2],y[(y[d>>2]+(y[i>>2]<<4)+8|0)>>2]=y[c+32>>2],y[i>>2]=y[i>>2]+1|0,y[(c+24|0)>>2]=0,(y[c+20>>2]|0)==0&&(b=b+44|0,y[b>>2]=y[b>>2]-1|0),b=0)}else{b=1}return b}Nf.X=1;function Of(b,c){var d=m;m+=40;for(var f=7,g=0;;){var e=f>>>0>>0;a:do{if(e){for(var i=c-f|0,h=-f|0,k=0;;){for(var l=f+k|0,j=(b+l*40|0)>>2,n=d>>2,p=j+10;j>>0>>0){break}if((Pf(j,d)|0)<=0){break}j>>=2;n=o>>2;for(p=j+10;j>2;n=o>>2;for(p=j+10;j>>=1}m=d}function Fe(b,c,d,f,g,e){y[b+36>>2]=65535;var i=f>>>0>1?f:1;y[b+24>>2]=i;f=b+28|0;y[f>>2]=(e|0)==0?d:i;y[b+32>>2]=g;y[b+56>>2]=e;y[b+44>>2]=0;y[b+40>>2]=0;y[b+48>>2]=0;d=jc(680);g=b|0;y[g>>2]=d;e=(d|0)==0;a:do{if(e){i=65535}else{Pc(d,0,680);for(var i=c*384|47,h=0;;){if(h>>>0>=(y[f>>2]+1|0)>>>0){break}var k=jc(i);y[(y[g>>2]+h*40+4|0)>>2]=k;var k=F[g>>2],l=y[k+h*40+4>>2];if((l|0)==0){i=65535;break a}y[k+h*40>>2]=l+(-l&15)|0;h=h+1|0}h=jc(68);i=b+4|0;y[i>>2]=h;h=jc((y[f>>2]<<4)+16|0);y[b+12>>2]=h;i=y[i>>2];(i|0)==0|(h|0)==0?i=65535:(Pc(i,0,68),y[b+20>>2]=0,i=y[b+16>>2]=0)}}while(0);return i}Fe.X=1;function Qf(b){var c=b+40|0,d=(y[c>>2]|0)==0;a:do{if(!d){for(var f=b|0,g=b+4|0,e=0;;){var i=e+1|0;y[(y[g>>2]+(e<<2)|0)>>2]=y[f>>2]+e*40|0;if(i>>>0>=F[c>>2]>>>0){break a}e=i}}}while(0)}function Pf(b,c){var d=F[b+20>>2],f=(d|0)==0,g=F[c+20>>2],e=(g|0)==0;a:do{if(f){if(e){var i=(y[c+24>>2]|0)==0;if((y[b+24>>2]|0)==0){if(!i){i=1;break}}else{if(i){i=-1;break}}i=0}else{i=1}}else{if(e){i=-1}else{do{if(d==0){i=1;break a}else{if((d==1||d==2)&&(g-1|0)>>>0<2){d=y[b+8>>2];f=y[c+8>>2];if((d|0)>(f|0)){i=-1;break a}i=(d|0)<(f|0)&1;break a}}}while(0);if((d-1|0)>>>0<2){i=-1}else{if((g-1|0)>>>0<2){i=1}else{var i=y[b+8>>2],h=y[c+8>>2],i=(i|0)>(h|0)?1:((i|0)<(h|0))<<31>>31}}}}}while(0);return i}Pf.X=1;function rd(b,c){for(var d=y[b+4>>2],f=y[b+12>>2],g=y[b+16>>2],e=y[b+20>>2],i=d<<4,h=0;;){var k=i*h|0,l=f+(k|4)|0,j=f+(k|8)|0,n=f+(k|12)|0,p=h<<4,r=c+(p|8)|0,o=c+(p|12)|0,t=y[c+(p|4)>>2];y[(f+k|0)>>2]=y[c+p>>2];y[l>>2]=t;k=y[o>>2];y[j>>2]=y[r>>2];y[n>>2]=k;h=h+1|0;if((h|0)==16){break}}f=d<<3;h=y[c+260>>2];y[g>>2]=y[c+256>>2];y[(g+4|0)>>2]=h;h=f|4;j=y[c+268>>2];y[(g+f|0)>>2]=y[c+264>>2];y[(g+h|0)>>2]=j;j=i|4;n=y[c+276>>2];y[(g+i|0)>>2]=y[c+272>>2];y[(g+j|0)>>2]=n;n=d*24|0;r=n|4;k=y[c+284>>2];y[(g+n|0)>>2]=y[c+280>>2];y[(g+r|0)>>2]=k;k=d<<5;l=k|4;p=y[c+292>>2];y[(g+k|0)>>2]=y[c+288>>2];y[(g+l|0)>>2]=p;p=d*40|0;o=p|4;t=y[c+300>>2];y[(g+p|0)>>2]=y[c+296>>2];y[(g+o|0)>>2]=t;var t=d*48|0,s=t|4,u=y[c+308>>2];y[(g+t|0)>>2]=y[c+304>>2];y[(g+s|0)>>2]=u;var d=d*56|0,u=d|4,w=y[c+316>>2];y[(g+d|0)>>2]=y[c+312>>2];y[(g+u|0)>>2]=w;g=y[c+324>>2];y[e>>2]=y[c+320>>2];y[(e+4|0)>>2]=g;g=y[c+332>>2];y[(e+f|0)>>2]=y[c+328>>2];y[(e+h|0)>>2]=g;g=y[c+340>>2];y[(e+i|0)>>2]=y[c+336>>2];y[(e+j|0)>>2]=g;i=y[c+348>>2];y[(e+n|0)>>2]=y[c+344>>2];y[(e+r|0)>>2]=i;i=y[c+356>>2];y[(e+k|0)>>2]=y[c+352>>2];y[(e+l|0)>>2]=i;i=y[c+364>>2];y[(e+p|0)>>2]=y[c+360>>2];y[(e+o|0)>>2]=i;i=y[c+372>>2];y[(e+t|0)>>2]=y[c+368>>2];y[(e+s|0)>>2]=i;i=y[c+380>>2];y[(e+d|0)>>2]=y[c+376>>2];y[(e+u|0)>>2]=i}rd.X=1;function Ee(b){var c=b|0,d=F[c>>2],f=(d|0)==0;a:do{if(f){var g=0}else{var e=b+28|0;if((y[e>>2]|0)==-1){g=d}else{for(var i=0,h=d;;){var k=i+1|0;Ae(y[h+i*40+4>>2]);y[(y[c>>2]+i*40+4|0)>>2]=0;h=y[c>>2];if(k>>>0>=(y[e>>2]+1|0)>>>0){g=h;break a}i=k}}}}while(0);Ae(g);y[c>>2]=0;c=b+4|0;Ae(y[c>>2]);y[c>>2]=0;b=b+12|0;Ae(y[b>>2]);y[b>>2]=0}function Rf(b,c,d,f){var g,e=b+16|0;y[e>>2]=0;y[b+20>>2]=0;f=(f|0)==0;a:do{if(f){var i=0}else{var h=b+48|0,k=F[h>>2],l=(k|0)==(c|0);do{if(l){g=17}else{var j=b+32|0,n=((k+1|0)>>>0)%(F[j>>2]>>>0);if((n|0)==(c|0)){g=17}else{g=b+28|0;for(var p=b|0,r=y[y[p>>2]+y[g>>2]*40>>2],o=b+44|0,t=b+40|0;;){Cf(b,n);if((If(b)|0)!=0){i=1;break a}var s=F[g>>2],u=F[o>>2]>>>0>>0;b:do{if(u){var w=s}else{for(;;){Nf(b);var v=F[g>>2];if(F[o>>2]>>>0>>0){w=v;break b}}}}while(0);y[(y[p>>2]+w*40+20|0)>>2]=1;y[(y[p>>2]+y[g>>2]*40+12|0)>>2]=n;y[(y[p>>2]+y[g>>2]*40+8|0)>>2]=n;y[(y[p>>2]+y[g>>2]*40+16|0)>>2]=0;y[(y[p>>2]+y[g>>2]*40+24|0)>>2]=0;y[o>>2]=y[o>>2]+1|0;y[t>>2]=y[t>>2]+1|0;Of(y[p>>2],y[g>>2]+1|0);n=((n+1|0)>>>0)%(F[j>>2]>>>0);if((n|0)==(c|0)){break}}j=F[e>>2];o=(j|0)==0;b:do{if(!o){t=b+12|0;for(n=0;;){if(n>>>0>=j>>>0){break b}var z=F[g>>2],B=F[p>>2],D=F[B+z*40>>2];if((y[y[t>>2]+(n<<4)>>2]|0)==(D|0)){var C=0;break}n=n+1|0}for(;;){if(C>>>0>=z>>>0){break b}var E=B+C*40|0;if((y[E>>2]|0)==(r|0)){break}C=C+1|0}y[E>>2]=D;y[(y[p>>2]+y[g>>2]*40|0)>>2]=r}}while(0);if((d|0)!=0){g=21}else{var G=y[h>>2];g=22}}}}while(0);do{if(g==17){if((d|0)==0){G=k,g=22}else{if(l){i=1;break a}g=21}}}while(0);g==22?((G|0)!=(c|0)&&(i=F[b+32>>2],y[h>>2]=((c-1+i|0)>>>0)%(i>>>0)),i=0):g==21&&(y[h>>2]=c,i=0)}}while(0);return i}Rf.X=1;function jf(b,c,d,f){for(var g=F[b+4>>2],e=y[b+8>>2]*g|0,i=(c>>>0)%(g>>>0),h=F[b>>2],k=c-i|0,l=e<<8,j=i<<3,n=g<<4,p=(k<<8)+(i<<4)|0,r=g<<2&1073741820,o=r<<1,t=o+r|0,s=c<<8,u=i*240|0,w=(s|1)-u|0,v=(s|2)-u|0,z=(s|3)-u|0,B=s-u|0,D=0;;){var C=y[$e+(D<<2)>>2],E=y[Ze+(D<<2)>>2],G=E<<4,H=G+C|0,K=(y[f+(D<<6)>>2]|0)==16777215;a:do{if(K){var L=h+(p+C+E*n)|0,N=y[H+(d+16)>>2],O=H+(d+32)|0;y[L>>2]=y[d+H>>2];y[(L+(r<<2)|0)>>2]=N;var R=y[H+(d+48)>>2];y[(L+(o<<2)|0)>>2]=y[O>>2];y[(L+(t<<2)|0)>>2]=R}else{for(var U=n*E|0,Y=w+C+U|0,X=v+C+U|0,ba=z+C+U|0,$=B+C+U|0,ja=G+(C+1)|0,sa=G+(C+2)|0,Ea=G+(C+3)|0,Xa=C+G|0,ea=0;;){var fa=ea<<2,va=f+(D<<6)+((fa|3)<<2)|0,ob=f+(D<<6)+((fa|2)<<2)|0,wa=n*ea|0,pb=h+(Y+wa)|0,gb=h+(X+wa)|0,Ib=h+(ba+wa)|0,Fa=ea<<4,qb=d+(sa+Fa)|0,Ya=d+(Ea+Fa)|0,Na=A[d+(ja+Fa)|0]&255,za=y[f+(D<<6)+((fa|1)<<2)>>2];q[h+($+wa)|0]=q[Q.a+(y[f+(D<<6)+(fa<<2)>>2]+512+(A[d+(Xa+Fa)|0]&255))|0];var da=A[qb]&255,Oa=y[ob>>2];q[pb]=q[Q.a+((Na|512)+za)|0];var Za=A[Ya]&255,Aa=y[va>>2];q[gb]=q[Q.a+(da+(Oa+512))|0];q[Ib]=q[Q.a+(Za+(Aa+512))|0];var hb=ea+1|0;if((hb|0)==4){break a}ea=hb}}}while(0);var Ga=D+1|0;if((Ga|0)==16){break}D=Ga}for(var Pa=e<<6,$a=g<<3&2147483640,Ab=d+256|0,cb=d+320|0,rb=l+j+(k<<6)|0,Qa=$a>>>2,pa=$a>>>1,ia=pa+Qa|0,qa=l+(c<<6)|0,Ra=i*56|0,ra=(qa|1)-Ra|0,ib=(qa|2)-Ra|0,sb=(qa|3)-Ra|0,jb=qa-Ra|0,db=0;;){var Sa=db+16|0,kb=Sa&3,ta=F[$e+(kb<<2)>>2],Bb=F[Ze+(kb<<2)>>2],Ha=Sa>>>0>19,ya=Ha?cb:Ab,xa=Ha?Pa:0,Ba=Bb<<3,Ca=Ba+ta|0,Ta=(y[f+(Sa<<6)>>2]|0)==16777215;a:do{if(Ta){var lb=h+(rb+xa+ta+Bb*$a)|0,Jb=y[Ca+(ya+8)>>2],eb=Ca+(ya+16)|0;y[lb>>2]=y[ya+Ca>>2];y[(lb+(Qa<<2)|0)>>2]=Jb;var Da=y[Ca+(ya+24)>>2];y[(lb+(pa<<2)|0)>>2]=y[eb>>2];y[(lb+(ia<<2)|0)>>2]=Da}else{for(var Ia=$a*Bb|0,mb=ra+xa+ta+Ia|0,Ua=ib+xa+ta+Ia|0,Ja=sb+xa+ta+Ia|0,Ka=jb+xa+ta+Ia|0,Cb=Ba+(ta+1)|0,Db=Ba+(ta+2)|0,Eb=Ba+(ta+3)|0,tb=ta+Ba|0,Va=0;;){var fb=Va<<2,ub=f+(Sa<<6)+((fb|3)<<2)|0,nb=f+(Sa<<6)+((fb|2)<<2)|0,Fb=$a*Va|0,Qb=h+(mb+Fb)|0,wb=h+(Ua+Fb)|0,Lb=h+(Ja+Fb)|0,Rb=Va<<3,Wb=ya+(Db+Rb)|0,Tb=ya+(Eb+Rb)|0,Xb=A[ya+(Cb+Rb)|0]&255,Vb=y[f+(Sa<<6)+((fb|1)<<2)>>2];q[h+(Ka+Fb)|0]=q[Q.a+(y[f+(Sa<<6)+(fb<<2)>>2]+512+(A[ya+(tb+Rb)|0]&255))|0];var Yb=A[Wb]&255,fc=y[nb>>2];q[Qb]=q[Q.a+((Xb|512)+Vb)|0];var ga=A[Tb]&255,pc=y[ub>>2];q[wb]=q[Q.a+(Yb+(fc+512))|0];q[Lb]=q[Q.a+(ga+(pc+512))|0];var Ub=Va+1|0;if((Ub|0)==4){break a}Va=Ub}}}while(0);var Fc=db+1|0;if((Fc|0)==8){break}db=Fc}}jf.X=1;function Sf(b,c){var d=m;m+=164;var f=d+128,g=y[b+4>>2],e=b|0,i=b+8|0,h=y[i>>2],k=h*g|0,h=(h|0)==0;a:do{if(!h){for(var l=d|0,j=f|0,n=g<<4,p=k<<8,r=k<<6,o=g<<3,t=0,s=0,u=0;;){var w=c+u*216|0,v=c+u*216+24|0,z,B=y[w+8>>2];if((B|0)==1){B=0}else{z=y[w+200>>2];z=(z|0)==0?1:(B|0)==2&&((y[w+4>>2]|0)!=(y[z+4>>2]|0)&1|0)!=0?1:5;var D=y[w+204>>2],B=(D|0)==0?z:(B|0)==2&&((y[w+4>>2]|0)!=(y[D+4>>2]|0)&1|0)!=0?z:z|2}z=B;(z|0)!=0&&(Tf(w,l,z)|0)!=0&&(Uf(j,w,z),B=t*g|0,Vf(y[e>>2]+((B<<8)+(s<<4))|0,l,j,n),Wf(j,w,z,y[v>>2]),w=y[e>>2],v=(s<<3)+p+(B<<6)|0,Xf(w+v|0,w+(v+r)|0,l,j,o));s=s+1|0;w=(s|0)==(g|0);t=(w&1)+t|0;s=w?0:s;if(t>>>0>=F[i>>2]>>>0){break a}u=u+1|0}}}while(0);m=d}Sf.X=1;function Tf(b,c,d){var f=(d&2|0)==0;a:do{if(f){y[c+24>>2]=0;y[c+16>>2]=0;y[c+8>>2]=0;var g=y[c>>2]=0}else{var e=F[b>>2]>>>0>5;do{if(!e){var g=b+204|0,i=F[g>>2];if(F[i>>2]>>>0<=5){f=Yf(b,i,0,10);y[c>>2]=f;e=Yf(b,y[g>>2],1,11);y[c+8>>2]=e;i=Yf(b,y[g>>2],4,14);y[c+16>>2]=i;g=Yf(b,y[g>>2],5,15);y[c+24>>2]=g;if((f|e|0)==0&&(i|g|0)==0){g=0;break a}g=1;break a}}}while(0);y[c+24>>2]=4;y[c+16>>2]=4;y[c+8>>2]=4;y[c>>2]=4;g=1}}while(0);e=(d&4|0)==0;a:do{if(e){y[c+100>>2]=0,y[c+68>>2]=0,y[c+36>>2]=0,y[c+4>>2]=0,d=g,f=b|0}else{f=b|0;i=F[f>>2]>>>0>5;do{if(!i){var d=b+200|0,h=F[d>>2];if(F[h>>2]>>>0<=5){e=Yf(b,h,0,5);y[c+4>>2]=e;i=Yf(b,y[d>>2],2,7);y[c+36>>2]=i;h=Yf(b,y[d>>2],8,13);y[c+68>>2]=h;d=Yf(b,y[d>>2],10,15);y[c+100>>2]=d;if((g|0)!=0){d=g;break a}if((e|i|0)==0&&(h|d|0)==0){d=g;break a}d=1;break a}}}while(0);y[c+100>>2]=4;y[c+68>>2]=4;y[c+36>>2]=4;y[c+4>>2]=4;d=1}}while(0);g=F[f>>2];f=g>>>0>5;a:do{if(f){y[c+120>>2]=3,y[c+112>>2]=3,y[c+104>>2]=3,y[c+96>>2]=3,y[c+88>>2]=3,y[c+80>>2]=3,y[c+72>>2]=3,y[c+64>>2]=3,y[c+56>>2]=3,y[c+48>>2]=3,y[c+40>>2]=3,y[c+32>>2]=3,y[c+124>>2]=3,y[c+116>>2]=3,y[c+108>>2]=3,y[c+92>>2]=3,y[c+84>>2]=3,y[c+76>>2]=3,y[c+60>>2]=3,y[c+52>>2]=3,y[c+44>>2]=3,y[c+28>>2]=3,y[c+20>>2]=3,y[c+12>>2]=3,e=1}else{if((cd(g)|0)==1){Zf(b,c)}else{if(g==2){var k=b+32|0;y[c+32>>2]=x[k>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var l=b+34|0;y[c+40>>2]=x[l>>1]<<16>>16==0?x[b+30>>1]<<16>>16!=0?2:0:2;var j=b+40|0;y[c+48>>2]=x[j>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;var n=b+42|0;y[c+56>>2]=x[n>>1]<<16>>16==0?x[b+38>>1]<<16>>16!=0?2:0:2;e=b+48|0;y[c+96>>2]=x[e>>1]<<16>>16==0?x[b+44>>1]<<16>>16!=0?2:0:2;i=b+50|0;y[c+104>>2]=x[i>>1]<<16>>16==0?x[b+46>>1]<<16>>16!=0?2:0:2;h=b+56|0;y[c+112>>2]=x[h>>1]<<16>>16==0?x[b+52>>1]<<16>>16!=0?2:0:2;var p=b+58|0;y[c+120>>2]=x[p>>1]<<16>>16==0?x[b+54>>1]<<16>>16!=0?2:0:2;var r=$f(b,8,2);y[c+64>>2]=r;r=$f(b,9,3);y[c+72>>2]=r;r=$f(b,12,6);y[c+80>>2]=r;r=$f(b,13,7);y[c+88>>2]=r;r=b+30|0;y[c+12>>2]=x[r>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var o=b+36|0;y[c+20>>2]=x[o>>1]<<16>>16==0?x[r>>1]<<16>>16!=0?2:0:2;y[c+28>>2]=x[b+38>>1]<<16>>16==0?x[o>>1]<<16>>16!=0?2:0:2;y[c+44>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+52>>2]=x[j>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;y[c+60>>2]=x[n>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;k=b+46|0;y[c+76>>2]=x[k>>1]<<16>>16==0?x[b+44>>1]<<16>>16!=0?2:0:2;l=b+52|0;y[c+84>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+92>>2]=x[b+54>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;y[c+108>>2]=x[i>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;y[c+116>>2]=x[h>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;y[c+124>>2]=x[p>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2}else{if(g==3){e=b+32|0;y[c+32>>2]=x[e>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;i=b+34|0;y[c+40>>2]=x[i>>1]<<16>>16==0?x[b+30>>1]<<16>>16!=0?2:0:2;h=b+40|0;y[c+48>>2]=x[h>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;p=b+42|0;y[c+56>>2]=x[p>>1]<<16>>16==0?x[b+38>>1]<<16>>16!=0?2:0:2;k=b+44|0;y[c+64>>2]=x[k>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;l=b+46|0;y[c+72>>2]=x[l>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;j=b+52|0;y[c+80>>2]=x[j>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;n=b+54|0;y[c+88>>2]=x[n>>1]<<16>>16==0?x[p>>1]<<16>>16!=0?2:0:2;r=b+48|0;y[c+96>>2]=x[r>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;o=b+50|0;y[c+104>>2]=x[o>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;var t=b+56|0;y[c+112>>2]=x[t>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;var s=b+58|0;y[c+120>>2]=x[s>>1]<<16>>16==0?x[n>>1]<<16>>16!=0?2:0:2;y[c+12>>2]=x[b+30>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;y[c+28>>2]=x[b+38>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;y[c+44>>2]=x[i>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;y[c+60>>2]=x[p>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;y[c+76>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+92>>2]=x[n>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;y[c+108>>2]=x[o>>1]<<16>>16==0?x[r>>1]<<16>>16!=0?2:0:2;y[c+124>>2]=x[s>>1]<<16>>16==0?x[t>>1]<<16>>16!=0?2:0:2;e=$f(b,4,1);y[c+20>>2]=e;e=$f(b,6,3);y[c+52>>2]=e;e=$f(b,12,9);y[c+84>>2]=e;e=$f(b,14,11);y[c+116>>2]=e}else{e=$f(b,2,0),y[c+32>>2]=e,e=$f(b,3,1),y[c+40>>2]=e,e=$f(b,6,4),y[c+48>>2]=e,e=$f(b,7,5),y[c+56>>2]=e,e=$f(b,8,2),y[c+64>>2]=e,e=$f(b,9,3),y[c+72>>2]=e,e=$f(b,12,6),y[c+80>>2]=e,e=$f(b,13,7),y[c+88>>2]=e,e=$f(b,10,8),y[c+96>>2]=e,e=$f(b,11,9),y[c+104>>2]=e,e=$f(b,14,12),y[c+112>>2]=e,e=$f(b,15,13),y[c+120>>2]=e,e=$f(b,1,0),y[c+12>>2]=e,e=$f(b,4,1),y[c+20>>2]=e,e=$f(b,5,4),y[c+28>>2]=e,e=$f(b,3,2),y[c+44>>2]=e,e=$f(b,6,3),y[c+52>>2]=e,e=$f(b,7,6),y[c+60>>2]=e,e=$f(b,9,8),y[c+76>>2]=e,e=$f(b,12,9),y[c+84>>2]=e,e=$f(b,13,12),y[c+92>>2]=e,e=$f(b,11,10),y[c+108>>2]=e,e=$f(b,14,11),y[c+116>>2]=e,e=$f(b,15,14),y[c+124>>2]=e}}}if((d|0)!=0){e=d}else{e=(y[c+32>>2]|0)==0;do{if(e&&(y[c+40>>2]|0)==0&&(y[c+48>>2]|0)==0&&(y[c+56>>2]|0)==0&&(y[c+64>>2]|0)==0&&(y[c+72>>2]|0)==0&&(y[c+80>>2]|0)==0&&(y[c+88>>2]|0)==0&&(y[c+96>>2]|0)==0&&(y[c+104>>2]|0)==0&&(y[c+112>>2]|0)==0&&(y[c+120>>2]|0)==0&&(y[c+12>>2]|0)==0&&(y[c+20>>2]|0)==0&&(y[c+28>>2]|0)==0&&(y[c+44>>2]|0)==0&&(y[c+52>>2]|0)==0&&(y[c+60>>2]|0)==0&&(y[c+76>>2]|0)==0&&(y[c+84>>2]|0)==0&&(y[c+92>>2]|0)==0&&(y[c+108>>2]|0)==0&&(y[c+116>>2]|0)==0&&(y[c+124>>2]|0)==0){e=d;break a}}while(0);e=1}}}while(0);return e}Tf.X=1;function Zf(b,c){var d=b+32|0;y[c+32>>2]=x[d>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var f=b+34|0;y[c+40>>2]=x[f>>1]<<16>>16==0?x[b+30>>1]<<16>>16!=0?2:0:2;var g=b+40|0;y[c+48>>2]=x[g>>1]<<16>>16==0?x[b+36>>1]<<16>>16!=0?2:0:2;var e=b+42|0;y[c+56>>2]=x[e>>1]<<16>>16==0?x[b+38>>1]<<16>>16!=0?2:0:2;var i=b+44|0;y[c+64>>2]=x[i>>1]<<16>>16==0?x[d>>1]<<16>>16!=0?2:0:2;var h=b+46|0;y[c+72>>2]=x[h>>1]<<16>>16==0?x[f>>1]<<16>>16!=0?2:0:2;var k=b+52|0;y[c+80>>2]=x[k>>1]<<16>>16==0?x[g>>1]<<16>>16!=0?2:0:2;var l=b+54|0;y[c+88>>2]=x[l>>1]<<16>>16==0?x[e>>1]<<16>>16!=0?2:0:2;var j=b+48|0;y[c+96>>2]=x[j>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;var n=b+50|0;y[c+104>>2]=x[n>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;var p=b+56|0;y[c+112>>2]=x[p>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;var r=b+58|0;y[c+120>>2]=x[r>>1]<<16>>16==0?x[l>>1]<<16>>16!=0?2:0:2;var o=b+30|0;y[c+12>>2]=x[o>>1]<<16>>16==0?x[b+28>>1]<<16>>16!=0?2:0:2;var t=b+36|0;y[c+20>>2]=x[t>>1]<<16>>16==0?x[o>>1]<<16>>16!=0?2:0:2;y[c+28>>2]=x[b+38>>1]<<16>>16==0?x[t>>1]<<16>>16!=0?2:0:2;y[c+44>>2]=x[f>>1]<<16>>16==0?x[d>>1]<<16>>16!=0?2:0:2;y[c+52>>2]=x[g>>1]<<16>>16==0?x[f>>1]<<16>>16!=0?2:0:2;y[c+60>>2]=x[e>>1]<<16>>16==0?x[g>>1]<<16>>16!=0?2:0:2;y[c+76>>2]=x[h>>1]<<16>>16==0?x[i>>1]<<16>>16!=0?2:0:2;y[c+84>>2]=x[k>>1]<<16>>16==0?x[h>>1]<<16>>16!=0?2:0:2;y[c+92>>2]=x[l>>1]<<16>>16==0?x[k>>1]<<16>>16!=0?2:0:2;y[c+108>>2]=x[n>>1]<<16>>16==0?x[j>>1]<<16>>16!=0?2:0:2;y[c+116>>2]=x[p>>1]<<16>>16==0?x[n>>1]<<16>>16!=0?2:0:2;y[c+124>>2]=x[r>>1]<<16>>16==0?x[p>>1]<<16>>16!=0?2:0:2}Zf.X=1;function Uf(b,c,d){var f=F[c+20>>2],g=c+12|0,e=Cc(0,51,y[g>>2]+f|0),i=c+16|0,h=Cc(0,51,y[i>>2]+f|0),k=A[Q.f+e|0]&255;y[b+28>>2]=k;h=A[Q.g+h|0]&255;y[b+32>>2]=h;e=Q.h+e*3|0;y[b+24>>2]=e;if((d&2|0)!=0){var l=y[y[c+204>>2]+20>>2];if((l|0)==(f|0)){y[b+4>>2]=k,y[b+8>>2]=h,y[b>>2]=e}else{var j=(l+(f+1)|0)>>>1,l=Cc(0,51,y[g>>2]+j|0),j=Cc(0,51,y[i>>2]+j|0);y[b+4>>2]=A[Q.f+l|0]&255;y[b+8>>2]=A[Q.g+j|0]&255;y[b>>2]=Q.h+l*3|0}}(d&4|0)!=0&&(c=y[y[c+200>>2]+20>>2],(c|0)==(f|0)?(y[b+16>>2]=k,y[b+20>>2]=h,y[b+12>>2]=e):(f=(c+(f+1)|0)>>>1,g=Cc(0,51,y[g>>2]+f|0),i=Cc(0,51,y[i>>2]+f|0),y[b+16>>2]=A[Q.f+g|0]&255,y[b+20>>2]=A[Q.g+i|0]&255,y[b+12>>2]=Q.h+g*3|0))}Uf.X=1;function Vf(b,c,d,f){for(var g,e=d+24|0,i=d+12|0,h=f<<2,k=0,l=0;;){var j=h*l|0,n=b+j|0,p=j+(b+4)|0,r=j+(b+8)|0,j=j+(b+12)|0,o=l<<2,t=c+(o<<3)|0,s=o|1,u=c+(s<<3)+4|0,w=o|2;g=c+(w<<3)+4|0;var v=o|3,z=c+(v<<3)+4|0,s=c+(s<<3)|0,w=c+(w<<3)|0,v=c+(v<<3)|0,o=y[c+(o<<3)+4>>2];(o|0)!=0&&ag(n,o,i,f);u=y[u>>2];(u|0)!=0&&ag(p,u,e,f);g=y[g>>2];(g|0)!=0&&ag(r,g,e,f);z=y[z>>2];(z|0)!=0&&ag(j,z,e,f);t=y[t>>2];z=y[s>>2];(t|0)==(z|0)?(g=y[w>>2],(z|0)!=(g|0)?g=14:(g|0)!=(y[v>>2]|0)?g=14:((t|0)!=0&&bg(n,t,d+k*12|0,f),g=22)):g=14;g==14&&((t|0)==0?n=z:(cg(n,t,d+k*12|0,f),n=y[s>>2]),(n|0)!=0&&cg(p,n,d+k*12|0,f),p=y[w>>2],(p|0)!=0&&cg(r,p,d+k*12|0,f),r=y[v>>2],(r|0)!=0&&cg(j,r,d+k*12|0,f));l=l+1|0;if((l|0)==4){break}k=2}}Vf.X=1;function Wf(b,c,d,f){var g=c+20|0,e=F[Ad+(Cc(0,51,y[g>>2]+f|0)<<2)>>2],i=c+12|0,h=Cc(0,51,y[i>>2]+e|0),k=c+16|0,l=Cc(0,51,y[k>>2]+e|0),j=A[Q.f+h|0]&255;y[b+28>>2]=j;l=A[Q.g+l|0]&255;y[b+32>>2]=l;h=Q.h+h*3|0;y[b+24>>2]=h;if((d&2|0)!=0){var n=y[y[c+204>>2]+20>>2];if((n|0)==(y[g>>2]|0)){y[b+4>>2]=j,y[b+8>>2]=l,y[b>>2]=h}else{var p=(e+1+y[Ad+(Cc(0,51,n+f|0)<<2)>>2]|0)>>>1,n=Cc(0,51,p+y[i>>2]|0),p=Cc(0,51,y[k>>2]+p|0);y[b+4>>2]=A[Q.f+n|0]&255;y[b+8>>2]=A[Q.g+p|0]&255;y[b>>2]=Q.h+n*3|0}}(d&4|0)!=0&&(c=y[y[c+200>>2]+20>>2],(c|0)==(y[g>>2]|0)?(y[b+16>>2]=j,y[b+20>>2]=l,y[b+12>>2]=h):(f=(e+1+y[Ad+(Cc(0,51,c+f|0)<<2)>>2]|0)>>>1,i=Cc(0,51,f+y[i>>2]|0),k=Cc(0,51,y[k>>2]+f|0),y[b+16>>2]=A[Q.f+i|0]&255,y[b+20>>2]=A[Q.g+k|0]&255,y[b+12>>2]=Q.h+i*3|0))}Wf.X=1;function Xf(b,c,d,f,g){for(var e,i=f+24|0,h=f+12|0,k=g<<2,l=g<<1,j=l+4|0,n=0,p=0;;){var r=k*n|0,o=b+r|0,t=l+r|0,s=b+t|0,u=r+4|0,w=b+u|0,v=r|2,z=b+v|0,B=r+6|0,D=b+B|0,C=j+r|0,E=b+C|0,r=c+r|0;e=c+t|0;var u=c+u|0,v=c+v|0,B=c+B|0,G=c+C|0,C=n<<3,H=d+(C<<3)+4|0,K=d+(C<<3)|0,L=d+((C|4)<<3)+4|0,t=C|2,N=d+(t<<3)+4|0,O=d+((C|6)<<3)+4|0,R=d+((C|1)<<3)|0,t=d+(t<<3)|0,C=d+((C|3)<<3)|0,U=y[H>>2];(U|0)!=0&&(dg(o,U,h,g),dg(r,y[H>>2],h,g));H=y[L>>2];(H|0)!=0&&(dg(s,H,h,g),dg(e,y[L>>2],h,g));s=y[N>>2];(s|0)!=0&&(dg(w,s,i,g),dg(u,y[N>>2],i,g));s=y[O>>2];(s|0)!=0&&(dg(E,s,i,g),dg(G,y[O>>2],i,g));E=y[K>>2];s=y[R>>2];(E|0)==(s|0)?(e=y[t>>2],(s|0)!=(e|0)?e=14:(e|0)!=(y[C>>2]|0)?e=14:((E|0)!=0&&(e=f+p*12|0,eg(o,E,e,g),eg(r,y[K>>2],e,g)),e=22)):e=14;e==14&&((E|0)==0?o=s:(s=f+p*12|0,fg(o,E,s,g),fg(r,y[K>>2],s,g),o=y[R>>2]),(o|0)!=0&&(r=f+p*12|0,fg(z,o,r,g),fg(v,y[R>>2],r,g)),z=y[t>>2],(z|0)!=0&&(o=f+p*12|0,fg(w,z,o,g),fg(u,y[t>>2],o,g)),w=y[C>>2],(w|0)!=0&&(p=f+p*12|0,fg(D,w,p,g),fg(B,y[C>>2],p,g)));n=n+1|0;if((n|0)==2){break}p=2}}Xf.X=1;function dg(b,c,d,f){var g=b-1|0,e=A[b+1|0],i=A[g]&255,h=A[b]&255,k=Bc(i-h|0),l=d+4|0;if(k>>>0>2]>>>0){var k=A[b-2|0]&255,j=Bc(k-i|0),n=F[d+8>>2];j>>>0>>0&&(e&=255,Bc(e-h|0)>>>0>>0&&(c>>>0<4?(n=A[y[d>>2]+(c-1)|0]&255,k=Cc(n^-1,n+1|0,4-e+(h-i<<2)+k>>3),h=q[Q.a+((h|512)-k)|0],q[g]=q[Q.a+((i|512)+k)|0],q[b]=h):(q[g]=(e+(i+2)+(k<<1)|0)>>>2&255,q[b]=(h+2+(e<<1)+k|0)>>>2&255)))}g=b+f|0;i=b+(f-1)|0;e=A[f+(b+1)|0];h=A[i]&255;k=A[g]&255;Bc(h-k|0)>>>0>2]>>>0&&(b=A[b+(f-2)|0]&255,l=Bc(b-h|0),f=F[d+8>>2],l>>>0>>0&&(l=e&255,Bc(l-k|0)>>>0>>0&&(c>>>0<4?(c=A[y[d>>2]+(c-1)|0]&255,c=Cc(c^-1,c+1|0,4-l+(k-h<<2)+b>>3),d=q[Q.a+((k|512)-c)|0],q[i]=q[Q.a+((h|512)+c)|0],q[g]=d):(q[i]=(l+(h+2)+(b<<1)|0)>>>2&255,q[g]=(k+2+(l<<1)+b|0)>>>2&255))))}dg.X=1;function eg(b,c,d,f){var g=c>>>0<4;a:do{if(g){var e=A[y[d>>2]+(c-1)|0]&255,i=e+1|0,h=d+4|0,k=d+8|0;e^=-1;for(var l=f*-2|0,j=0;;){var n=b+(j-f)|0,p=b+j|0,r=A[b+(j+f)|0],o=A[n]&255,t=A[p]&255;if(Bc(o-t|0)>>>0>2]>>>0){var s=A[b+(l+j)|0]&255,u=Bc(s-o|0),w=F[k>>2];u>>>0>>0&&(r&=255,Bc(r-t|0)>>>0>>0&&(s=Cc(e,i,4-r+(t-o<<2)+s>>3),t=q[Q.a+((t|512)-s)|0],q[n]=q[Q.a+((o|512)+s)|0],q[p]=t))}j=j+1|0;if((j|0)==8){break a}}}else{i=d+4|0;h=d+8|0;k=f*-2|0;for(e=0;;){if(l=b+(e-f)|0,j=b+e|0,s=A[b+(e+f)|0],n=A[l]&255,p=A[j]&255,Bc(n-p|0)>>>0>2]>>>0&&(o=A[b+(k+e)|0]&255,w=Bc(o-n|0),t=F[h>>2],w>>>0>>0&&(s&=255,Bc(s-p|0)>>>0>>0&&(q[l]=(s+(n+2)+(o<<1)|0)>>>2&255,q[j]=(p+2+(s<<1)+o|0)>>>2&255))),e=e+1|0,(e|0)==8){break a}}}}while(0)}eg.X=1;function fg(b,c,d,f){var g=A[y[d>>2]+(c-1)|0]&255,c=g+1|0,e=d+4|0,i=d+8|0,d=g^-1,g=f*-2|0,h=b+ -f|0,k=A[b+f|0],l=A[h]&255,j=A[b]&255,n=Bc(l-j|0),p=F[e>>2];if(n>>>0

>>0){var n=A[b+g|0]&255,r=Bc(n-l|0),o=F[i>>2];r>>>0>>0&&(k&=255,Bc(k-j|0)>>>0>>0&&(p=Cc(d,c,4-k+(j-l<<2)+n>>3),j=q[Q.a+((j|512)-p)|0],q[h]=q[Q.a+((l|512)+p)|0],q[b]=j,p=y[e>>2]))}e=b+(1-f)|0;h=b+1|0;j=A[f+(b+1)|0];f=A[e]&255;l=A[h]&255;Bc(f-l|0)>>>0

>>0&&(b=A[b+(g|1)|0]&255,g=Bc(b-f|0),i=F[i>>2],g>>>0>>0&&(g=j&255,Bc(g-l|0)>>>0>>0&&(c=Cc(d,c,4-g+(l-f<<2)+b>>3),d=q[Q.a+((l|512)-c)|0],q[e]=q[Q.a+((f|512)+c)|0],q[h]=d)))}fg.X=1;function ag(b,c,d,f){var g=F[d+4>>2],e=F[d+8>>2],i=c>>>0<4;a:do{if(i){for(var h=A[y[d>>2]+(c-1)|0]&255,k=-h|0,l=h+1|0,j=0;;){var n=j*f|0,p=b+(n-2)|0,r=b+(n-1)|0,o=n+(b+1)|0,t=b+(n-3)|0,s=n+(b+2)|0,n=b+n|0,u=A[p]&255,w=A[r]&255,v=A[n]&255,z=A[o]&255;Bc(w-v|0)>>>0>>0&&Bc(u-w|0)>>>0>>0&&Bc(z-v|0)>>>0>>0&&(t=A[t]&255,s=A[s]&255,Bc(t-w|0)>>>0>>0?(q[p]=Cc(k,h,(v+(w+1)>>1)-(u<<1)+t>>1)+u&255,p=l):p=h,Bc(s-v|0)>>>0>>0?(q[o]=Cc(k,h,(v+(w+1)>>1)-(z<<1)+s>>1)+z&255,o=p+1|0):o=p,o=Cc(-o|0,o,u+4-z+(v-w<<2)>>3),v=q[Q.a+((v|512)-o)|0],q[r]=q[Q.a+((w|512)+o)|0],q[n]=v);j=j+1|0;if((j|0)==4){break a}}}else{h=(g>>>2)+2|0;for(k=0;;){var u=k*f|0,n=b+(u-2)|0,w=b+(u-1)|0,l=u+(b+1)|0,v=b+(u-3)|0,j=u+(b+2)|0,o=b+(u-4)|0,r=u+(b+3)|0,u=b+u|0,z=A[n]&255,s=A[w]&255,t=A[u]&255,B=A[l]&255,D=Bc(s-t|0),C=D>>>0>>0;b:do{if(C&&Bc(z-s|0)>>>0>>0&&Bc(B-t|0)>>>0>>0){var E=D>>>0>>0,G=A[v]&255,p=A[j]&255;do{if(E){if(Bc(G-s|0)>>>0>>0){E=s+z+t|0,q[w]=(B+4+(E<<1)+G|0)>>>3&255,q[n]=(G+(E+2)|0)>>>2&255,q[v]=(E+4+G*3+((A[o]&255)<<1)|0)>>>3&255}else{if(q[w]=(s+2+(z<<1)+B|0)>>>2&255,!E){break}}if(Bc(p-t|0)>>>0>=e>>>0){break}n=t+s+B|0;q[u]=(z+4+(n<<1)+p|0)>>>3&255;q[l]=(p+(n+2)|0)>>>2&255;q[j]=(n+4+p*3+((A[r]&255)<<1)|0)>>>3&255;break b}q[w]=(s+2+(z<<1)+B|0)>>>2&255}while(0);q[u]=(t+(z+2)+(B<<1)|0)>>>2&255}}while(0);k=k+1|0;if((k|0)==4){break a}}}}while(0)}ag.X=1;function bg(b,c,d,f){var g=F[d+4>>2],e=F[d+8>>2],i=c>>>0<4;a:do{if(i){for(var h=A[y[d>>2]+(c-1)|0]&255,k=-h|0,l=h+1|0,j=f*-2|0,n=f*-3|0,p=f<<1,r=0;;){var o=b+(j+r)|0,t=b+(r-f)|0,s=b+(r+f)|0,u=b+(n+r)|0,w=b+(p+r)|0,v=b+r|0,z=A[o]&255,B=A[t]&255,D=A[v]&255,C=A[s]&255;Bc(B-D|0)>>>0>>0&&Bc(z-B|0)>>>0>>0&&Bc(C-D|0)>>>0>>0&&(u=A[u]&255,Bc(u-B|0)>>>0>>0?(q[o]=Cc(k,h,(D+(B+1)>>1)-(z<<1)+u>>1)+z&255,o=l):o=h,w=A[w]&255,Bc(w-D|0)>>>0>>0?(q[s]=Cc(k,h,(D+(B+1)>>1)-(C<<1)+w>>1)+C&255,s=o+1|0):s=o,z=Cc(-s|0,s,z+4-C+(D-B<<2)>>3),D=q[Q.a+((D|512)-z)|0],q[t]=q[Q.a+((B|512)+z)|0],q[v]=D);r=r+1|0;if((r|0)==16){break a}}}else{h=(g>>>2)+2|0;k=f*-3|0;l=f*3|0;j=f*-2|0;n=f<<1;p=f*-4|0;for(r=0;;){var s=b+(j+r)|0,w=b+(r-f)|0,t=b+(r+f)|0,o=b+(k+r)|0,v=b+(n+r)|0,u=b+(p+r)|0,B=b+(l+r)|0,D=b+r|0,z=A[s]&255,E=A[w]&255,G=A[D]&255,H=A[t]&255,K=Bc(E-G|0),L=K>>>0>>0;b:do{if(L&&Bc(z-E|0)>>>0>>0&&Bc(H-G|0)>>>0>>0){var N=K>>>0>>0,O=A[o]&255,C=A[v]&255;do{if(N){if(Bc(O-E|0)>>>0>>0){N=E+z+G|0,q[w]=(H+4+(N<<1)+O|0)>>>3&255,q[s]=(O+(N+2)|0)>>>2&255,q[o]=(N+4+O*3+((A[u]&255)<<1)|0)>>>3&255}else{if(q[w]=(E+2+(z<<1)+H|0)>>>2&255,!N){break}}if(Bc(C-G|0)>>>0>=e>>>0){break}s=G+E+H|0;q[D]=(z+4+(s<<1)+C|0)>>>3&255;q[t]=(C+(s+2)|0)>>>2&255;q[v]=(s+4+C*3+((A[B]&255)<<1)|0)>>>3&255;break b}q[w]=(E+2+(z<<1)+H|0)>>>2&255}while(0);q[D]=(G+(z+2)+(H<<1)|0)>>>2&255}}while(0);r=r+1|0;if((r|0)==16){break a}}}}while(0)}bg.X=1;function cg(b,c,d,f){for(var c=A[y[d>>2]+(c-1)|0]&255,g=d+4|0,d=d+8|0,e=-c|0,i=c+1|0,h=f*-2|0,k=f*-3|0,l=f<<1,j=0;;){var n=b+(h+j)|0,p=b+(j-f)|0,r=b+(j+f)|0,o=b+(k+j)|0,t=b+(l+j)|0,s=b+j|0,u=A[r],w=A[p]&255,v=A[s]&255;if(Bc(w-v|0)>>>0>2]>>>0){var z=A[n]&255,B=Bc(z-w|0),D=F[d>>2];B>>>0>>0&&(u&=255,Bc(u-v|0)>>>0>>0&&(o=A[o]&255,Bc(o-w|0)>>>0>>0?(q[n]=Cc(e,c,(v+(w+1)>>1)-(z<<1)+o>>1)+z&255,n=i,D=y[d>>2]):n=c,t=A[t]&255,Bc(t-v|0)>>>0>>0?(q[r]=Cc(e,c,(v+(w+1)>>1)-(u<<1)+t>>1)+u&255,r=n+1|0):r=n,z=Cc(-r|0,r,4-u+(v-w<<2)+z>>3),v=q[Q.a+((v|512)-z)|0],q[p]=q[Q.a+((w|512)+z)|0],q[s]=v))}j=j+1|0;if((j|0)==4){break}}}cg.X=1;function Yf(b,c,d,f){return x[b+28+(d<<1)>>1]<<16>>16==0?x[c+28+(f<<1)>>1]<<16>>16!=0?2:(y[b+116+(d>>>2<<2)>>2]|0)!=(y[c+116+(f>>>2<<2)>>2]|0)?1:(Bc((x[b+132+(d<<2)>>1]<<16>>16)-(x[c+132+(f<<2)>>1]<<16>>16)|0)|0)>3?1:(Bc((x[b+132+(d<<2)+2>>1]<<16>>16)-(x[c+132+(f<<2)+2>>1]<<16>>16)|0)|0)>3?1:0:2}function $f(b,c,d){var f=x[b+132+(c<<2)>>1]<<16>>16,g=x[b+132+(d<<2)>>1]<<16>>16,e=x[b+132+(c<<2)+2>>1]<<16>>16,i=x[b+132+(d<<2)+2>>1]<<16>>16;return x[b+28+(c<<1)>>1]<<16>>16==0?x[b+28+(d<<1)>>1]<<16>>16!=0?2:(Bc(f-g|0)|0)>3?1:(Bc(e-i|0)|0)>3?1:(y[b+116+(c>>>2<<2)>>2]|0)!=(y[b+116+(d>>>2<<2)>>2]|0)?1:0:2}function gg(b,c,d){var f,g=F[c+4>>2],e=F[c+8>>2];if(d==5||d==0){f=2}else{if((y[b+3384>>2]|0)==0){var i=0;f=4}else{f=2}}a:do{if(f==2){for(var h=b+1220|0,k=0;;){var l=k+1|0,k=gf(h,k);if(!(l>>>0<16&(k|0)==0)){i=k;break a}k=l}}}while(0);for(var h=b+1212|0,l=b+1176|0,j=F[l>>2],n=0,k=f=0;;){if(f>>>0>=j>>>0){break}if((y[y[h>>2]+f*216+196>>2]|0)!=0){break}f=f+1|0;var n=n+1|0,p=(n|0)==(g|0),k=(p&1)+k|0,n=p?0:n}j=(f|0)==(j|0);a:do{if(j){do{if(d==7||d==2){if((y[b+3384>>2]|0)==0|(i|0)==0){f=13;break}}else{if((i|0)==0){f=13;break}}f=14}while(0);f==13?Pc(y[c>>2],128,g*384*e|0):f==14&&sd(y[c>>2],i,g*384*e|0);f=y[l>>2];y[b+1204>>2]=f;if((f|0)!=0){for(f=0;;){p=f+1|0;y[(y[h>>2]+f*216+8|0)>>2]=1;if(p>>>0>=F[l>>2]>>>0){break a}f=p}}}else{f=F[h>>2];p=(n|0)==0;b:do{if(!p){for(var r=b+1204|0,o=g*k|0,t=n+o|0,s=n-1|0,o=s+o|0,u=0;;){var w=f+(t-u)*216-20|0;hg(f+(o-u)*216|0,c,k,s-u|0,d,i);y[w>>2]=1;y[r>>2]=y[r>>2]+1|0;u=u+1|0;if((u|0)==(n|0)){break b}}}}while(0);p=n+1|0;r=p>>>0>>0;b:do{if(r){t=b+1204|0;s=g-1-n|0;o=p+g*k|0;for(u=0;;){var w=o+u|0,v=f+w*216+196|0;(y[v>>2]|0)==0&&(hg(f+w*216|0,c,k,p+u|0,d,i),y[v>>2]=1,y[t>>2]=y[t>>2]+1|0);u=u+1|0;if((u|0)==(s|0)){break b}}}}while(0);f=(k|0)==0;b:do{if(f){var z=0}else{if((g|0)==0){z=k}else{p=k-1|0;r=b+1204|0;t=-g|0;s=g*p|0;for(o=0;;){u=y[h>>2]+(s+o)*216|0;for(w=0;;){hg(u,c,p-w|0,o,d,i);y[u+196>>2]=1;y[r>>2]=y[r>>2]+1|0;w=w+1|0;if((w|0)==(k|0)){break}u=u+t*216|0}o=o+1|0;if((o|0)==(g|0)){z=k;break b}}}}}while(0);f=z+1|0;if(f>>>0>>0){p=(g|0)==0;r=b+1204|0;t=e-1-z|0;for(s=0;;){o=f+s|0;u=g*o|0;w=y[h>>2];b:do{if(!p){for(v=0;;){var B=u+v|0,D=w+B*216+196|0;(y[D>>2]|0)==0&&(hg(w+B*216|0,c,o,v,d,i),y[D>>2]=1,y[r>>2]=y[r>>2]+1|0);v=v+1|0;if((v|0)==(g|0)){break b}}}}while(0);s=s+1|0;if((s|0)==(t|0)){break a}}}}}while(0);return 0}gg.X=1;function hg(b,c,d,f,g,e){var i=m;m+=452;var h,k=i+384,l=i+448,j=m;m+=24;var n=F[c+4>>2],p=F[c+8>>2];Lc(c,n*d+f|0);var r=c|0,o=F[r>>2],t=d<<4,s=f<<4,u=(d<<8)*n+s|0;y[b+20>>2]=40;y[b+8>>2]=0;y[b>>2]=6;y[b+12>>2]=0;y[b+16>>2]=0;y[b+24>>2]=0;if(g==7||g==2){Pc(i|0,0,384),h=5}else{y[l>>2]=0;y[j+4>>2]=n;y[j+8>>2]=p;y[j>>2]=e;var w=i|0;(e|0)==0?(Pc(w,0,384),h=5):(df(w,l,j,s,t,0,0,16,16),rd(c,w),h=70)}if(h==5){var v=k|0;Pc(k,0,64);if((d|0)==0){var z=0,B=I,D=I,C=I,E=I}else{if((y[b+ -n*216+196>>2]|0)==0){z=0,E=C=D=B=I}else{var G=u-(n<<4)|0,H=G|1,K=G|3,L=(A[o+H|0]&255)+(A[o+G|0]&255)+(A[H+(o+1)|0]&255)+(A[o+K|0]&255)|0,N=G|7,O=(A[K+(o+2)|0]&255)+(A[K+(o+1)|0]&255)+(A[K+(o+3)|0]&255)+(A[o+N|0]&255)|0,R=(A[N+(o+2)|0]&255)+(A[N+(o+1)|0]&255)+(A[N+(o+3)|0]&255)+(A[N+(o+4)|0]&255)|0,U=(A[N+(o+6)|0]&255)+(A[N+(o+5)|0]&255)+(A[N+(o+7)|0]&255)+(A[o+(G|15)|0]&255)|0,Y=O+L|0;y[v>>2]=R+Y+y[v>>2]+U|0;var X=k+4|0;y[X>>2]=Y-R+y[X>>2]-U|0;z=1;B=L;D=O;C=R;E=U}}if((p-1|0)==(d|0)){var ba=0,$=z,ja=I,sa=I,Ea=I,Xa=I}else{if((y[b+n*216+196>>2]|0)==0){ba=0,$=z,Xa=Ea=sa=ja=I}else{var ea=u+(n<<8)|0,fa=ea|1,va=ea|3,ob=(A[o+fa|0]&255)+(A[o+ea|0]&255)+(A[fa+(o+1)|0]&255)+(A[o+va|0]&255)|0,wa=ea|7,pb=(A[va+(o+2)|0]&255)+(A[va+(o+1)|0]&255)+(A[va+(o+3)|0]&255)+(A[o+wa|0]&255)|0,gb=(A[wa+(o+2)|0]&255)+(A[wa+(o+1)|0]&255)+(A[wa+(o+3)|0]&255)+(A[wa+(o+4)|0]&255)|0,Ib=(A[wa+(o+6)|0]&255)+(A[wa+(o+5)|0]&255)+(A[wa+(o+7)|0]&255)+(A[o+(ea|15)|0]&255)|0,Fa=pb+ob|0;y[v>>2]=gb+Fa+y[v>>2]+Ib|0;var qb=k+4|0;y[qb>>2]=Fa-gb+y[qb>>2]-Ib|0;ba=1;$=z+1|0;ja=ob;sa=pb;Ea=gb;Xa=Ib}}if((f|0)==0){var Ya=$,Na=0,za=I,da=I,Oa=I,Za=I}else{if((y[b-216+196>>2]|0)==0){Ya=$,Na=0,Za=Oa=da=za=I}else{var Aa=u-1|0,hb=n<<4,Ga=n<<5,Pa=n*48|0,$a=(A[o+(Aa+hb)|0]&255)+(A[o+Aa|0]&255)+(A[o+(Aa+Ga)|0]&255)+(A[o+(Aa+Pa)|0]&255)|0,Ab=n<<6,cb=Aa+Ab|0,rb=(A[o+(cb+hb)|0]&255)+(A[o+cb|0]&255)+(A[o+(cb+Ga)|0]&255)+(A[o+(cb+Pa)|0]&255)|0,Qa=cb+Ab|0,pa=(A[o+(Qa+hb)|0]&255)+(A[o+Qa|0]&255)+(A[o+(Qa+Ga)|0]&255)+(A[o+(Qa+Pa)|0]&255)|0,ia=Qa+Ab|0,qa=(A[o+(ia+hb)|0]&255)+(A[o+ia|0]&255)+(A[o+(ia+Ga)|0]&255)+(A[o+(ia+Pa)|0]&255)|0,Ra=rb+$a|0;y[v>>2]=pa+Ra+y[v>>2]+qa|0;var ra=k+16|0;y[ra>>2]=Ra-pa+y[ra>>2]-qa|0;Ya=$+1|0;Na=1;za=$a;da=rb;Oa=pa;Za=qa}}if((n-1|0)==(f|0)){h=16}else{if((y[b+412>>2]|0)==0){h=16}else{var ib=u+16|0,sb=n<<4,jb=n<<5,db=n*48|0,Sa=(A[o+(ib+sb)|0]&255)+(A[o+ib|0]&255)+(A[o+(ib+jb)|0]&255)+(A[o+(ib+db)|0]&255)|0,kb=n<<6,ta=ib+kb|0,Bb=(A[o+(ta+sb)|0]&255)+(A[o+ta|0]&255)+(A[o+(ta+jb)|0]&255)+(A[o+(ta+db)|0]&255)|0,Ha=ta+kb|0,ya=(A[o+(Ha+sb)|0]&255)+(A[o+Ha|0]&255)+(A[o+(Ha+jb)|0]&255)+(A[o+(Ha+db)|0]&255)|0,xa=Ha+kb|0,Ba=(A[o+(xa+sb)|0]&255)+(A[o+xa|0]&255)+(A[o+(xa+jb)|0]&255)+(A[o+(xa+db)|0]&255)|0,Ca=Ya+1|0,Ta=Na+1|0,lb=Bb+Sa|0;y[v>>2]=ya+lb+y[v>>2]+Ba|0;var Jb=k+16|0,eb=lb-ya+y[Jb>>2]-Ba|0;y[Jb>>2]=eb;var Da=($|0)!=0;if(Da|(Na|0)==0){if(Da){var Ia=1,mb=Ca,Ua=Ta;h=20}else{Ja=Ta,Ka=Ca,Cb=1,Db=eb,h=25}}else{y[k+4>>2]=Oa+Za+da+za-Sa-Bb-ya-Ba>>5;var Ja=Ta,Ka=Ca,Cb=1,Db=eb;h=25}}}if(h==16){if(($|0)==0){var Eb=Na,tb=Ya,Va=0;h=21}else{Ia=0,mb=Ya,Ua=Na,h=20}}h==20&&(y[(k+4|0)>>2]>>=$+3,Eb=Ua,tb=mb,Va=Ia,h=21);if(h==21){var fb=(Eb|0)!=0;if(fb|(z|0)==0|(ba|0)==0){if(fb){Ja=Eb,Ka=tb,Cb=Va,Db=y[k+16>>2],h=25}else{var ub=Va,nb=tb;h=26}}else{y[k+16>>2]=C+E+D+B-Xa-Ea-sa-ja>>5,ub=Va,nb=tb,h=26}}h==25&&(y[k+16>>2]=Db>>Ja+3,ub=Cb,nb=Ka);nb==1?y[v>>2]>>=4:nb==2?y[v>>2]>>=5:nb==3?y[v>>2]=y[v>>2]*21>>10:y[v>>2]>>=6;ig(v);var Fb=i|0,Qb=0,wb=Fb,Lb=0;a:for(;;){for(var Rb=Lb<<2,Wb=Qb+1|0,Tb=0;;){var Xb=Tb+1|0,Vb=Wb+Tb|0,Yb=Qb+Tb|0;if(Yb>>>0>=256){break a}var fc=F[k+((Rb|Yb>>>2&3)<<2)>>2];q[wb+Tb|0]=(fc|0)<0?0:(fc|0)>255?-1:fc&255;if((Vb&63|0)==0){break}Tb=Xb}Qb=Vb;wb=wb+Xb|0;Lb=Lb+1|0}for(var ga=F[r>>2],pc=(z|0)!=0,Ub=k+4|0,Fc=(ba|0)!=0,Fg=(Na|0)!=0,qc=k+16|0,Gg=(ub|0)!=0,Yh=Fg^1,Zh=Gg^1,$h=pc^1,ai=Fc^1,bi=p*n<<6,Zb=(p<<8)+(d<<6)|0,$b=f<<3,hc=n*(Zb-8)+$b|0,ic=n*(Zb+64)+$b|0,Hg=n*Zb+$b|0,ci=Hg-1|0,di=Hg+8|0,Ig=n*(Zb|8)+$b|0,ei=Ig+8|0,Jg=n*(Zb|16)+$b|0,fi=Jg+8|0,Kg=n*(Zb|24)+$b|0,gi=Kg+8|0,Lg=n*(Zb|32)+$b|0,hi=Lg+8|0,Mg=n*(Zb|40)+$b|0,ii=Mg+8|0,Ng=n*(Zb|48)+$b|0,ji=Ng+8|0,Og=n*(Zb|56)+$b|0,ki=Og+8|0,li=Ig-1|0,mi=Jg-1|0,ni=Kg-1|0,oi=Lg-1|0,pi=Mg-1|0,qi=Ng-1|0,ri=Og-1|0,si=ic|1,ti=ic|2,ui=ic|3,vi=ic|4,wi=ic|5,xi=ic|6,yi=ic|7,zi=hc|1,Ai=hc|2,Bi=hc|3,Ci=hc|4,Di=hc|5,Ei=hc|6,Fi=hc|7,Pg=Za,Qg=Oa,Rg=da,Sg=za,Tg=Xa,Ug=Ea,Vg=sa,Wg=ja,Xg=E,Yg=C,Zg=D,$g=B,Yc=0;;){var Gi=i+((Yc<<6)+256)|0,la=bi*Yc|0,Hi=ga+(ic+la)|0,Ii=ga+(ci+la)|0,Ji=ga+(di+la)|0,Ki=ga+(ei+la)|0,Li=ga+(fi+la)|0,Mi=ga+(gi+la)|0,Ni=ga+(hi+la)|0,Oi=ga+(ii+la)|0,Pi=ga+(ji+la)|0,Qi=ga+(ki+la)|0,Ri=ga+(li+la)|0,Si=ga+(mi+la)|0,Ti=ga+(ni+la)|0,Ui=ga+(oi+la)|0,Vi=ga+(pi+la)|0,Wi=ga+(qi+la)|0,Xi=ga+(ri+la)|0,Yi=ga+(si+la)|0,Zi=ga+(ti+la)|0,$i=ga+(ui+la)|0,aj=ga+(vi+la)|0,bj=ga+(wi+la)|0,cj=ga+(xi+la)|0,dj=ga+(yi+la)|0;Pc(k,0,64);if(pc){var ah=(A[ga+(zi+la)|0]&255)+(A[ga+(hc+la)|0]&255)|0,bh=(A[ga+(Bi+la)|0]&255)+(A[ga+(Ai+la)|0]&255)|0,Ed=(A[ga+(Di+la)|0]&255)+(A[ga+(Ci+la)|0]&255)|0,Fd=(A[ga+(Fi+la)|0]&255)+(A[ga+(Ei+la)|0]&255)|0,ch=bh+ah|0;y[v>>2]=Ed+ch+y[v>>2]+Fd|0;y[Ub>>2]=ch-Ed+y[Ub>>2]-Fd|0;var Gd=1,Hd=ah,Id=bh,Jd=Ed,Kd=Fd}else{Gd=0,Hd=$g,Id=Zg,Jd=Yg,Kd=Xg}if(Fc){var dh=(A[Yi]&255)+(A[Hi]&255)|0,eh=(A[$i]&255)+(A[Zi]&255)|0,Ld=(A[bj]&255)+(A[aj]&255)|0,Md=(A[dj]&255)+(A[cj]&255)|0,fh=eh+dh|0;y[v>>2]=Ld+fh+y[v>>2]+Md|0;y[Ub>>2]=fh-Ld+y[Ub>>2]-Md|0;var yc=Gd+1|0,Nd=dh,Od=eh,Pd=Ld,Qd=Md}else{yc=Gd,Nd=Wg,Od=Vg,Pd=Ug,Qd=Tg}if(Fg){var gh=(A[Ri]&255)+(A[Ii]&255)|0,hh=(A[Ti]&255)+(A[Si]&255)|0,Rd=(A[Vi]&255)+(A[Ui]&255)|0,Sd=(A[Xi]&255)+(A[Wi]&255)|0,ih=hh+gh|0;y[v>>2]=Rd+ih+y[v>>2]+Sd|0;y[qc>>2]=ih-Rd+y[qc>>2]-Sd|0;var Zc=yc+1|0,$c=1,Td=gh,Ud=hh,Vd=Rd,Wd=Sd}else{Zc=yc,$c=0,Td=Sg,Ud=Rg,Vd=Qg,Wd=Pg}if(Gg){var jh=(A[Ki]&255)+(A[Ji]&255)|0,kh=(A[Mi]&255)+(A[Li]&255)|0,Xd=(A[Oi]&255)+(A[Ni]&255)|0,Yd=(A[Qi]&255)+(A[Pi]&255)|0,Zd=Zc+1|0,$d=$c+1|0,lh=kh+jh|0;y[v>>2]=Xd+lh+y[v>>2]+Yd|0;var ae=lh-Xd+y[qc>>2]-Yd|0;y[qc>>2]=ae;var mh=(yc|0)!=0;if(mh|Yh|Zh){if(mh){var nh=Zd,oh=$d;h=50}else{be=$d,ce=Zd,de=ae,h=55}}else{y[Ub>>2]=Vd+Wd+Ud+Td-jh-kh-Xd-Yd>>4;var be=$d,ce=Zd,de=ae;h=55}}else{if((yc|0)==0){var ee=$c,ad=Zc;h=51}else{nh=Zc,oh=$c,h=50}}h==50&&(y[Ub>>2]>>=yc+2,ee=oh,ad=nh,h=51);if(h==51){var ph=(ee|0)!=0;if(ph|$h|ai){if(ph){be=ee,ce=ad,de=y[qc>>2],h=55}else{var Jc=ad;h=56}}else{y[qc>>2]=Jd+Kd+Id+Hd-Qd-Pd-Od-Nd>>4,Jc=ad,h=56}}h==55&&(y[qc>>2]=de>>be+2,Jc=ce);Jc==1?y[v>>2]>>=3:Jc==2?y[v>>2]>>=4:Jc==3?y[v>>2]=y[v>>2]*21>>9:y[v>>2]>>=5;ig(v);var fe=0,ge=Gi,he=0;a:for(;;){for(var ej=he<<2,fj=fe+1|0,Kc=0;;){var qh=Kc+1|0,rh=fj+Kc|0,sh=fe+Kc|0;if(sh>>>0>=64){break a}var ie=F[k+((ej|sh>>>1&3)<<2)>>2];q[ge+Kc|0]=(ie|0)<0?0:(ie|0)>255?-1:ie&255;if((rh&15|0)==0){break}Kc=qh}fe=rh;ge=ge+qh|0;he=he+1|0}var th=Yc+1|0;if((th|0)==2){break}Pg=Wd;Qg=Vd;Rg=Ud;Sg=Td;Tg=Qd;Ug=Pd;Vg=Od;Wg=Nd;Xg=Kd;Yg=Jd;Zg=Id;$g=Hd;Yc=th}rd(c,Fb)}m=i}hg.X=1;function ig(b){var c=b+4|0,d=y[c>>2],f=b+16|0,g=y[f>>2],e=y[b>>2];if((d|g|0)==0){y[b+60>>2]=e,y[b+56>>2]=e,y[b+52>>2]=e,y[b+48>>2]=e,y[b+44>>2]=e,y[b+40>>2]=e,y[b+36>>2]=e,y[b+32>>2]=e,y[b+28>>2]=e,y[b+24>>2]=e,y[b+20>>2]=e,y[f>>2]=e,y[b+12>>2]=e,y[b+8>>2]=e,y[c>>2]=e}else{var i=d+e|0,h=d>>1,k=h+e|0,h=e-h|0,d=e-d|0;y[b>>2]=g+i|0;e=g>>1;y[f>>2]=e+i|0;y[(b+32|0)>>2]=i-e|0;y[(b+48|0)>>2]=i-g|0;y[c>>2]=g+k|0;y[(b+20|0)>>2]=e+k|0;y[(b+36|0)>>2]=k-e|0;y[(b+52|0)>>2]=k-g|0;y[(b+8|0)>>2]=g+h|0;y[(b+24|0)>>2]=e+h|0;y[(b+40|0)>>2]=h-e|0;y[(b+56|0)>>2]=h-g|0;y[(b+12|0)>>2]=g+d|0;y[(b+28|0)>>2]=e+d|0;y[(b+44|0)>>2]=d-e|0;y[(b+60|0)>>2]=d-g|0}}ig.X=1;function jg(b,c,d,f){var g,e=(y[d+284>>2]|0)==0;a:do{if(e){var i=0}else{for(i=0;;){var h=y[d+288+i*20>>2];if(h==0){i=0;break a}else{if(h==5){break}}i=i+1|0}i=1}}while(0);e=y[c+16>>2];do{if(e==0){if((y[f>>2]|0)==5){y[b+4>>2]=0;var k=y[b>>2]=0}else{k=y[b>>2]}var l=d+20|0,j=F[l>>2],h=b|0;if(j>>>0>>0){if(g=F[c+20>>2],(k-j|0)>>>0>>1>>>0){g=11}else{var n=y[b+4>>2]+g|0;g=15}}else{g=11}a:do{if(g==11){n=j>>>0>k>>>0;do{if(n){var p=F[c+20>>2];if((j-k|0)>>>0>p>>>1>>>0){n=y[b+4>>2]-p|0;break a}}}while(0);n=y[b+4>>2]}}while(0);k=f+4|0;(y[k>>2]|0)==0?(h=y[d+24>>2],h=j+n+((h|0)<0?h:0)|0):(j=b+4|0,y[j>>2]=n,l=y[l>>2],g=d+24|0,p=y[g>>2],p=l+n+((p|0)<0?p:0)|0,(y[k>>2]|0)==0?h=p:(i|0)==0?(y[h>>2]=l,h=p):(y[j>>2]=0,l=y[g>>2],y[h>>2]=(l|0)<0?-l|0:0,h=0))}else{if(e==1){(y[f>>2]|0)==5?h=0:(h=y[b+12>>2],h=F[b+8>>2]>>>0>F[d+12>>2]>>>0?y[c+12>>2]+h|0:h);var p=F[c+36>>2],r=(p|0)==0,j=r?0:y[d+12>>2]+h|0,k=(l=(y[f+4>>2]|0)==0)?(((j|0)!=0)<<31>>31)+j|0:j;(j=(k|0)!=0)?(g=k-1|0,k=(g>>>0)%(p>>>0),g=Math.floor((g>>>0)/(p>>>0))):g=k=I;a:do{if(r){var o=0}else{for(var t=y[c+40>>2],s=p>>>0>1?p:1,u=0,w=0;;){if(w=y[t+(u<<2)>>2]+w|0,u=u+1|0,(u|0)==(s|0)){o=w;break a}}}}while(0);a:do{if(j){p=y[c+40>>2];t=o*g|0;for(s=0;;){r=s+1|0;t=y[p+(s<<2)>>2]+t|0;if(r>>>0>k>>>0){var v=t;break a}s=r}}else{v=0}}while(0);j=l?y[c+28>>2]+v|0:v;k=y[d+32>>2]+y[c+32>>2]|0;l=b+12|0;(i|0)==0?(j=((k|0)<0?k:0)+j+y[d+28>>2]|0,y[l>>2]=h,y[b+8>>2]=y[d+12>>2],h=j):(y[l>>2]=0,h=y[b+8>>2]=0)}else{(y[f>>2]|0)==5?(j=l=0,h=b+12|0):(l=F[d+12>>2],h=b+12|0,j=y[h>>2],j=F[b+8>>2]>>>0>l>>>0?y[c+12>>2]+j|0:j,l=l+j<<1,l=(y[f+4>>2]|0)!=0?l:l-1|0),(i|0)==0?(y[h>>2]=j,y[b+8>>2]=y[d+12>>2],h=l):(y[h>>2]=0,h=y[b+8>>2]=0)}}}while(0);return h}jg.X=1;function Rc(b,c){var d;Pc(c,0,952);var f=S(b,1),g=(f|0)==-1;a:do{if(g){d=1}else{d=(f|0)==1;y[c>>2]=d&1;do{if(d){var e=S(b,8);if((e|0)==-1){d=1;break a}y[c+4>>2]=e;if((e|0)==255){e=S(b,16);if((e|0)==-1){d=1;break a}y[c+8>>2]=e;e=S(b,16);if((e|0)==-1){d=1;break a}y[c+12>>2]=e}}}while(0);d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+16>>2]=d&1;if(d){d=S(b,1);if((d|0)==-1){d=1;break}y[c+20>>2]=(d|0)==1&1}d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+24>>2]=d&1;if(d){d=S(b,3);if((d|0)==-1){d=1;break}y[c+28>>2]=d;d=S(b,1);if((d|0)==-1){d=1;break}y[c+32>>2]=(d|0)==1&1;d=S(b,1);if((d|0)==-1){d=1;break}d=(d|0)==1;y[c+36>>2]=d&1;if(d){d=S(b,8);if((d|0)==-1){d=1;break}y[c+40>>2]=d;d=S(b,8);if((d|0)==-1){d=1;break}y[c+44>>2]=d;d=S(b,8);if((d|0)==-1){d=1;break}y[c+48>>2]=d}else{y[c+40>>2]=2,y[c+44>>2]=2,y[c+48>>2]=2}}else{y[c+28>>2]=5,y[c+40>>2]=2,y[c+44>>2]=2,y[c+48>>2]=2}d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+52>>2]=d&1;if(d){d=c+56|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>5){d=1;break}d=c+60|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>5){d=1;break}}d=S(b,1);if((d|0)==-1){d=1}else{d=(d|0)==1;y[c+64>>2]=d&1;if(d){d=id(b);if((od(b,32)|0)==-1|(d|0)==0){d=1;break}y[c+68>>2]=d;d=id(b);if((od(b,32)|0)==-1|(d|0)==0){d=1;break}y[c+72>>2]=d;d=S(b,1);if((d|0)==-1){d=1;break}y[c+76>>2]=(d|0)==1&1}d=S(b,1);if((d|0)==-1){d=1}else{e=(d|0)==1;d=c+80|0;y[d>>2]=e&1;if(e){if(e=kg(b,c+84|0),(e|0)!=0){d=e;break}}else{y[c+84>>2]=1,y[c+96>>2]=288000001,y[c+224>>2]=288000001,y[c+480>>2]=24,y[c+484>>2]=24,y[c+488>>2]=24,y[c+492>>2]=24}e=S(b,1);if((e|0)==-1){d=1}else{var i=(e|0)==1,e=c+496|0;y[e>>2]=i&1;if(i){if(i=kg(b,c+500|0),(i|0)!=0){d=i;break}}else{y[c+500>>2]=1,y[c+512>>2]=240000001,y[c+640>>2]=240000001,y[c+896>>2]=24,y[c+900>>2]=24,y[c+904>>2]=24,y[c+908>>2]=24}d=(y[d>>2]|0)==0?(y[e>>2]|0)==0?47:45:45;if(d==45){d=S(b,1);if((d|0)==-1){d=1;break}y[c+912>>2]=(d|0)==1&1}d=S(b,1);if((d|0)==-1){d=1}else{if(y[c+916>>2]=(d|0)==1&1,d=S(b,1),(d|0)==-1){d=1}else{d=(d|0)==1;y[c+920>>2]=d&1;if(d){d=S(b,1);if((d|0)==-1){d=1;break}y[c+924>>2]=(d|0)==1&1;d=c+928|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=c+932|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=c+936|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=c+940|0;e=T(b,d);if((e|0)!=0){d=e;break}if(F[d>>2]>>>0>16){d=1;break}d=T(b,c+944|0);if((d|0)!=0){break}d=T(b,c+948|0);if((d|0)!=0){break}}else{y[c+924>>2]=1,y[c+928>>2]=2,y[c+932>>2]=1,y[c+936>>2]=16,y[c+940>>2]=16,y[c+944>>2]=16,y[c+948>>2]=16}d=0}}}}}}}}}}while(0);return d}Rc.X=1;function kg(b,c){var d=c|0,f=T(b,d),g=(f|0)==0;a:do{if(g){var e=y[d>>2]+1|0;y[d>>2]=e;if(e>>>0>32){e=1}else{var i=S(b,4);if((i|0)==-1){e=1}else{e=c+4|0;y[e>>2]=i;var h=S(b,4);if((h|0)==-1){e=1}else{i=c+8|0;y[i>>2]=h;for(h=0;;){var k=c+268+(h<<2)|0,l=c+140+(h<<2)|0,j=c+12+(h<<2)|0;if(h>>>0>=F[d>>2]>>>0){break}var n=T(b,j);if((n|0)!=0){e=n;break a}n=y[j>>2];if((n|0)==-1){e=1;break a}n=n+1|0;y[j>>2]=n;y[j>>2]=n<>2]+6;j=T(b,l);if((j|0)!=0){e=j;break a}j=y[l>>2];if((j|0)==-1){e=1;break a}j=j+1|0;y[l>>2]=j;y[l>>2]=j<>2]+4;l=S(b,1);if((l|0)==-1){e=1;break a}y[k>>2]=(l|0)==1&1;h=h+1|0}e=S(b,5);(e|0)==-1?e=1:(y[c+396>>2]=e+1|0,e=S(b,5),(e|0)==-1?e=1:(y[c+400>>2]=e+1|0,e=S(b,5),(e|0)==-1?e=1:(y[c+404>>2]=e+1|0,e=S(b,5),(e|0)==-1?e=1:(y[c+408>>2]=e,e=0))))}}}}else{e=f}}while(0);return e}kg.X=1;function lg(b,c,d,f,g,e){var b=b+16|0,i=y[b>>2];if((i|0)==0){b=3}else{if((y[i+60>>2]|0)==0){b=3}else{y[c>>2]=1;y[d>>2]=y[y[b>>2]+64>>2]<<1;var h=y[b>>2];y[f>>2]=(y[h+52>>2]<<4)-(y[h+68>>2]+y[h+64>>2]<<1)|0;y[g>>2]=y[y[b>>2]+72>>2]<<1;h=y[b>>2];h=(y[h+56>>2]<<4)-(y[h+76>>2]+y[h+72>>2]<<1)|0;b=4}}b==3&&(y[c>>2]=0,y[d>>2]=0,y[f>>2]=0,h=y[g>>2]=0);y[e>>2]=h}lg.X=1;function mg(b,c,d,f,g){var e=m;m+=204;var i,h=e+4,k=e+12,l=e+104,j=e+176,n=e+196,p=e+200;y[n>>2]=0;var r=b+3344|0;(y[r>>2]|0)==0?i=3:(y[b+3348>>2]|0)!=(c|0)?i=3:(i=b+3356|0,y[j>>2]=y[i>>2],y[j+4>>2]=y[i+4>>2],y[j+8>>2]=y[i+8>>2],y[j+12>>2]=y[i+12>>2],y[j+16>>2]=y[i+16>>2],y[j+4>>2]=y[j>>2],y[j+8>>2]=0,y[j+16>>2]=0,y[g>>2]=y[b+3352>>2],i=5);if(i==3){if((Mc(c,d,j,g)|0)!=0){var o=3;i=58}else{i=b+3356|0,y[i>>2]=y[j>>2],y[i+4>>2]=y[j+4>>2],y[i+8>>2]=y[j+8>>2],y[i+12>>2]=y[j+12>>2],y[i+16>>2]=y[j+16>>2],y[b+3352>>2]=y[g>>2],y[b+3348>>2]=c,i=5}}a:do{if(i==5){y[r>>2]=0;d=j;c=h;if((S(d,1)|0)==-1){c=1}else{var t=S(d,2),o=c+4|0;y[o>>2]=t;d=S(d,5);y[c>>2]=d;c=(d-2|0)>>>0<3?1:(d-7|0)>>>0<2|(d|0)==5&&(y[o>>2]|0)==0?1:(d==12||d==11||d==10||d==9||d==6)&&(y[o>>2]|0)!=0?1:0}if((c|0)!=0){o=3}else{if(c=h|0,o=F[c>>2],(o|0)==0|o>>>0>12){o=0}else{if(o=Ie(j,h,b,n),o==0){o=(y[n>>2]|0)==0;b:do{if(!o){i=(y[b+1184>>2]|0)==0;do{if(!i&&(y[b+16>>2]|0)!=0){if((y[b+3380>>2]|0)!=0){o=3;break a}if((y[b+1188>>2]|0)==0){i=b+1220|0;var s=Jf(i),u=b+1336|0;y[b+1336>>2]=s;Qf(i);gg(b,u,0)}else{gg(b,b+1336|0,y[b+1372>>2])}y[g>>2]=0;y[r>>2]=1;y[b+1180>>2]=0;var s=b+1336|0,u=b+1368|0,w=b+1360|0;i=53;break b}}while(0);y[b+1188>>2]=0;y[b+1180>>2]=0}i=18}while(0);if(i==18){if(w=F[c>>2],w==7){if((Oc(j,k)|0)==0){ze(b,k);o=0;break}b=k+40|0;Ae(y[b>>2]);y[b>>2]=0;b=k+84|0;Ae(y[b>>2]);y[b>>2]=0;o=3;break}else{if(w==8){if((Sc(j,l)|0)==0){Be(b,l);o=0;break}b=l+20|0;Ae(y[b>>2]);y[b>>2]=0;b=l+24|0;Ae(y[b>>2]);y[b>>2]=0;b=l+28|0;Ae(y[b>>2]);y[b>>2]=0;b=l+44|0;Ae(y[b>>2]);y[b>>2]=0;o=3;break}else{if(w==5||w==1){s=b+1180|0;if((y[s>>2]|0)!=0){o=0;break}y[b+1184>>2]=1;u=((y[b+1188>>2]|0)==0&1|0)==0;do{if(!u){y[b+1204>>2]=0;y[b+1208>>2]=f;Wc(j,e);u=b+8|0;o=y[u>>2];w=(w|0)==5;d=Ce(b,y[e>>2],w&1);if((d|0)==0){if((o|0)==(y[u>>2]|0)){break}k=F[b+16>>2];y[p>>2]=1;l=b|0;f=F[l>>2];f=f>>>0<32?y[b+20+(f<<2)>>2]:0;y[g>>2]=0;y[r>>2]=1;if(w){if(g=ed(p,j,k,y[b+12>>2]),(y[p>>2]|g|0)!=0){i=38}else{if(p=b+1220|0,(y[b+1276>>2]|0)!=0|(f|0)==0){i=38}else{if((y[f+52>>2]|0)!=(y[k+52>>2]|0)){i=38}else{if((y[f+56>>2]|0)!=(y[k+56>>2]|0)){i=38}else{if((y[f+88>>2]|0)!=(y[k+88>>2]|0)){i=38}else{g=(y[p>>2]|0)==0;b:do{if(!g){for(y[p+60>>2]=1;;){if((Nf(p)|0)!=0){break b}}}}while(0);i=40}}}}}}else{i=38}i==38&&(y[b+1280>>2]=0);y[l>>2]=y[u>>2];o=2;break a}y[b+4>>2]=256;y[b+12>>2]=0;y[u>>2]=32;y[b+16>>2]=0;y[b+3380>>2]=0;o=(d|0)==65535?5:4;break a}}while(0);if((y[b+3380>>2]|0)!=0){o=3;break}u=b+1368|0;w=b+2356|0;d=b+16|0;if((Uc(j,w,y[d>>2],y[b+12>>2],h)|0)!=0){o=3;break}if(((y[b+1188>>2]|0)==0&1|0)==0){c=b+1220|0}else{o=b+1220|0;if((y[c>>2]|0)!=5&&(Rf(o,y[b+2368>>2],(y[h+4>>2]|0)!=0&1,y[y[d>>2]+48>>2])|0)!=0){o=3;break}c=Jf(o);y[b+1336>>2]=c;c=o}w>>=2;o=u>>2;for(d=w+247;w>2]=1;w=b+1360|0;o=h;d=w;t=y[o+4>>2];y[d>>2]=y[o>>2];y[d+4>>2]=t;o=y[b+16>>2];Je(y[b+1172>>2],y[b+12>>2],y[b+1432>>2],y[o+52>>2],y[o+56>>2]);Qf(c);if((Gf(c,b+1436|0,y[b+1380>>2],y[b+1412>>2])|0)!=0){o=3;break}c=b+1336|0;if((fd(j,b,c,u)|0)!=0){jd(b,y[b+1368>>2]);o=3;break}d=aa;o=(y[b+1404>>2]|0)==0;do{if(o){if((y[b+1196>>2]|0)==(y[b+1176>>2]|0)){var v=1,d=7;break}}else{d=F[b+1176>>2];t=(d|0)==0;b:do{if(t){var z=0}else{for(var B=y[b+1212>>2],D=d>>>0>1?d:1,C=0,E=0;;){if(E=((y[B+C*216+196>>2]|0)!=0&1)+E|0,C=C+1|0,(C|0)==(D|0)){z=E;break b}}}}while(0);if((z|0)==(d|0)){v=1;d=7;break}}d=6}while(0);d==6&&(v=0);if((v|0)==0){o=0;break}y[s>>2]=1;s=c}else{o=0;break}}}}Sf(s,y[b+1212>>2]);c=b;y[c+1196>>2]=0;y[c+1192>>2]=0;o=c+1176|0;d=(y[o>>2]|0)==0;b:do{if(!d){t=c+1212|0;for(B=0;;){D=B+1|0;y[(y[t>>2]+B*216+4|0)>>2]=0;y[(y[t>>2]+B*216+196|0)>>2]=0;if(D>>>0>=F[o>>2]>>>0){break b}B=D}}}while(0);c=jg(b+1284|0,y[b+16>>2],u,w);o=b+1188|0;(y[o>>2]|0)!=0&&(d=b+1220|0,(y[b+1364>>2]|0)==0?Kf(d,0,s,y[b+1380>>2],c,(y[b+1360>>2]|0)==5&1,y[b+1208>>2],y[b+1204>>2]):Kf(d,b+1644|0,s,y[b+1380>>2],c,(y[b+1360>>2]|0)==5&1,y[b+1208>>2],y[b+1204>>2]));y[b+1184>>2]=0;y[o>>2]=0;o=1}else{o=o==65520?4:3}}}}}while(0);m=e;return o}mg.X=1;function ng(b){for(var c=0;;){var d=b+20+(c<<2)|0,f=y[d>>2];(f|0)!=0&&(Ae(y[f+40>>2]),y[(y[d>>2]+40|0)>>2]=0,Ae(y[y[d>>2]+84>>2]),y[(y[d>>2]+84|0)>>2]=0,Ae(y[d>>2]),y[d>>2]=0);c=c+1|0;if((c|0)==32){var g=0;break}}for(;;){if(c=b+148+(g<<2)|0,d=y[c>>2],(d|0)!=0&&(Ae(y[d+20>>2]),y[(y[c>>2]+20|0)>>2]=0,Ae(y[y[c>>2]+24>>2]),y[(y[c>>2]+24|0)>>2]=0,Ae(y[y[c>>2]+28>>2]),y[(y[c>>2]+28|0)>>2]=0,Ae(y[y[c>>2]+44>>2]),y[(y[c>>2]+44|0)>>2]=0,Ae(y[c>>2]),y[c>>2]=0),g=g+1|0,(g|0)==256){break}}g=b+3376|0;Ae(y[g>>2]);y[g>>2]=0;g=b+1212|0;Ae(y[g>>2]);y[g>>2]=0;g=b+1172|0;Ae(y[g>>2]);y[g>>2]=0;Ee(b+1220|0)}ng.X=1;Module._broadwaySetStreamLength=(function(b){y[og>>2]=b});function pg(b,c,d){var f=m;m+=4;var g=(c|0)==0|(d|0)==0;a:do{if(g){var e=-1}else{var i=c|0;if((y[i>>2]|0)==0){e=-1}else{var h=c+4|0;if((y[h>>2]|0)==0){e=-1}else{if((b|0)==0){e=-3}else{if(e=b,(y[e>>2]|0)==0){e=-3}else{var k=d|0;y[k>>2]=0;y[f>>2]=0;var l=y[h>>2],j=y[i>>2],i=b+8|0;y[b+3392>>2]=y[c+12>>2];var h=c+8|0,n=1,p=j,r=l,l=0;b:for(;;){if((y[e>>2]|0)==2){y[e>>2]=1;y[k>>2]=p+l|0;break}l=mg(i,p,r,y[h>>2],f);j=y[f>>2];p=p+j|0;r=r-j|0;r=(r|0)<0?0:r;y[k>>2]=p;do{if(l==2){break b}else{if(l==1){b=b+4|0;y[b>>2]=y[b>>2]+1|0;e=(r|0)==0?2:3;break a}else{if(l==4){var o=0;c:for(;;){if(o>>>0>=256){var t=1;break}var s=F[i+148+(o<<2)>>2],u=(s|0)==0;do{if(!u){var w=y[i+20+(y[s+4>>2]<<2)>>2];if((w|0)!=0&&(De(s,y[w+52>>2],y[w+56>>2])|0)==0){t=0;break c}}}while(0);o=o+1|0}o=((t|0)==0&1|r|0)!=0?n:-2}else{if(l==5){e=-4;break a}else{o=n}}}}}while(0);if((r|0)==0){e=o;break a}n=o;l=j}k=b+1288|0;(y[k>>2]|0)==0?e=4:(y[b+1244>>2]|0)==(y[b+1248>>2]|0)?e=4:(y[k>>2]=0,y[e>>2]=2,e=3)}}}}}}while(0);m=f;return e}pg.X=1;function qg(){var b=y[rg>>2],c=sg,d=m;m+=12;var f=d+4,g=d+8;if((b|0)==0|(c|0)==0){c=-1}else{var e=(b+8|0)+1220|0,b=e+20|0,i=F[b>>2];i>>>0>2]>>>0?(e=y[e+12>>2],y[b>>2]=i+1|0,b=e+(i<<4)|0):b=0;(b|0)==0?b=0:(y[g>>2]=y[b+4>>2],y[f>>2]=y[b+12>>2],y[d>>2]=y[b+8>>2],b=y[b>>2]);(b|0)==0?c=0:(y[c>>2]=b,y[c+4>>2]=y[g>>2],y[c+8>>2]=y[f>>2],y[c+12>>2]=y[d>>2],c=2)}m=d;return c}Module._broadwayCreateStream=(function(b){var c=og,d=jc(b);y[c+8>>2]=d;y[c+4>>2]=d;y[c>>2]=b;y[c+12>>2]=d+b|0;return y[og+4>>2]});Module._broadwayPlayStream=(function(){var b=og;y[tg>>2]=y[b+4>>2];for(y[tg+4>>2]=y[b>>2];;){if(ug(),(y[tg+4>>2]|0)==0){break}}});Module._broadwayInit=(function(){var b=rg;if((b|0)==0){b=-1}else{var c=jc(3396);if((c|0)==0){b=-4}else{var d=c+8|0;Pc(d,0,3388);y[d+8>>2]=32;y[d+4>>2]=256;y[d+1332>>2]=1;var f=jc(2112);y[d+3376>>2]=f;(((f|0)==0?1:0)|0)==0?(y[c>>2]=1,y[c+4>>2]=0,y[b>>2]=c,b=0):((c|0)!=0&&(ng(c+8|0),Ae(c)),b=-4)}}(b|0)==0?(y[vg>>2]=1,y[wg>>2]=1):(xg(Q.aa|0),yg());return-1});function ug(){var b;y[tg+8>>2]=y[wg>>2];var c=pg(y[rg>>2],tg,zg);if(c==4){var d=y[rg>>2],f=Ag;if((d|0)==0|(f|0)==0){f=-1}else{if(b=d+8|0,(y[d+24>>2]|0)==0){f=-6}else{if((y[d+20>>2]|0)==0){f=-6}else{d=y[b+16>>2];y[f+4>>2]=((d|0)==0?0:y[d+52>>2])<<4;d=y[b+16>>2];y[f+8>>2]=((d|0)==0?0:y[d+56>>2])<<4;d=y[b+16>>2];if((d|0)==0){d=5}else{if((y[d+80>>2]|0)==0){d=5}else{if(d=y[d+84>>2],(d|0)==0){d=5}else{if((y[d+24>>2]|0)==0){d=5}else{if((y[d+32>>2]|0)==0){d=5}else{var g=1,d=6}}}}}d==5&&(g=0);y[f+12>>2]=g;g=y[b+16>>2];(g|0)==0?g=2:(y[g+80>>2]|0)==0?g=2:(g=y[g+84>>2],g=(g|0)==0?2:(y[g+24>>2]|0)==0?2:(y[g+36>>2]|0)==0?2:y[g+48>>2]);y[f+16>>2]=g;lg(b,f+28|0,f+32|0,f+36|0,f+40|0,f+44|0);g=y[b+16>>2];(g|0)==0?g=d=1:(y[g+80>>2]|0)==0?g=d=1:(d=y[g+84>>2],(d|0)==0?g=d=1:(y[d>>2]|0)==0?g=d=1:(g=y[d+4>>2],g==255?(g=y[d+8>>2],d=y[d+12>>2],(g|0)==0|(d|0)==0&&(g=d=0)):g==1?g=d=1:g==2?(d=11,g=12):g==3?(d=11,g=10):g==4?(d=11,g=16):g==5?(d=33,g=40):g==6?(d=11,g=24):g==7?(d=11,g=20):g==8?(d=11,g=32):g==9?(d=33,g=80):g==10?(d=11,g=18):g==11?(d=11,g=15):g==12?(d=33,g=64):g==13?(d=99,g=160):g=d=0));y[(f+20|0)>>2]=g;y[(f+24|0)>>2]=d;b=y[b+16>>2];y[f>>2]=(b|0)==0?0:y[b>>2];f=0}}}(f|0)!=0?f=-1:(y[Bg>>2]=(y[Ag+4>>2]*3*y[Ag+8>>2]|0)>>>1,Cg((Pb=m,m+=1,m=m+3>>2<<2,y[Pb>>2]=0,Pb)),f=F[zg>>2],y[tg+4>>2]=y[tg+4>>2]-f+y[tg>>2]|0,y[tg>>2]=f,f=0);b=8}else{c==3?(b=y[zg>>2],y[tg+4>>2]=y[tg+4>>2]-b+y[tg>>2]|0,y[tg>>2]=b,b=5):c==-2||c==1?(y[tg+4>>2]=0,f=c,b=8):c==2?(y[tg+4>>2]=0,b=5):(f=c,b=8)}a:do{if(b==5){if(y[wg>>2]=y[wg>>2]+1|0,(qg()|0)!=2){f=c}else{for(;;){if(y[vg>>2]=y[vg>>2]+1|0,Dg(y[sg>>2],y[Ag+4>>2],y[Ag+8>>2]),(qg()|0)!=2){f=c;break a}}}}}while(0);return f}ug.X=1;function yg(){var b=y[Eg>>2];(b|0)!=0&&Ae(b)}Module._broadwayExit=yg;Module._broadwayGetMajorVersion=(function(){var b=m;m+=8;y[b>>2]=2;y[b+4>>2]=3;var c=y[b>>2];m=b;return c});Module._broadwayGetMinorVersion=(function(){var b=m;m+=8;y[b>>2]=2;y[b+4>>2]=3;var c=y[b+4>>2];m=b;return c});function Pc(b,c,d){kc(b,c&255,d)}function jc(b){var c,d=b>>>0<245;do{if(d){var f=b>>>0<11?16:b+11&-8,g=f>>>3;c=F[V>>2];var e=c>>>(g>>>0);if((e&3|0)!=0){var i=(e&1^1)+g|0,f=i<<1,h=V+40+(f<<2)|0,d=V+40+(f+2<<2)|0,f=F[d>>2],b=f+8|0,k=F[b>>2];(h|0)==(k|0)?y[V>>2]=c&(1<>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[d>>2]=k,y[k+12>>2]=h);i<<=3;y[f+4>>2]=i|3;y[(f+(i|4)|0)>>2]|=1;k=b;c=37;break}if(f>>>0<=F[V+8>>2]>>>0){var l=f;c=29;break}if((e|0)!=0){b=1<>>12&16;k=d>>>(b>>>0);d=k>>>5&8;g=k>>>(d>>>0);k=g>>>2&4;e=g>>>(k>>>0);g=e>>>1&2;e>>>=g>>>0;var j=e>>>1&1,k=(d|b|k|g|j)+(e>>>(j>>>0))|0,b=k<<1,g=V+40+(b<<2)|0,e=V+40+(b+2<<2)|0,d=F[e>>2],b=d+8|0,j=F[b>>2];(g|0)==(j|0)?y[V>>2]=c&(1<>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[e>>2]=j,y[j+12>>2]=g);k<<=3;c=k-f|0;y[d+4>>2]=f|3;g=d;d=g+f|0;y[g+(f|4)>>2]=c|1;y[g+k>>2]=c;j=F[V+8>>2];(j|0)!=0&&(f=y[V+20>>2],g=j>>>2&1073741822,k=V+40+(g<<2)|0,e=F[V>>2],j=1<<(j>>>3),(e&j|0)==0?(y[V>>2]=e|j,i=k,h=V+40+(g+2<<2)|0):(g=V+40+(g+2<<2)|0,e=F[g>>2],e>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(i=e,h=g)),y[h>>2]=f,y[i+12>>2]=f,y[(f+8|0)>>2]=i,y[(f+12|0)>>2]=k);y[V+8>>2]=c;y[V+20>>2]=d;k=b;c=37;break}if((y[V+4>>2]|0)==0){l=f;c=29;break}c=uh(f);if((c|0)==0){l=f;c=29;break}k=c}else{if(b>>>0>4294967231){l=-1;c=29;break}c=b+11&-8;if((y[V+4>>2]|0)==0){l=c;c=29;break}f=vh(c);if((f|0)==0){l=c;c=29;break}k=f}c=37}while(0);c==29&&(i=F[V+8>>2],l>>>0>i>>>0?(i=F[V+12>>2],l>>>0>>0?(i=i-l|0,y[V+12>>2]=i,h=F[V+24>>2],y[V+24>>2]=h+l|0,y[l+(h+4)>>2]=i|1,y[h+4>>2]=l|3,k=h+8|0):k=wh(l)):(h=i-l|0,c=F[V+20>>2],h>>>0>15?(y[V+20>>2]=c+l|0,y[V+8>>2]=h,y[l+(c+4)>>2]=h|1,y[c+i>>2]=h,y[c+4>>2]=l|3):(y[V+8>>2]=0,y[V+20>>2]=0,y[c+4>>2]=i|3,y[(i+(c+4)|0)>>2]|=1),k=c+8|0));return k}jc.X=1;function uh(b){var c=y[V+4>>2],d=(c&-c)-1|0,c=d>>>12&16,f=d>>>(c>>>0),d=f>>>5&8,g=f>>>(d>>>0),f=g>>>2&4,e=g>>>(f>>>0),g=e>>>1&2;e>>>=g>>>0;var i=e>>>1&1,c=d=F[V+304+((d|c|f|g|i)+(e>>>(i>>>0))<<2)>>2],d=(y[d+4>>2]&-8)-b|0;a:for(;;){for(f=c;;){g=y[f+16>>2];if((g|0)==0){if(f=y[f+20>>2],(f|0)==0){break a}}else{f=g}g=(y[f+4>>2]&-8)-b|0;if(g>>>0>>0){c=f;d=g;continue a}}}g=c;i=F[V+16>>2];e=g>>>0>>0;do{if(!e){var h=g+b|0,f=h;if(g>>>0>>0){var e=F[c+24>>2],h=F[c+12>>2],k=(h|0)==(c|0);do{if(k){var l=c+20|0,j=y[l>>2];if((j|0)==0&&(l=c+16|0,j=y[l>>2],(j|0)==0)){var n=0;break}for(;;){var p=j+20|0,r=y[p>>2];if((r|0)==0&&(p=j+16|0,r=F[p>>2],(r|0)==0)){break}l=p;j=r}l>>>0>>0?(W(),a("Reached an unreachable!")):(y[l>>2]=0,n=j)}else{l=F[c+8>>2],l>>>0>>0?(W(),a("Reached an unreachable!")):(y[l+12>>2]=h,y[h+8>>2]=l,n=h)}}while(0);i=(e|0)==0;a:do{if(!i){h=c+28|0;k=V+304+(y[h>>2]<<2)|0;l=(c|0)==(y[k>>2]|0);do{if(l){y[k>>2]=n;if((n|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break a}if(e>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{if(j=e+16|0,(y[j>>2]|0)==(c|0)?y[j>>2]=n:y[e+20>>2]=n,(n|0)==0){break a}}}while(0);n>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[n+24>>2]=e,h=F[c+16>>2],(h|0)!=0&&(h>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[n+16>>2]=h,y[h+24>>2]=n)),h=F[c+20>>2],(h|0)!=0&&(h>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[n+20>>2]=h,y[h+24>>2]=n)))}}while(0);if(d>>>0<16){var o=d+b|0;y[c+4>>2]=o|3;y[(o+(g+4)|0)>>2]|=1}else{y[c+4>>2]=b|3;y[b+(g+4)>>2]=d|1;y[g+(d+b)>>2]=d;i=F[V+8>>2];if((i|0)!=0){b=F[V+20>>2];g=i>>>2&1073741822;n=V+40+(g<<2)|0;e=F[V>>2];i=1<<(i>>>3);if((e&i|0)==0){y[V>>2]=e|i;var o=n,t=V+40+(g+2<<2)|0}else{g=V+40+(g+2<<2)|0,e=F[g>>2],e>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(o=e,t=g)}y[t>>2]=b;y[o+12>>2]=b;y[b+8>>2]=o;y[b+12>>2]=n}y[V+8>>2]=d;y[V+20>>2]=f}return c+8|0}}}while(0);W();a("Reached an unreachable!")}uh.X=1;function vh(b){var c=-b|0,d=b>>>8;if((d|0)==0){var f=0}else{if(b>>>0>16777215){f=31}else{var g=(d+1048320|0)>>>16&8,e=d<>>16&4,h=e<>>16&2,l=14-(i|g|k)+(h<>>15)|0,f=b>>>((l+7|0)>>>0)&1|l<<1}}var j=F[V+304+(f<<2)>>2],n=(j|0)==0;a:do{if(n){var p=0,r=c,o=0}else{for(var t=0,s=c,u=j,w=b<<((f|0)==31?0:25-(f>>>1)|0),v=0;;){var z=y[u+4>>2]&-8,B=z-b|0;if(B>>>0>>0){if((z|0)==(b|0)){p=u;r=B;o=u;break a}var D=u,C=B}else{D=t,C=s}var E=F[u+20>>2],G=F[u+16+(w>>>31<<2)>>2],H=(E|0)==0|(E|0)==(G|0)?v:E;if((G|0)==0){p=D;r=C;o=H;break a}t=D;s=C;u=G;w<<=1;v=H}}}while(0);if((o|0)==0&(p|0)==0){var K=1<>2]&(K|-K);if((L|0)==0){var N=o}else{var O=(L&-L)-1|0,R=O>>>12&16,U=O>>>(R>>>0),Y=U>>>5&8,X=U>>>(Y>>>0),ba=X>>>2&4,$=X>>>(ba>>>0),ja=$>>>1&2,sa=$>>>(ja>>>0),Ea=sa>>>1&1,N=y[V+304+((Y|R|ba|ja|Ea)+(sa>>>(Ea>>>0))<<2)>>2]}}else{N=o}var Xa=(N|0)==0;a:do{if(Xa){var ea=r,fa=p}else{for(var va=N,ob=r,wa=p;;){var pb=(y[va+4>>2]&-8)-b|0,gb=pb>>>0>>0,Ib=gb?pb:ob,Fa=gb?va:wa,qb=F[va+16>>2];if((qb|0)!=0){va=qb}else{var Ya=F[va+20>>2];if((Ya|0)==0){ea=Ib;fa=Fa;break a}va=Ya}ob=Ib;wa=Fa}}}while(0);var Na=(fa|0)==0;a:do{if(Na){var za=0}else{if(ea>>>0<(y[V+8>>2]-b|0)>>>0){var da=fa,Oa=F[V+16>>2],Za=da>>>0>>0;do{if(!Za){var Aa=da+b|0,hb=Aa;if(da>>>0>>0){var Ga=F[fa+24>>2],Pa=F[fa+12>>2],$a=(Pa|0)==(fa|0);do{if($a){var Ab=fa+20|0,cb=y[Ab>>2];if((cb|0)==0){var rb=fa+16|0,Qa=y[rb>>2];if((Qa|0)==0){var pa=0;break}var ia=rb,qa=Qa}else{ia=Ab,qa=cb}for(;;){var Ra=qa+20|0,ra=y[Ra>>2];if((ra|0)!=0){ia=Ra,qa=ra}else{var ib=qa+16|0,sb=F[ib>>2];if((sb|0)==0){break}ia=ib;qa=sb}}ia>>>0>>0?(W(),a("Reached an unreachable!")):(y[ia>>2]=0,pa=qa)}else{var jb=F[fa+8>>2];jb>>>0>>0?(W(),a("Reached an unreachable!")):(y[jb+12>>2]=Pa,y[Pa+8>>2]=jb,pa=Pa)}}while(0);var db=(Ga|0)==0;b:do{if(!db){var Sa=fa+28|0,kb=V+304+(y[Sa>>2]<<2)|0,ta=(fa|0)==(y[kb>>2]|0);do{if(ta){y[kb>>2]=pa;if((pa|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break b}if(Ga>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{var Bb=Ga+16|0;(y[Bb>>2]|0)==(fa|0)?y[Bb>>2]=pa:y[Ga+20>>2]=pa;if((pa|0)==0){break b}}}while(0);if(pa>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{y[pa+24>>2]=Ga;var Ha=F[fa+16>>2];(Ha|0)!=0&&(Ha>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[pa+16>>2]=Ha,y[Ha+24>>2]=pa));var ya=F[fa+20>>2];(ya|0)!=0&&(ya>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[pa+20>>2]=ya,y[ya+24>>2]=pa))}}}while(0);var xa=ea>>>0<16;b:do{if(xa){var Ba=ea+b|0;y[fa+4>>2]=Ba|3;y[(Ba+(da+4)|0)>>2]|=1}else{if(y[fa+4>>2]=b|3,y[b+(da+4)>>2]=ea|1,y[da+(ea+b)>>2]=ea,ea>>>0<256){var Ca=ea>>>2&1073741822,Ta=V+40+(Ca<<2)|0,lb=F[V>>2],Jb=1<<(ea>>>3);if((lb&Jb|0)==0){y[V>>2]=lb|Jb;var eb=Ta,Da=V+40+(Ca+2<<2)|0}else{var Ia=V+40+(Ca+2<<2)|0,mb=F[Ia>>2];mb>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(eb=mb,Da=Ia)}y[Da>>2]=hb;y[eb+12>>2]=hb;y[b+(da+8)>>2]=eb;y[b+(da+12)>>2]=Ta}else{var Ua=Aa,Ja=ea>>>8;if((Ja|0)==0){var Ka=0}else{if(ea>>>0>16777215){Ka=31}else{var Cb=(Ja+1048320|0)>>>16&8,Db=Ja<>>16&4,tb=Db<>>16&2,fb=14-(Eb|Cb|Va)+(tb<>>15)|0,Ka=ea>>>((fb+7|0)>>>0)&1|fb<<1}}var ub=V+304+(Ka<<2)|0;y[b+(da+28)>>2]=Ka;var nb=b+(da+16)|0;y[b+(da+20)>>2]=0;y[nb>>2]=0;var Fb=y[V+4>>2],Qb=1<>2]=Fb|Qb,y[ub>>2]=Ua,y[b+(da+24)>>2]=ub,y[b+(da+12)>>2]=Ua,y[b+(da+8)>>2]=Ua}else{for(var wb=ea<<((Ka|0)==31?0:25-(Ka>>>1)|0),Lb=y[ub>>2];;){if((y[Lb+4>>2]&-8|0)==(ea|0)){var Rb=Lb+8|0,Wb=F[Rb>>2],Tb=F[V+16>>2],Xb=Lb>>>0>>0;do{if(!Xb&&Wb>>>0>=Tb>>>0){y[Wb+12>>2]=Ua;y[Rb>>2]=Ua;y[b+(da+8)>>2]=Wb;y[b+(da+12)>>2]=Lb;y[b+(da+24)>>2]=0;break b}}while(0);W();a("Reached an unreachable!")}else{var Vb=Lb+16+(wb>>>31<<2)|0,Yb=F[Vb>>2];if((Yb|0)==0){if(Vb>>>0>=F[V+16>>2]>>>0){y[Vb>>2]=Ua;y[b+(da+24)>>2]=Lb;y[b+(da+12)>>2]=Ua;y[b+(da+8)>>2]=Ua;break b}W();a("Reached an unreachable!")}else{wb<<=1,Lb=Yb}}}}}}}while(0);za=fa+8|0;break a}}}while(0);W();a("Reached an unreachable!")}else{za=0}}}while(0);return za}vh.X=1;function wh(b){var c;(y[xh>>2]|0)==0&&yh();var d=(y[V+440>>2]&4|0)==0;do{if(d){c=y[V+24>>2];if((c|0)==0){c=5}else{if(c=zh(c),(c|0)==0){c=5}else{var f=y[xh+8>>2],f=b+47-y[V+12>>2]+f&-f;if(f>>>0<2147483647){var g=Ah(f);if((g|0)==(y[c>>2]+y[c+4>>2]|0)){var e=g,i=f,h=g;c=12}else{var k=g,l=f;c=14}}else{c=13}}}if(c==5){if(c=Ah(0),(c|0)==-1){c=13}else{var f=y[xh+8>>2],f=f+(b+47)&-f,g=c,j=y[xh+4>>2],n=j-1|0,f=(n&g|0)==0?f:f-g+(n+g&-j)|0;f>>>0<2147483647?(g=Ah(f),(g|0)==(c|0)?(e=c,i=f,h=g,c=12):(k=g,l=f,c=14)):c=13}}if(c==13){y[V+440>>2]|=4,c=22}else{if(c==12){if((e|0)!=-1){var p=i,r=e;c=25;break}k=h;l=i}c=-l|0;if((k|0)!=-1&l>>>0<2147483647){if(l>>>0<(b+48|0)>>>0){f=y[xh+8>>2],f=b+47-l+f&-f,f>>>0<2147483647?(Ah(f)|0)==-1?(Ah(c),c=21):(o=f+l|0,c=20):(o=l,c=20)}else{var o=l;c=20}}else{o=l,c=20}c==20&&(k|0)!=-1?(p=o,r=k,c=25):(y[V+440>>2]|=4,c=22)}}else{c=22}}while(0);c==22&&(d=y[xh+8>>2],d=d+(b+47)&-d,d>>>0<2147483647?(d=Ah(d),e=Ah(0),(e|0)!=-1&(d|0)!=-1&d>>>0>>0?(e=e-d|0,e>>>0<=(b+40|0)>>>0|(d|0)==-1?c=48:(p=e,r=d,c=25)):c=48):c=48);a:do{if(c==25){d=y[V+432>>2]+p|0;y[V+432>>2]=d;d>>>0>F[V+436>>2]>>>0&&(y[V+436>>2]=d);d=F[V+24>>2];e=(d|0)==0;b:do{if(e){i=F[V+16>>2];(i|0)==0|r>>>0>>0&&(y[V+16>>2]=r);y[V+444>>2]=r;y[V+448>>2]=p;y[V+456>>2]=0;y[V+36>>2]=y[xh>>2];y[V+32>>2]=-1;for(i=0;;){if(h=i<<1,k=V+40+(h+2<<2)|0,l=V+40+(h<<2)|0,y[V+40+(h+3<<2)>>2]=l,y[k>>2]=l,i=i+1|0,(i|0)==32){break}}Bh(r,p-40|0)}else{for(o=V+444|0;;){if((o|0)==0){break}i=F[o>>2];h=o+4|0;k=F[h>>2];l=i+k|0;if((r|0)==(l|0)){if((y[o+12>>2]&8|0)!=0){break}o=d;if(!(o>>>0>=i>>>0&o>>>0>>0)){break}y[h>>2]=k+p|0;Bh(y[V+24>>2],y[V+12>>2]+p|0);break b}o=y[o+8>>2]}r>>>0>2]>>>0&&(y[V+16>>2]=r);h=r+p|0;for(k=V+444|0;;){if((k|0)==0){break}l=k|0;i=F[l>>2];if((i|0)==(h|0)){if((y[k+12>>2]&8|0)!=0){break}y[l>>2]=r;var t=k+4|0;y[t>>2]=y[t>>2]+p|0;t=Ch(r,i,b);c=49;break a}k=y[k+8>>2]}Dh(r,p)}}while(0);d=F[V+12>>2];d>>>0>b>>>0?(t=d-b|0,y[V+12>>2]=t,e=d=F[V+24>>2],y[V+24>>2]=e+b|0,y[b+(e+4)>>2]=t|1,y[d+4>>2]=b|3,t=d+8|0,c=49):c=48}}while(0);c==48&&(y[Eh>>2]=12,t=0);return t}wh.X=1;function Ae(b){var c,d=(b|0)==0;a:do{if(!d){var f=b-8|0,g=f,e=F[V+16>>2],i=f>>>0>>0;b:do{if(!i){var h=F[b-4>>2],k=h&3;if((k|0)!=1){var l=h&-8,j=b+(l-8)|0,n=j,p=(h&1|0)==0;c:do{if(p){var r=F[f>>2];if((k|0)==0){break a}var o=-8-r|0,t=b+o|0,s=t,u=r+l|0;if(t>>>0>>0){break b}if((s|0)==(y[V+20>>2]|0)){var w=b+(l-4)|0;if((y[w>>2]&3|0)!=3){var v=s,z=u;break}y[V+8>>2]=u;y[w>>2]&=-2;y[o+(b+4)>>2]=u|1;y[j>>2]=u;break a}if(r>>>0<256){var B=F[o+(b+8)>>2],D=F[o+(b+12)>>2];if((B|0)==(D|0)){y[V>>2]&=1<<(r>>>3)^-1,v=s,z=u}else{var C=V+40+((r>>>2&1073741822)<<2)|0,E=(B|0)!=(C|0)&B>>>0>>0;do{if(!E&&!((D|0)!=(C|0)&D>>>0>>0)){y[B+12>>2]=D;y[D+8>>2]=B;v=s;z=u;break c}}while(0);W();a("Reached an unreachable!")}}else{var G=t,H=F[o+(b+24)>>2],K=F[o+(b+12)>>2],L=(K|0)==(G|0);do{if(L){var N=o+(b+20)|0,O=y[N>>2];if((O|0)==0){var R=o+(b+16)|0,U=y[R>>2];if((U|0)==0){var Y=0;break}var X=R,ba=U}else{X=N,ba=O,c=20}for(;;){var $=ba+20|0,ja=y[$>>2];if((ja|0)!=0){X=$,ba=ja}else{var sa=ba+16|0,Ea=F[sa>>2];if((Ea|0)==0){break}X=sa;ba=Ea}}X>>>0>>0?(W(),a("Reached an unreachable!")):(y[X>>2]=0,Y=ba)}else{var Xa=F[o+(b+8)>>2];Xa>>>0>>0?(W(),a("Reached an unreachable!")):(y[Xa+12>>2]=K,y[K+8>>2]=Xa,Y=K)}}while(0);if((H|0)==0){v=s,z=u}else{var ea=o+(b+28)|0,fa=V+304+(y[ea>>2]<<2)|0,va=(G|0)==(y[fa>>2]|0);do{if(va){y[fa>>2]=Y;if((Y|0)!=0){break}y[V+4>>2]&=1<>2]^-1;v=s;z=u;break c}if(H>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{var ob=H+16|0;(y[ob>>2]|0)==(G|0)?y[ob>>2]=Y:y[H+20>>2]=Y;if((Y|0)==0){v=s;z=u;break c}}}while(0);if(Y>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{y[Y+24>>2]=H;var wa=F[o+(b+16)>>2];(wa|0)!=0&&(wa>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[Y+16>>2]=wa,y[wa+24>>2]=Y));var pb=F[o+(b+20)>>2];(pb|0)==0?(v=s,z=u):pb>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[Y+20>>2]=pb,y[pb+24>>2]=Y,v=s,z=u)}}}}else{v=g,z=l}}while(0);var gb=v;if(gb>>>0>>0){var Ib=b+(l-4)|0,Fa=F[Ib>>2];if((Fa&1|0)!=0){var qb=(Fa&2|0)==0;do{if(qb){if((n|0)==(y[V+24>>2]|0)){var Ya=y[V+12>>2]+z|0;y[V+12>>2]=Ya;y[V+24>>2]=v;y[v+4>>2]=Ya|1;(v|0)==(y[V+20>>2]|0)&&(y[V+20>>2]=0,y[V+8>>2]=0);if(Ya>>>0<=F[V+28>>2]>>>0){break a}Fh(0);break a}if((n|0)==(y[V+20>>2]|0)){var Na=y[V+8>>2]+z|0;y[V+8>>2]=Na;y[V+20>>2]=v;y[v+4>>2]=Na|1;y[(gb+Na|0)>>2]=Na;break a}var za=(Fa&-8)+z|0,da=Fa>>>3,Oa=Fa>>>0<256;c:do{if(Oa){var Za=F[b+l>>2],Aa=F[b+(l|4)>>2];if((Za|0)==(Aa|0)){y[V>>2]&=1<>>2&1073741822)<<2)|0;c=(Za|0)==(hb|0)?62:Za>>>0>2]>>>0?65:62;do{if(c==62&&!((Aa|0)!=(hb|0)&&Aa>>>0>2]>>>0)){y[Za+12>>2]=Aa;y[Aa+8>>2]=Za;break c}}while(0);W();a("Reached an unreachable!")}}else{var Ga=j,Pa=F[l+(b+16)>>2],$a=F[b+(l|4)>>2],Ab=($a|0)==(Ga|0);do{if(Ab){var cb=l+(b+12)|0,rb=y[cb>>2];if((rb|0)==0){var Qa=l+(b+8)|0,pa=y[Qa>>2];if((pa|0)==0){var ia=0;break}var qa=Qa,Ra=pa}else{qa=cb,Ra=rb,c=72}for(;;){var ra=Ra+20|0,ib=y[ra>>2];if((ib|0)!=0){qa=ra,Ra=ib}else{var sb=Ra+16|0,jb=F[sb>>2];if((jb|0)==0){break}qa=sb;Ra=jb}}qa>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[qa>>2]=0,ia=Ra)}else{var db=F[b+l>>2];db>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[db+12>>2]=$a,y[$a+8>>2]=db,ia=$a)}}while(0);if((Pa|0)!=0){var Sa=l+(b+20)|0,kb=V+304+(y[Sa>>2]<<2)|0,ta=(Ga|0)==(y[kb>>2]|0);do{if(ta){y[kb>>2]=ia;if((ia|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break c}if(Pa>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{var Bb=Pa+16|0;(y[Bb>>2]|0)==(Ga|0)?y[Bb>>2]=ia:y[Pa+20>>2]=ia;if((ia|0)==0){break c}}}while(0);if(ia>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{y[ia+24>>2]=Pa;var Ha=F[l+(b+8)>>2];(Ha|0)!=0&&(Ha>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[ia+16>>2]=Ha,y[Ha+24>>2]=ia));var ya=F[l+(b+12)>>2];(ya|0)!=0&&(ya>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[ia+20>>2]=ya,y[ya+24>>2]=ia))}}}}while(0);y[v+4>>2]=za|1;y[gb+za>>2]=za;if((v|0)!=(y[V+20>>2]|0)){var xa=za}else{y[V+8>>2]=za;break a}}else{y[Ib>>2]=Fa&-2,y[v+4>>2]=z|1,xa=y[gb+z>>2]=z}}while(0);if(xa>>>0<256){var Ba=xa>>>2&1073741822,Ca=V+40+(Ba<<2)|0,Ta=F[V>>2],lb=1<<(xa>>>3);if((Ta&lb|0)==0){y[V>>2]=Ta|lb;var Jb=Ca,eb=V+40+(Ba+2<<2)|0}else{var Da=V+40+(Ba+2<<2)|0,Ia=F[Da>>2];Ia>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(Jb=Ia,eb=Da)}y[eb>>2]=v;y[Jb+12>>2]=v;y[v+8>>2]=Jb;y[v+12>>2]=Ca;break a}var mb=v,Ua=xa>>>8;if((Ua|0)==0){var Ja=0}else{if(xa>>>0>16777215){Ja=31}else{var Ka=(Ua+1048320|0)>>>16&8,Cb=Ua<>>16&4,Eb=Cb<>>16&2,Va=14-(Db|Ka|tb)+(Eb<>>15)|0,Ja=xa>>>((Va+7|0)>>>0)&1|Va<<1}}var fb=V+304+(Ja<<2)|0;y[v+28>>2]=Ja;y[v+20>>2]=0;y[v+16>>2]=0;var ub=y[V+4>>2],nb=1<>2]=ub|nb,y[fb>>2]=mb,y[v+24>>2]=fb,y[v+12>>2]=v,y[v+8>>2]=v}else{for(var Qb=xa<<((Ja|0)==31?0:25-(Ja>>>1)|0),wb=y[fb>>2];;){if((y[wb+4>>2]&-8|0)==(xa|0)){var Lb=wb+8|0,Rb=F[Lb>>2],Wb=F[V+16>>2],Tb=wb>>>0>>0;do{if(!Tb&&Rb>>>0>=Wb>>>0){y[Rb+12>>2]=mb;y[Lb>>2]=mb;y[v+8>>2]=Rb;y[v+12>>2]=wb;y[v+24>>2]=0;break c}}while(0);W();a("Reached an unreachable!")}else{var Xb=wb+16+(Qb>>>31<<2)|0,Vb=F[Xb>>2];if((Vb|0)==0){if(Xb>>>0>=F[V+16>>2]>>>0){y[Xb>>2]=mb;y[v+24>>2]=wb;y[v+12>>2]=v;y[v+8>>2]=v;break c}W();a("Reached an unreachable!")}else{Qb<<=1,wb=Vb}}}}}while(0);var Yb=y[V+32>>2]-1|0;y[V+32>>2]=Yb;if((Yb|0)!=0){break a}var fc=y[V+452>>2],ga=(fc|0)==0;c:do{if(!ga){for(var pc=fc;;){var Ub=y[pc+8>>2];if((Ub|0)==0){break c}pc=Ub}}}while(0);y[V+32>>2]=-1;break a}}}}}while(0);W();a("Reached an unreachable!")}}while(0)}Ae.X=1;function Fh(b){(y[xh>>2]|0)==0&&yh();var c=b>>>0<4294967232;a:do{if(c){var d=F[V+24>>2];if((d|0)==0){d=0;break}var f=F[V+12>>2],g=f>>>0>(b+40|0)>>>0;do{if(g){var e=F[xh+8>>2],i=(Math.floor(((-40-b-1+f+e|0)>>>0)/(e>>>0))-1)*e|0,h=zh(d);if((y[h+12>>2]&8|0)==0){var k=Ah(0),l=h+4|0;if((k|0)==(y[h>>2]+y[l>>2]|0)&&(i=Ah(-(i>>>0>2147483646?-2147483648-e|0:i)|0),e=Ah(0),(i|0)!=-1&e>>>0>>0&&(i=k-e|0,(k|0)!=(e|0)))){y[l>>2]=y[l>>2]-i|0;y[V+432>>2]=y[V+432>>2]-i|0;Bh(y[V+24>>2],y[V+12>>2]-i|0);d=(k|0)!=(e|0);break a}}}}while(0);if(F[V+12>>2]>>>0<=F[V+28>>2]>>>0){d=0;break}y[V+28>>2]=-1}d=0}while(0);return d&1}Fh.X=1;function yh(){if((y[xh>>2]|0)==0){var b=Gh();(b-1&b|0)==0?(y[xh+8>>2]=b,y[xh+4>>2]=b,y[xh+12>>2]=-1,y[xh+16>>2]=2097152,y[xh+20>>2]=0,y[V+440>>2]=0,y[xh>>2]=Math.floor(Date.now()/1e3)&-16^1431655768):(W(),a("Reached an unreachable!"))}}function zh(b){for(var c=V+444|0;;){var d=F[c>>2];if(d>>>0<=b>>>0&&(d+y[c+4>>2]|0)>>>0>b>>>0){var f=c;break}c=F[c+8>>2];if((c|0)==0){f=0;break}}return f}function Bh(b,c){var d=b+8|0,d=(d&7|0)==0?0:-d&7,f=c-d|0;y[V+24>>2]=b+d|0;y[V+12>>2]=f;y[d+(b+4)>>2]=f|1;y[c+(b+4)>>2]=40;y[V+28>>2]=y[xh+16>>2]}function Ch(b,c,d){var f,g=b+8|0,g=(g&7|0)==0?0:-g&7,e=c+8|0,e=(e&7|0)==0?0:-e&7,i=c+e|0,h=g+d|0,k=b+h|0,l=i-(b+g)-d|0;y[g+(b+4)>>2]=d|3;d=(i|0)==(y[V+24>>2]|0);a:do{if(d){var j=y[V+12>>2]+l|0;y[V+12>>2]=j;y[V+24>>2]=k;y[h+(b+4)>>2]=j|1}else{if((i|0)==(y[V+20>>2]|0)){j=y[V+8>>2]+l|0,y[V+8>>2]=j,y[V+20>>2]=k,y[h+(b+4)>>2]=j|1,y[(b+(j+h)|0)>>2]=j}else{var n=F[e+(c+4)>>2];if((n&3|0)==1){var j=n&-8,p=n>>>3,r=n>>>0<256;b:do{if(r){var o=F[c+(e|8)>>2],t=F[e+(c+12)>>2];if((o|0)==(t|0)){y[V>>2]&=1<>>2&1073741822)<<2)|0;f=(o|0)==(s|0)?14:o>>>0>2]>>>0?17:14;do{if(f==14&&!((t|0)!=(s|0)&&t>>>0>2]>>>0)){y[o+12>>2]=t;y[t+8>>2]=o;break b}}while(0);W();a("Reached an unreachable!")}}else{f=i;o=F[c+(e|24)>>2];t=F[e+(c+12)>>2];s=(t|0)==(f|0);do{if(s){var u=e|16,w=u+(c+4)|0,v=y[w>>2];if((v|0)==0){if(u=c+u|0,v=y[u>>2],(v|0)==0){var z=0;break}}else{u=w}for(;;){var w=v+20|0,B=y[w>>2];if((B|0)==0&&(w=v+16|0,B=F[w>>2],(B|0)==0)){break}u=w;v=B}u>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[u>>2]=0,z=v)}else{u=F[c+(e|8)>>2],u>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[u+12>>2]=t,y[t+8>>2]=u,z=t)}}while(0);if((o|0)!=0){t=e+(c+28)|0;s=V+304+(y[t>>2]<<2)|0;u=(f|0)==(y[s>>2]|0);do{if(u){y[s>>2]=z;if((z|0)!=0){break}y[V+4>>2]&=1<>2]^-1;break b}if(o>>>0>2]>>>0){W(),a("Reached an unreachable!")}else{if(v=o+16|0,(y[v>>2]|0)==(f|0)?y[v>>2]=z:y[o+20>>2]=z,(z|0)==0){break b}}}while(0);z>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[z+24>>2]=o,f=e|16,o=F[c+f>>2],(o|0)!=0&&(o>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[z+16>>2]=o,y[o+24>>2]=z)),f=F[f+(c+4)>>2],(f|0)!=0&&(f>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(y[z+20>>2]=f,y[f+24>>2]=z)))}}}while(0);n=c+(j|e)|0;j=j+l|0}else{n=i,j=l}y[(n+4|0)>>2]&=-2;y[h+(b+4)>>2]=j|1;y[b+(j+h)>>2]=j;if(j>>>0<256){p=j>>>2&1073741822;n=V+40+(p<<2)|0;r=F[V>>2];j=1<<(j>>>3);if((r&j|0)==0){y[V>>2]=r|j;var D=n,C=V+40+(p+2<<2)|0}else{j=V+40+(p+2<<2)|0,p=F[j>>2],p>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(D=p,C=j)}y[C>>2]=k;y[D+12>>2]=k;y[h+(b+8)>>2]=D;y[h+(b+12)>>2]=n}else{if(n=k,r=j>>>8,(r|0)==0?p=0:j>>>0>16777215?p=31:(p=(r+1048320|0)>>>16&8,f=r<>>16&4,f<<=r,o=(f+245760|0)>>>16&2,p=14-(r|p|o)+(f<>>15)|0,p=j>>>((p+7|0)>>>0)&1|p<<1),r=V+304+(p<<2)|0,y[h+(b+28)>>2]=p,f=h+(b+16)|0,y[h+(b+20)>>2]=0,y[f>>2]=0,f=y[V+4>>2],o=1<>2]=f|o,y[r>>2]=n,y[h+(b+24)>>2]=r,y[h+(b+12)>>2]=n,y[h+(b+8)>>2]=n}else{p=j<<((p|0)==31?0:25-(p>>>1)|0);for(r=y[r>>2];;){if((y[r+4>>2]&-8|0)==(j|0)){f=r+8|0;o=F[f>>2];t=F[V+16>>2];s=r>>>0>>0;do{if(!s&&o>>>0>=t>>>0){y[o+12>>2]=n;y[f>>2]=n;y[h+(b+8)>>2]=o;y[h+(b+12)>>2]=r;y[h+(b+24)>>2]=0;break a}}while(0);W();a("Reached an unreachable!")}else{if(f=r+16+(p>>>31<<2)|0,o=F[f>>2],(o|0)==0){if(f>>>0>=F[V+16>>2]>>>0){y[f>>2]=n;y[h+(b+24)>>2]=r;y[h+(b+12)>>2]=n;y[h+(b+8)>>2]=n;break a}W();a("Reached an unreachable!")}else{p<<=1,r=o}}}}}}}}while(0);return b+(g|8)|0}Ch.X=1;function Dh(b,c){var d=F[V+24>>2],f=zh(d),g=y[f>>2],e=y[f+4>>2],f=g+e|0,i=g+(e-39)|0,g=g+(e-47+((i&7|0)==0?0:-i&7))|0,g=g>>>0<(d+16|0)>>>0?d:g,e=g+8|0;Bh(b,c-40|0);y[(g+4|0)>>2]=27;y[e>>2]=y[V+444>>2];y[e+4>>2]=y[V+448>>2];y[e+8>>2]=y[V+452>>2];y[e+12>>2]=y[V+456>>2];y[V+444>>2]=b;y[V+448>>2]=c;y[V+456>>2]=0;y[V+452>>2]=e;y[(g+28|0)>>2]=7;e=(g+32|0)>>>0>>0;a:do{if(e){for(i=0;;){var h=i<<2,k=h+(g+36)|0;y[(h+(g+32)|0)>>2]=7;if(k>>>0>=f>>>0){break a}i=i+1|0}}}while(0);f=(g|0)==(d|0);a:do{if(!f){if(e=g-d|0,i=d+e|0,y[(e+(d+4)|0)>>2]&=-2,y[d+4>>2]=e|1,y[i>>2]=e,e>>>0<256){h=e>>>2&1073741822;i=V+40+(h<<2)|0;k=F[V>>2];e=1<<(e>>>3);if((k&e|0)==0){y[V>>2]=k|e;var l=i,j=V+40+(h+2<<2)|0}else{e=V+40+(h+2<<2)|0,h=F[e>>2],h>>>0>2]>>>0?(W(),a("Reached an unreachable!")):(l=h,j=e)}y[j>>2]=d;y[l+12>>2]=d;y[d+8>>2]=l;y[d+12>>2]=i}else{i=d;k=e>>>8;if((k|0)==0){h=0}else{if(e>>>0>16777215){h=31}else{var h=(k+1048320|0)>>>16&8,n=k<>>16&4;n<<=k;var p=(n+245760|0)>>>16&2,h=14-(k|h|p)+(n<

>>15)|0,h=e>>>((h+7|0)>>>0)&1|h<<1}}k=V+304+(h<<2)|0;y[d+28>>2]=h;y[d+20>>2]=0;y[d+16>>2]=0;n=y[V+4>>2];p=1<>2]=n|p,y[k>>2]=i,y[d+24>>2]=k,y[d+12>>2]=d,y[d+8>>2]=d}else{h=e<<((h|0)==31?0:25-(h>>>1)|0);for(k=y[k>>2];;){if((y[k+4>>2]&-8|0)==(e|0)){var n=k+8|0,p=F[n>>2],r=F[V+16>>2],o=k>>>0>>0;do{if(!o&&p>>>0>=r>>>0){y[p+12>>2]=i;y[n>>2]=i;y[d+8>>2]=p;y[d+12>>2]=k;y[d+24>>2]=0;break a}}while(0);W();a("Reached an unreachable!")}else{if(n=k+16+(h>>>31<<2)|0,p=F[n>>2],(p|0)==0){if(n>>>0>=F[V+16>>2]>>>0){y[n>>2]=i;y[d+24>>2]=k;y[d+12>>2]=d;y[d+8>>2]=d;break a}W();a("Reached an unreachable!")}else{h<<=1,k=p}}}}}}}while(0)}Dh.X=1;function Hh(b){y[b>>2]=Ih+8|0;Jh(b)}function sd(b,c,d){if(d>=20&&c%2==b%2){if(c%4==b%4){for(d=c+d;c%4;){q[b++]=q[c++]}c>>=2;b>>=2;for(var f=d>>2;c>=1;b>>=1;for(f=d>>1;c=20){for(d=b+d;b%4;){q[b++]=c}c<0&&(c+=256);b>>=2;for(var f=d>>2,g=c|c<<8|c<<16|c<<24;b>2]=b}var Eh,Rh=0,Sh=0,Th=0,Z={va:"/",ya:2,b:[ha],D:ca,t:(function(b,c){if(typeof b!=="string"){return ha}if(c===aa){c=Z.va}b&&b[0]=="/"&&(c="");for(var d=(c+"/"+b).split("/").reverse(),f=[""];d.length;){var g=d.pop();g==""||g=="."||(g==".."?f.length>1&&f.pop():f.push(g))}return f.length==1?"/":f.join("/")}),u:(function(b,c,d){var f={xa:ka,r:ka,error:0,name:ha,path:ha,object:ha,H:ka,J:ha,I:ha},b=Z.t(b);if(b=="/"){f.xa=ca,f.r=f.H=ca,f.name="/",f.path=f.J="/",f.object=f.I=Z.root}else{if(b!==ha){for(var d=d||0,b=b.slice(1).split("/"),g=Z.root,e=[""];b.length;){if(b.length==1&&g.e){f.H=ca,f.J=e.length==1?"/":e.join("/"),f.I=g,f.name=b[0]}var i=b.shift();if(g.e){if(g.L){if(!g.c.hasOwnProperty(i)){f.error=2;break}}else{f.error=Kh;break}}else{f.error=20;break}g=g.c[i];if(g.link&&!(c&&b.length==0)){if(d>40){f.error=40;break}f=Z.t(g.link,e.join("/"));return Z.u([f].concat(b).join("/"),c,d+1)}e.push(i);if(b.length==0){f.r=ca,f.path=e.join("/"),f.object=g}}}}return f}),B:(function(b,c){Z.z();var d=Z.u(b,c);return d.r?d.object:(Qh(d.error),ha)}),w:(function(b,c,d,f,g){b||(b="/");typeof b==="string"&&(b=Z.B(b));b||(Qh(Kh),a(Error("Parent path must exist.")));b.e||(Qh(20),a(Error("Parent must be a folder.")));!b.write&&!Z.D&&(Qh(Kh),a(Error("Parent folder must be writeable.")));if(!c||c=="."||c==".."){Qh(2),a(Error("Name must not be empty."))}b.c.hasOwnProperty(c)&&(Qh(17),a(Error("Can't overwrite object.")));b.c[c]={L:f===aa?ca:f,write:g===aa?ka:g,timestamp:Date.now(),wa:Z.ya++};for(var e in d){d.hasOwnProperty(e)&&(b.c[c][e]=d[e])}return b.c[c]}),q:(function(b,c,d,f){return Z.w(b,c,{e:ca,d:ka,c:{}},d,f)}),ua:(function(b,c,d,f){b=Z.B(b);b===ha&&a(Error("Invalid parent."));for(c=c.split("/").reverse();c.length;){var g=c.pop();g&&(b.c.hasOwnProperty(g)||Z.q(b,g,d,f),b=b.c[g])}return b}),l:(function(b,c,d,f,g){d.e=ka;return Z.w(b,c,d,f,g)}),ta:(function(b,c,d,f,g){if(typeof d==="string"){for(var e=[],i=0;i0&&Z.b[2].object.i("\n".charCodeAt(0)),Z.b[3].object.i.buffer.length>0&&Z.b[3].object.i("\n".charCodeAt(0)))})};function Uh(b,c,d){var f=Z.b[b];if(f){if(f.m){if(d<0){return Qh(Mh),-1}else{if(f.object.d){if(f.object.i){for(var g=0;g>2];if(Uh(c,b,Ac(b))>=0&&(b="\n".charCodeAt(0)&255,q[Wh]=b>=0?b:Math.pow(2,aa)+b,Uh(c,Wh,1)==-1&&c in Z.b)){Z.b[c].error=ca}}wc.unshift({C:(function(){Z.D=ka;Z.j.s||Z.j()})});xc.push({C:(function(){Z.za()})});Qh(0);P(12,"void*",M);var Wh=P([0],"i8",M);Module.sa=(function(b){function c(){for(var b=0;b<3;b++){f.push(0)}}var d=b.length+1,f=[P(rc("/bin/this.program"),"i8",M)];c();for(var g=0;g>2]=hj;y[Xh+4>>2]=ij;gj=P([2,0,0,0,0],["i8*",0,0,0,0],M);y[hj>>2]=gj+8|0;y[hj+4>>2]=Q.P|0;y[hj+8>>2]=aa;y[ij>>2]=gj+8|0;y[ij+4>>2]=Q.O|0;y[ij+8>>2]=hj;lc=[0,0,(function(b,c,d,f,g){(d|0)!=0&&(kc(c,q[b],d),c=c+d|0);if((f|0)!=0){for(d=0;;){if(q[c+d|0]=q[b+d|0],d=d+1|0,(d|0)==(f|0)){break}}c=c+f|0;b=b+f|0}(g|0)!=0&&kc(c,q[b-1|0],g)}),0,(function(b,c,d,f){sd(c,b,f)}),0,(function(){}),0,(function(b){Hh(b)}),0,(function(b){Hh(b);b|=0;(b|0)!=0&&Ae(b)}),0,(function(){return Q.R|0}),0,(function(b){y[b>>2]=Xh+8|0;Hh(b)}),0,(function(b){y[b>>2]=Xh+8|0;Hh(b);b|=0;(b|0)!=0&&Ae(b)}),0,(function(){return Q.Q|0}),0];Module.FUNCTION_TABLE=lc;function jj(b){b=b||Module.arguments;vc(wc);var c=ha;Module._main&&(c=Module.sa(b),vc(xc),Ob.print());return c}Module.run=jj;Module.preRun&&Module.preRun();Module.noInitialRun=ca;Module.noInitialRun||jj();Module.postRun&&Module.postRun();Z&&(Module.FS=Z);Module.HEAPU8=A;Module.CorrectionsMonitor=Ob;Z.createDataFile=Z.ta;var kj=ka;_runMainLoop=(function(){window.addEventListener("message",(function(){_mainLoopIteration();kj||window.postMessage(0,"*")}),ka)});Module.play=(function(){kj=ka;window.postMessage(0,"*")});Module.stop=(function(){kj=ca});Module.onFrameDecoded=(function(){});_broadwayOnFrameDecoded=(function(){Module.onFrameDecoded()});Module.createStreamBuffer=(function(b){b=jc(b);(b|0)==0&&xg(Q.ba|0);return b});var lj=Module.patches={};function mj(){return(function(){return this}).call(ha)}Sb=(function(b,c){b||a("Assertion: "+c)});Module.patch=(function(b,c,d){Sb(typeof d=="function");b||(b=mj());Module.CC_VARIABLE_MAP&&(c=Module.CC_VARIABLE_MAP[c]);Sb(c in b&&(typeof b[c]==="function"||typeof b[c]==="undefined"),"Can only patch functions.");lj[c]=b[c];b[c]=d;return lj[c]});Module.unpatch=(function(b,c){b||(b=mj());Module.CC_VARIABLE_MAP&&(c=Module.CC_VARIABLE_MAP[c]);Sb(c in b&&typeof b[c]=="function");c in lj&&(b[c]=lj[c])});Bc=Math.abs;Cc=(function(b,c,d){return dc?c:d});Module.CC_VARIABLE_MAP={"___setErrNo":"Qh","_Mmcop3":"Lf","_h264bsdCheckDeltaPicOrderCntBottom":"bd","_h264bsdFilterPicture":"Sf","_h264bsdReorderRefPicList":"Gf","_sbrk":"Ah","_CheckPps":"De","_Intra4x4VerticalLeftPrediction":"Xe","_coeffToken4_0":"oe","_DecRefPicMarking":"Vc","_coeffToken4_1":"pe","_h264bsdStoreSeqParamSet":"ze","_Mmcop6":"Hf","_Mmcop5":"Mf","intArrayFromString":"rc","_add_segment":"Dh","_init_top":"Bh","_h264bsdFillBlock":"sf","ENVIRONMENT_IS_WORKER":"ua","_decInfo":"Ag","_h264bsdCroppingParams":"lg","_h264bsdGetRefPicData":"gf","_EdgeBoundaryStrength":"Yf","e$$5":"ab","_Intra4x4DiagonalDownLeftPrediction":"Te","_sys_alloc":"wh","_h264bsdConceal":"gg","_DecodeCoeffToken":"Bd","FS":"Z","_clip":"Cc","_h264bsdQpC":"Ad","_h264bsdMarkSliceCorrupted":"jd","_OutputPicture":"Nf","i":"tc","_FilterHorChromaEdge":"fg","_sbrk$called":"Vh","base":"sc","_h264bsdNextMbAddress":"Ic","_DecodeTotalZeros":"we","_h264bsdDecodePicOrderCnt":"jg","_DecodeHrdParameters":"kg","_N_B_SUB_PART":"of","_init_mparams":"yh","_N_D_SUB_PART":"qf","_decPicture":"sg","_MvPrediction16x16":"cf","_coeffToken0_1":"Dd","_coeffToken0_0":"Cd","_levelScale":"Ec","_coeffToken0_3":"ke","_h264bsdDecodeExpGolombUnsigned":"T","_coeffToken0_2":"je","_tmalloc_small":"uh","Array_copy":"zc","PAGE_SIZE":"zb","Runtime":"Mb","_decInput":"tg","_h264bsdCheckPicOrderCntLsb":"Xc","TOTAL_MEMORY":"yb","__ATEXIT__":"xc","_h264bsdInterPrediction":"ud","_decOutput":"zg","_N_C_SUB_PART":"pf","__ZTVN10__cxxabiv120__si_class_type_infoE":"gj","_h264bsdIntra4x4Prediction":"xd","_h264bsdDecodeExpGolombTruncated":"nd","_h264bsdFlushBits":"od","_GetLumaEdgeThresholds":"Uf","Pointer_stringify":"cc","_broadwayOnHeadersDecoded":"Cg","_h264bsdInterpolateHorQuarter":"yf","_h264bsdInterpolateHorHalf":"xf","JSCompiler_alias_NULL":"ha","_stdout":"Sh","_h264bsdMbPartPredMode":"dd","HEAPU32":"F","HEAP8":"q","_mparams":"xh","Runtime$QUANTUM_SIZE":"Kb","_h264bsdPredictSamples":"df","_h264bsdProcessChromaDc":"Hc","_h264bsdDecodeSliceData":"fd","_h264bsdInterpolateVerHalf":"vf","_broadwayDecode":"ug","CorrectionsMonitor":"Ob","_stdin":"Rh","JSCompiler_alias_FALSE":"ka","_h264bsdDecodeMacroblockLayer":"gd","_Intra16x16PlanePrediction":"Ne","_N_B_4x4B":"ue","_lumaFracPos":"Ff","_DetermineNc":"qd","_free":"Ae","_h264bsdInterpolateChromaHorVer":"uf","_h264bsdGetNeighbourPels":"vd","__ZTISt9bad_alloc":"hj","_Intra4x4HorizontalUpPrediction":"Ye","_sys_trim":"Fh","globalScope":"ac","_h264bsdDecodeExpGolombSigned":"Qc","patches":"lj","Runtime$staticAlloc":"vb","_memcpy":"sd","_Intra16x16DcPrediction":"Me","_broadwayOnPictureDecoded":"Dg","ENVIRONMENT_IS_SHELL":"La","_broadwayExit":"yg","_MvPrediction":"hf","__ZTVSt9bad_alloc":"Ih","_h264bsdIntra16x16Prediction":"wd","_InnerBoundaryStrength":"$f","_h264bsdCheckAccessUnitBoundary":"Ie","String_len":"Ac","_ShellSort":"Of","_h264bsdDecodeResidualBlockCavlc":"pd","_H264SwDecNextPicture":"qg","JSCompiler_alias_TRUE":"ca","_DecodeSubMbPred":"kd","buffer":"oc","_Intra16x16VerticalPrediction":"Ke","STACK_MAX":"mc","_Intra4x4VerticalRightPrediction":"Ve","_DecodeForegroundLeftOverMap":"Ge","ALLOC_STATIC":"M","__ATINIT__":"wc","_CeilLog2NumSliceGroups":"Tc","_MvPrediction16x8":"ef","_GetBoundaryStrengths":"Tf","_dcCoeffIndex":"zd","_segment_holding":"zh","_Intra4x4DcPrediction":"Se","__ZTISt20bad_array_new_length":"ij","_Intra16x16HorizontalPrediction":"Le","tempInt":"Pb","_ProcessResidual":"td","_picDecodeNumber":"wg","globalEval":"Wa","_N_C_4x4B":"Pe","___setErrNo$ret":"Eh","_streamBuffer":"Eg","_prepend_alloc":"Ch","_coeffToken8":"qe","_h264bsdInterpolateMidHorQuarter":"Ef","_h264bsdGetBits":"S","_h264bsdFreeDpb":"Ee","_H264SwDecMemset":"Pc","ERRNO_CODES$EACCES":"Kh","_h264bsdMarkDecRefPic":"Kf","_h264bsdInterpolateChromaVer":"tf","_ComparePictures":"Pf","ERRNO_CODES$EIO":"Nh","_h264bsdInterpolateHorVerQuarter":"zf","_h264bsdNumMbPart":"cd","_sysconf":"Gh","arguments_":"ma","_DecodeMbPred":"ld","ERRNO_CODES$EINVAL":"Mh","_GetInterNeighbour":"kf","_N_D_4x4B":"Qe","STACKTOP":"m","_DecodeBoxOutMap":"He","_write":"Uh","undef":"I","_memset":"kc","_IntraChromaPlanePrediction":"bf","_h264bsdCheckPpsId":"Wc","_h264bsdInterpolateMidHalf":"Af","_N_A_4x4B":"te","_h264bsdIntraChromaPrediction":"yd","_h264bsdCompareSeqParamSets":"Nc","run":"jj","_GetBoundaryStrengthsA":"Zf","_h264bsdAddResidual":"Oe","_abs":"Bc","_h264bsdActivateParamSets":"Ce","allocate":"P","_fputc$ret":"Wh","assert":"Sb","abort":"Nb","_ConcealMb":"hg","_h264bsdBlockY":"Ze","_FilterLuma":"Vf","_h264bsdBlockX":"$e","_h264bsdShowBits32":"id","_FindDpbPic":"Df","_coeffTokenMinus1_0":"re","HEAPF32":"Hb","_Intra4x4DiagonalDownRightPrediction":"Ue","_coeffTokenMinus1_1":"se","breakLoop":"kj","_h264bsdDecodeSliceGroupMap":"Je","__ZNSt9bad_allocD2Ev":"Hh","__ZNSt9exceptionD2Ev":"Jh","_h264bsdInitRefPicList":"Qf","_h264bsdGetNeighbourMb":"ye","JSCompiler_alias_VOID":"aa","__gm_":"V","_h264bsdInterpolateMidVerQuarter":"Bf","_IntraChromaDcPrediction":"af","_abort":"W","_Transform":"ig","TOTAL_STACK":"nc","_h264bsdWriteMacroblock":"rd","_MedianFilter":"mf","setValue":"dc","_decInst":"rg","_FilterHorChroma":"eg","_FilterChroma":"Xf","_FilterVerLumaEdge":"ag","JSCompiler_alias_THROW":"a","_h264bsdAllocateDpbImage":"Jf","HEAP16":"x","ERRNO_CODES$ENXIO":"Ph","_puts":"xg","_DecodeResidual":"md","_h264bsdInterpolateVerQuarter":"wf","FUNCTION_TABLE":"lc","_h264bsdProcessBlock":"Dc","_h264bsdInterpolateChromaHor":"rf","tempDoublePtr":"uc","callRuntimeCallbacks":"vc","_picSize":"Bg","_h264bsdSetCurrImageMbPointers":"Lc","_FilterVerChromaEdge":"dg","_h264bsdShutdown":"ng","STRING_TABLE":"Q","STATICTOP":"xb","HEAPU8":"A","_FilterHorLuma":"bg","_picDisplayNumber":"vg","HEAP32":"y","_h264bsdCheckPriorPicsFlag":"ed","getGlobalScope":"mj","_malloc":"jc","_coeffToken2_2":"ne","_N_A_SUB_PART":"nf","_h264bsdExtractNalUnit":"Mc","_coeffToken2_0":"le","_coeffToken2_1":"me","_GetChromaEdgeThresholds":"Wf","nodeFS":"Ma","ERRNO_CODES$EBADF":"Lh","_MvPrediction8x16":"ff","_h264bsdWriteOutputBlocks":"jf","_h264bsdDecodePicParamSet":"Sc","ERRNO_CODES$EISDIR":"Oh","_h264bsdDecodeMacroblock":"hd","ENVIRONMENT_IS_NODE":"na","_h264bsdDecode":"mg","_SlidingWindowRefPicMarking":"If","_FilterHorLumaEdge":"cg","_stderr":"Th","_h264bsdIsNeighbourAvailable":"ve","__ZTVSt20bad_array_new_length":"Xh","_tmalloc_large":"vh","tempBigInt":"J","tempDoubleF64":"ec","tempDoubleI32":"gc","_SetPicNums":"Cf","_Get4x4NeighbourPels":"Re","_h264bsdProcessLumaDc":"Gc","_h264bsdStorePicParamSet":"Be","Runtime$stackAlloc":"bb","_H264SwDecDecode":"pg","_DecodeRunBefore":"xe","writeStringToMemory":"bc","_h264bsdDecodeVuiParameters":"Rc","_Intra4x4HorizontalDownPrediction":"We","_h264bsdCheckGapsInFrameNum":"Rf","_h264bsdInitDpb":"Fe","_broadwayStream":"og","_GetPredictionMv":"lf","ENVIRONMENT_IS_WEB":"oa","HEAPU16":"Gb","_h264bsdDecodeSliceHeader":"Uc","_h264bsdDecodeSeqParamSet":"Oc"} diff --git a/node_modules/dronestream/dist/vendor/broadway/avc.js b/node_modules/dronestream/dist/vendor/broadway/avc.js new file mode 100644 index 0000000..48a4f89 --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/avc.js @@ -0,0 +1,283 @@ +/** + * Requires: avc-codec.js + **/ + +assert (Module); + +HEAP8 = Module.HEAP8; +HEAPU8 = Module.HEAPU8; +HEAP16 = Module.HEAP16; +HEAP32 = Module.HEAP32; +_h264bsdClip = Module._get_h264bsdClip(); + +var Avc = (function avc() { + var MAX_STREAM_BUFFER_LENGTH = 1024 * 1024; + + function constructor() { + Module._broadwayInit(); + this.streamBuffer = toU8Array(Module._broadwayCreateStream(MAX_STREAM_BUFFER_LENGTH), MAX_STREAM_BUFFER_LENGTH); + this.pictureBuffers = {}; + + this.onPictureDecoded = function (buffer, width, height) { + // console.info(buffer.length); + } + + Module.patch(null, "_broadwayOnHeadersDecoded", function () { + + }); + + + Module.patch(null, "_broadwayOnPictureDecoded", function ($buffer, width, height) { + var buffer = this.pictureBuffers[$buffer]; + if (!buffer) { + buffer = this.pictureBuffers[$buffer] = toU8Array($buffer, (width * height * 3) / 2); + } + this.onPictureDecoded(buffer, width, height); + }.bind(this)); + + } + + /** + * Creates a typed array from a HEAP8 pointer. + */ + function toU8Array(ptr, length) { + return HEAPU8.subarray(ptr, ptr + length); + } + + constructor.prototype = { + /** + * Decodes a stream buffer. This may be one single (unframed) NAL unit without the + * start code, or a sequence of NAL units with framing start code prefixes. This + * function overwrites stream buffer allocated by the codec with the supplied buffer. + */ + decode: function decode(buffer) { + // console.info("Decoding: " + buffer.length); + this.streamBuffer.set(buffer); + Module._broadwaySetStreamLength(buffer.length); + Module._broadwayPlayStream(); + }, + configure: function (config) { + patchOptimizations(config, patches); + console.info("Broadway Configured: " + JSON.stringify(config)); + } + }; + + return constructor; +})(); + +function patchOptimizations(config, patches) { + var scope = getGlobalScope(); + for (var name in patches) { + var patch = patches[name]; + if (patch) { + var option = config[name]; + if (!option) option = "original"; + console.info(name + ": " + option); + assert (option in patch.options); + var fn = patch.options[option].fn; + if (fn) { + scope[patch.original] = Module.patch(null, patch.name, fn); + console.info("Patching: " + patch.name + ", with: " + option); + } + } + } +} + +var patches = { + "filter": { + name: "_h264bsdFilterPicture", + display: "Filter Picture", + original: "Original_h264bsdFilterPicture", + options: { + none: {display: "None", fn: function () {}}, + original: {display: "Original", fn: null}, + } + }, + "filterHorLuma": { + name: "_FilterHorLuma", + display: "Filter Hor Luma", + original: "OriginalFilterHorLuma", + options: { + none: {display: "None", fn: function () {}}, + original: {display: "Original", fn: null}, + optimized: {display: "Optimized", fn: OptimizedFilterHorLuma} + } + }, + "filterVerLumaEdge": { + name: "_FilterVerLumaEdge", + display: "Filter Ver Luma Edge", + original: "OriginalFilterVerLumaEdge", + options: { + none: {display: "None", fn: function () {}}, + original: {display: "Original", fn: null}, + optimized: {display: "Optimized", fn: OptimizedFilterVerLumaEdge} + } + }, + "getBoundaryStrengthsA": { + name: "_GetBoundaryStrengthsA", + display: "Get Boundary Strengths", + original: "OriginalGetBoundaryStrengthsA", + options: { + none: {display: "None", fn: function () {}}, + original: {display: "Original", fn: null}, + optimized: {display: "Optimized", fn: OptimizedGetBoundaryStrengthsA} + } + } +}; + +function getGlobalScope() { + return function () { return this; }.call(null); +} + +/* Optimizations */ + +function clip(x, y, z) { + return z < x ? x : (z > y ? y : z); +} + +function OptimizedGetBoundaryStrengthsA($mb, $bS) { + var $totalCoeff = $mb + 28; + + var tc0 = HEAP16[$totalCoeff + 0 >> 1]; + var tc1 = HEAP16[$totalCoeff + 2 >> 1]; + var tc2 = HEAP16[$totalCoeff + 4 >> 1]; + var tc3 = HEAP16[$totalCoeff + 6 >> 1]; + var tc4 = HEAP16[$totalCoeff + 8 >> 1]; + var tc5 = HEAP16[$totalCoeff + 10 >> 1]; + var tc6 = HEAP16[$totalCoeff + 12 >> 1]; + var tc7 = HEAP16[$totalCoeff + 14 >> 1]; + var tc8 = HEAP16[$totalCoeff + 16 >> 1]; + var tc9 = HEAP16[$totalCoeff + 18 >> 1]; + var tc10 = HEAP16[$totalCoeff + 20 >> 1]; + var tc11 = HEAP16[$totalCoeff + 22 >> 1]; + var tc12 = HEAP16[$totalCoeff + 24 >> 1]; + var tc13 = HEAP16[$totalCoeff + 26 >> 1]; + var tc14 = HEAP16[$totalCoeff + 28 >> 1]; + var tc15 = HEAP16[$totalCoeff + 30 >> 1]; + + HEAP32[$bS + 32 >> 2] = tc2 || tc0 ? 2 : 0; + HEAP32[$bS + 40 >> 2] = tc3 || tc1 ? 2 : 0; + HEAP32[$bS + 48 >> 2] = tc6 || tc4 ? 2 : 0; + HEAP32[$bS + 56 >> 2] = tc7 || tc5 ? 2 : 0; + HEAP32[$bS + 64 >> 2] = tc8 || tc2 ? 2 : 0; + HEAP32[$bS + 72 >> 2] = tc9 || tc3 ? 2 : 0; + HEAP32[$bS + 80 >> 2] = tc12 || tc6 ? 2 : 0; + HEAP32[$bS + 88 >> 2] = tc13 || tc7 ? 2 : 0; + HEAP32[$bS + 96 >> 2] = tc10 || tc8 ? 2 : 0; + HEAP32[$bS + 104 >> 2] = tc11 || tc9 ? 2 : 0; + HEAP32[$bS + 112 >> 2] = tc14 || tc12 ? 2 : 0; + HEAP32[$bS + 120 >> 2] = tc15 || tc13 ? 2 : 0; + + HEAP32[$bS + 12 >> 2] = tc1 || tc0 ? 2 : 0; + HEAP32[$bS + 20 >> 2] = tc4 || tc1 ? 2 : 0; + HEAP32[$bS + 28 >> 2] = tc5 || tc4 ? 2 : 0; + HEAP32[$bS + 44 >> 2] = tc3 || tc2 ? 2 : 0; + HEAP32[$bS + 52 >> 2] = tc6 || tc3 ? 2 : 0; + HEAP32[$bS + 60 >> 2] = tc7 || tc6 ? 2 : 0; + HEAP32[$bS + 76 >> 2] = tc9 || tc8 ? 2 : 0; + HEAP32[$bS + 84 >> 2] = tc12 || tc9 ? 2 : 0; + HEAP32[$bS + 92 >> 2] = tc13 || tc12 ? 2 : 0; + HEAP32[$bS + 108 >> 2] = tc11 || tc10 ? 2 : 0; + HEAP32[$bS + 116 >> 2] = tc14 || tc11 ? 2 : 0; + HEAP32[$bS + 124 >> 2] = tc15 || tc14 ? 2 : 0; +} + +function OptimizedFilterVerLumaEdge ($data, bS, $thresholds, imageWidth) { + var delta, tc, tmp; + var p0, q0, p1, q1, p2, q2; + var tmpFlag; + var $clp = _h264bsdClip + 512; + var alpha = HEAP32[$thresholds + 4 >> 2]; + var beta = HEAP32[$thresholds + 8 >> 2]; + var val; + + if (bS < 4) { + tmp = tc = HEAPU8[HEAP32[$thresholds >> 2] + (bS - 1)] & 255; + for (var i = 4; i > 0; i--) { + p1 = HEAPU8[$data + -2] & 255; + p0 = HEAPU8[$data + -1] & 255; + q0 = HEAPU8[$data] & 255; + q1 = HEAPU8[$data + 1] & 255; + if ((Math.abs(p0 - q0) < alpha) && (Math.abs(p1 - p0) < beta) && (Math.abs(q1 - q0) < beta)) { + p2 = HEAPU8[$data - 3] & 255; + if (Math.abs(p2 - p0) < beta) { + val = (p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1; + HEAP8[$data - 2] = p1 + clip(-tc, tc, val); + tmp++; + } + + q2 = HEAPU8[$data + 2] & 255; + if (Math.abs(q2 - q0) < beta) { + val = (q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1; + HEAP8[$data + 1] = (q1 + clip(-tc, tc, val)); + tmp++; + } + + val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3); + delta = clip(-tmp, tmp, val); + + p0 = HEAPU8[$clp + (p0 + delta)] & 255; + q0 = HEAPU8[$clp + (q0 - delta)] & 255; + tmp = tc; + HEAP8[$data - 1] = p0; + HEAP8[$data] = q0; + + $data += imageWidth; + } + } + } else { + OriginalFilterVerLumaEdge($data, bS, $thresholds, imageWidth); + } +} + +/** + * Filter all four successive horizontal 4-pixel luma edges. This can be done when bS is equal to all four edges. + */ +function OptimizedFilterHorLuma ($data, bS, $thresholds, imageWidth) { + var delta, tc, tmp; + var p0, q0, p1, q1, p2, q2; + var tmpFlag; + var $clp = _h264bsdClip + 512; + var alpha = HEAP32[$thresholds + 4 >> 2]; + var beta = HEAP32[$thresholds + 8 >> 2]; + var val; + + if (bS < 4) { + tmp = tc = HEAPU8[HEAP32[$thresholds >> 2] + (bS - 1)] & 255; + for (var i = 16; i > 0; i--) { + p1 = HEAPU8[$data + (-imageWidth << 1)] & 255; + p0 = HEAPU8[$data + -imageWidth] & 255; + q0 = HEAPU8[$data] & 255; + q1 = HEAPU8[$data + imageWidth] & 255; + + if ((Math.abs(p0 - q0) < alpha) && (Math.abs(p1 - p0) < beta) && (Math.abs(q1 - q0) < beta)) { + p2 = HEAPU8[$data + (-imageWidth * 3)] & 255; + if (Math.abs(p2 - p0) < beta) { + val = (p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1; + HEAP8[$data + (-imageWidth << 1)] = p1 + clip(-tc, tc, val); + tmp++; + } + + q2 = HEAPU8[$data + (imageWidth << 2)] & 255; + if (Math.abs(q2 - q0) < beta) { + val = (q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1; + HEAP8[$data + imageWidth] = (q1 + clip(-tc, tc, val)); + tmp++; + } + + val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3); + delta = clip(-tmp, tmp, val); + + p0 = HEAPU8[$clp + (p0 + delta)] & 255; + q0 = HEAPU8[$clp + (q0 - delta)] & 255; + tmp = tc; + HEAP8[$data - imageWidth] = p0; + HEAP8[$data] = q0; + + $data ++; + } + } + } else { + OriginalFilterHorLuma($data, bS, $thresholds, imageWidth); + } +} diff --git a/node_modules/dronestream/dist/vendor/broadway/canvas.js b/node_modules/dronestream/dist/vendor/broadway/canvas.js new file mode 100644 index 0000000..18ae85d --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/canvas.js @@ -0,0 +1,553 @@ +/* + * This file wraps several WebGL constructs and provides a simple, single texture based WebGLCanvas as well as a + * specialized YUVWebGLCanvas that can handle YUV->RGB conversion. + */ + +/** + * Represents a WebGL shader script. + */ +var Script = (function script() { + function constructor() {} + + constructor.createFromElementId = function(id) { + var script = document.getElementById(id); + + // Didn't find an element with the specified ID, abort. + assert(script , "Could not find shader with ID: " + id); + + // Walk through the source element's children, building the shader source string. + var source = ""; + var currentChild = script .firstChild; + while(currentChild) { + if (currentChild.nodeType == 3) { + source += currentChild.textContent; + } + currentChild = currentChild.nextSibling; + } + + var res = new constructor(); + res.type = script.type; + res.source = source; + return res; + }; + + constructor.createFromSource = function(type, source) { + var res = new constructor(); + res.type = type; + res.source = source; + return res; + } + return constructor; +})(); + +/** + * Represents a WebGL shader object and provides a mechanism to load shaders from HTML + * script tags. + */ +var Shader = (function shader() { + function constructor(gl, script) { + + // Now figure out what type of shader script we have, based on its MIME type. + if (script.type == "x-shader/x-fragment") { + this.shader = gl.createShader(gl.FRAGMENT_SHADER); + } else if (script.type == "x-shader/x-vertex") { + this.shader = gl.createShader(gl.VERTEX_SHADER); + } else { + error("Unknown shader type: " + script.type); + return; + } + + // Send the source to the shader object. + gl.shaderSource(this.shader, script.source); + + // Compile the shader program. + gl.compileShader(this.shader); + + // See if it compiled successfully. + if (!gl.getShaderParameter(this.shader, gl.COMPILE_STATUS)) { + error("An error occurred compiling the shaders: " + gl.getShaderInfoLog(this.shader)); + return; + } + } + return constructor; +})(); + +var Program = (function () { + function constructor(gl) { + this.gl = gl; + this.program = this.gl.createProgram(); + } + constructor.prototype = { + attach: function (shader) { + this.gl.attachShader(this.program, shader.shader); + }, + link: function () { + this.gl.linkProgram(this.program); + // If creating the shader program failed, alert. + assert(this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS), + "Unable to initialize the shader program."); + }, + use: function () { + this.gl.useProgram(this.program); + }, + getAttributeLocation: function(name) { + return this.gl.getAttribLocation(this.program, name); + }, + setMatrixUniform: function(name, array) { + var uniform = this.gl.getUniformLocation(this.program, name); + this.gl.uniformMatrix4fv(uniform, false, array); + } + }; + return constructor; +})(); + +/** + * Represents a WebGL texture object. + */ +var Texture = (function texture() { + function constructor(gl, size, format) { + this.gl = gl; + this.size = size; + this.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + this.format = format ? format : gl.LUMINANCE; + gl.texImage2D(gl.TEXTURE_2D, 0, this.format, size.w, size.h, 0, this.format, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + } + var textureIDs = null; + constructor.prototype = { + fill: function(textureData, useTexSubImage2D) { + var gl = this.gl; + assert(textureData.length >= this.size.w * this.size.h, + "Texture size mismatch, data:" + textureData.length + ", texture: " + this.size.w * this.size.h); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + if (useTexSubImage2D) { + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.size.w , this.size.h, this.format, gl.UNSIGNED_BYTE, textureData); + } else { + // texImage2D seems to be faster, thus keeping it as the default + gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.size.w, this.size.h, 0, this.format, gl.UNSIGNED_BYTE, textureData); + } + }, + bind: function(n, program, name) { + var gl = this.gl; + if (!textureIDs) { + textureIDs = [gl.TEXTURE0, gl.TEXTURE1, gl.TEXTURE2]; + } + gl.activeTexture(textureIDs[n]); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.uniform1i(gl.getUniformLocation(program.program, name), n); + } + }; + return constructor; +})(); + +/** + * Generic WebGL backed canvas that sets up: a quad to paint a texture on, appropriate vertex/fragment shaders, + * scene parameters and other things. Specialized versions of this class can be created by overriding several + * initialization methods. + * + * + * var canvas = new WebGLCanvas(document.getElementById('canvas'), new Size(512, 512); + * canvas.texture.fill(data); + * canvas.drawScene(); + * + */ +var WebGLCanvas = (function () { + + var vertexShaderScript = Script.createFromSource("x-shader/x-vertex", text([ + "attribute vec3 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "uniform mat4 uMVMatrix;", + "uniform mat4 uPMatrix;", + "varying highp vec2 vTextureCoord;", + "void main(void) {", + " gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);", + " vTextureCoord = aTextureCoord;", + "}" + ])); + + var fragmentShaderScript = Script.createFromSource("x-shader/x-fragment", text([ + "precision highp float;", + "varying highp vec2 vTextureCoord;", + "uniform sampler2D texture;", + "void main(void) {", + " gl_FragColor = texture2D(texture, vTextureCoord);", + "}" + ])); + + function constructor(canvas, size, useFrameBuffer) { + this.canvas = canvas; + this.size = size; + this.canvas.width = size.w; + this.canvas.height = size.h; + + this.onInitWebGL(); + this.onInitShaders(); + initBuffers.call(this); + if (useFrameBuffer) { + initFramebuffer.call(this); + } + this.onInitTextures(); + initScene.call(this); + } + + /** + * Initialize a frame buffer so that we can render off-screen. + */ + function initFramebuffer() { + var gl = this.gl; + + // Create framebuffer object and texture. + this.framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); + this.framebufferTexture = new Texture(this.gl, this.size, gl.RGBA); + + // Create and allocate renderbuffer for depth data. + var renderbuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.size.w, this.size.h); + + // Attach texture and renderbuffer to the framebuffer. + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.framebufferTexture.texture, 0); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer); + } + + /** + * Initialize vertex and texture coordinate buffers for a plane. + */ + function initBuffers() { + var tmp; + var gl = this.gl; + + // Create vertex position buffer. + this.quadVPBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVPBuffer); + tmp = [ + 1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, + 1.0, -1.0, 0.0, + -1.0, -1.0, 0.0]; + + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tmp), gl.STATIC_DRAW); + this.quadVPBuffer.itemSize = 3; + this.quadVPBuffer.numItems = 4; + + /* + +--------------------+ + | -1,1 (1) | 1,1 (0) + | | + | | + | | + | | + | | + | -1,-1 (3) | 1,-1 (2) + +--------------------+ + */ + + var scaleX = 1.0; + var scaleY = 1.0; + + // Create vertex texture coordinate buffer. + this.quadVTCBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVTCBuffer); + tmp = [ + scaleX, 0.0, + 0.0, 0.0, + scaleX, scaleY, + 0.0, scaleY, + ]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tmp), gl.STATIC_DRAW); + } + + function mvIdentity() { + this.mvMatrix = Matrix.I(4); + } + + function mvMultiply(m) { + this.mvMatrix = this.mvMatrix.x(m); + } + + function mvTranslate(m) { + mvMultiply.call(this, Matrix.Translation($V([m[0], m[1], m[2]])).ensure4x4()); + } + + function setMatrixUniforms() { + this.program.setMatrixUniform("uPMatrix", new Float32Array(this.perspectiveMatrix.flatten())); + this.program.setMatrixUniform("uMVMatrix", new Float32Array(this.mvMatrix.flatten())); + } + + function initScene() { + var gl = this.gl; + + // Establish the perspective with which we want to view the + // scene. Our field of view is 45 degrees, with a width/height + // ratio of 640:480, and we only want to see objects between 0.1 units + // and 100 units away from the camera. + + this.perspectiveMatrix = makePerspective(45, 1, 0.1, 100.0); + + // Set the drawing position to the "identity" point, which is + // the center of the scene. + mvIdentity.call(this); + + // Now move the drawing position a bit to where we want to start + // drawing the square. + mvTranslate.call(this, [0.0, 0.0, -2.4]); + + // Draw the cube by binding the array buffer to the cube's vertices + // array, setting attributes, and pushing it to GL. + gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVPBuffer); + gl.vertexAttribPointer(this.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); + + // Set the texture coordinates attribute for the vertices. + + gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVTCBuffer); + gl.vertexAttribPointer(this.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); + + this.onInitSceneTextures(); + + setMatrixUniforms.call(this); + + if (this.framebuffer) { + console.log("Bound Frame Buffer"); + gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); + } + } + + constructor.prototype = { + toString: function() { + return "WebGLCanvas Size: " + this.size; + }, + checkLastError: function (operation) { + var err = this.gl.getError(); + if (err != this.gl.NO_ERROR) { + var name = this.glNames[err]; + name = (name !== undefined) ? name + "(" + err + ")": + ("Unknown WebGL ENUM (0x" + value.toString(16) + ")"); + if (operation) { + console.log("WebGL Error: %s, %s", operation, name); + } else { + console.log("WebGL Error: %s", name); + } + console.trace(); + } + }, + onInitWebGL: function () { + try { + this.gl = this.canvas.getContext("experimental-webgl"); + } catch(e) {} + + if (!this.gl) { + error("Unable to initialize WebGL. Your browser may not support it."); + } + if (this.glNames) { + return; + } + this.glNames = {}; + for (var propertyName in this.gl) { + if (typeof this.gl[propertyName] == 'number') { + this.glNames[this.gl[propertyName]] = propertyName; + } + } + }, + onInitShaders: function() { + this.program = new Program(this.gl); + this.program.attach(new Shader(this.gl, vertexShaderScript)); + this.program.attach(new Shader(this.gl, fragmentShaderScript)); + this.program.link(); + this.program.use(); + this.vertexPositionAttribute = this.program.getAttributeLocation("aVertexPosition"); + this.gl.enableVertexAttribArray(this.vertexPositionAttribute); + this.textureCoordAttribute = this.program.getAttributeLocation("aTextureCoord");; + this.gl.enableVertexAttribArray(this.textureCoordAttribute); + }, + onInitTextures: function () { + var gl = this.gl; + this.texture = new Texture(gl, this.size, gl.RGBA); + }, + onInitSceneTextures: function () { + this.texture.bind(0, this.program, "texture"); + }, + drawScene: function() { + this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4); + }, + readPixels: function(buffer) { + var gl = this.gl; + gl.readPixels(0, 0, this.size.w, this.size.h, gl.RGBA, gl.UNSIGNED_BYTE, buffer); + } + }; + return constructor; +})(); + +var YUVWebGLCanvas = (function () { + var vertexShaderScript = Script.createFromSource("x-shader/x-vertex", text([ + "attribute vec3 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "uniform mat4 uMVMatrix;", + "uniform mat4 uPMatrix;", + "varying highp vec2 vTextureCoord;", + "void main(void) {", + " gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);", + " vTextureCoord = aTextureCoord;", + "}" + ])); + + var fragmentShaderScriptOld = Script.createFromSource("x-shader/x-fragment", text([ + "precision highp float;", + "varying highp vec2 vTextureCoord;", + "uniform sampler2D YTexture;", + "uniform sampler2D UTexture;", + "uniform sampler2D VTexture;", + + "void main(void) {", + " vec3 YUV = vec3", + " (", + " texture2D(YTexture, vTextureCoord).x * 1.1643828125, // premultiply Y", + " texture2D(UTexture, vTextureCoord).x,", + " texture2D(VTexture, vTextureCoord).x", + " );", + " gl_FragColor = vec4", + " (", + " YUV.x + 1.59602734375 * YUV.z - 0.87078515625,", + " YUV.x - 0.39176171875 * YUV.y - 0.81296875 * YUV.z + 0.52959375,", + " YUV.x + 2.017234375 * YUV.y - 1.081390625,", + " 1", + " );", + "}" + ])); + + var fragmentShaderScriptSimple = Script.createFromSource("x-shader/x-fragment", text([ + "precision highp float;", + "varying highp vec2 vTextureCoord;", + "uniform sampler2D YTexture;", + "uniform sampler2D UTexture;", + "uniform sampler2D VTexture;", + + "void main(void) {", + " gl_FragColor = texture2D(YTexture, vTextureCoord);", + "}" + ])); + + var fragmentShaderScript = Script.createFromSource("x-shader/x-fragment", text([ + "precision highp float;", + "varying highp vec2 vTextureCoord;", + "uniform sampler2D YTexture;", + "uniform sampler2D UTexture;", + "uniform sampler2D VTexture;", + "const mat4 YUV2RGB = mat4", + "(", + " 1.1643828125, 0, 1.59602734375, -.87078515625,", + " 1.1643828125, -.39176171875, -.81296875, .52959375,", + " 1.1643828125, 2.017234375, 0, -1.081390625,", + " 0, 0, 0, 1", + ");", + + "void main(void) {", + " gl_FragColor = vec4( texture2D(YTexture, vTextureCoord).x, texture2D(UTexture, vTextureCoord).x, texture2D(VTexture, vTextureCoord).x, 1) * YUV2RGB;", + "}" + ])); + + + function constructor(canvas, size) { + WebGLCanvas.call(this, canvas, size); + } + + constructor.prototype = inherit(WebGLCanvas, { + onInitShaders: function() { + this.program = new Program(this.gl); + this.program.attach(new Shader(this.gl, vertexShaderScript)); + this.program.attach(new Shader(this.gl, fragmentShaderScript)); + this.program.link(); + this.program.use(); + this.vertexPositionAttribute = this.program.getAttributeLocation("aVertexPosition"); + this.gl.enableVertexAttribArray(this.vertexPositionAttribute); + this.textureCoordAttribute = this.program.getAttributeLocation("aTextureCoord");; + this.gl.enableVertexAttribArray(this.textureCoordAttribute); + }, + onInitTextures: function () { + console.log("creatingTextures: size: " + this.size); + this.YTexture = new Texture(this.gl, this.size); + this.UTexture = new Texture(this.gl, this.size.getHalfSize()); + this.VTexture = new Texture(this.gl, this.size.getHalfSize()); + }, + onInitSceneTextures: function () { + this.YTexture.bind(0, this.program, "YTexture"); + this.UTexture.bind(1, this.program, "UTexture"); + this.VTexture.bind(2, this.program, "VTexture"); + }, + fillYUVTextures: function(y, u, v) { + this.YTexture.fill(y); + this.UTexture.fill(u); + this.VTexture.fill(v); + }, + toString: function() { + return "YUVCanvas Size: " + this.size; + } + }); + + return constructor; +})(); + + +var FilterWebGLCanvas = (function () { + var vertexShaderScript = Script.createFromSource("x-shader/x-vertex", text([ + "attribute vec3 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "uniform mat4 uMVMatrix;", + "uniform mat4 uPMatrix;", + "varying highp vec2 vTextureCoord;", + "void main(void) {", + " gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);", + " vTextureCoord = aTextureCoord;", + "}" + ])); + + var fragmentShaderScript = Script.createFromSource("x-shader/x-fragment", text([ + "precision highp float;", + "varying highp vec2 vTextureCoord;", + "uniform sampler2D FTexture;", + + "void main(void) {", + " gl_FragColor = texture2D(FTexture, vTextureCoord);", + "}" + ])); + + + function constructor(canvas, size, useFrameBuffer) { + WebGLCanvas.call(this, canvas, size, useFrameBuffer); + } + + constructor.prototype = inherit(WebGLCanvas, { + onInitShaders: function() { + this.program = new Program(this.gl); + this.program.attach(new Shader(this.gl, vertexShaderScript)); + this.program.attach(new Shader(this.gl, fragmentShaderScript)); + this.program.link(); + this.program.use(); + this.vertexPositionAttribute = this.program.getAttributeLocation("aVertexPosition"); + this.gl.enableVertexAttribArray(this.vertexPositionAttribute); + this.textureCoordAttribute = this.program.getAttributeLocation("aTextureCoord"); + this.gl.enableVertexAttribArray(this.textureCoordAttribute); + }, + onInitTextures: function () { + console.log("creatingTextures: size: " + this.size); + this.FTexture = new Texture(this.gl, this.size, this.gl.RGBA); + }, + onInitSceneTextures: function () { + this.FTexture.bind(0, this.program, "FTexture"); + }, + process: function(buffer, output) { + this.FTexture.fill(buffer); + this.drawScene(); + this.readPixels(output); + }, + toString: function() { + return "FilterWebGLCanvas Size: " + this.size; + } + }); + + return constructor; +})(); \ No newline at end of file diff --git a/node_modules/dronestream/dist/vendor/broadway/glUtils.js b/node_modules/dronestream/dist/vendor/broadway/glUtils.js new file mode 100644 index 0000000..ac3b802 --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/glUtils.js @@ -0,0 +1,193 @@ +// augment Sylvester some +Matrix.Translation = function (v) +{ + if (v.elements.length == 2) { + var r = Matrix.I(3); + r.elements[2][0] = v.elements[0]; + r.elements[2][1] = v.elements[1]; + return r; + } + + if (v.elements.length == 3) { + var r = Matrix.I(4); + r.elements[0][3] = v.elements[0]; + r.elements[1][3] = v.elements[1]; + r.elements[2][3] = v.elements[2]; + return r; + } + + throw "Invalid length for Translation"; +} + +Matrix.prototype.flatten = function () +{ + var result = []; + if (this.elements.length == 0) + return []; + + + for (var j = 0; j < this.elements[0].length; j++) + for (var i = 0; i < this.elements.length; i++) + result.push(this.elements[i][j]); + return result; +} + +Matrix.prototype.ensure4x4 = function() +{ + if (this.elements.length == 4 && + this.elements[0].length == 4) + return this; + + if (this.elements.length > 4 || + this.elements[0].length > 4) + return null; + + for (var i = 0; i < this.elements.length; i++) { + for (var j = this.elements[i].length; j < 4; j++) { + if (i == j) + this.elements[i].push(1); + else + this.elements[i].push(0); + } + } + + for (var i = this.elements.length; i < 4; i++) { + if (i == 0) + this.elements.push([1, 0, 0, 0]); + else if (i == 1) + this.elements.push([0, 1, 0, 0]); + else if (i == 2) + this.elements.push([0, 0, 1, 0]); + else if (i == 3) + this.elements.push([0, 0, 0, 1]); + } + + return this; +}; + +Matrix.prototype.make3x3 = function() +{ + if (this.elements.length != 4 || + this.elements[0].length != 4) + return null; + + return Matrix.create([[this.elements[0][0], this.elements[0][1], this.elements[0][2]], + [this.elements[1][0], this.elements[1][1], this.elements[1][2]], + [this.elements[2][0], this.elements[2][1], this.elements[2][2]]]); +}; + +Vector.prototype.flatten = function () +{ + return this.elements; +}; + +function mht(m) { + var s = ""; + if (m.length == 16) { + for (var i = 0; i < 4; i++) { + s += "[" + m[i*4+0].toFixed(4) + "," + m[i*4+1].toFixed(4) + "," + m[i*4+2].toFixed(4) + "," + m[i*4+3].toFixed(4) + "]
"; + } + } else if (m.length == 9) { + for (var i = 0; i < 3; i++) { + s += "[" + m[i*3+0].toFixed(4) + "," + m[i*3+1].toFixed(4) + "," + m[i*3+2].toFixed(4) + "]
"; + } + } else { + return m.toString(); + } + return s; +} + +// +// gluLookAt +// +function makeLookAt(ex, ey, ez, + cx, cy, cz, + ux, uy, uz) +{ + var eye = $V([ex, ey, ez]); + var center = $V([cx, cy, cz]); + var up = $V([ux, uy, uz]); + + var mag; + + var z = eye.subtract(center).toUnitVector(); + var x = up.cross(z).toUnitVector(); + var y = z.cross(x).toUnitVector(); + + var m = $M([[x.e(1), x.e(2), x.e(3), 0], + [y.e(1), y.e(2), y.e(3), 0], + [z.e(1), z.e(2), z.e(3), 0], + [0, 0, 0, 1]]); + + var t = $M([[1, 0, 0, -ex], + [0, 1, 0, -ey], + [0, 0, 1, -ez], + [0, 0, 0, 1]]); + return m.x(t); +} + +// +// glOrtho +// +function makeOrtho(left, right, + bottom, top, + znear, zfar) +{ + var tx = -(right+left)/(right-left); + var ty = -(top+bottom)/(top-bottom); + var tz = -(zfar+znear)/(zfar-znear); + + return $M([[2/(right-left), 0, 0, tx], + [0, 2/(top-bottom), 0, ty], + [0, 0, -2/(zfar-znear), tz], + [0, 0, 0, 1]]); +} + +// +// gluPerspective +// +function makePerspective(fovy, aspect, znear, zfar) +{ + var ymax = znear * Math.tan(fovy * Math.PI / 360.0); + var ymin = -ymax; + var xmin = ymin * aspect; + var xmax = ymax * aspect; + + return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); +} + +// +// glFrustum +// +function makeFrustum(left, right, + bottom, top, + znear, zfar) +{ + var X = 2*znear/(right-left); + var Y = 2*znear/(top-bottom); + var A = (right+left)/(right-left); + var B = (top+bottom)/(top-bottom); + var C = -(zfar+znear)/(zfar-znear); + var D = -2*zfar*znear/(zfar-znear); + + return $M([[X, 0, A, 0], + [0, Y, B, 0], + [0, 0, C, D], + [0, 0, -1, 0]]); +} + +// +// glOrtho +// +function makeOrtho(left, right, bottom, top, znear, zfar) +{ + var tx = - (right + left) / (right - left); + var ty = - (top + bottom) / (top - bottom); + var tz = - (zfar + znear) / (zfar - znear); + + return $M([[2 / (right - left), 0, 0, tx], + [0, 2 / (top - bottom), 0, ty], + [0, 0, -2 / (zfar - znear), tz], + [0, 0, 0, 1]]); +} + diff --git a/node_modules/dronestream/dist/vendor/broadway/sylvester.js b/node_modules/dronestream/dist/vendor/broadway/sylvester.js new file mode 100644 index 0000000..3e83bee --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/sylvester.js @@ -0,0 +1 @@ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{})) \ No newline at end of file diff --git a/node_modules/dronestream/dist/vendor/broadway/util.js b/node_modules/dronestream/dist/vendor/broadway/util.js new file mode 100644 index 0000000..e5291d3 --- /dev/null +++ b/node_modules/dronestream/dist/vendor/broadway/util.js @@ -0,0 +1,71 @@ +'use strict'; + +function error(message) { + console.error(message); + console.trace(); +} + +function assert(condition, message) { + if (!condition) { + error(message); + } +} + +function isPowerOfTwo(x) { + return (x & (x - 1)) == 0; +} + +/** + * Joins a list of lines using a newline separator, not the fastest + * thing in the world but good enough for initialization code. + */ +function text(lines) { + return lines.join("\n"); +} + +/** + * Rounds up to the next highest power of two. + */ +function nextHighestPowerOfTwo(x) { + --x; + for (var i = 1; i < 32; i <<= 1) { + x = x | x >> i; + } + return x + 1; +} + +/** + * Represents a 2-dimensional size value. + */ +var Size = (function size() { + function constructor(w, h) { + this.w = w; + this.h = h; + } + constructor.prototype = { + toString: function () { + return "(" + this.w + ", " + this.h + ")"; + }, + getHalfSize: function() { + return new Size(this.w >>> 1, this.h >>> 1); + }, + length: function() { + return this.w * this.h; + } + } + return constructor; +})(); + +/** + * Creates a new prototype object derived from another objects prototype along with a list of additional properties. + * + * @param base object whose prototype to use as the created prototype object's prototype + * @param properties additional properties to add to the created prototype object + */ +function inherit(base, properties) { + var prot = Object.create(base.prototype); + for (var p in properties) { + prot[p] = properties[p]; + } + return prot; +} \ No newline at end of file diff --git a/node_modules/dronestream/example/createServer/app.js b/node_modules/dronestream/example/createServer/app.js new file mode 100644 index 0000000..e2c8594 --- /dev/null +++ b/node_modules/dronestream/example/createServer/app.js @@ -0,0 +1,10 @@ +var http = require("http"), + drone = require("../../index"); + + +var server = http.createServer(function(req, res) { + require("fs").createReadStream(__dirname + "/index.html").pipe(res); +}); + +drone.listen(server); +server.listen(5555); diff --git a/node_modules/dronestream/example/createServer/index.html b/node_modules/dronestream/example/createServer/index.html new file mode 100644 index 0000000..6d5f158 --- /dev/null +++ b/node_modules/dronestream/example/createServer/index.html @@ -0,0 +1,16 @@ + + + + + Stream as module + + + +

Stream through a normal require("http").createServer

+
+ + + + diff --git a/node_modules/dronestream/example/express/app.js b/node_modules/dronestream/example/express/app.js new file mode 100644 index 0000000..2509f62 --- /dev/null +++ b/node_modules/dronestream/example/express/app.js @@ -0,0 +1,33 @@ +var express = require('express') + , routes = require('./routes') + , app = express() + , path = require('path') + , server = require("http").createServer(app) + ; + + +app.configure(function () { + app.set('views', __dirname + '/views'); + app.set('view engine', 'jade', { pretty: true }); + app.use(express.favicon()); + app.use(express.logger('dev')); + app.use(app.router); + app.use(express.static(path.join(__dirname, 'public'))); +}); + +app.configure('development', function () { + app.use(express.errorHandler()); + app.locals.pretty = true; +}); + +app.get('/', routes.index); + +/* + * Important: + * + * pass in the server object to listen, not the express app + * call 'listen' on the server, not the express app + */ +// should be require("dronestream").listen(server); +require("../../index").listen(server); +server.listen(3000); diff --git a/node_modules/dronestream/example/express/package.json b/node_modules/dronestream/example/express/package.json new file mode 100644 index 0000000..f816551 --- /dev/null +++ b/node_modules/dronestream/example/express/package.json @@ -0,0 +1,13 @@ +{ + "name": "dronestream-example", + "version": "0.1.1", + "dependencies": { + "express": "3.0.x", + "jade": "*" + }, + "scripts": { + "start": "node app" + }, + "author": "Bernhard K. Weisshuhn ", + "license": "BSD" +} diff --git a/node_modules/dronestream/example/express/public/css/normalize.min.css b/node_modules/dronestream/example/express/public/css/normalize.min.css new file mode 100644 index 0000000..a783c53 --- /dev/null +++ b/node_modules/dronestream/example/express/public/css/normalize.min.css @@ -0,0 +1,50 @@ +/*! normalize.css v1.0.1 | MIT License | git.io/normalize */ +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1} +audio:not([controls]){display:none;height:0} +[hidden]{display:none} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%} +html,button,input,select,textarea{font-family:sans-serif} +body{margin:0} +a:focus{outline:thin dotted} +a:active,a:hover{outline:0} +h1{font-size:2em;margin:.67em 0} +h2{font-size:1.5em;margin:.83em 0} +h3{font-size:1.17em;margin:1em 0} +h4{font-size:1em;margin:1.33em 0} +h5{font-size:.83em;margin:1.67em 0} +h6{font-size:.75em;margin:2.33em 0} +abbr[title]{border-bottom:1px dotted} +b,strong{font-weight:bold} +blockquote{margin:1em 40px} +dfn{font-style:italic} +mark{background:#ff0;color:#000} +p,pre{margin:1em 0} +code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em} +pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word} +q{quotes:none} +q:before,q:after{content:'';content:none} +small{font-size:80%} +sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} +sup{top:-0.5em} +sub{bottom:-0.25em} +dl,menu,ol,ul{margin:1em 0} +dd{margin:0 0 0 40px} +menu,ol,ul{padding:0 0 0 40px} +nav ul,nav ol{list-style:none;list-style-image:none} +img{border:0;-ms-interpolation-mode:bicubic} +svg:not(:root){overflow:hidden} +figure{margin:0} +form{margin:0} +fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em} +legend{border:0;padding:0;white-space:normal;*margin-left:-7px} +button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle} +button,input{line-height:normal} +button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;*overflow:visible} +button[disabled],input[disabled]{cursor:default} +input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*height:13px;*width:13px} +input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box} +input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none} +button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} +textarea{overflow:auto;vertical-align:top} +table{border-collapse:collapse;border-spacing:0} \ No newline at end of file diff --git a/node_modules/dronestream/example/express/public/css/style.css b/node_modules/dronestream/example/express/public/css/style.css new file mode 100644 index 0000000..30e047d --- /dev/null +++ b/node_modules/dronestream/example/express/public/css/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} \ No newline at end of file diff --git a/node_modules/dronestream/example/express/routes/index.js b/node_modules/dronestream/example/express/routes/index.js new file mode 100644 index 0000000..855734d --- /dev/null +++ b/node_modules/dronestream/example/express/routes/index.js @@ -0,0 +1,10 @@ +'use strict'; + +/* + * GET home page. + */ + +exports.index = function (req, res) { + res.render('index', { title: 'Express' }); +}; + diff --git a/node_modules/dronestream/example/express/views/index.jade b/node_modules/dronestream/example/express/views/index.jade new file mode 100644 index 0000000..c348f15 --- /dev/null +++ b/node_modules/dronestream/example/express/views/index.jade @@ -0,0 +1,22 @@ +extends layout + +block append head + script(type='text/javascript', src='/dronestream/nodecopter-client.js') + +-# for developing the client, use those url:s +-# script(type='text/javascript', src='/dronestream/vendor/broadway/sylvester.js') +-# script(type='text/javascript', src='/dronestream/vendor/broadway/glUtils.js') +-# script(type='text/javascript', src='/dronestream/vendor/broadway/util.js') +-# script(type='text/javascript', src='/dronestream/vendor/broadway/avc-codec.js') +-# script(type='text/javascript', src='/dronestream/vendor/broadway/avc.js') +-# script(type='text/javascript', src='/dronestream/vendor/broadway/canvas.js') +-# script(type='text/javascript', src='/dronestream/nodecopter-stream.js') +-# concatenated version of client + + +block append bodyscripts + script. + var copterStream = new NodecopterStream(document.querySelector('#dronestream')); + +block content + div#dronestream(width=640, height=360) diff --git a/node_modules/dronestream/example/express/views/layout.jade b/node_modules/dronestream/example/express/views/layout.jade new file mode 100644 index 0000000..bca64ac --- /dev/null +++ b/node_modules/dronestream/example/express/views/layout.jade @@ -0,0 +1,30 @@ +!!! 5 +html + block head + head + meta(http-equiv='X-UA-Compatible', content='IE=edge,chrome=1') + meta(name='viewport', content='width=device-width') + title= title + link(rel='stylesheet', href='/css/normalize.min.css') + link(rel='stylesheet', href='/css/style.css') + body + div.header-container + header.wrapper.clearfix + block header + nav + block navigation + + div.main-container + div.main.wrapper.clearfix + + block content + + + div.footer-container + footer.wrapper + block footer + + block bodyscripts + // script(src='//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js') + // script + // window.jQuery || document.write(' + + + +

This example will upload an entire directory tree to the node.js server via a fast and persistent WebSocket connection.

+

Note that the example is Chrome only for now.

+

+ Upload status: +
Please select a directory to upload.
+ + diff --git a/node_modules/dronestream/node_modules/ws/examples/fileapi/public/uploader.js b/node_modules/dronestream/node_modules/ws/examples/fileapi/public/uploader.js new file mode 100644 index 0000000..0c34a7f --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/fileapi/public/uploader.js @@ -0,0 +1,55 @@ +function Uploader(url, cb) { + this.ws = new WebSocket(url); + if (cb) this.ws.onopen = cb; + this.sendQueue = []; + this.sending = null; + this.sendCallback = null; + this.ondone = null; + var self = this; + this.ws.onmessage = function(event) { + var data = JSON.parse(event.data); + if (data.event == 'complete') { + if (data.path != self.sending.path) { + self.sendQueue = []; + self.sending = null; + self.sendCallback = null; + throw new Error('Got message for wrong file!'); + } + self.sending = null; + var callback = self.sendCallback; + self.sendCallback = null; + if (callback) callback(); + if (self.sendQueue.length === 0 && self.ondone) self.ondone(null); + if (self.sendQueue.length > 0) { + var args = self.sendQueue.pop(); + setTimeout(function() { self.sendFile.apply(self, args); }, 0); + } + } + else if (data.event == 'error') { + self.sendQueue = []; + self.sending = null; + var callback = self.sendCallback; + self.sendCallback = null; + var error = new Error('Server reported send error for file ' + data.path); + if (callback) callback(error); + if (self.ondone) self.ondone(error); + } + } +} + +Uploader.prototype.sendFile = function(file, cb) { + if (this.ws.readyState != WebSocket.OPEN) throw new Error('Not connected'); + if (this.sending) { + this.sendQueue.push(arguments); + return; + } + var fileData = { name: file.name, path: file.webkitRelativePath }; + this.sending = fileData; + this.sendCallback = cb; + this.ws.send(JSON.stringify(fileData)); + this.ws.send(file); +} + +Uploader.prototype.close = function() { + this.ws.close(); +} diff --git a/node_modules/dronestream/node_modules/ws/examples/fileapi/server.js b/node_modules/dronestream/node_modules/ws/examples/fileapi/server.js new file mode 100644 index 0000000..badfeba --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/fileapi/server.js @@ -0,0 +1,103 @@ +var WebSocketServer = require('../../').Server + , express = require('express') + , fs = require('fs') + , http = require('http') + , util = require('util') + , path = require('path') + , app = express.createServer() + , events = require('events') + , ansi = require('ansi') + , cursor = ansi(process.stdout); + +function BandwidthSampler(ws, interval) { + interval = interval || 2000; + var previousByteCount = 0; + var self = this; + var intervalId = setInterval(function() { + var byteCount = ws.bytesReceived; + var bytesPerSec = (byteCount - previousByteCount) / (interval / 1000); + previousByteCount = byteCount; + self.emit('sample', bytesPerSec); + }, interval); + ws.on('close', function() { + clearInterval(intervalId); + }); +} +util.inherits(BandwidthSampler, events.EventEmitter); + +function makePathForFile(filePath, prefix, cb) { + if (typeof cb !== 'function') throw new Error('callback is required'); + filePath = path.dirname(path.normalize(filePath)).replace(/^(\/|\\)+/, ''); + var pieces = filePath.split(/(\\|\/)/); + var incrementalPath = prefix; + function step(error) { + if (error) return cb(error); + if (pieces.length == 0) return cb(null, incrementalPath); + incrementalPath += '/' + pieces.shift(); + fs.exists(incrementalPath, function(exists) { + if (!exists) fs.mkdir(incrementalPath, step); + else process.nextTick(step); + }); + } + step(); +} + +cursor.eraseData(2).goto(1, 1); +app.use(express.static(__dirname + '/public')); + +var clientId = 0; +var wss = new WebSocketServer({server: app}); +wss.on('connection', function(ws) { + var thisId = ++clientId; + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('Client #%d connected', thisId); + + var sampler = new BandwidthSampler(ws); + sampler.on('sample', function(bps) { + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('WebSocket #%d incoming bandwidth: %d MB/s', thisId, Math.round(bps / (1024*1024))); + }); + + var filesReceived = 0; + var currentFile = null; + ws.on('message', function(data, flags) { + if (!flags.binary) { + currentFile = JSON.parse(data); + // note: a real-world app would want to sanity check the data + } + else { + if (currentFile == null) return; + makePathForFile(currentFile.path, __dirname + '/uploaded', function(error, path) { + if (error) { + console.log(error); + ws.send(JSON.stringify({event: 'error', path: currentFile.path, message: error.message})); + return; + } + fs.writeFile(path + '/' + currentFile.name, data, function(error) { + ++filesReceived; + // console.log('received %d bytes long file, %s', data.length, currentFile.path); + ws.send(JSON.stringify({event: 'complete', path: currentFile.path})); + currentFile = null; + }); + }); + } + }); + + ws.on('close', function() { + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('Client #%d disconnected. %d files received.', thisId, filesReceived); + }); + + ws.on('error', function(e) { + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('Client #%d error: %s', thisId, e.message); + }); +}); + +fs.mkdir(__dirname + '/uploaded', function(error) { + // ignore errors, most likely means directory exists + console.log('Uploaded files will be saved to %s/uploaded.', __dirname); + console.log('Remember to wipe this directory if you upload lots and lots.'); + app.listen(8080); + console.log('Listening on http://localhost:8080'); +}); diff --git a/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/package.json b/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/package.json new file mode 100644 index 0000000..99722c4 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/package.json @@ -0,0 +1,17 @@ +{ + "author": "", + "name": "serverstats", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "git://github.com/einaros/ws.git" + }, + "engines": { + "node": ">0.4.0" + }, + "dependencies": { + "express": "~3.0.0" + }, + "devDependencies": {}, + "optionalDependencies": {} +} diff --git a/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/public/index.html b/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/public/index.html new file mode 100644 index 0000000..24d84e1 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/public/index.html @@ -0,0 +1,33 @@ + + + + + + + + Server Stats
+ RSS:

+ Heap total:

+ Heap used:

+ + diff --git a/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/server.js b/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/server.js new file mode 100644 index 0000000..88bbc9e --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/serverstats-express_3/server.js @@ -0,0 +1,21 @@ +var WebSocketServer = require('../../').Server + , http = require('http') + , express = require('express') + , app = express(); + +app.use(express.static(__dirname + '/public')); + +var server = http.createServer(app); +server.listen(8080); + +var wss = new WebSocketServer({server: server}); +wss.on('connection', function(ws) { + var id = setInterval(function() { + ws.send(JSON.stringify(process.memoryUsage()), function() { /* ignore errors */ }); + }, 100); + console.log('started client interval'); + ws.on('close', function() { + console.log('stopping client interval'); + clearInterval(id); + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/examples/serverstats/package.json b/node_modules/dronestream/node_modules/ws/examples/serverstats/package.json new file mode 100644 index 0000000..65c900a --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/serverstats/package.json @@ -0,0 +1,17 @@ +{ + "author": "", + "name": "serverstats", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "git://github.com/einaros/ws.git" + }, + "engines": { + "node": ">0.4.0" + }, + "dependencies": { + "express": "2.x" + }, + "devDependencies": {}, + "optionalDependencies": {} +} diff --git a/node_modules/dronestream/node_modules/ws/examples/serverstats/public/index.html b/node_modules/dronestream/node_modules/ws/examples/serverstats/public/index.html new file mode 100644 index 0000000..24d84e1 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/serverstats/public/index.html @@ -0,0 +1,33 @@ + + + + + + + + Server Stats
+ RSS:

+ Heap total:

+ Heap used:

+ + diff --git a/node_modules/dronestream/node_modules/ws/examples/serverstats/server.js b/node_modules/dronestream/node_modules/ws/examples/serverstats/server.js new file mode 100644 index 0000000..0bbce36 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/serverstats/server.js @@ -0,0 +1,19 @@ +var WebSocketServer = require('../../').Server + , http = require('http') + , express = require('express') + , app = express.createServer(); + +app.use(express.static(__dirname + '/public')); +app.listen(8080); + +var wss = new WebSocketServer({server: app}); +wss.on('connection', function(ws) { + var id = setInterval(function() { + ws.send(JSON.stringify(process.memoryUsage()), function() { /* ignore errors */ }); + }, 100); + console.log('started client interval'); + ws.on('close', function() { + console.log('stopping client interval'); + clearInterval(id); + }) +}); diff --git a/node_modules/dronestream/node_modules/ws/examples/ssl.js b/node_modules/dronestream/node_modules/ws/examples/ssl.js new file mode 100644 index 0000000..bf1bf53 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/examples/ssl.js @@ -0,0 +1,59 @@ + +(function(){ + + "use strict"; + + var fs = require('fs'); + + // you'll probably load configuration from config + var cfg = { + ssl: true, + port: 8080, + ssl_key: '/path/to/you/ssl.key', + ssl_cert: '/path/to/you/ssl.crt' + }; + + var httpServ = ( cfg.ssl ) ? require('https') : require('http'); + + var WebSocketServer = require('../').Server; + + var app = null; + + // dummy request processing + var processRequest = function( req, res ) { + + res.writeHead(200); + res.end("All glory to WebSockets!\n"); + }; + + if ( cfg.ssl ) { + + app = httpServ.createServer({ + + // providing server with SSL key/cert + key: fs.readFileSync( cfg.ssl_key ), + cert: fs.readFileSync( cfg.ssl_cert ) + + }, processRequest ).listen( cfg.port ); + + } else { + + app = httpServ.createServer( processRequest ).listen( cfg.port ); + } + + // passing or reference to web server so WS would knew port and SSL capabilities + var wss = new WebSocketServer( { server: app } ); + + + wss.on( 'connection', function ( wsConnect ) { + + wsConnect.on( 'message', function ( message ) { + + console.log( message ); + + }); + + }); + + +}()); \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/index.js b/node_modules/dronestream/node_modules/ws/index.js new file mode 100644 index 0000000..3423ff2 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/index.js @@ -0,0 +1,26 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports = require('./lib/WebSocket'); +module.exports.Server = require('./lib/WebSocketServer'); +module.exports.Sender = require('./lib/Sender'); +module.exports.Receiver = require('./lib/Receiver'); + +module.exports.createServer = function (options, connectionListener) { + var server = new module.exports.Server(options); + if (typeof connectionListener === 'function') { + server.on('connection', connectionListener); + } + return server; +}; + +module.exports.connect = module.exports.createConnection = function (address, openListener) { + var client = new module.exports(address); + if (typeof openListener === 'function') { + client.on('open', openListener); + } + return client; +}; diff --git a/node_modules/dronestream/node_modules/ws/lib/BufferPool.js b/node_modules/dronestream/node_modules/ws/lib/BufferPool.js new file mode 100644 index 0000000..faf8637 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/BufferPool.js @@ -0,0 +1,59 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util'); + +function BufferPool(initialSize, growStrategy, shrinkStrategy) { + if (typeof initialSize === 'function') { + shrinkStrategy = growStrategy; + growStrategy = initialSize; + initialSize = 0; + } + else if (typeof initialSize === 'undefined') { + initialSize = 0; + } + this._growStrategy = (growStrategy || function(db, size) { + return db.used + size; + }).bind(null, this); + this._shrinkStrategy = (shrinkStrategy || function(db) { + return initialSize; + }).bind(null, this); + this._buffer = initialSize ? new Buffer(initialSize) : null; + this._offset = 0; + this._used = 0; + this._changeFactor = 0; + this.__defineGetter__('size', function(){ + return this._buffer == null ? 0 : this._buffer.length; + }); + this.__defineGetter__('used', function(){ + return this._used; + }); +} + +BufferPool.prototype.get = function(length) { + if (this._buffer == null || this._offset + length > this._buffer.length) { + var newBuf = new Buffer(this._growStrategy(length)); + this._buffer = newBuf; + this._offset = 0; + } + this._used += length; + var buf = this._buffer.slice(this._offset, this._offset + length); + this._offset += length; + return buf; +} + +BufferPool.prototype.reset = function(forceNewBuffer) { + var len = this._shrinkStrategy(); + if (len < this.size) this._changeFactor -= 1; + if (forceNewBuffer || this._changeFactor < -2) { + this._changeFactor = 0; + this._buffer = len ? new Buffer(len) : null; + } + this._offset = 0; + this._used = 0; +} + +module.exports = BufferPool; diff --git a/node_modules/dronestream/node_modules/ws/lib/BufferUtil.fallback.js b/node_modules/dronestream/node_modules/ws/lib/BufferUtil.fallback.js new file mode 100644 index 0000000..508542c --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/BufferUtil.fallback.js @@ -0,0 +1,47 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.BufferUtil = { + merge: function(mergedBuffer, buffers) { + var offset = 0; + for (var i = 0, l = buffers.length; i < l; ++i) { + var buf = buffers[i]; + buf.copy(mergedBuffer, offset); + offset += buf.length; + } + }, + mask: function(source, mask, output, offset, length) { + var maskNum = mask.readUInt32LE(0, true); + var i = 0; + for (; i < length - 3; i += 4) { + var num = maskNum ^ source.readUInt32LE(i, true); + if (num < 0) num = 4294967296 + num; + output.writeUInt32LE(num, offset + i, true); + } + switch (length % 4) { + case 3: output[offset + i + 2] = source[i + 2] ^ mask[2]; + case 2: output[offset + i + 1] = source[i + 1] ^ mask[1]; + case 1: output[offset + i] = source[i] ^ mask[0]; + case 0:; + } + }, + unmask: function(data, mask) { + var maskNum = mask.readUInt32LE(0, true); + var length = data.length; + var i = 0; + for (; i < length - 3; i += 4) { + var num = maskNum ^ data.readUInt32LE(i, true); + if (num < 0) num = 4294967296 + num; + data.writeUInt32LE(num, i, true); + } + switch (length % 4) { + case 3: data[i + 2] = data[i + 2] ^ mask[2]; + case 2: data[i + 1] = data[i + 1] ^ mask[1]; + case 1: data[i] = data[i] ^ mask[0]; + case 0:; + } + } +} diff --git a/node_modules/dronestream/node_modules/ws/lib/BufferUtil.js b/node_modules/dronestream/node_modules/ws/lib/BufferUtil.js new file mode 100644 index 0000000..15d35b9 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/BufferUtil.js @@ -0,0 +1,16 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +try { + module.exports = require('../build/Release/bufferutil'); +} catch (e) { try { + module.exports = require('../build/default/bufferutil'); +} catch (e) { try { + module.exports = require('./BufferUtil.fallback'); +} catch (e) { + console.error('bufferutil.node seems to not have been built. Run npm install.'); + throw e; +}}} diff --git a/node_modules/dronestream/node_modules/ws/lib/ErrorCodes.js b/node_modules/dronestream/node_modules/ws/lib/ErrorCodes.js new file mode 100644 index 0000000..55ebd52 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/ErrorCodes.js @@ -0,0 +1,24 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports = { + isValidErrorCode: function(code) { + return (code >= 1000 && code <= 1011 && code != 1004 && code != 1005 && code != 1006) || + (code >= 3000 && code <= 4999); + }, + 1000: 'normal', + 1001: 'going away', + 1002: 'protocol error', + 1003: 'unsupported data', + 1004: 'reserved', + 1005: 'reserved for extensions', + 1006: 'reserved for extensions', + 1007: 'inconsistent or invalid data', + 1008: 'policy violation', + 1009: 'message too big', + 1010: 'extension handshake missing', + 1011: 'an unexpected condition prevented the request from being fulfilled', +}; \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/lib/Receiver.hixie.js b/node_modules/dronestream/node_modules/ws/lib/Receiver.hixie.js new file mode 100644 index 0000000..f54ad96 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/Receiver.hixie.js @@ -0,0 +1,180 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util'); + +/** + * State constants + */ + +var EMPTY = 0 + , BODY = 1; +var BINARYLENGTH = 2 + , BINARYBODY = 3; + +/** + * Hixie Receiver implementation + */ + +function Receiver () { + this.state = EMPTY; + this.buffers = []; + this.messageEnd = -1; + this.spanLength = 0; + this.dead = false; + + this.onerror = function() {}; + this.ontext = function() {}; + this.onbinary = function() {}; + this.onclose = function() {}; + this.onping = function() {}; + this.onpong = function() {}; +} + +module.exports = Receiver; + +/** + * Add new data to the parser. + * + * @api public + */ + +Receiver.prototype.add = function(data) { + var self = this; + function doAdd() { + if (self.state === EMPTY) { + if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) { + self.reset(); + self.onclose(); + return; + } + if (data[0] === 0x80) { + self.messageEnd = 0; + self.state = BINARYLENGTH; + data = data.slice(1); + } else { + + if (data[0] !== 0x00) { + self.error('payload must start with 0x00 byte', true); + return; + } + data = data.slice(1); + self.state = BODY; + + } + } + if (self.state === BINARYLENGTH) { + var i = 0; + while ((i < data.length) && (data[i] & 0x80)) { + self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f); + ++i; + } + if (i < data.length) { + self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f); + self.state = BINARYBODY; + ++i; + } + if (i > 0) + data = data.slice(i); + } + if (self.state === BINARYBODY) { + var dataleft = self.messageEnd - self.spanLength; + if (data.length >= dataleft) { + // consume the whole buffer to finish the frame + self.buffers.push(data); + self.spanLength += dataleft; + self.messageEnd = dataleft; + return self.parse(); + } + // frame's not done even if we consume it all + self.buffers.push(data); + self.spanLength += data.length; + return; + } + self.buffers.push(data); + if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) { + self.spanLength += self.messageEnd; + return self.parse(); + } + else self.spanLength += data.length; + } + while(data) data = doAdd(); +} + +/** + * Releases all resources used by the receiver. + * + * @api public + */ + +Receiver.prototype.cleanup = function() { + this.dead = true; + this.state = EMPTY; + this.buffers = []; +} + +/** + * Process buffered data. + * + * @api public + */ + +Receiver.prototype.parse = function() { + var output = new Buffer(this.spanLength); + var outputIndex = 0; + for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) { + var buffer = this.buffers[bi]; + buffer.copy(output, outputIndex); + outputIndex += buffer.length; + } + var lastBuffer = this.buffers[this.buffers.length - 1]; + if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd); + if (this.state !== BODY) --this.messageEnd; + var tail = null; + if (this.messageEnd < lastBuffer.length - 1) { + tail = lastBuffer.slice(this.messageEnd + 1); + } + this.reset(); + this.ontext(output.toString('utf8')); + return tail; +} + +/** + * Handles an error + * + * @api private + */ + +Receiver.prototype.error = function (reason, terminate) { + this.reset(); + this.onerror(reason, terminate); + return this; +} + +/** + * Reset parser state + * + * @api private + */ + +Receiver.prototype.reset = function (reason) { + if (this.dead) return; + this.state = EMPTY; + this.buffers = []; + this.messageEnd = -1; + this.spanLength = 0; +} + +/** + * Internal api + */ + +function bufferIndex(buffer, byte) { + for (var i = 0, l = buffer.length; i < l; ++i) { + if (buffer[i] === byte) return i; + } + return -1; +} diff --git a/node_modules/dronestream/node_modules/ws/lib/Receiver.js b/node_modules/dronestream/node_modules/ws/lib/Receiver.js new file mode 100644 index 0000000..2752726 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/Receiver.js @@ -0,0 +1,591 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , Validation = require('./Validation').Validation + , ErrorCodes = require('./ErrorCodes') + , BufferPool = require('./BufferPool') + , bufferUtil = require('./BufferUtil').BufferUtil; + +/** + * Node version 0.4 and 0.6 compatibility + */ + +var isNodeV4 = /^v0\.4/.test(process.version); + +/** + * HyBi Receiver implementation + */ + +function Receiver () { + // memory pool for fragmented messages + var fragmentedPoolPrevUsed = -1; + this.fragmentedBufferPool = new BufferPool(1024, function(db, length) { + return db.used + length; + }, function(db) { + return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ? + (fragmentedPoolPrevUsed + db.used) / 2 : + db.used; + }); + + // memory pool for unfragmented messages + var unfragmentedPoolPrevUsed = -1; + this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) { + return db.used + length; + }, function(db) { + return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ? + (unfragmentedPoolPrevUsed + db.used) / 2 : + db.used; + }); + + this.state = { + activeFragmentedOperation: null, + lastFragment: false, + masked: false, + opcode: 0, + fragmentedOperation: false + }; + this.overflow = []; + this.headerBuffer = new Buffer(10); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + this.currentMessage = []; + this.expectHeader(2, this.processPacket); + this.dead = false; + + this.onerror = function() {}; + this.ontext = function() {}; + this.onbinary = function() {}; + this.onclose = function() {}; + this.onping = function() {}; + this.onpong = function() {}; +}; + +module.exports = Receiver; + +/** + * Add new data to the parser. + * + * @api public + */ + +Receiver.prototype.add = function(data) { + var dataLength = data.length; + if (dataLength == 0) return; + if (this.expectBuffer == null) { + this.overflow.push(data); + return; + } + var toRead = Math.min(dataLength, this.expectBuffer.length - this.expectOffset); + fastCopy(toRead, data, this.expectBuffer, this.expectOffset); + this.expectOffset += toRead; + if (toRead < dataLength) { + this.overflow.push(data.slice(toRead)); + } + while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) { + var bufferForHandler = this.expectBuffer; + this.expectBuffer = null; + this.expectOffset = 0; + this.expectHandler.call(this, bufferForHandler); + } +} + +/** + * Releases all resources used by the receiver. + * + * @api public + */ + +Receiver.prototype.cleanup = function() { + this.dead = true; + this.overflow = null; + this.headerBuffer = null; + this.expectBuffer = null; + this.expectHandler = null; + this.unfragmentedBufferPool = null; + this.fragmentedBufferPool = null; + this.state = null; + this.currentMessage = null; + this.onerror = null; + this.ontext = null; + this.onbinary = null; + this.onclose = null; + this.onping = null; + this.onpong = null; +} + +/** + * Waits for a certain amount of header bytes to be available, then fires a callback. + * + * @api private + */ + +Receiver.prototype.expectHeader = function(length, handler) { + if (length == 0) { + handler(null); + return; + } + this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length); + this.expectHandler = handler; + var toRead = length; + while (toRead > 0 && this.overflow.length > 0) { + var fromOverflow = this.overflow.pop(); + if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); + var read = Math.min(fromOverflow.length, toRead); + fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); + this.expectOffset += read; + toRead -= read; + } +} + +/** + * Waits for a certain amount of data bytes to be available, then fires a callback. + * + * @api private + */ + +Receiver.prototype.expectData = function(length, handler) { + if (length == 0) { + handler(null); + return; + } + this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation); + this.expectHandler = handler; + var toRead = length; + while (toRead > 0 && this.overflow.length > 0) { + var fromOverflow = this.overflow.pop(); + if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); + var read = Math.min(fromOverflow.length, toRead); + fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); + this.expectOffset += read; + toRead -= read; + } +} + +/** + * Allocates memory from the buffer pool. + * + * @api private + */ + +Receiver.prototype.allocateFromPool = !isNodeV4 + ? function(length, isFragmented) { return (isFragmented ? this.fragmentedBufferPool : this.unfragmentedBufferPool).get(length); } + : function(length) { return new Buffer(length); }; + +/** + * Start processing a new packet. + * + * @api private + */ + +Receiver.prototype.processPacket = function (data) { + if ((data[0] & 0x70) != 0) { + this.error('reserved fields must be empty', 1002); + return; + } + this.state.lastFragment = (data[0] & 0x80) == 0x80; + this.state.masked = (data[1] & 0x80) == 0x80; + var opcode = data[0] & 0xf; + if (opcode === 0) { + // continuation frame + this.state.fragmentedOperation = true; + this.state.opcode = this.state.activeFragmentedOperation; + if (!(this.state.opcode == 1 || this.state.opcode == 2)) { + this.error('continuation frame cannot follow current opcode', 1002); + return; + } + } + else { + if (opcode < 3 && this.state.activeFragmentedOperation != null) { + this.error('data frames after the initial data frame must have opcode 0', 1002); + return; + } + this.state.opcode = opcode; + if (this.state.lastFragment === false) { + this.state.fragmentedOperation = true; + this.state.activeFragmentedOperation = opcode; + } + else this.state.fragmentedOperation = false; + } + var handler = opcodes[this.state.opcode]; + if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode, 1002); + else { + handler.start.call(this, data); + } +} + +/** + * Endprocessing a packet. + * + * @api private + */ + +Receiver.prototype.endPacket = function() { + if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true); + else if (this.state.lastFragment) this.fragmentedBufferPool.reset(false); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + if (this.state.lastFragment && this.state.opcode === this.state.activeFragmentedOperation) { + // end current fragmented operation + this.state.activeFragmentedOperation = null; + } + this.state.lastFragment = false; + this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0; + this.state.masked = false; + this.expectHeader(2, this.processPacket); +} + +/** + * Reset the parser state. + * + * @api private + */ + +Receiver.prototype.reset = function() { + if (this.dead) return; + this.state = { + activeFragmentedOperation: null, + lastFragment: false, + masked: false, + opcode: 0, + fragmentedOperation: false + }; + this.fragmentedBufferPool.reset(true); + this.unfragmentedBufferPool.reset(true); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + this.overflow = []; + this.currentMessage = []; +} + +/** + * Unmask received data. + * + * @api private + */ + +Receiver.prototype.unmask = function (mask, buf, binary) { + if (mask != null && buf != null) bufferUtil.unmask(buf, mask); + if (binary) return buf; + return buf != null ? buf.toString('utf8') : ''; +} + +/** + * Concatenates a list of buffers. + * + * @api private + */ + +Receiver.prototype.concatBuffers = function(buffers) { + var length = 0; + for (var i = 0, l = buffers.length; i < l; ++i) length += buffers[i].length; + var mergedBuffer = new Buffer(length); + bufferUtil.merge(mergedBuffer, buffers); + return mergedBuffer; +} + +/** + * Handles an error + * + * @api private + */ + +Receiver.prototype.error = function (reason, protocolErrorCode) { + this.reset(); + this.onerror(reason, protocolErrorCode); + return this; +} + +/** + * Buffer utilities + */ + +function readUInt16BE(start) { + return (this[start]<<8) + + this[start+1]; +} + +function readUInt32BE(start) { + return (this[start]<<24) + + (this[start+1]<<16) + + (this[start+2]<<8) + + this[start+3]; +} + +function fastCopy(length, srcBuffer, dstBuffer, dstOffset) { + switch (length) { + default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break; + case 16: dstBuffer[dstOffset+15] = srcBuffer[15]; + case 15: dstBuffer[dstOffset+14] = srcBuffer[14]; + case 14: dstBuffer[dstOffset+13] = srcBuffer[13]; + case 13: dstBuffer[dstOffset+12] = srcBuffer[12]; + case 12: dstBuffer[dstOffset+11] = srcBuffer[11]; + case 11: dstBuffer[dstOffset+10] = srcBuffer[10]; + case 10: dstBuffer[dstOffset+9] = srcBuffer[9]; + case 9: dstBuffer[dstOffset+8] = srcBuffer[8]; + case 8: dstBuffer[dstOffset+7] = srcBuffer[7]; + case 7: dstBuffer[dstOffset+6] = srcBuffer[6]; + case 6: dstBuffer[dstOffset+5] = srcBuffer[5]; + case 5: dstBuffer[dstOffset+4] = srcBuffer[4]; + case 4: dstBuffer[dstOffset+3] = srcBuffer[3]; + case 3: dstBuffer[dstOffset+2] = srcBuffer[2]; + case 2: dstBuffer[dstOffset+1] = srcBuffer[1]; + case 1: dstBuffer[dstOffset] = srcBuffer[0]; + } +} + +/** + * Opcode handlers + */ + +var opcodes = { + // text + '1': { + start: function(data) { + var self = this; + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['1'].getData.call(self, firstLength); + } + else if (firstLength == 126) { + self.expectHeader(2, function(data) { + opcodes['1'].getData.call(self, readUInt16BE.call(data, 0)); + }); + } + else if (firstLength == 127) { + self.expectHeader(8, function(data) { + if (readUInt32BE.call(data, 0) != 0) { + self.error('packets with length spanning more than 32 bit is currently not supported', 1008); + return; + } + opcodes['1'].getData.call(self, readUInt32BE.call(data, 4)); + }); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['1'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['1'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var packet = this.unmask(mask, data, true); + if (packet != null) this.currentMessage.push(packet); + if (this.state.lastFragment) { + var messageBuffer = this.concatBuffers(this.currentMessage); + if (!Validation.isValidUTF8(messageBuffer)) { + this.error('invalid utf8 sequence', 1007); + return; + } + this.ontext(messageBuffer.toString('utf8'), {masked: this.state.masked, buffer: messageBuffer}); + this.currentMessage = []; + } + this.endPacket(); + } + }, + // binary + '2': { + start: function(data) { + var self = this; + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['2'].getData.call(self, firstLength); + } + else if (firstLength == 126) { + self.expectHeader(2, function(data) { + opcodes['2'].getData.call(self, readUInt16BE.call(data, 0)); + }); + } + else if (firstLength == 127) { + self.expectHeader(8, function(data) { + if (readUInt32BE.call(data, 0) != 0) { + self.error('packets with length spanning more than 32 bit is currently not supported', 1008); + return; + } + opcodes['2'].getData.call(self, readUInt32BE.call(data, 4, true)); + }); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['2'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['2'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var packet = this.unmask(mask, data, true); + if (packet != null) this.currentMessage.push(packet); + if (this.state.lastFragment) { + var messageBuffer = this.concatBuffers(this.currentMessage); + this.onbinary(messageBuffer, {masked: this.state.masked, buffer: messageBuffer}); + this.currentMessage = []; + } + this.endPacket(); + } + }, + // close + '8': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented close is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['8'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['8'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['8'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var self = this; + data = self.unmask(mask, data, true); + if (data && data.length == 1) { + self.error('close packets with data must be at least two bytes long', 1002); + return; + } + var code = data && data.length > 1 ? readUInt16BE.call(data, 0) : 1000; + if (!ErrorCodes.isValidErrorCode(code)) { + self.error('invalid error code', 1002); + return; + } + var message = ''; + if (data && data.length > 2) { + var messageBuffer = data.slice(2); + if (!Validation.isValidUTF8(messageBuffer)) { + self.error('invalid utf8 sequence', 1007); + return; + } + message = messageBuffer.toString('utf8'); + } + this.onclose(code, message, {masked: self.state.masked}); + this.reset(); + }, + }, + // ping + '9': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented ping is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['9'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['9'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['9'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + this.onping(this.unmask(mask, data, true), {masked: this.state.masked, binary: true}); + this.endPacket(); + } + }, + // pong + '10': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented pong is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['10'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (this.state.masked) { + this.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['10'].finish.call(self, mask, data); + }); + }); + } + else { + this.expectData(length, function(data) { + opcodes['10'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + this.onpong(this.unmask(mask, data, true), {masked: this.state.masked, binary: true}); + this.endPacket(); + } + } +} diff --git a/node_modules/dronestream/node_modules/ws/lib/Sender.hixie.js b/node_modules/dronestream/node_modules/ws/lib/Sender.hixie.js new file mode 100644 index 0000000..1754afb --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/Sender.hixie.js @@ -0,0 +1,123 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var events = require('events') + , util = require('util') + , EventEmitter = events.EventEmitter; + +/** + * Hixie Sender implementation + */ + +function Sender(socket) { + this.socket = socket; + this.continuationFrame = false; + this.isClosed = false; +} + +module.exports = Sender; + +/** + * Inherits from EventEmitter. + */ + +util.inherits(Sender, events.EventEmitter); + +/** + * Frames and writes data. + * + * @api public + */ + +Sender.prototype.send = function(data, options, cb) { + if (this.isClosed) return; +/* + if (options && options.binary) { + this.error('hixie websockets do not support binary'); + return; + } +*/ + var isString = typeof data == 'string' + , length = isString ? Buffer.byteLength(data) : data.length + , lengthbytes = (length > 127) ? 2 : 1 // assume less than 2**14 bytes + , writeStartMarker = this.continuationFrame == false + , writeEndMarker = !options || !(typeof options.fin != 'undefined' && !options.fin) + , buffer = new Buffer((writeStartMarker ? ((options && options.binary) ? (1 + lengthbytes) : 1) : 0) + length + ((writeEndMarker && !(options && options.binary)) ? 1 : 0)) + , offset = writeStartMarker ? 1 : 0; + + if (writeStartMarker) { + if (options && options.binary) { + buffer.write('\x80', 'binary'); + // assume length less than 2**14 bytes + if (lengthbytes > 1) + buffer.write(String.fromCharCode(128+length/128), offset++, 'binary'); + buffer.write(String.fromCharCode(length&0x7f), offset++, 'binary'); + } else + buffer.write('\x00', 'binary'); + } + + if (isString) buffer.write(data, offset, 'utf8'); + else data.copy(buffer, offset, 0); + + if (writeEndMarker) { + if (options && options.binary) { + // sending binary, not writing end marker + } else + buffer.write('\xff', offset + length, 'binary'); + this.continuationFrame = false; + } + else this.continuationFrame = true; + + try { + this.socket.write(buffer, 'binary', cb); + } catch (e) { + this.error(e.toString()); + } +} + +/** + * Sends a close instruction to the remote party. + * + * @api public + */ + +Sender.prototype.close = function(code, data, mask, cb) { + if (this.isClosed) return; + this.isClosed = true; + try { + if (this.continuationFrame) this.socket.write(new Buffer([0xff], 'binary')); + this.socket.write(new Buffer([0xff, 0x00]), 'binary', cb); + } catch (e) { + this.error(e.toString()); + } +} + +/** + * Sends a ping message to the remote party. Not available for hixie. + * + * @api public + */ + +Sender.prototype.ping = function(data, options) {} + +/** + * Sends a pong message to the remote party. Not available for hixie. + * + * @api public + */ + +Sender.prototype.pong = function(data, options) {} + +/** + * Handles an error + * + * @api private + */ + +Sender.prototype.error = function (reason) { + this.emit('error', reason); + return this; +} diff --git a/node_modules/dronestream/node_modules/ws/lib/Sender.js b/node_modules/dronestream/node_modules/ws/lib/Sender.js new file mode 100644 index 0000000..db109be --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/Sender.js @@ -0,0 +1,226 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var events = require('events') + , util = require('util') + , EventEmitter = events.EventEmitter + , ErrorCodes = require('./ErrorCodes') + , bufferUtil = require('./BufferUtil').BufferUtil; + +/** + * HyBi Sender implementation + */ + +function Sender(socket) { + this._socket = socket; + this.firstFragment = true; +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(Sender, events.EventEmitter); + +/** + * Sends a close instruction to the remote party. + * + * @api public + */ + +Sender.prototype.close = function(code, data, mask) { + if (typeof code !== 'undefined') { + if (typeof code !== 'number' || + !ErrorCodes.isValidErrorCode(code)) throw new Error('first argument must be a valid error code number'); + } + code = code || 1000; + var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0)); + writeUInt16BE.call(dataBuffer, code, 0); + if (dataBuffer.length > 2) dataBuffer.write(data, 2); + this.frameAndSend(0x8, dataBuffer, true, mask); +} + +/** + * Sends a ping message to the remote party. + * + * @api public + */ + +Sender.prototype.ping = function(data, options) { + var mask = options && options.mask; + this.frameAndSend(0x9, data || '', true, mask); +} + +/** + * Sends a pong message to the remote party. + * + * @api public + */ + +Sender.prototype.pong = function(data, options) { + var mask = options && options.mask; + this.frameAndSend(0xa, data || '', true, mask); +} + +/** + * Sends text or binary data to the remote party. + * + * @api public + */ + +Sender.prototype.send = function(data, options, cb) { + var finalFragment = options && options.fin === false ? false : true; + var mask = options && options.mask; + var opcode = options && options.binary ? 2 : 1; + if (this.firstFragment === false) opcode = 0; + else this.firstFragment = false; + if (finalFragment) this.firstFragment = true + this.frameAndSend(opcode, data, finalFragment, mask, cb); +} + +/** + * Frames and sends a piece of data according to the HyBi WebSocket protocol. + * + * @api private + */ + +Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData, cb) { + var canModifyData = false; + + if (!data) { + try { + this._socket.write(new Buffer([opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)].concat(maskData ? [0, 0, 0, 0] : [])), 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + return; + } + + if (!Buffer.isBuffer(data)) { + canModifyData = true; + if (data && (typeof data.byteLength !== 'undefined' || typeof data.buffer !== 'undefined')) { + data = getArrayBuffer(data); + } else { + data = new Buffer(data); + } + } + + var dataLength = data.length + , dataOffset = maskData ? 6 : 2 + , secondByte = dataLength; + + if (dataLength >= 65536) { + dataOffset += 8; + secondByte = 127; + } + else if (dataLength > 125) { + dataOffset += 2; + secondByte = 126; + } + + var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData); + var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset; + var outputBuffer = new Buffer(totalLength); + outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode; + + switch (secondByte) { + case 126: + writeUInt16BE.call(outputBuffer, dataLength, 2); + break; + case 127: + writeUInt32BE.call(outputBuffer, 0, 2); + writeUInt32BE.call(outputBuffer, dataLength, 6); + } + + if (maskData) { + outputBuffer[1] = secondByte | 0x80; + var mask = this._randomMask || (this._randomMask = getRandomMask()); + outputBuffer[dataOffset - 4] = mask[0]; + outputBuffer[dataOffset - 3] = mask[1]; + outputBuffer[dataOffset - 2] = mask[2]; + outputBuffer[dataOffset - 1] = mask[3]; + if (mergeBuffers) { + bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength); + try { + this._socket.write(outputBuffer, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + else { + bufferUtil.mask(data, mask, data, 0, dataLength); + try { + this._socket.write(outputBuffer, 'binary'); + this._socket.write(data, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + } + else { + outputBuffer[1] = secondByte; + if (mergeBuffers) { + data.copy(outputBuffer, dataOffset); + try { + this._socket.write(outputBuffer, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + else { + try { + this._socket.write(outputBuffer, 'binary'); + this._socket.write(data, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + } +} + +module.exports = Sender; + +function writeUInt16BE(value, offset) { + this[offset] = (value & 0xff00)>>8; + this[offset+1] = value & 0xff; +} + +function writeUInt32BE(value, offset) { + this[offset] = (value & 0xff000000)>>24; + this[offset+1] = (value & 0xff0000)>>16; + this[offset+2] = (value & 0xff00)>>8; + this[offset+3] = value & 0xff; +} + +function getArrayBuffer(data) { + // data is either an ArrayBuffer or ArrayBufferView. + var array = data.buffer || data + , l = data.byteLength || data.length + , buffer = new Buffer(l); + for (var i = 0; i < l; ++i) { + buffer[i] = array[i]; + } + return buffer; +} + +function getRandomMask() { + return new Buffer([ + ~~(Math.random() * 255), + ~~(Math.random() * 255), + ~~(Math.random() * 255), + ~~(Math.random() * 255) + ]); +} diff --git a/node_modules/dronestream/node_modules/ws/lib/Validation.fallback.js b/node_modules/dronestream/node_modules/ws/lib/Validation.fallback.js new file mode 100644 index 0000000..2c7c4fd --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/Validation.fallback.js @@ -0,0 +1,12 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.Validation = { + isValidUTF8: function(buffer) { + return true; + } +}; + diff --git a/node_modules/dronestream/node_modules/ws/lib/Validation.js b/node_modules/dronestream/node_modules/ws/lib/Validation.js new file mode 100644 index 0000000..0f3109a --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/Validation.js @@ -0,0 +1,16 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +try { + module.exports = require('../build/Release/validation'); +} catch (e) { try { + module.exports = require('../build/default/validation'); +} catch (e) { try { + module.exports = require('./Validation.fallback'); +} catch (e) { + console.error('validation.node seems to not have been built. Run npm install.'); + throw e; +}}} diff --git a/node_modules/dronestream/node_modules/ws/lib/WebSocket.js b/node_modules/dronestream/node_modules/ws/lib/WebSocket.js new file mode 100644 index 0000000..5f40658 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/WebSocket.js @@ -0,0 +1,766 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , events = require('events') + , http = require('http') + , https = require('https') + , crypto = require('crypto') + , url = require('url') + , fs = require('fs') + , Options = require('options') + , Sender = require('./Sender') + , Receiver = require('./Receiver') + , SenderHixie = require('./Sender.hixie') + , ReceiverHixie = require('./Receiver.hixie'); + +/** + * Constants + */ + +// Default protocol version + +var protocolVersion = 13; + +// Close timeout + +var closeTimeout = 30000; // Allow 5 seconds to terminate the connection cleanly + +/** + * Node version 0.4 and 0.6 compatibility + */ + +var isNodeV4 = /^v0\.4/.test(process.version); + +/** + * WebSocket implementation + */ + +function WebSocket(address, options) { + var self = this; + + this._socket = null; + this.bytesReceived = 0; + this.readyState = null; + this.supports = {}; + + if (Object.prototype.toString.call(address) == '[object Array]') { + initAsServerClient.apply(this, address.concat(options)); + } + else initAsClient.apply(this, arguments); +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(WebSocket, events.EventEmitter); + +/** + * Ready States + */ + +["CONNECTING", "OPEN", "CLOSING", "CLOSED"].forEach(function (state, index) { + WebSocket.prototype[state] = WebSocket[state] = index; +}); + +/** + * Gracefully closes the connection, after sending a description message to the server + * + * @param {Object} data to be sent to the server + * @api public + */ + +WebSocket.prototype.close = function(code, data) { + if (this.readyState == WebSocket.CLOSING || this.readyState == WebSocket.CLOSED) return; + if (this.readyState == WebSocket.CONNECTING) { + this.readyState = WebSocket.CLOSED; + return; + } + try { + this.readyState = WebSocket.CLOSING; + this._closeCode = code; + this._closeMessage = data; + var mask = !this._isServer; + this._sender.close(code, data, mask); + } + catch (e) { + this.emit('error', e); + } + finally { + this.terminate(); + } +} + +/** + * Pause the client stream + * + * @api public + */ + +WebSocket.prototype.pause = function() { + if (this.readyState != WebSocket.OPEN) throw new Error('not opened'); + return this._socket.pause(); +} + +/** + * Sends a ping + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open + * @api public + */ + +WebSocket.prototype.ping = function(data, options, dontFailWhenClosed) { + if (this.readyState != WebSocket.OPEN) { + if (dontFailWhenClosed === true) return; + throw new Error('not opened'); + } + options = options || {}; + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + this._sender.ping(data, options); +} + +/** + * Sends a pong + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open + * @api public + */ + +WebSocket.prototype.pong = function(data, options, dontFailWhenClosed) { + if (this.readyState != WebSocket.OPEN) { + if (dontFailWhenClosed === true) return; + throw new Error('not opened'); + } + options = options || {}; + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + this._sender.pong(data, options); +} + +/** + * Resume the client stream + * + * @api public + */ + +WebSocket.prototype.resume = function() { + if (this.readyState != WebSocket.OPEN) throw new Error('not opened'); + return this._socket.resume(); +} + +/** + * Sends a piece of data + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {function} Optional callback which is executed after the send completes + * @api public + */ + +WebSocket.prototype.send = function(data, options, cb) { + if (typeof options == 'function') { + cb = options; + options = {}; + } + if (this.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else throw new Error('not opened'); + return; + } + if (!data) data = ''; + if (this._queue) { + var self = this; + this._queue.push(function() { self.send(data, options, cb); }); + return; + } + options = options || {}; + options.fin = true; + if (typeof options.binary == 'undefined') { + options.binary = (data instanceof ArrayBuffer || data instanceof Buffer); + } + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + if (data instanceof fs.ReadStream) { + startQueue(this); + var self = this; + sendStream(this, data, options, function(error) { + process.nextTick(function() { executeQueueSends(self); }); + if (typeof cb == 'function') cb(error); + }); + } + else this._sender.send(data, options, cb); +} + +/** + * Streams data through calls to a user supplied function + * + * @param {Object} Members - mask: boolean, binary: boolean + * @param {function} 'function (error, send)' which is executed on successive ticks of which send is 'function (data, final)'. + * @api public + */ + +WebSocket.prototype.stream = function(options, cb) { + if (typeof options == 'function') { + cb = options; + options = {}; + } + if (typeof cb != 'function') throw new Error('callback must be provided'); + if (this.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else throw new Error('not opened'); + return; + } + if (this._queue) { + var self = this; + this._queue.push(function() { self.stream(options, cb); }); + return; + } + options = options || {}; + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + startQueue(this); + var self = this; + var send = function(data, final) { + try { + if (self.readyState != WebSocket.OPEN) throw new Error('not opened'); + options.fin = final === true; + self._sender.send(data, options); + if (!final) process.nextTick(cb.bind(null, null, send)); + else executeQueueSends(self); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else { + delete self._queue; + self.emit('error', e); + } + } + } + process.nextTick(cb.bind(null, null, send)); +} + +/** + * Immediately shuts down the connection + * + * @api public + */ + +WebSocket.prototype.terminate = function() { + if (this.readyState == WebSocket.CLOSED) return; + if (this._socket) { + try { + // End the connection + this._socket.end(); + } + catch (e) { + // Socket error during end() call, so just destroy it right now + cleanupWebsocketResources.call(this, true); + return; + } + + // Add a timeout to ensure that the connection is completely + // cleaned up within 30 seconds, even if the clean close procedure + // fails for whatever reason + this._closeTimer = setTimeout(cleanupWebsocketResources.bind(this, true), closeTimeout); + } + else if (this.readyState == WebSocket.CONNECTING) { + cleanupWebsocketResources.call(this, true); + } +}; + +/** + * Expose bufferedAmount + * + * @api public + */ + +Object.defineProperty(WebSocket.prototype, 'bufferedAmount', { + get: function get() { + return this._socket ? this._socket.bufferSize : 0; + } +}); + +/** + * Emulates the W3C Browser based WebSocket interface using function members. + * + * @see http://dev.w3.org/html5/websockets/#the-websocket-interface + * @api public + */ + +['open', 'error', 'close', 'message'].forEach(function(method) { + Object.defineProperty(WebSocket.prototype, 'on' + method, { + /** + * Returns the current listener + * + * @returns {Mixed} the set function or undefined + * @api public + */ + + get: function get() { + var listener = this.listeners(method)[0]; + return listener ? (listener._listener ? listener._listener : listener) : undefined; + }, + + /** + * Start listening for events + * + * @param {Function} listener the listener + * @returns {Mixed} the set function or undefined + * @api public + */ + + set: function set(listener) { + this.removeAllListeners(method); + this.addEventListener(method, listener); + } + }); +}); + +/** + * Emulates the W3C Browser based WebSocket interface using addEventListener. + * + * @see https://developer.mozilla.org/en/DOM/element.addEventListener + * @see http://dev.w3.org/html5/websockets/#the-websocket-interface + * @api public + */ +WebSocket.prototype.addEventListener = function(method, listener) { + var target = this; + if (typeof listener === 'function') { + if (method === 'message') { + function onMessage (data, flags) { + listener.call(this, new MessageEvent(data, flags.binary ? 'Binary' : 'Text', target)); + } + // store a reference so we can return the original function from the addEventListener hook + onMessage._listener = listener; + this.on(method, onMessage); + } else if (method === 'close') { + function onClose (code, message) { + listener.call(this, new CloseEvent(code, message, target)); + } + // store a reference so we can return the original function from the addEventListener hook + onClose._listener = listener; + this.on(method, onClose); + } else if (method === 'error') { + function onError (event) { + event.target = target; + listener.call(this, event); + } + // store a reference so we can return the original function from the addEventListener hook + onError._listener = listener; + this.on(method, onError); + } else if (method === 'open') { + function onOpen () { + listener.call(this, new OpenEvent(target)); + } + // store a reference so we can return the original function from the addEventListener hook + onOpen._listener = listener; + this.on(method, onOpen); + } else { + this.on(method, listener); + } + } +} + +module.exports = WebSocket; + +/** + * W3C MessageEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @api private + */ + +function MessageEvent(dataArg, typeArg, target) { + this.data = dataArg; + this.type = typeArg; + this.target = target; +} + +/** + * W3C CloseEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @api private + */ + +function CloseEvent(code, reason, target) { + this.wasClean = (typeof code == 'undefined' || code == 1000); + this.code = code; + this.reason = reason; + this.target = target; +} + +/** + * W3C OpenEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @api private + */ + +function OpenEvent(target) { + this.target = target; +} + +/** + * Entirely private apis, + * which may or may not be bound to a sepcific WebSocket instance. + */ + +function initAsServerClient(req, socket, upgradeHead, options) { + options = new Options({ + protocolVersion: protocolVersion, + protocol: null + }).merge(options); + + // expose state properties + this.protocol = options.value.protocol; + this.protocolVersion = options.value.protocolVersion; + this.supports.binary = (this.protocolVersion != 'hixie-76'); + this.upgradeReq = req; + this.readyState = WebSocket.CONNECTING; + this._isServer = true; + + // establish connection + if (options.value.protocolVersion == 'hixie-76') establishConnection.call(this, ReceiverHixie, SenderHixie, socket, upgradeHead); + else establishConnection.call(this, Receiver, Sender, socket, upgradeHead); +} + +function initAsClient(address, options) { + options = new Options({ + origin: null, + protocolVersion: protocolVersion, + host: null, + protocol: null, + + // ssl-related options + pfx: null, + key: null, + passphrase: null, + cert: null, + ca: null, + ciphers: null, + rejectUnauthorized: null + }).merge(options); + if (options.value.protocolVersion != 8 && options.value.protocolVersion != 13) { + throw new Error('unsupported protocol version'); + } + + // verify url and establish http class + var serverUrl = url.parse(address); + var isUnixSocket = serverUrl.protocol === 'ws+unix:'; + if (!serverUrl.host && !isUnixSocket) throw new Error('invalid url'); + var isSecure = serverUrl.protocol === 'wss:' || serverUrl.protocol === 'https:'; + var httpObj = isSecure ? https : http; + var port = serverUrl.port || (isSecure ? 443 : 80); + + // expose state properties + this._isServer = false; + this.url = address; + this.protocolVersion = options.value.protocolVersion; + this.supports.binary = (this.protocolVersion != 'hixie-76'); + + // begin handshake + var key = new Buffer(options.value.protocolVersion + '-' + Date.now()).toString('base64'); + var shasum = crypto.createHash('sha1'); + shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); + var expectedServerKey = shasum.digest('base64'); + + // node<=v0.4.x compatibility + var agent; + if (isNodeV4) { + isNodeV4 = true; + agent = new httpObj.Agent({ + host: serverUrl.hostname, + port: port + }); + } + + var headerHost = serverUrl.hostname + ':' + port; + var requestOptions = { + port: port, + host: serverUrl.hostname, + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Host': headerHost, + 'Origin': headerHost, + 'Sec-WebSocket-Version': options.value.protocolVersion, + 'Sec-WebSocket-Key': key + } + }; + if (options.value.protocol) { + requestOptions.headers['Sec-WebSocket-Protocol'] = options.value.protocol; + } + if (options.value.host) { + requestOptions.headers['Host'] = options.value.host; + } + + if (options.isDefinedAndNonNull('pfx') + || options.isDefinedAndNonNull('key') + || options.isDefinedAndNonNull('passphrase') + || options.isDefinedAndNonNull('cert') + || options.isDefinedAndNonNull('ca') + || options.isDefinedAndNonNull('ciphers') + || options.isDefinedAndNonNull('rejectUnauthorized')) { + + if (isNodeV4) { + throw new Error('Client side certificates are not supported on Node 0.4.x'); + } + + if (options.isDefinedAndNonNull('pfx')) requestOptions.pfx = options.value.pfx; + if (options.isDefinedAndNonNull('key')) requestOptions.key = options.value.key; + if (options.isDefinedAndNonNull('passphrase')) requestOptions.passphrase = options.value.passphrase; + if (options.isDefinedAndNonNull('cert')) requestOptions.cert = options.value.cert; + if (options.isDefinedAndNonNull('ca')) requestOptions.ca = options.value.ca; + if (options.isDefinedAndNonNull('ciphers')) requestOptions.ciphers = options.value.ciphers; + if (options.isDefinedAndNonNull('rejectUnauthorized')) requestOptions.rejectUnauthorized = options.value.rejectUnauthorized; + + // global agent ignores client side certificates + agent = new httpObj.Agent(requestOptions); + } + + if (isNodeV4) { + requestOptions.path = (serverUrl.pathname || '/') + (serverUrl.search || ''); + } + else requestOptions.path = serverUrl.path || '/'; + + if (agent) { + requestOptions.agent = agent; + } + + if (isUnixSocket) { + requestOptions.socketPath = serverUrl.pathname; + } + if (options.value.origin) { + if (options.value.protocolVersion < 13) requestOptions.headers['Sec-WebSocket-Origin'] = options.value.origin; + else requestOptions.headers['Origin'] = options.value.origin; + } + + var self = this; + var req = httpObj.request(requestOptions); + + (isNodeV4 ? agent : req).on('error', function(error) { + self.emit('error', error); + cleanupWebsocketResources.call(this, error); + }); + (isNodeV4 ? agent : req).once('response', function(res) { + var error = new Error('unexpected server response (' + res.statusCode + ')'); + self.emit('error', error); + cleanupWebsocketResources.call(this, error); + }); + (isNodeV4 ? agent : req).once('upgrade', function(res, socket, upgradeHead) { + if (self.readyState == WebSocket.CLOSED) { + // client closed before server accepted connection + self.emit('close'); + removeAllListeners(self); + socket.end(); + return; + } + var serverKey = res.headers['sec-websocket-accept']; + if (typeof serverKey == 'undefined' || serverKey !== expectedServerKey) { + self.emit('error', 'invalid server key'); + removeAllListeners(self); + socket.end(); + return; + } + + var serverProt = res.headers['sec-websocket-protocol']; + var protList = (options.value.protocol || "").split(/, */); + var protError = null; + if (!options.value.protocol && serverProt) { + protError = 'server sent a subprotocol even though none requested'; + } else if (options.value.protocol && !serverProt) { + protError = 'server sent no subprotocol even though requested'; + } else if (serverProt && protList.indexOf(serverProt) === -1) { + protError = 'server responded with an invalid protocol'; + } + if (protError) { + self.emit('error', protError); + removeAllListeners(self); + socket.end(); + return; + } else if (serverProt) { + self.protocol = serverProt; + } + + establishConnection.call(self, Receiver, Sender, socket, upgradeHead); + + // perform cleanup on http resources + removeAllListeners(isNodeV4 ? agent : req); + req = null; + agent = null; + }); + + req.end(); + this.readyState = WebSocket.CONNECTING; +} + +function establishConnection(ReceiverClass, SenderClass, socket, upgradeHead) { + this._socket = socket; + socket.setTimeout(0); + socket.setNoDelay(true); + var self = this; + this._receiver = new ReceiverClass(); + + // socket cleanup handlers + socket.on('end', cleanupWebsocketResources.bind(this)); + socket.on('close', cleanupWebsocketResources.bind(this)); + socket.on('error', cleanupWebsocketResources.bind(this)); + + // ensure that the upgradeHead is added to the receiver + function firstHandler(data) { + if (self.readyState != WebSocket.OPEN) return; + if (upgradeHead && upgradeHead.length > 0) { + self.bytesReceived += upgradeHead.length; + var head = upgradeHead; + upgradeHead = null; + self._receiver.add(head); + } + dataHandler = realHandler; + if (data) { + self.bytesReceived += data.length; + self._receiver.add(data); + } + } + // subsequent packets are pushed straight to the receiver + function realHandler(data) { + if (data) self.bytesReceived += data.length; + self._receiver.add(data); + } + var dataHandler = firstHandler; + socket.on('data', dataHandler); + // if data was passed along with the http upgrade, + // this will schedule a push of that on to the receiver. + // this has to be done on next tick, since the caller + // hasn't had a chance to set event handlers on this client + // object yet. + process.nextTick(firstHandler); + + // receiver event handlers + self._receiver.ontext = function (data, flags) { + flags = flags || {}; + self.emit('message', data, flags); + }; + self._receiver.onbinary = function (data, flags) { + flags = flags || {}; + flags.binary = true; + self.emit('message', data, flags); + }; + self._receiver.onping = function(data, flags) { + flags = flags || {}; + self.pong(data, {mask: !self._isServer, binary: flags.binary === true}, true); + self.emit('ping', data, flags); + }; + self._receiver.onpong = function(data, flags) { + self.emit('pong', data, flags); + }; + self._receiver.onclose = function(code, data, flags) { + flags = flags || {}; + self.close(code, data); + }; + self._receiver.onerror = function(reason, errorCode) { + // close the connection when the receiver reports a HyBi error code + self.close(typeof errorCode != 'undefined' ? errorCode : 1002, ''); + self.emit('error', reason, errorCode); + }; + + // finalize the client + this._sender = new SenderClass(socket); + this._sender.on('error', function(error) { + self.close(1002, ''); + self.emit('error', error); + }); + this.readyState = WebSocket.OPEN; + this.emit('open'); +} + +function startQueue(instance) { + instance._queue = instance._queue || []; +} + +function executeQueueSends(instance) { + var queue = instance._queue; + if (typeof queue == 'undefined') return; + delete instance._queue; + for (var i = 0, l = queue.length; i < l; ++i) { + queue[i](); + } +} + +function sendStream(instance, stream, options, cb) { + stream.on('data', function(data) { + if (instance.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else { + delete instance._queue; + instance.emit('error', new Error('not opened')); + } + return; + } + options.fin = false; + instance._sender.send(data, options); + }); + stream.on('end', function() { + if (instance.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else { + delete instance._queue; + instance.emit('error', new Error('not opened')); + } + return; + } + options.fin = true; + instance._sender.send(null, options); + if (typeof cb == 'function') cb(null); + }); +} + +function cleanupWebsocketResources(error) { + if (this.readyState == WebSocket.CLOSED) return; + var emitClose = this.readyState != WebSocket.CONNECTING; + this.readyState = WebSocket.CLOSED; + + clearTimeout(this._closeTimer); + this._closeTimer = null; + if (emitClose) this.emit('close', this._closeCode || 1000, this._closeMessage || ''); + + if (this._socket) { + removeAllListeners(this._socket); + // catch all socket error after removing all standard handlers + var socket = this._socket; + this._socket.on('error', function() { + try { socket.destroy(); } catch (e) {} + }); + try { + if (!error) this._socket.end(); + else this._socket.destroy(); + } + catch (e) { /* Ignore termination errors */ } + this._socket = null; + } + if (this._sender) { + removeAllListeners(this._sender); + this._sender = null; + } + if (this._receiver) { + this._receiver.cleanup(); + this._receiver = null; + } + removeAllListeners(this); + this.on('error', function() {}); // catch all errors after this + delete this._queue; +} + +function removeAllListeners(instance) { + if (isNodeV4) { + // node v4 doesn't *actually* remove all listeners globally, + // so we do that instead + instance._events = {}; + } + else instance.removeAllListeners(); +} diff --git a/node_modules/dronestream/node_modules/ws/lib/WebSocketServer.js b/node_modules/dronestream/node_modules/ws/lib/WebSocketServer.js new file mode 100644 index 0000000..ee47f10 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/WebSocketServer.js @@ -0,0 +1,460 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , events = require('events') + , http = require('http') + , crypto = require('crypto') + , url = require('url') + , Options = require('options') + , WebSocket = require('./WebSocket') + , tls = require('tls') + , url = require('url'); + +/** + * WebSocket Server implementation + */ + +function WebSocketServer(options, callback) { + options = new Options({ + host: '0.0.0.0', + port: null, + server: null, + verifyClient: null, + handleProtocols: null, + path: null, + noServer: false, + disableHixie: false, + clientTracking: true + }).merge(options); + + if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) { + throw new TypeError('`port` or a `server` must be provided'); + } + + var self = this; + + if (options.isDefinedAndNonNull('port')) { + this._server = http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Not implemented'); + }); + this._server.listen(options.value.port, options.value.host, callback); + this._closeServer = function() { self._server.close(); }; + } + else if (options.value.server) { + this._server = options.value.server; + if (options.value.path) { + // take note of the path, to avoid collisions when multiple websocket servers are + // listening on the same http server + if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) { + throw new Error('two instances of WebSocketServer cannot listen on the same http server path'); + } + if (typeof this._server._webSocketPaths !== 'object') { + this._server._webSocketPaths = {}; + } + this._server._webSocketPaths[options.value.path] = 1; + } + } + if (this._server) this._server.once('listening', function() { self.emit('listening'); }); + + if (typeof this._server != 'undefined') { + this._server.on('error', function(error) { + self.emit('error', error) + }); + this._server.on('upgrade', function(req, socket, upgradeHead) { + //copy upgradeHead to avoid retention of large slab buffers used in node core + var head = new Buffer(upgradeHead.length); + upgradeHead.copy(head); + + self.handleUpgrade(req, socket, head, function(client) { + self.emit('connection'+req.url, client); + self.emit('connection', client); + }); + }); + } + + this.options = options.value; + this.path = options.value.path; + this.clients = []; +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(WebSocketServer, events.EventEmitter); + +/** + * Immediately shuts down the connection. + * + * @api public + */ + +WebSocketServer.prototype.close = function() { + // terminate all associated clients + var error = null; + try { + for (var i = 0, l = this.clients.length; i < l; ++i) { + this.clients[i].terminate(); + } + } + catch (e) { + error = e; + } + + // remove path descriptor, if any + if (this.path && this._server._webSocketPaths) { + delete this._server._webSocketPaths[this.path]; + if (Object.keys(this._server._webSocketPaths).length == 0) { + delete this._server._webSocketPaths; + } + } + + // close the http server if it was internally created + try { + if (typeof this._closeServer !== 'undefined') { + this._closeServer(); + } + } + finally { + delete this._server; + } + if (error) throw error; +} + +/** + * Handle a HTTP Upgrade request. + * + * @api public + */ + +WebSocketServer.prototype.handleUpgrade = function(req, socket, upgradeHead, cb) { + // check for wrong path + if (this.options.path) { + var u = url.parse(req.url); + if (u && u.pathname !== this.options.path) return; + } + + if (typeof req.headers.upgrade === 'undefined' || req.headers.upgrade.toLowerCase() !== 'websocket') { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + if (req.headers['sec-websocket-key1']) handleHixieUpgrade.apply(this, arguments); + else handleHybiUpgrade.apply(this, arguments); +} + +module.exports = WebSocketServer; + +/** + * Entirely private apis, + * which may or may not be bound to a sepcific WebSocket instance. + */ + +function handleHybiUpgrade(req, socket, upgradeHead, cb) { + // handle premature socket errors + var errorHandler = function() { + try { socket.destroy(); } catch (e) {} + } + socket.on('error', errorHandler); + + // verify key presence + if (!req.headers['sec-websocket-key']) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + // verify version + var version = parseInt(req.headers['sec-websocket-version']); + if ([8, 13].indexOf(version) === -1) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + // verify protocol + var protocols = req.headers['sec-websocket-protocol']; + + // verify client + var origin = version < 13 ? + req.headers['sec-websocket-origin'] : + req.headers['origin']; + + // handler to call when the connection sequence completes + var self = this; + var completeHybiUpgrade2 = function(protocol) { + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + if (typeof protocol != 'undefined') { + headers.push('Sec-WebSocket-Protocol: ' + protocol); + } + + // allows external modification/inspection of handshake headers + self.emit('headers', headers); + + socket.setTimeout(0); + socket.setNoDelay(true); + try { + socket.write(headers.concat('', '').join('\r\n')); + } + catch (e) { + // if the upgrade write fails, shut the connection down hard + try { socket.destroy(); } catch (e) {} + return; + } + + var client = new WebSocket([req, socket, upgradeHead], { + protocolVersion: version, + protocol: protocol + }); + + if (self.options.clientTracking) { + self.clients.push(client); + client.on('close', function() { + var index = self.clients.indexOf(client); + if (index != -1) { + self.clients.splice(index, 1); + } + }); + } + + // signal upgrade complete + socket.removeListener('error', errorHandler); + cb(client); + } + + // optionally call external protocol selection handler before + // calling completeHybiUpgrade2 + var completeHybiUpgrade1 = function() { + // choose from the sub-protocols + if (typeof self.options.handleProtocols == 'function') { + var protList = (protocols || "").split(/, */); + var callbackCalled = false; + var res = self.options.handleProtocols(protList, function(result, protocol) { + callbackCalled = true; + if (!result) abortConnection(socket, 404, 'Unauthorized') + else completeHybiUpgrade2(protocol); + }); + if (!callbackCalled) { + // the handleProtocols handler never called our callback + abortConnection(socket, 501, 'Could not process protocols'); + } + return; + } else { + if (typeof protocols !== 'undefined') { + completeHybiUpgrade2(protocols.split(/, */)[0]); + } + else { + completeHybiUpgrade2(); + } + } + } + + // optionally call external client verification handler + if (typeof this.options.verifyClient == 'function') { + var info = { + origin: origin, + secure: typeof req.connection.encrypted !== 'undefined', + req: req + }; + if (this.options.verifyClient.length == 2) { + this.options.verifyClient(info, function(result) { + if (!result) abortConnection(socket, 401, 'Unauthorized') + else completeHybiUpgrade1(); + }); + return; + } + else if (!this.options.verifyClient(info)) { + abortConnection(socket, 401, 'Unauthorized'); + return; + } + } + + completeHybiUpgrade1(); +} + +function handleHixieUpgrade(req, socket, upgradeHead, cb) { + // handle premature socket errors + var errorHandler = function() { + try { socket.destroy(); } catch (e) {} + } + socket.on('error', errorHandler); + + // bail if options prevent hixie + if (this.options.disableHixie) { + abortConnection(socket, 401, 'Hixie support disabled'); + return; + } + + // verify key presence + if (!req.headers['sec-websocket-key2']) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + var origin = req.headers['origin'] + , self = this; + + // setup handshake completion to run after client has been verified + var onClientVerified = function() { + var wshost; + if (!req.headers['x-forwarded-host']) + wshost = req.headers.host; + else + wshost = req.headers['x-forwarded-host']; + var location = ((req.headers['x-forwarded-proto'] === 'https' || socket.encrypted) ? 'wss' : 'ws') + '://' + wshost + req.url + , protocol = req.headers['sec-websocket-protocol']; + + // handshake completion code to run once nonce has been successfully retrieved + var completeHandshake = function(nonce, rest) { + // calculate key + var k1 = req.headers['sec-websocket-key1'] + , k2 = req.headers['sec-websocket-key2'] + , md5 = crypto.createHash('md5'); + + [k1, k2].forEach(function (k) { + var n = parseInt(k.replace(/[^\d]/g, '')) + , spaces = k.replace(/[^ ]/g, '').length; + if (spaces === 0 || n % spaces !== 0){ + abortConnection(socket, 400, 'Bad Request'); + return; + } + n /= spaces; + md5.update(String.fromCharCode( + n >> 24 & 0xFF, + n >> 16 & 0xFF, + n >> 8 & 0xFF, + n & 0xFF)); + }); + md5.update(nonce.toString('binary')); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: WebSocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Location: ' + location + ]; + if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol); + if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin); + + socket.setTimeout(0); + socket.setNoDelay(true); + try { + // merge header and hash buffer + var headerBuffer = new Buffer(headers.concat('', '').join('\r\n')); + var hashBuffer = new Buffer(md5.digest('binary'), 'binary'); + var handshakeBuffer = new Buffer(headerBuffer.length + hashBuffer.length); + headerBuffer.copy(handshakeBuffer, 0); + hashBuffer.copy(handshakeBuffer, headerBuffer.length); + + // do a single write, which - upon success - causes a new client websocket to be setup + socket.write(handshakeBuffer, 'binary', function(err) { + if (err) return; // do not create client if an error happens + var client = new WebSocket([req, socket, rest], { + protocolVersion: 'hixie-76', + protocol: protocol + }); + if (self.options.clientTracking) { + self.clients.push(client); + client.on('close', function() { + var index = self.clients.indexOf(client); + if (index != -1) { + self.clients.splice(index, 1); + } + }); + } + + // signal upgrade complete + socket.removeListener('error', errorHandler); + cb(client); + }); + } + catch (e) { + try { socket.destroy(); } catch (e) {} + return; + } + } + + // retrieve nonce + var nonceLength = 8; + if (upgradeHead && upgradeHead.length >= nonceLength) { + var nonce = upgradeHead.slice(0, nonceLength); + var rest = upgradeHead.length > nonceLength ? upgradeHead.slice(nonceLength) : null; + completeHandshake.call(self, nonce, rest); + } + else { + // nonce not present in upgradeHead, so we must wait for enough data + // data to arrive before continuing + var nonce = new Buffer(nonceLength); + upgradeHead.copy(nonce, 0); + var received = upgradeHead.length; + var rest = null; + var handler = function (data) { + var toRead = Math.min(data.length, nonceLength - received); + if (toRead === 0) return; + data.copy(nonce, received, 0, toRead); + received += toRead; + if (received == nonceLength) { + socket.removeListener('data', handler); + if (toRead < data.length) rest = data.slice(toRead); + completeHandshake.call(self, nonce, rest); + } + } + socket.on('data', handler); + } + } + + // verify client + if (typeof this.options.verifyClient == 'function') { + var info = { + origin: origin, + secure: typeof req.connection.encrypted !== 'undefined', + req: req + }; + if (this.options.verifyClient.length == 2) { + var self = this; + this.options.verifyClient(info, function(result) { + if (!result) abortConnection(socket, 401, 'Unauthorized') + else onClientVerified.apply(self); + }); + return; + } + else if (!this.options.verifyClient(info)) { + abortConnection(socket, 401, 'Unauthorized'); + return; + } + } + + // no client verification required + onClientVerified(); +} + +function abortConnection(socket, code, name) { + try { + var response = [ + 'HTTP/1.1 ' + code + ' ' + name, + 'Content-type: text/html' + ]; + socket.write(response.concat('', '').join('\r\n')); + } + catch (e) { /* ignore errors - we've aborted this connection */ } + finally { + // ensure that an early aborted connection is shut down completely + try { socket.destroy(); } catch (e) {} + } +} diff --git a/node_modules/dronestream/node_modules/ws/lib/browser.js b/node_modules/dronestream/node_modules/ws/lib/browser.js new file mode 100644 index 0000000..37cafe1 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/lib/browser.js @@ -0,0 +1,5 @@ +/// shim for browser packaging + +module.exports = function() { + return global.WebSocket || global.MozWebSocket; +} diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/.npmignore b/node_modules/dronestream/node_modules/ws/node_modules/commander/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/.travis.yml b/node_modules/dronestream/node_modules/ws/node_modules/commander/.travis.yml new file mode 100644 index 0000000..f1d0f13 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.4 + - 0.6 diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/History.md b/node_modules/dronestream/node_modules/ws/node_modules/commander/History.md new file mode 100644 index 0000000..4961d2e --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/History.md @@ -0,0 +1,107 @@ + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/Makefile b/node_modules/dronestream/node_modules/ws/node_modules/commander/Makefile new file mode 100644 index 0000000..0074625 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/Makefile @@ -0,0 +1,7 @@ + +TESTS = $(shell find test/test.*.js) + +test: + @./test/run $(TESTS) + +.PHONY: test \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/Readme.md b/node_modules/dronestream/node_modules/ws/node_modules/commander/Readme.md new file mode 100644 index 0000000..b8328c3 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/Readme.md @@ -0,0 +1,262 @@ +# Commander.js + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). + + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) + +## Installation + + $ npm install commander + +## Option parsing + + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.0.1') + .option('-p, --peppers', 'Add peppers') + .option('-P, --pineapple', 'Add pineapple') + .option('-b, --bbq', 'Add bbq sauce') + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') + .parse(process.argv); + +console.log('you ordered a pizza with:'); +if (program.peppers) console.log(' - peppers'); +if (program.pineapple) console.log(' - pineappe'); +if (program.bbq) console.log(' - bbq'); +console.log(' - %s cheese', program.cheese); +``` + + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + Options: + + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineappe + -b, --bbq Add bbq sauce + -c, --cheese Add the specified type of cheese [marble] + -h, --help output usage information + +``` + +## Coercion + +```js +function range(val) { + return val.split('..').map(Number); +} + +function list(val) { + return val.split(','); +} + +program + .version('0.0.1') + .usage('[options] ') + .option('-i, --integer ', 'An integer argument', parseInt) + .option('-f, --float ', 'A float argument', parseFloat) + .option('-r, --range ..', 'A range', range) + .option('-l, --list ', 'A list', list) + .option('-o, --optional [value]', 'An optional value') + .parse(process.argv); + +console.log(' int: %j', program.integer); +console.log(' float: %j', program.float); +console.log(' optional: %j', program.optional); +program.range = program.range || []; +console.log(' range: %j..%j', program.range[0], program.range[1]); +console.log(' list: %j', program.list); +console.log(' args: %j', program.args); +``` + +## Custom help + + You can display arbitrary `-h, --help` information + by listening for "--help". Commander will automatically + exit once you are done so that the remainder of your program + does not execute causing undesired behaviours, for example + in the following executable "stuff" will not output when + `--help` is used. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('../'); + +function list(val) { + return val.split(',').map(Number); +} + +program + .version('0.0.1') + .option('-f, --foo', 'enable some foo') + .option('-b, --bar', 'enable some bar') + .option('-B, --baz', 'enable some baz'); + +// must be before .parse() since +// node's emit() is immediate + +program.on('--help', function(){ + console.log(' Examples:'); + console.log(''); + console.log(' $ custom-help --help'); + console.log(' $ custom-help -h'); + console.log(''); +}); + +program.parse(process.argv); + +console.log('stuff'); +``` + +yielding the following help output: + +``` + +Usage: custom-help [options] + +Options: + + -h, --help output usage information + -V, --version output the version number + -f, --foo enable some foo + -b, --bar enable some bar + -B, --baz enable some baz + +Examples: + + $ custom-help --help + $ custom-help -h + +``` + +## .prompt(msg, fn) + + Single-line prompt: + +```js +program.prompt('name: ', function(name){ + console.log('hi %s', name); +}); +``` + + Multi-line prompt: + +```js +program.prompt('description:', function(name){ + console.log('hi %s', name); +}); +``` + + Coercion: + +```js +program.prompt('Age: ', Number, function(age){ + console.log('age: %j', age); +}); +``` + +```js +program.prompt('Birthdate: ', Date, function(date){ + console.log('date: %s', date); +}); +``` + +## .password(msg[, mask], fn) + +Prompt for password without echoing: + +```js +program.password('Password: ', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +Prompt for password with mask char "*": + +```js +program.password('Password: ', '*', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +## .confirm(msg, fn) + + Confirm with the given `msg`: + +```js +program.confirm('continue? ', function(ok){ + console.log(' got %j', ok); +}); +``` + +## .choose(list, fn) + + Let the user choose from a `list`: + +```js +var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + +console.log('Choose the coolest pet:'); +program.choose(list, function(i){ + console.log('you chose %d "%s"', i, list[i]); +}); +``` + +## Links + + - [API documentation](http://visionmedia.github.com/commander.js/) + - [ascii tables](https://github.com/LearnBoost/cli-table) + - [progress bars](https://github.com/visionmedia/node-progress) + - [more progress bars](https://github.com/substack/node-multimeter) + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) + +## License + +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/index.js b/node_modules/dronestream/node_modules/ws/node_modules/commander/index.js new file mode 100644 index 0000000..06ec1e4 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/commander'); \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/lib/commander.js b/node_modules/dronestream/node_modules/ws/node_modules/commander/lib/commander.js new file mode 100644 index 0000000..5ba87eb --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/lib/commander.js @@ -0,0 +1,1026 @@ + +/*! + * commander + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , path = require('path') + , tty = require('tty') + , basename = path.basename; + +/** + * Expose the root command. + */ + +exports = module.exports = new Command; + +/** + * Expose `Command`. + */ + +exports.Command = Command; + +/** + * Expose `Option`. + */ + +exports.Option = Option; + +/** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {String} flags + * @param {String} description + * @api public + */ + +function Option(flags, description) { + this.flags = flags; + this.required = ~flags.indexOf('<'); + this.optional = ~flags.indexOf('['); + this.bool = !~flags.indexOf('-no-'); + flags = flags.split(/[ ,|]+/); + if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); + this.long = flags.shift(); + this.description = description; +} + +/** + * Return option name. + * + * @return {String} + * @api private + */ + +Option.prototype.name = function(){ + return this.long + .replace('--', '') + .replace('no-', ''); +}; + +/** + * Check if `arg` matches the short or long flag. + * + * @param {String} arg + * @return {Boolean} + * @api private + */ + +Option.prototype.is = function(arg){ + return arg == this.short + || arg == this.long; +}; + +/** + * Initialize a new `Command`. + * + * @param {String} name + * @api public + */ + +function Command(name) { + this.commands = []; + this.options = []; + this.args = []; + this.name = name; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Command.prototype.__proto__ = EventEmitter.prototype; + +/** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * Examples: + * + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function(){ + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd){ + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env){ + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {String} name + * @return {Command} the new command + * @api public + */ + +Command.prototype.command = function(name){ + var args = name.split(/ +/); + var cmd = new Command(args.shift()); + this.commands.push(cmd); + cmd.parseExpectedArgs(args); + cmd.parent = this; + return cmd; +}; + +/** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {Array} args + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parseExpectedArgs = function(args){ + if (!args.length) return; + var self = this; + args.forEach(function(arg){ + switch (arg[0]) { + case '<': + self.args.push({ required: true, name: arg.slice(1, -1) }); + break; + case '[': + self.args.push({ required: false, name: arg.slice(1, -1) }); + break; + } + }); + return this; +}; + +/** + * Register callback `fn` for the command. + * + * Examples: + * + * program + * .command('help') + * .description('display verbose help') + * .action(function(){ + * // output help here + * }); + * + * @param {Function} fn + * @return {Command} for chaining + * @api public + */ + +Command.prototype.action = function(fn){ + var self = this; + this.parent.on(this.name, function(args, unknown){ + // Parse any so-far unknown options + unknown = unknown || []; + var parsed = self.parseOptions(unknown); + + // Output help if necessary + outputHelpIfNecessary(self, parsed.unknown); + + // If there are still any unknown options, then we simply + // die, unless someone asked for help, in which case we give it + // to them, and then we die. + if (parsed.unknown.length > 0) { + self.unknownOption(parsed.unknown[0]); + } + + self.args.forEach(function(arg, i){ + if (arg.required && null == args[i]) { + self.missingArgument(arg.name); + } + }); + + // Always append ourselves to the end of the arguments, + // to make sure we match the number of arguments the user + // expects + if (self.args.length) { + args[self.args.length] = self; + } else { + args.push(self); + } + + fn.apply(this, args); + }); + return this; +}; + +/** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * Examples: + * + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to false + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => true + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {String} flags + * @param {String} description + * @param {Function|Mixed} fn or default + * @param {Mixed} defaultValue + * @return {Command} for chaining + * @api public + */ + +Command.prototype.option = function(flags, description, fn, defaultValue){ + var self = this + , option = new Option(flags, description) + , oname = option.name() + , name = camelcase(oname); + + // default as 3rd arg + if ('function' != typeof fn) defaultValue = fn, fn = null; + + // preassign default value only for --no-*, [optional], or + if (false == option.bool || option.optional || option.required) { + // when --no-* we make sure default is true + if (false == option.bool) defaultValue = true; + // preassign only if we have a default + if (undefined !== defaultValue) self[name] = defaultValue; + } + + // register the option + this.options.push(option); + + // when it's passed assign the value + // and conditionally invoke the callback + this.on(oname, function(val){ + // coercion + if (null != val && fn) val = fn(val); + + // unassigned or bool + if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { + // if no value, bool true, and we have a default, then use it! + if (null == val) { + self[name] = option.bool + ? defaultValue || true + : false; + } else { + self[name] = val; + } + } else if (null !== val) { + // reassign + self[name] = val; + } + }); + + return this; +}; + +/** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {Array} argv + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parse = function(argv){ + // store raw args + this.rawArgs = argv; + + // guess name + if (!this.name) this.name = basename(argv[1]); + + // process argv + var parsed = this.parseOptions(this.normalize(argv.slice(2))); + this.args = parsed.args; + return this.parseArgs(this.args, parsed.unknown); +}; + +/** + * Normalize `args`, splitting joined short flags. For example + * the arg "-abc" is equivalent to "-a -b -c". + * + * @param {Array} args + * @return {Array} + * @api private + */ + +Command.prototype.normalize = function(args){ + var ret = [] + , arg; + + for (var i = 0, len = args.length; i < len; ++i) { + arg = args[i]; + if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { + arg.slice(1).split('').forEach(function(c){ + ret.push('-' + c); + }); + } else { + ret.push(arg); + } + } + + return ret; +}; + +/** + * Parse command `args`. + * + * When listener(s) are available those + * callbacks are invoked, otherwise the "*" + * event is emitted and those actions are invoked. + * + * @param {Array} args + * @return {Command} for chaining + * @api private + */ + +Command.prototype.parseArgs = function(args, unknown){ + var cmds = this.commands + , len = cmds.length + , name; + + if (args.length) { + name = args[0]; + if (this.listeners(name).length) { + this.emit(args.shift(), args, unknown); + } else { + this.emit('*', args); + } + } else { + outputHelpIfNecessary(this, unknown); + + // If there were no args and we have unknown options, + // then they are extraneous and we need to error. + if (unknown.length > 0) { + this.unknownOption(unknown[0]); + } + } + + return this; +}; + +/** + * Return an option matching `arg` if any. + * + * @param {String} arg + * @return {Option} + * @api private + */ + +Command.prototype.optionFor = function(arg){ + for (var i = 0, len = this.options.length; i < len; ++i) { + if (this.options[i].is(arg)) { + return this.options[i]; + } + } +}; + +/** + * Parse options from `argv` returning `argv` + * void of these options. + * + * @param {Array} argv + * @return {Array} + * @api public + */ + +Command.prototype.parseOptions = function(argv){ + var args = [] + , len = argv.length + , literal + , option + , arg; + + var unknownOptions = []; + + // parse options + for (var i = 0; i < len; ++i) { + arg = argv[i]; + + // literal args after -- + if ('--' == arg) { + literal = true; + continue; + } + + if (literal) { + args.push(arg); + continue; + } + + // find matching Option + option = this.optionFor(arg); + + // option is defined + if (option) { + // requires arg + if (option.required) { + arg = argv[++i]; + if (null == arg) return this.optionMissingArgument(option); + if ('-' == arg[0]) return this.optionMissingArgument(option, arg); + this.emit(option.name(), arg); + // optional arg + } else if (option.optional) { + arg = argv[i+1]; + if (null == arg || '-' == arg[0]) { + arg = null; + } else { + ++i; + } + this.emit(option.name(), arg); + // bool + } else { + this.emit(option.name()); + } + continue; + } + + // looks like an option + if (arg.length > 1 && '-' == arg[0]) { + unknownOptions.push(arg); + + // If the next argument looks like it might be + // an argument for this option, we pass it on. + // If it isn't, then it'll simply be ignored + if (argv[i+1] && '-' != argv[i+1][0]) { + unknownOptions.push(argv[++i]); + } + continue; + } + + // arg + args.push(arg); + } + + return { args: args, unknown: unknownOptions }; +}; + +/** + * Argument `name` is missing. + * + * @param {String} name + * @api private + */ + +Command.prototype.missingArgument = function(name){ + console.error(); + console.error(" error: missing required argument `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * `Option` is missing an argument, but received `flag` or nothing. + * + * @param {String} option + * @param {String} flag + * @api private + */ + +Command.prototype.optionMissingArgument = function(option, flag){ + console.error(); + if (flag) { + console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + } else { + console.error(" error: option `%s' argument missing", option.flags); + } + console.error(); + process.exit(1); +}; + +/** + * Unknown option `flag`. + * + * @param {String} flag + * @api private + */ + +Command.prototype.unknownOption = function(flag){ + console.error(); + console.error(" error: unknown option `%s'", flag); + console.error(); + process.exit(1); +}; + +/** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {String} str + * @param {String} flags + * @return {Command} for chaining + * @api public + */ + +Command.prototype.version = function(str, flags){ + if (0 == arguments.length) return this._version; + this._version = str; + flags = flags || '-V, --version'; + this.option(flags, 'output the version number'); + this.on('version', function(){ + console.log(str); + process.exit(0); + }); + return this; +}; + +/** + * Set the description `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.description = function(str){ + if (0 == arguments.length) return this._description; + this._description = str; + return this; +}; + +/** + * Set / get the command usage `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.usage = function(str){ + var args = this.args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }); + + var usage = '[options' + + (this.commands.length ? '] [command' : '') + + ']' + + (this.args.length ? ' ' + args : ''); + if (0 == arguments.length) return this._usage || usage; + this._usage = str; + + return this; +}; + +/** + * Return the largest option length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestOptionLength = function(){ + return this.options.reduce(function(max, option){ + return Math.max(max, option.flags.length); + }, 0); +}; + +/** + * Return help for options. + * + * @return {String} + * @api private + */ + +Command.prototype.optionHelp = function(){ + var width = this.largestOptionLength(); + + // Prepend the help information + return [pad('-h, --help', width) + ' ' + 'output usage information'] + .concat(this.options.map(function(option){ + return pad(option.flags, width) + + ' ' + option.description; + })) + .join('\n'); +}; + +/** + * Return command help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.commandHelp = function(){ + if (!this.commands.length) return ''; + return [ + '' + , ' Commands:' + , '' + , this.commands.map(function(cmd){ + var args = cmd.args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }).join(' '); + + return cmd.name + + (cmd.options.length + ? ' [options]' + : '') + ' ' + args + + (cmd.description() + ? '\n' + cmd.description() + : ''); + }).join('\n\n').replace(/^/gm, ' ') + , '' + ].join('\n'); +}; + +/** + * Return program help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.helpInformation = function(){ + return [ + '' + , ' Usage: ' + this.name + ' ' + this.usage() + , '' + this.commandHelp() + , ' Options:' + , '' + , '' + this.optionHelp().replace(/^/gm, ' ') + , '' + , '' + ].join('\n'); +}; + +/** + * Prompt for a `Number`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForNumber = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseNumber(val){ + val = Number(val); + if (isNaN(val)) return self.promptSingleLine(str + '(must be a number) ', parseNumber); + fn(val); + }); +}; + +/** + * Prompt for a `Date`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForDate = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseDate(val){ + val = new Date(val); + if (isNaN(val.getTime())) return self.promptSingleLine(str + '(must be a date) ', parseDate); + fn(val); + }); +}; + +/** + * Single-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptSingleLine = function(str, fn){ + if ('function' == typeof arguments[2]) { + return this['promptFor' + (fn.name || fn)](str, arguments[2]); + } + + process.stdout.write(str); + process.stdin.setEncoding('utf8'); + process.stdin.once('data', function(val){ + fn(val.trim()); + }).resume(); +}; + +/** + * Multi-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptMultiLine = function(str, fn){ + var buf = []; + console.log(str); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function(val){ + if ('\n' == val || '\r\n' == val) { + process.stdin.removeAllListeners('data'); + fn(buf.join('\n')); + } else { + buf.push(val.trimRight()); + } + }).resume(); +}; + +/** + * Prompt `str` and callback `fn(val)` + * + * Commander supports single-line and multi-line prompts. + * To issue a single-line prompt simply add white-space + * to the end of `str`, something like "name: ", whereas + * for a multi-line prompt omit this "description:". + * + * + * Examples: + * + * program.prompt('Username: ', function(name){ + * console.log('hi %s', name); + * }); + * + * program.prompt('Description:', function(desc){ + * console.log('description was "%s"', desc.trim()); + * }); + * + * @param {String|Object} str + * @param {Function} fn + * @api public + */ + +Command.prototype.prompt = function(str, fn){ + var self = this; + + if ('string' == typeof str) { + if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments); + this.promptMultiLine(str, fn); + } else { + var keys = Object.keys(str) + , obj = {}; + + function next() { + var key = keys.shift() + , label = str[key]; + + if (!key) return fn(obj); + self.prompt(label, function(val){ + obj[key] = val; + next(); + }); + } + + next(); + } +}; + +/** + * Prompt for password with `str`, `mask` char and callback `fn(val)`. + * + * The mask string defaults to '', aka no output is + * written while typing, you may want to use "*" etc. + * + * Examples: + * + * program.password('Password: ', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * program.password('Password: ', '*', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {String} mask + * @param {Function} fn + * @api public + */ + +Command.prototype.password = function(str, mask, fn){ + var self = this + , buf = ''; + + // default mask + if ('function' == typeof mask) { + fn = mask; + mask = ''; + } + + process.stdin.resume(); + tty.setRawMode(true); + process.stdout.write(str); + + // keypress + process.stdin.on('keypress', function(c, key){ + if (key && 'enter' == key.name) { + console.log(); + process.stdin.removeAllListeners('keypress'); + tty.setRawMode(false); + if (!buf.trim().length) return self.password(str, mask, fn); + fn(buf); + return; + } + + if (key && key.ctrl && 'c' == key.name) { + console.log('%s', buf); + process.exit(); + } + + process.stdout.write(mask); + buf += c; + }).resume(); +}; + +/** + * Confirmation prompt with `str` and callback `fn(bool)` + * + * Examples: + * + * program.confirm('continue? ', function(ok){ + * console.log(' got %j', ok); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {Function} fn + * @api public + */ + + +Command.prototype.confirm = function(str, fn, verbose){ + var self = this; + this.prompt(str, function(ok){ + if (!ok.trim()) { + if (!verbose) str += '(yes or no) '; + return self.confirm(str, fn, true); + } + fn(parseBool(ok)); + }); +}; + +/** + * Choice prompt with `list` of items and callback `fn(index, item)` + * + * Examples: + * + * var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + * + * console.log('Choose the coolest pet:'); + * program.choose(list, function(i){ + * console.log('you chose %d "%s"', i, list[i]); + * process.stdin.destroy(); + * }); + * + * @param {Array} list + * @param {Number|Function} index or fn + * @param {Function} fn + * @api public + */ + +Command.prototype.choose = function(list, index, fn){ + var self = this + , hasDefault = 'number' == typeof index; + + if (!hasDefault) { + fn = index; + index = null; + } + + list.forEach(function(item, i){ + if (hasDefault && i == index) { + console.log('* %d) %s', i + 1, item); + } else { + console.log(' %d) %s', i + 1, item); + } + }); + + function again() { + self.prompt(' : ', function(val){ + val = parseInt(val, 10) - 1; + if (hasDefault && isNaN(val)) val = index; + + if (null == list[val]) { + again(); + } else { + fn(val, list[val]); + } + }); + } + + again(); +}; + +/** + * Camel-case the given `flag` + * + * @param {String} flag + * @return {String} + * @api private + */ + +function camelcase(flag) { + return flag.split('-').reduce(function(str, word){ + return str + word[0].toUpperCase() + word.slice(1); + }); +} + +/** + * Parse a boolean `str`. + * + * @param {String} str + * @return {Boolean} + * @api private + */ + +function parseBool(str) { + return /^y|yes|ok|true$/i.test(str); +} + +/** + * Pad `str` to `width`. + * + * @param {String} str + * @param {Number} width + * @return {String} + * @api private + */ + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +/** + * Output help information if necessary + * + * @param {Command} command to output help for + * @param {Array} array of options to search for -h or --help + * @api private + */ + +function outputHelpIfNecessary(cmd, options) { + options = options || []; + for (var i = 0; i < options.length; i++) { + if (options[i] == '--help' || options[i] == '-h') { + process.stdout.write(cmd.helpInformation()); + cmd.emit('--help'); + process.exit(0); + } + } +} diff --git a/node_modules/dronestream/node_modules/ws/node_modules/commander/package.json b/node_modules/dronestream/node_modules/ws/node_modules/commander/package.json new file mode 100644 index 0000000..bb8a2c2 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/commander/package.json @@ -0,0 +1,38 @@ +{ + "name": "commander", + "version": "0.6.1", + "description": "the complete solution for node.js command-line programs", + "keywords": [ + "command", + "option", + "parser", + "prompt", + "stdin" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "https://github.com/visionmedia/commander.js.git" + }, + "dependencies": {}, + "devDependencies": { + "should": ">= 0.0.1" + }, + "scripts": { + "test": "make test" + }, + "main": "index", + "engines": { + "node": ">= 0.4.x" + }, + "readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineappe');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineappe\n -b, --bbq Add bbq sauce\n -c, --cheese Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] ')\n .option('-i, --integer ', 'An integer argument', parseInt)\n .option('-f, --float ', 'A float argument', parseFloat)\n .option('-r, --range ..', 'A range', range)\n .option('-l, --list ', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .prompt(msg, fn)\n\n Single-line prompt:\n\n```js\nprogram.prompt('name: ', function(name){\n console.log('hi %s', name);\n});\n```\n\n Multi-line prompt:\n\n```js\nprogram.prompt('description:', function(name){\n console.log('hi %s', name);\n});\n```\n\n Coercion:\n\n```js\nprogram.prompt('Age: ', Number, function(age){\n console.log('age: %j', age);\n});\n```\n\n```js\nprogram.prompt('Birthdate: ', Date, function(date){\n console.log('date: %s', date);\n});\n```\n\n## .password(msg[, mask], fn)\n\nPrompt for password without echoing:\n\n```js\nprogram.password('Password: ', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\nPrompt for password with mask char \"*\":\n\n```js\nprogram.password('Password: ', '*', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\n## .confirm(msg, fn)\n\n Confirm with the given `msg`:\n\n```js\nprogram.confirm('continue? ', function(ok){\n console.log(' got %j', ok);\n});\n```\n\n## .choose(list, fn)\n\n Let the user choose from a `list`:\n\n```js\nvar list = ['tobi', 'loki', 'jane', 'manny', 'luna'];\n\nconsole.log('Choose the coolest pet:');\nprogram.choose(list, function(i){\n console.log('you chose %d \"%s\"', i, list[i]);\n});\n```\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/commander.js/issues" + }, + "_id": "commander@0.6.1", + "_from": "commander@~0.6.1" +} diff --git a/node_modules/dronestream/node_modules/ws/node_modules/options/.npmignore b/node_modules/dronestream/node_modules/ws/node_modules/options/.npmignore new file mode 100644 index 0000000..6bfffbb --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/options/.npmignore @@ -0,0 +1,5 @@ +npm-debug.log +node_modules +.*.swp +.lock-* +build/ diff --git a/node_modules/dronestream/node_modules/ws/node_modules/options/Makefile b/node_modules/dronestream/node_modules/ws/node_modules/options/Makefile new file mode 100644 index 0000000..7496b6f --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/options/Makefile @@ -0,0 +1,12 @@ +ALL_TESTS = $(shell find test/ -name '*.test.js') + +run-tests: + @./node_modules/.bin/mocha \ + -t 2000 \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests + +.PHONY: test diff --git a/node_modules/dronestream/node_modules/ws/node_modules/options/README.md b/node_modules/dronestream/node_modules/ws/node_modules/options/README.md new file mode 100644 index 0000000..4b39a2a --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/options/README.md @@ -0,0 +1,28 @@ +# options.js # + +A very light-weight in-code option parsers for node.js. + +## License ## + +(The MIT License) + +Copyright (c) 2012 Einar Otto Stangvik <einaros@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/dronestream/node_modules/ws/node_modules/options/lib/options.js b/node_modules/dronestream/node_modules/ws/node_modules/options/lib/options.js new file mode 100644 index 0000000..4fc45e9 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/options/lib/options.js @@ -0,0 +1,86 @@ +/*! + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var fs = require('fs'); + +function Options(defaults) { + var internalValues = {}; + var values = this.value = {}; + Object.keys(defaults).forEach(function(key) { + internalValues[key] = defaults[key]; + Object.defineProperty(values, key, { + get: function() { return internalValues[key]; }, + configurable: false, + enumerable: true + }); + }); + this.reset = function() { + Object.keys(defaults).forEach(function(key) { + internalValues[key] = defaults[key]; + }); + return this; + }; + this.merge = function(options, required) { + options = options || {}; + if (Object.prototype.toString.call(required) === '[object Array]') { + var missing = []; + for (var i = 0, l = required.length; i < l; ++i) { + var key = required[i]; + if (!(key in options)) { + missing.push(key); + } + } + if (missing.length > 0) { + if (missing.length > 1) { + throw new Error('options ' + + missing.slice(0, missing.length - 1).join(', ') + ' and ' + + missing[missing.length - 1] + ' must be defined'); + } + else throw new Error('option ' + missing[0] + ' must be defined'); + } + } + Object.keys(options).forEach(function(key) { + if (key in internalValues) { + internalValues[key] = options[key]; + } + }); + return this; + }; + this.copy = function(keys) { + var obj = {}; + Object.keys(defaults).forEach(function(key) { + if (keys.indexOf(key) !== -1) { + obj[key] = values[key]; + } + }); + return obj; + }; + this.read = function(filename, cb) { + if (typeof cb == 'function') { + var self = this; + fs.readFile(filename, function(error, data) { + if (error) return cb(error); + var conf = JSON.parse(data); + self.merge(conf); + cb(); + }); + } + else { + var conf = JSON.parse(fs.readFileSync(filename)); + this.merge(conf); + } + return this; + }; + this.isDefined = function(key) { + return typeof values[key] != 'undefined'; + }; + this.isDefinedAndNonNull = function(key) { + return typeof values[key] != 'undefined' && values[key] !== null; + }; + Object.freeze(values); + Object.freeze(this); +} + +module.exports = Options; diff --git a/node_modules/dronestream/node_modules/ws/node_modules/options/package.json b/node_modules/dronestream/node_modules/ws/node_modules/options/package.json new file mode 100644 index 0000000..04e8978 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/options/package.json @@ -0,0 +1,32 @@ +{ + "author": { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com", + "url": "http://2x.io" + }, + "name": "options", + "description": "A very light-weight in-code option parsers for node.js.", + "version": "0.0.5", + "repository": { + "type": "git", + "url": "git://github.com/einaros/options.js.git" + }, + "main": "lib/options", + "scripts": { + "test": "make test" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "latest" + }, + "readme": "# options.js #\n\nA very light-weight in-code option parsers for node.js.\n\n## License ##\n\n(The MIT License)\n\nCopyright (c) 2012 Einar Otto Stangvik <einaros@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/einaros/options.js/issues" + }, + "_id": "options@0.0.5", + "_from": "options@>=0.0.5" +} diff --git a/node_modules/dronestream/node_modules/ws/node_modules/options/test/fixtures/test.conf b/node_modules/dronestream/node_modules/ws/node_modules/options/test/fixtures/test.conf new file mode 100644 index 0000000..6e62444 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/options/test/fixtures/test.conf @@ -0,0 +1,4 @@ +{ + "a": "foobar", + "b": false +} \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/node_modules/options/test/options.test.js b/node_modules/dronestream/node_modules/ws/node_modules/options/test/options.test.js new file mode 100644 index 0000000..6a1d9f5 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/options/test/options.test.js @@ -0,0 +1,140 @@ +var Options = require('options') + , assert = require('assert'); + +describe('Options', function() { + describe('#ctor', function() { + it('initializes options', function() { + var option = new Options({a: true, b: false}); + assert.strictEqual(true, option.value.a); + assert.strictEqual(false, option.value.b); + }); + }); + + describe('#merge', function() { + it('merges options from another object', function() { + var option = new Options({a: true, b: false}); + option.merge({b: true}); + assert.strictEqual(true, option.value.a); + assert.strictEqual(true, option.value.b); + }); + it('does nothing when arguments are undefined', function() { + var option = new Options({a: true, b: false}); + option.merge(undefined); + assert.strictEqual(true, option.value.a); + assert.strictEqual(false, option.value.b); + }); + it('cannot set values that werent already there', function() { + var option = new Options({a: true, b: false}); + option.merge({c: true}); + assert.strictEqual('undefined', typeof option.value.c); + }); + it('can require certain options to be defined', function() { + var option = new Options({a: true, b: false, c: 3}); + var caughtException = false; + try { + option.merge({}, ['a', 'b', 'c']); + } + catch (e) { + caughtException = e.toString() == 'Error: options a, b and c must be defined'; + } + assert.strictEqual(true, caughtException); + }); + it('can require certain options to be defined, when options are undefined', function() { + var option = new Options({a: true, b: false, c: 3}); + var caughtException = false; + try { + option.merge(undefined, ['a', 'b', 'c']); + } + catch (e) { + caughtException = e.toString() == 'Error: options a, b and c must be defined'; + } + assert.strictEqual(true, caughtException); + }); + it('returns "this"', function() { + var option = new Options({a: true, b: false, c: 3}); + assert.strictEqual(option, option.merge()); + }); + }); + + describe('#copy', function() { + it('returns a new object with the indicated options', function() { + var option = new Options({a: true, b: false, c: 3}); + option.merge({c: 4}); + var obj = option.copy(['a', 'c']); + assert.strictEqual(true, obj.a); + assert.strictEqual(4, obj.c); + assert.strictEqual('undefined', typeof obj.b); + }); + }); + + describe('#value', function() { + it('can be enumerated', function() { + var option = new Options({a: true, b: false}); + assert.strictEqual(2, Object.keys(option.value).length); + }); + it('can not be used to set values', function() { + var option = new Options({a: true, b: false}); + option.value.b = true; + assert.strictEqual(false, option.value.b); + }); + it('can not be used to add values', function() { + var option = new Options({a: true, b: false}); + option.value.c = 3; + assert.strictEqual('undefined', typeof option.value.c); + }); + }); + + describe('#isDefined', function() { + it('returns true if the named value is defined', function() { + var option = new Options({a: undefined}); + assert.strictEqual(false, option.isDefined('a')); + option.merge({a: false}); + assert.strictEqual(true, option.isDefined('a')); + }); + }); + + describe('#isDefinedAndNonNull', function() { + it('returns true if the named value is defined and non-null', function() { + var option = new Options({a: undefined}); + assert.strictEqual(false, option.isDefinedAndNonNull('a')); + option.merge({a: null}); + assert.strictEqual(false, option.isDefinedAndNonNull('a')); + option.merge({a: 2}); + assert.strictEqual(true, option.isDefinedAndNonNull('a')); + }); + }); + + describe('#read', function() { + it('reads and merges config from a file', function() { + var option = new Options({a: true, b: true}); + option.read(__dirname + '/fixtures/test.conf'); + assert.strictEqual('foobar', option.value.a); + assert.strictEqual(false, option.value.b); + }); + + it('asynchronously reads and merges config from a file when a callback is passed', function(done) { + var option = new Options({a: true, b: true}); + option.read(__dirname + '/fixtures/test.conf', function(error) { + assert.strictEqual('foobar', option.value.a); + assert.strictEqual(false, option.value.b); + done(); + }); + }); + }); + + describe('#reset', function() { + it('resets options to defaults', function() { + var option = new Options({a: true, b: false}); + option.merge({b: true}); + assert.strictEqual(true, option.value.b); + option.reset(); + assert.strictEqual(false, option.value.b); + }); + }); + + it('is immutable', function() { + var option = new Options({a: true, b: false}); + option.foo = 2; + assert.strictEqual('undefined', typeof option.foo); + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/.npmignore b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/.npmignore new file mode 100644 index 0000000..6bfffbb --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/.npmignore @@ -0,0 +1,5 @@ +npm-debug.log +node_modules +.*.swp +.lock-* +build/ diff --git a/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/README.md b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/README.md new file mode 100644 index 0000000..55eb3c1 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/README.md @@ -0,0 +1,3 @@ +# tinycolor # + +This is a no-fuzz, barebone, zero muppetry color module for node.js. \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/example.js b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/example.js new file mode 100644 index 0000000..f754046 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/example.js @@ -0,0 +1,3 @@ +require('./tinycolor'); +console.log('this should be red and have an underline!'.grey.underline); +console.log('this should have a blue background!'.bgBlue); \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/package.json b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/package.json new file mode 100644 index 0000000..8c56dce --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/package.json @@ -0,0 +1,27 @@ +{ + "author": { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com", + "url": "http://2x.io" + }, + "name": "tinycolor", + "description": "a to-the-point color module for node", + "version": "0.0.1", + "repository": { + "type": "git", + "url": "git://github.com/einaros/tinycolor.git" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": {}, + "devDependencies": {}, + "main": "tinycolor", + "readme": "# tinycolor #\n\nThis is a no-fuzz, barebone, zero muppetry color module for node.js.", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/einaros/tinycolor/issues" + }, + "_id": "tinycolor@0.0.1", + "_from": "tinycolor@0.x" +} diff --git a/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/tinycolor.js b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/tinycolor.js new file mode 100644 index 0000000..36e552c --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/node_modules/tinycolor/tinycolor.js @@ -0,0 +1,31 @@ +var styles = { + 'bold': ['\033[1m', '\033[22m'], + 'italic': ['\033[3m', '\033[23m'], + 'underline': ['\033[4m', '\033[24m'], + 'inverse': ['\033[7m', '\033[27m'], + 'black': ['\033[30m', '\033[39m'], + 'red': ['\033[31m', '\033[39m'], + 'green': ['\033[32m', '\033[39m'], + 'yellow': ['\033[33m', '\033[39m'], + 'blue': ['\033[34m', '\033[39m'], + 'magenta': ['\033[35m', '\033[39m'], + 'cyan': ['\033[36m', '\033[39m'], + 'white': ['\033[37m', '\033[39m'], + 'default': ['\033[39m', '\033[39m'], + 'grey': ['\033[90m', '\033[39m'], + 'bgBlack': ['\033[40m', '\033[49m'], + 'bgRed': ['\033[41m', '\033[49m'], + 'bgGreen': ['\033[42m', '\033[49m'], + 'bgYellow': ['\033[43m', '\033[49m'], + 'bgBlue': ['\033[44m', '\033[49m'], + 'bgMagenta': ['\033[45m', '\033[49m'], + 'bgCyan': ['\033[46m', '\033[49m'], + 'bgWhite': ['\033[47m', '\033[49m'], + 'bgDefault': ['\033[49m', '\033[49m'] +} +Object.keys(styles).forEach(function(style) { + Object.defineProperty(String.prototype, style, { + get: function() { return styles[style][0] + this + styles[style][1]; }, + enumerable: false + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/package.json b/node_modules/dronestream/node_modules/ws/package.json new file mode 100644 index 0000000..f4d9fa4 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/package.json @@ -0,0 +1,44 @@ +{ + "author": { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com", + "url": "http://2x.io" + }, + "name": "ws", + "description": "simple to use, blazing fast and thoroughly tested websocket client, server and console for node.js, up-to-date against RFC-6455", + "version": "0.4.27", + "repository": { + "type": "git", + "url": "git://github.com/einaros/ws.git" + }, + "bin": { + "wscat": "./bin/wscat" + }, + "scripts": { + "test": "make test", + "install": "(node-gyp rebuild 2> builderror.log) || (exit 0)" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": { + "commander": "~0.6.1", + "tinycolor": "0.x", + "options": ">=0.0.5" + }, + "devDependencies": { + "mocha": "~1.2.1", + "should": "0.6.x", + "expect.js": "0.1.x", + "benchmark": "0.3.x", + "ansi": "latest" + }, + "browser": "./lib/browser.js", + "readme": "[![Build Status](https://secure.travis-ci.org/einaros/ws.png)](http://travis-ci.org/einaros/ws)\n\n# ws: a node.js websocket library #\n\n`ws` is a simple to use websocket implementation, up-to-date against RFC-6455, and [probably the fastest WebSocket library for node.js](http://hobbycoding.posterous.com/the-fastest-websocket-module-for-nodejs).\n\nPasses the quite extensive Autobahn test suite. See http://einaros.github.com/ws for the full reports.\n\nComes with a command line utility, `wscat`, which can either act as a server (--listen), or client (--connect); Use it to debug simple websocket services.\n\n## Protocol support ##\n\n* **Hixie draft 76** (Old and deprecated, but still in use by Safari and Opera. Added to ws version 0.4.2, but server only. Can be disabled by setting the `disableHixie` option to true.)\n* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`, or argument `-p 8` for wscat)\n* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`, or argument `-p 13` for wscat)\n\n_See the echo.websocket.org example below for how to use the `protocolVersion` option._\n\n## Usage ##\n\n### Installing ###\n\n`npm install ws`\n\n### Sending and receiving text data ###\n\n```js\nvar WebSocket = require('ws');\nvar ws = new WebSocket('ws://www.host.com/path');\nws.on('open', function() {\n ws.send('something');\n});\nws.on('message', function(data, flags) {\n // flags.binary will be set if a binary data is received\n // flags.masked will be set if the data was masked\n});\n```\n\n### Sending binary data ###\n\n```js\nvar WebSocket = require('ws');\nvar ws = new WebSocket('ws://www.host.com/path');\nws.on('open', function() {\n var array = new Float32Array(5);\n for (var i = 0; i < array.length; ++i) array[i] = i / 2;\n ws.send(array, {binary: true, mask: true});\n});\n```\n\nSetting `mask`, as done for the send options above, will cause the data to be masked according to the websocket protocol. The same option applies for text data.\n\n### Server example ###\n\n```js\nvar WebSocketServer = require('ws').Server\n , wss = new WebSocketServer({port: 8080});\nwss.on('connection', function(ws) {\n ws.on('message', function(message) {\n console.log('received: %s', message);\n });\n ws.send('something');\n});\n```\n\n### Error handling best practices ###\n\n```js\n// If the WebSocket is closed before the following send is attempted\nws.send('something');\n\n// Errors (both immediate and async write errors) can be detected in an optional callback.\n// The callback is also the only way of being notified that data has actually been sent.\nws.send('something', function(error) {\n // if error is null, the send has been completed,\n // otherwise the error object will indicate what failed.\n});\n\n// Immediate errors can also be handled with try/catch-blocks, but **note**\n// that since sends are inherently asynchronous, socket write failures will *not*\n// be captured when this technique is used.\ntry {\n ws.send('something');\n}\ncatch (e) {\n // handle error\n}\n```\n\n### echo.websocket.org demo ###\n\n```js\nvar WebSocket = require('ws');\nvar ws = new WebSocket('ws://echo.websocket.org/', {protocolVersion: 8, origin: 'http://websocket.org'});\nws.on('open', function() {\n console.log('connected');\n ws.send(Date.now().toString(), {mask: true});\n});\nws.on('close', function() {\n console.log('disconnected');\n});\nws.on('message', function(data, flags) {\n console.log('Roundtrip time: ' + (Date.now() - parseInt(data)) + 'ms', flags);\n setTimeout(function() {\n ws.send(Date.now().toString(), {mask: true});\n }, 500);\n});\n```\n\n### wscat against echo.websocket.org ###\n\n $ npm install -g ws\n $ wscat -c ws://echo.websocket.org -p 8\n connected (press CTRL+C to quit)\n > hi there\n < hi there\n > are you a happy parrot?\n < are you a happy parrot?\n\n### Other examples ###\n\nFor a full example with a browser client communicating with a ws server, see the examples folder.\n\nNote that the usage together with Express 3.0 is quite different from Express 2.x. The difference is expressed in the two different serverstats-examples.\n\nOtherwise, see the test cases.\n\n### Running the tests ###\n\n`make test`\n\n## API Docs ##\n\nSee the doc/ directory for Node.js-like docs for the ws classes.\n\n## License ##\n\n(The MIT License)\n\nCopyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/einaros/ws/issues" + }, + "_id": "ws@0.4.27", + "_from": "ws@~0.4.27" +} diff --git a/node_modules/dronestream/node_modules/ws/src/bufferutil.cc b/node_modules/dronestream/node_modules/ws/src/bufferutil.cc new file mode 100644 index 0000000..866c28b --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/src/bufferutil.cc @@ -0,0 +1,115 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace v8; +using namespace node; + +class BufferUtil : public ObjectWrap +{ +public: + + static void Initialize(v8::Handle target) + { + HandleScope scope; + Local t = FunctionTemplate::New(New); + t->InstanceTemplate()->SetInternalFieldCount(1); + NODE_SET_METHOD(t->GetFunction(), "unmask", BufferUtil::Unmask); + NODE_SET_METHOD(t->GetFunction(), "mask", BufferUtil::Mask); + NODE_SET_METHOD(t->GetFunction(), "merge", BufferUtil::Merge); + target->Set(String::NewSymbol("BufferUtil"), t->GetFunction()); + } + +protected: + + static Handle New(const Arguments& args) + { + HandleScope scope; + BufferUtil* bufferUtil = new BufferUtil(); + bufferUtil->Wrap(args.This()); + return args.This(); + } + + static Handle Merge(const Arguments& args) + { + HandleScope scope; + Local bufferObj = args[0]->ToObject(); + char* buffer = Buffer::Data(bufferObj); + Local array = Local::Cast(args[1]); + unsigned int arrayLength = array->Length(); + unsigned int offset = 0; + unsigned int i; + for (i = 0; i < arrayLength; ++i) { + Local src = array->Get(i)->ToObject(); + unsigned int length = Buffer::Length(src); + memcpy(buffer + offset, Buffer::Data(src), length); + offset += length; + } + return scope.Close(True()); + } + + static Handle Unmask(const Arguments& args) + { + HandleScope scope; + Local buffer_obj = args[0]->ToObject(); + unsigned int length = Buffer::Length(buffer_obj); + Local mask_obj = args[1]->ToObject(); + unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj); + unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj); + unsigned int len32 = length / 4; + unsigned int i; + for (i = 0; i < len32; ++i) *(from + i) ^= *mask; + from += i; + switch (length % 4) { + case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2]; + case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1]; + case 1: *((unsigned char*)from ) = *((unsigned char*)from ) ^ ((unsigned char*)mask)[0]; + case 0:; + } + return True(); + } + + static Handle Mask(const Arguments& args) + { + HandleScope scope; + Local buffer_obj = args[0]->ToObject(); + Local mask_obj = args[1]->ToObject(); + unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj); + Local output_obj = args[2]->ToObject(); + unsigned int dataOffset = args[3]->Int32Value(); + unsigned int length = args[4]->Int32Value(); + unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset); + unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj); + unsigned int len32 = length / 4; + unsigned int i; + for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask; + to += i; + from += i; + switch (length % 4) { + case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2); + case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1); + case 1: *((unsigned char*)to ) = *((unsigned char*)from ) ^ *((unsigned char*)mask); + case 0:; + } + return True(); + } +}; + +extern "C" void init (Handle target) +{ + HandleScope scope; + BufferUtil::Initialize(target); +} + +NODE_MODULE(bufferutil, init) diff --git a/node_modules/dronestream/node_modules/ws/src/validation.cc b/node_modules/dronestream/node_modules/ws/src/validation.cc new file mode 100644 index 0000000..b900164 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/src/validation.cc @@ -0,0 +1,143 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace v8; +using namespace node; + +#define UNI_SUR_HIGH_START (uint32_t) 0xD800 +#define UNI_SUR_LOW_END (uint32_t) 0xDFFF +#define UNI_REPLACEMENT_CHAR (uint32_t) 0x0000FFFD +#define UNI_MAX_LEGAL_UTF32 (uint32_t) 0x0010FFFF + +static const uint8_t trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +static const uint32_t offsetsFromUTF8[6] = { + 0x00000000, 0x00003080, 0x000E2080, + 0x03C82080, 0xFA082080, 0x82082080 +}; + +static int isLegalUTF8(const uint8_t *source, const int length) +{ + uint8_t a; + const uint8_t *srcptr = source+length; + switch (length) { + default: return 0; + /* Everything else falls through when "true"... */ + /* RFC3629 makes 5 & 6 bytes UTF-8 illegal + case 6: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 5: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 2: if ((a = (*--srcptr)) > 0xBF) return 0; + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return 0; break; + case 0xED: if (a > 0x9F) return 0; break; + case 0xF0: if (a < 0x90) return 0; break; + case 0xF4: if (a > 0x8F) return 0; break; + default: if (a < 0x80) return 0; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return 0; + } + if (*source > 0xF4) return 0; + return 1; +} + +int is_valid_utf8 (size_t len, char *value) +{ + /* is the string valid UTF-8? */ + for (unsigned int i = 0; i < len; i++) { + uint32_t ch = 0; + uint8_t extrabytes = trailingBytesForUTF8[(uint8_t) value[i]]; + + if (extrabytes + i >= len) + return 0; + + if (isLegalUTF8 ((uint8_t *) (value + i), extrabytes + 1) == 0) return 0; + + switch (extrabytes) { + case 5 : ch += (uint8_t) value[i++]; ch <<= 6; + case 4 : ch += (uint8_t) value[i++]; ch <<= 6; + case 3 : ch += (uint8_t) value[i++]; ch <<= 6; + case 2 : ch += (uint8_t) value[i++]; ch <<= 6; + case 1 : ch += (uint8_t) value[i++]; ch <<= 6; + case 0 : ch += (uint8_t) value[i]; + } + + ch -= offsetsFromUTF8[extrabytes]; + + if (ch <= UNI_MAX_LEGAL_UTF32) { + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) + return 0; + } else { + return 0; + } + } + + return 1; +} + +class Validation : public ObjectWrap +{ +public: + + static void Initialize(v8::Handle target) + { + HandleScope scope; + Local t = FunctionTemplate::New(New); + t->InstanceTemplate()->SetInternalFieldCount(1); + NODE_SET_METHOD(t->GetFunction(), "isValidUTF8", Validation::IsValidUTF8); + target->Set(String::NewSymbol("Validation"), t->GetFunction()); + } + +protected: + + static Handle New(const Arguments& args) + { + HandleScope scope; + Validation* validation = new Validation(); + validation->Wrap(args.This()); + return args.This(); + } + + static Handle IsValidUTF8(const Arguments& args) + { + HandleScope scope; + if (!Buffer::HasInstance(args[0])) { + return ThrowException(Exception::Error(String::New("First argument needs to be a buffer"))); + } + Local buffer_obj = args[0]->ToObject(); + char *buffer_data = Buffer::Data(buffer_obj); + size_t buffer_length = Buffer::Length(buffer_obj); + return is_valid_utf8(buffer_length, buffer_data) == 1 ? scope.Close(True()) : scope.Close(False()); + } +}; + +extern "C" void init (Handle target) +{ + HandleScope scope; + Validation::Initialize(target); +} + +NODE_MODULE(validation, init) diff --git a/node_modules/dronestream/node_modules/ws/test/BufferPool.test.js b/node_modules/dronestream/node_modules/ws/test/BufferPool.test.js new file mode 100644 index 0000000..1ee7ff0 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/BufferPool.test.js @@ -0,0 +1,63 @@ +var BufferPool = require('../lib/BufferPool'); +require('should'); + +describe('BufferPool', function() { + describe('#ctor', function() { + it('allocates pool', function() { + var db = new BufferPool(1000); + db.size.should.eql(1000); + }); + }); + describe('#get', function() { + it('grows the pool if necessary', function() { + var db = new BufferPool(1000); + var buf = db.get(2000); + db.size.should.be.above(1000); + db.used.should.eql(2000); + buf.length.should.eql(2000); + }); + it('grows the pool after the first call, if necessary', function() { + var db = new BufferPool(1000); + var buf = db.get(1000); + db.used.should.eql(1000); + db.size.should.eql(1000); + buf.length.should.eql(1000); + var buf2 = db.get(1000); + db.used.should.eql(2000); + db.size.should.be.above(1000); + buf2.length.should.eql(1000); + }); + it('grows the pool according to the growStrategy if necessary', function() { + var db = new BufferPool(1000, function(db, length) { + return db.size + 2345; + }); + var buf = db.get(2000); + db.size.should.eql(3345); + buf.length.should.eql(2000); + }); + it('doesnt grow the pool if theres enough room available', function() { + var db = new BufferPool(1000); + var buf = db.get(1000); + db.size.should.eql(1000); + buf.length.should.eql(1000); + }); + }); + describe('#reset', function() { + it('shinks the pool', function() { + var db = new BufferPool(1000); + var buf = db.get(2000); + db.reset(true); + db.size.should.eql(1000); + }); + it('shrinks the pool according to the shrinkStrategy', function() { + var db = new BufferPool(1000, function(db, length) { + return db.used + length; + }, function(db) { + return 0; + }); + var buf = db.get(2000); + db.reset(true); + db.size.should.eql(0); + }); + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/test/Receiver.hixie.test.js b/node_modules/dronestream/node_modules/ws/test/Receiver.hixie.test.js new file mode 100644 index 0000000..043d3bc --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/Receiver.hixie.test.js @@ -0,0 +1,158 @@ +var assert = require('assert') + , expect = require('expect.js') + , Receiver = require('../lib/Receiver.hixie'); +require('./hybi-common'); + +describe('Receiver', function() { + it('can parse text message', function() { + var p = new Receiver(); + var packet = '00 48 65 6c 6c 6f ff'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('Hello', data); + }; + + p.add(getBufferFromHexString(packet)); + expect(gotData).to.equal(true); + }); + + it('can parse multiple text messages', function() { + var p = new Receiver(); + var packet = '00 48 65 6c 6c 6f ff 00 48 65 6c 6c 6f ff'; + + var gotData = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + + p.add(getBufferFromHexString(packet)); + expect(gotData).to.equal(true); + for (var i = 0; i < 2; ++i) { + expect(messages[i]).to.equal('Hello'); + } + }); + + it('can parse empty message', function() { + var p = new Receiver(); + var packet = '00 ff'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('', data); + }; + + p.add(getBufferFromHexString(packet)); + expect(gotData).to.equal(true); + }); + + it('can parse text messages delivered over multiple frames', function() { + var p = new Receiver(); + var packets = [ + '00 48', + '65 6c 6c', + '6f ff 00 48', + '65', + '6c 6c 6f', + 'ff' + ]; + + var gotData = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + + for (var i = 0; i < packets.length; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotData).to.equal(true); + for (var i = 0; i < 2; ++i) { + expect(messages[i]).to.equal('Hello'); + } + }); + + it('emits an error if a payload doesnt start with 0x00', function() { + var p = new Receiver(); + var packets = [ + '00 6c ff', + '00 6c ff ff', + 'ff 00 6c ff 00 6c ff', + '00', + '6c 6c 6f', + 'ff' + ]; + + var gotData = false; + var gotError = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + p.onerror = function(reason, code) { + gotError = code == true; + }; + + for (var i = 0; i < packets.length && !gotError; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotError).to.equal(true); + expect(messages[0]).to.equal('l'); + expect(messages[1]).to.equal('l'); + expect(messages.length).to.equal(2); + }); + + it('can parse close messages', function() { + var p = new Receiver(); + var packets = [ + 'ff 00' + ]; + + var gotClose = false; + var gotError = false; + p.onclose = function() { + gotClose = true; + }; + p.onerror = function(reason, code) { + gotError = code == true; + }; + + for (var i = 0; i < packets.length && !gotError; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotClose).to.equal(true); + expect(gotError).to.equal(false); + }); + + it('can parse binary messages delivered over multiple frames', function() { + var p = new Receiver(); + var packets = [ + '80 05 48', + '65 6c 6c', + '6f 80 80 05 48', + '65', + '6c 6c 6f' + ]; + + var gotData = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + + for (var i = 0; i < packets.length; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotData).to.equal(true); + for (var i = 0; i < 2; ++i) { + expect(messages[i]).to.equal('Hello'); + } + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/test/Receiver.test.js b/node_modules/dronestream/node_modules/ws/test/Receiver.test.js new file mode 100644 index 0000000..b0b5c0a --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/Receiver.test.js @@ -0,0 +1,255 @@ +var assert = require('assert') + , Receiver = require('../lib/Receiver'); +require('should'); +require('./hybi-common'); + +describe('Receiver', function() { + it('can parse unmasked text message', function() { + var p = new Receiver(); + var packet = '81 05 48 65 6c 6c 6f'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('Hello', data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse close message', function() { + var p = new Receiver(); + var packet = '88 00'; + + var gotClose = false; + p.onclose = function(data) { + gotClose = true; + }; + + p.add(getBufferFromHexString(packet)); + gotClose.should.be.ok; + }); + it('can parse masked text message', function() { + var p = new Receiver(); + var packet = '81 93 34 83 a8 68 01 b9 92 52 4f a1 c6 09 59 e6 8a 52 16 e6 cb 00 5b a1 d5'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('5:::{"name":"echo"}', data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a masked text message longer than 125 bytes', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + var packet = '81 FE ' + pack(4, message.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a really long masked text message', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 64*1024; ++i) message += (i % 5).toString(); + var packet = '81 FF ' + pack(16, message.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a fragmented masked text message of 300 bytes', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + var msgpiece1 = message.substr(0, 150); + var msgpiece2 = message.substr(150); + var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece1, '34 83 a8 68')); + var packet2 = '80 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece2, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet1)); + p.add(getBufferFromHexString(packet2)); + gotData.should.be.ok; + }); + it('can parse a ping message', function() { + var p = new Receiver(); + var message = 'Hello'; + var packet = '89 ' + getHybiLengthAsHexString(message.length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotPing = false; + p.onping = function(data) { + gotPing = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet)); + gotPing.should.be.ok; + }); + it('can parse a ping with no data', function() { + var p = new Receiver(); + var packet = '89 00'; + + var gotPing = false; + p.onping = function(data) { + gotPing = true; + }; + + p.add(getBufferFromHexString(packet)); + gotPing.should.be.ok; + }); + it('can parse a fragmented masked text message of 300 bytes with a ping in the middle', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + + var msgpiece1 = message.substr(0, 150); + var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece1, '34 83 a8 68')); + + var pingMessage = 'Hello'; + var pingPacket = '89 ' + getHybiLengthAsHexString(pingMessage.length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(pingMessage, '34 83 a8 68')); + + var msgpiece2 = message.substr(150); + var packet2 = '80 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece2, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + var gotPing = false; + p.onping = function(data) { + gotPing = true; + assert.equal(pingMessage, data); + }; + + p.add(getBufferFromHexString(packet1)); + p.add(getBufferFromHexString(pingPacket)); + p.add(getBufferFromHexString(packet2)); + gotData.should.be.ok; + gotPing.should.be.ok; + }); + it('can parse a fragmented masked text message of 300 bytes with a ping in the middle, which is delievered over sevaral tcp packets', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + + var msgpiece1 = message.substr(0, 150); + var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece1, '34 83 a8 68')); + + var pingMessage = 'Hello'; + var pingPacket = '89 ' + getHybiLengthAsHexString(pingMessage.length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(pingMessage, '34 83 a8 68')); + + var msgpiece2 = message.substr(150); + var packet2 = '80 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece2, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + var gotPing = false; + p.onping = function(data) { + gotPing = true; + assert.equal(pingMessage, data); + }; + + var buffers = []; + buffers = buffers.concat(splitBuffer(getBufferFromHexString(packet1))); + buffers = buffers.concat(splitBuffer(getBufferFromHexString(pingPacket))); + buffers = buffers.concat(splitBuffer(getBufferFromHexString(packet2))); + for (var i = 0; i < buffers.length; ++i) { + p.add(buffers[i]); + } + gotData.should.be.ok; + gotPing.should.be.ok; + }); + it('can parse a 100 byte long masked binary message', function() { + var p = new Receiver(); + var length = 100; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a 256 byte long masked binary message', function() { + var p = new Receiver(); + var length = 256; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a 200kb long masked binary message', function() { + var p = new Receiver(); + var length = 200 * 1024; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a 200kb long unmasked binary message', function() { + var p = new Receiver(); + var length = 200 * 1024; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, false) + ' ' + getHexStringFromBuffer(message); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); +}); + diff --git a/node_modules/dronestream/node_modules/ws/test/Sender.hixie.test.js b/node_modules/dronestream/node_modules/ws/test/Sender.hixie.test.js new file mode 100644 index 0000000..783f892 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/Sender.hixie.test.js @@ -0,0 +1,134 @@ +var assert = require('assert') + , Sender = require('../lib/Sender.hixie'); +require('should'); +require('./hybi-common'); + +describe('Sender', function() { + describe('#send', function() { + it('frames and sends a text message', function(done) { + var message = 'Hello world'; + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(message, {}, function() { + received.toString('utf8').should.eql('\u0000' + message + '\ufffd'); + done(); + }); + }); + + it('frames and sends an empty message', function(done) { + var socket = { + write: function(data, encoding, cb) { + done(); + } + }; + var sender = new Sender(socket, {}); + sender.send('', {}, function() {}); + }); + + it('frames and sends a buffer', function(done) { + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(new Buffer('foobar'), {}, function() { + received.toString('utf8').should.eql('\u0000foobar\ufffd'); + done(); + }); + }); + + it('frames and sends a binary message', function(done) { + var message = 'Hello world'; + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(message, {binary: true}, function() { + received.toString('hex').should.eql( + // 0x80 0x0b H e l l o w o r l d + '800b48656c6c6f20776f726c64'); + done(); + }); + }); +/* + it('throws an exception for binary data', function(done) { + var socket = { + write: function(data, encoding, cb) { + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.on('error', function() { + done(); + }); + sender.send(new Buffer(100), {binary: true}, function() {}); + }); +*/ + it('can fauxe stream data', function(done) { + var received = []; + var socket = { + write: function(data, encoding, cb) { + received.push(data); + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(new Buffer('foobar'), { fin: false }, function() {}); + sender.send('bazbar', { fin: false }, function() {}); + sender.send(new Buffer('end'), { fin: true }, function() { + received[0].toString('utf8').should.eql('\u0000foobar'); + received[1].toString('utf8').should.eql('bazbar'); + received[2].toString('utf8').should.eql('end\ufffd'); + done(); + }); + }); + }); + + describe('#close', function() { + it('sends a hixie close frame', function(done) { + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.close(null, null, null, function() { + received.toString('utf8').should.eql('\ufffd\u0000'); + done(); + }); + }); + + it('sends a message end marker if fauxe streaming has started, before hixie close frame', function(done) { + var received = []; + var socket = { + write: function(data, encoding, cb) { + received.push(data); + if (cb) process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(new Buffer('foobar'), { fin: false }, function() {}); + sender.close(null, null, null, function() { + received[0].toString('utf8').should.eql('\u0000foobar'); + received[1].toString('utf8').should.eql('\ufffd'); + received[2].toString('utf8').should.eql('\ufffd\u0000'); + done(); + }); + }); + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/test/Sender.test.js b/node_modules/dronestream/node_modules/ws/test/Sender.test.js new file mode 100644 index 0000000..43b4864 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/Sender.test.js @@ -0,0 +1,24 @@ +var Sender = require('../lib/Sender'); +require('should'); + +describe('Sender', function() { + describe('#frameAndSend', function() { + it('does not modify a masked binary buffer', function() { + var sender = new Sender({ write: function() {} }); + var buf = new Buffer([1, 2, 3, 4, 5]); + sender.frameAndSend(2, buf, true, true); + buf[0].should.eql(1); + buf[1].should.eql(2); + buf[2].should.eql(3); + buf[3].should.eql(4); + buf[4].should.eql(5); + }); + + it('does not modify a masked text buffer', function() { + var sender = new Sender({ write: function() {} }); + var text = 'hi there'; + sender.frameAndSend(1, text, true, true); + text.should.eql('hi there'); + }); + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/test/Validation.test.js b/node_modules/dronestream/node_modules/ws/test/Validation.test.js new file mode 100644 index 0000000..37c3399 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/Validation.test.js @@ -0,0 +1,23 @@ +var Validation = require('../lib/Validation').Validation; +require('should'); + +describe('Validation', function() { + describe('isValidUTF8', function() { + it('should return true for a valid utf8 string', function() { + var validBuffer = new Buffer('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque gravida mattis rhoncus. Donec iaculis, metus quis varius accumsan, erat mauris condimentum diam, et egestas erat enim ut ligula. Praesent sollicitudin tellus eget dolor euismod euismod. Nullam ac augue nec neque varius luctus. Curabitur elit mi, consequat ultricies adipiscing mollis, scelerisque in erat. Phasellus facilisis fermentum ullamcorper. Nulla et sem eu arcu pharetra pellentesque. Praesent consectetur tempor justo, vel iaculis dui ullamcorper sit amet. Integer tristique viverra ullamcorper. Vivamus laoreet, nulla eget suscipit eleifend, lacus lectus feugiat libero, non fermentum erat nisi at risus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut pulvinar dignissim tellus, eu dignissim lorem vulputate quis. Morbi ut pulvinar augue.'); + Validation.isValidUTF8(validBuffer).should.be.ok; + }); + it('should return false for an erroneous string', function() { + var invalidBuffer = new Buffer([0xce, 0xba, 0xe1, 0xbd, 0xb9, 0xcf, 0x83, 0xce, 0xbc, 0xce, 0xb5, 0xed, 0xa0, 0x80, 0x65, 0x64, 0x69, 0x74, 0x65, 0x64]); + Validation.isValidUTF8(invalidBuffer).should.not.be.ok; + }); + it('should return true for valid cases from the autobahn test suite', function() { + Validation.isValidUTF8(new Buffer('\xf0\x90\x80\x80')).should.be.ok; + Validation.isValidUTF8(new Buffer([0xf0, 0x90, 0x80, 0x80])).should.be.ok; + }); + it('should return false for erroneous autobahn strings', function() { + Validation.isValidUTF8(new Buffer([0xce, 0xba, 0xe1, 0xbd])).should.not.be.ok; + }); + }); +}); + diff --git a/node_modules/dronestream/node_modules/ws/test/WebSocket.integration.js b/node_modules/dronestream/node_modules/ws/test/WebSocket.integration.js new file mode 100644 index 0000000..51a7e3a --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/WebSocket.integration.js @@ -0,0 +1,42 @@ +var assert = require('assert') + , WebSocket = require('../') + , server = require('./testserver'); + +var port = 20000; + +function getArrayBuffer(buf) { + var l = buf.length; + var arrayBuf = new ArrayBuffer(l); + for (var i = 0; i < l; ++i) { + arrayBuf[i] = buf[i]; + } + return arrayBuf; +} + +function areArraysEqual(x, y) { + if (x.length != y.length) return false; + for (var i = 0, l = x.length; i < l; ++i) { + if (x[i] !== y[i]) return false; + } + return true; +} + +describe('WebSocket', function() { + it('communicates successfully with echo service', function(done) { + var ws = new WebSocket('ws://echo.websocket.org', {protocolVersion: 8, origin: 'http://websocket.org'}); + var str = Date.now().toString(); + var dataReceived = false; + ws.on('open', function() { + ws.send(str, {mask: true}); + }); + ws.on('close', function() { + assert.equal(true, dataReceived); + done(); + }); + ws.on('message', function(data, flags) { + assert.equal(str, data); + ws.terminate(); + dataReceived = true; + }); + }); +}); \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/test/WebSocket.test.js b/node_modules/dronestream/node_modules/ws/test/WebSocket.test.js new file mode 100644 index 0000000..93e95da --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/WebSocket.test.js @@ -0,0 +1,1609 @@ +var assert = require('assert') + , https = require('https') + , http = require('http') + , should = require('should') + , WebSocket = require('../') + , WebSocketServer = require('../').Server + , fs = require('fs') + , server = require('./testserver') + , crypto = require('crypto'); + +var port = 20000; + +function getArrayBuffer(buf) { + var l = buf.length; + var arrayBuf = new ArrayBuffer(l); + for (var i = 0; i < l; ++i) { + arrayBuf[i] = buf[i]; + } + return arrayBuf; +} + +function areArraysEqual(x, y) { + if (x.length != y.length) return false; + for (var i = 0, l = x.length; i < l; ++i) { + if (x[i] !== y[i]) return false; + } + return true; +} + +describe('WebSocket', function() { + describe('#ctor', function() { + it('throws exception for invalid url', function(done) { + try { + var ws = new WebSocket('echo.websocket.org'); + } + catch (e) { + done(); + } + }); + }); + + describe('properties', function() { + it('#bytesReceived exposes number of bytes received', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('message', function() { + ws.bytesReceived.should.eql(8); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + ws.send('foobar'); + }); + }); + + it('#url exposes the server url', function(done) { + server.createServer(++port, function(srv) { + var url = 'ws://localhost:' + port; + var ws = new WebSocket(url); + assert.equal(url, ws.url); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('#protocolVersion exposes the protocol version', function(done) { + server.createServer(++port, function(srv) { + var url = 'ws://localhost:' + port; + var ws = new WebSocket(url); + assert.equal(13, ws.protocolVersion); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + describe('#bufferedAmount', function() { + it('defaults to zero', function(done) { + server.createServer(++port, function(srv) { + var url = 'ws://localhost:' + port; + var ws = new WebSocket(url); + assert.equal(0, ws.bufferedAmount); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('stress kernel write buffer', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(ws) { + while (true) { + if (ws.bufferedAmount > 0) break; + ws.send((new Array(10000)).join('hello')); + } + ws.terminate(); + ws.on('close', function() { + wss.close(); + done(); + }); + }); + }); + }); + + describe('#readyState', function() { + it('defaults to connecting', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + assert.equal(WebSocket.CONNECTING, ws.readyState); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('set to open once connection is established', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + assert.equal(WebSocket.OPEN, ws.readyState); + srv.close(); + done(); + }); + }); + }); + + it('set to closed once connection is closed', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.close(1001); + ws.on('close', function() { + assert.equal(WebSocket.CLOSED, ws.readyState); + srv.close(); + done(); + }); + }); + }); + + it('set to closed once connection is terminated', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.terminate(); + ws.on('close', function() { + assert.equal(WebSocket.CLOSED, ws.readyState); + srv.close(); + done(); + }); + }); + }); + }); + + /* + * Ready state constants + */ + + var readyStates = { + CONNECTING: 0, + OPEN: 1, + CLOSING: 2, + CLOSED: 3 + }; + + /* + * Ready state constant tests + */ + + Object.keys(readyStates).forEach(function(state) { + describe('.' + state, function() { + it('is enumerable property of class', function() { + var propertyDescripter = Object.getOwnPropertyDescriptor(WebSocket, state) + assert.equal(readyStates[state], propertyDescripter.value); + assert.equal(true, propertyDescripter.enumerable); + }); + }); + }); + + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + Object.keys(readyStates).forEach(function(state) { + describe('.' + state, function() { + it('is property of instance', function() { + assert.equal(readyStates[state], ws[state]); + }); + }); + }); + }); + }); + + describe('events', function() { + it('emits a ping event', function(done) { + var wss = new WebSocketServer({port: ++port}); + wss.on('connection', function(client) { + client.ping(); + }); + var ws = new WebSocket('ws://localhost:' + port); + ws.on('ping', function() { + ws.terminate(); + wss.close(); + done(); + }); + }); + + it('emits a pong event', function(done) { + var wss = new WebSocketServer({port: ++port}); + wss.on('connection', function(client) { + client.pong(); + }); + var ws = new WebSocket('ws://localhost:' + port); + ws.on('pong', function() { + ws.terminate(); + wss.close(); + done(); + }); + }); + }); + + describe('connection establishing', function() { + it('can disconnect before connection is established', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.terminate(); + ws.on('open', function() { + assert.fail('connect shouldnt be raised here'); + }); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('can close before connection is established', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.close(1001); + ws.on('open', function() { + assert.fail('connect shouldnt be raised here'); + }); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('invalid server key is denied', function(done) { + server.createServer(++port, server.handlers.invalidKey, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() { + srv.close(); + done(); + }); + }); + }); + + it('close event is raised when server closes connection', function(done) { + server.createServer(++port, server.handlers.closeAfterConnect, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('error is emitted if server aborts connection', function(done) { + server.createServer(++port, server.handlers.return401, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + assert.fail('connect shouldnt be raised here'); + }); + ws.on('error', function() { + srv.close(); + done(); + }); + }); + }); + }); + + describe('#pause and #resume', function() { + it('pauses the underlying stream', function(done) { + // this test is sort-of racecondition'y, since an unlikely slow connection + // to localhost can cause the test to succeed even when the stream pausing + // isn't working as intended. that is an extremely unlikely scenario, though + // and an acceptable risk for the test. + var client; + var serverClient; + var openCount = 0; + function onOpen() { + if (++openCount == 2) { + var paused = true; + serverClient.on('message', function() { + paused.should.not.be.ok; + wss.close(); + done(); + }); + serverClient.pause(); + setTimeout(function() { + paused = false; + serverClient.resume(); + }, 200); + client.send('foo'); + } + } + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + serverClient = ws; + serverClient.on('open', onOpen); + }); + wss.on('connection', function(ws) { + client = ws; + onOpen(); + }); + }); + }); + + describe('#ping', function() { + it('before connect should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + try { + ws.ping(); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + + it('before connect can silently fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.ping('', {}, true); + srv.close(); + ws.terminate(); + done(); + }); + }); + + it('without message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.ping(); + }); + srv.on('ping', function(message) { + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.ping('hi'); + }); + srv.on('ping', function(message) { + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.ping('hi', {mask: true}); + }); + srv.on('ping', function(message, flags) { + assert.ok(flags.masked); + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + describe('#pong', function() { + it('before connect should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + try { + ws.pong(); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + + it('before connect can silently fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.pong('', {}, true); + srv.close(); + ws.terminate(); + done(); + }); + }); + + it('without message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.pong(); + }); + srv.on('pong', function(message) { + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.pong('hi'); + }); + srv.on('pong', function(message) { + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.pong('hi', {mask: true}); + }); + srv.on('pong', function(message, flags) { + assert.ok(flags.masked); + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + describe('#send', function() { + it('very long binary data can be sent and received (with echoing server)', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5 * 1024 * 1024); + for (var i = 0; i < array.length; ++i) array[i] = i / 5; + ws.on('open', function() { + ws.send(array, {binary: true}); + }); + ws.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('can send and receive text data', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi'); + }); + ws.on('message', function(message, flags) { + assert.equal('hi', message); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('send and receive binary data as an array', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.on('open', function() { + ws.send(array, {binary: true}); + }); + ws.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('binary data can be sent and received as buffer', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var buf = new Buffer('foobar'); + ws.on('open', function() { + ws.send(buf, {binary: true}); + }); + ws.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(buf, message)); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('ArrayBuffer is auto-detected without binary flag', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.on('open', function() { + ws.send(array.buffer); + }); + ws.onmessage = function (event) { + assert.ok(event.type = 'Binary'); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(event.data)))); + ws.terminate(); + srv.close(); + done(); + }; + }); + }); + + it('Buffer is auto-detected without binary flag', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var buf = new Buffer('foobar'); + ws.on('open', function() { + ws.send(buf); + }); + ws.onmessage = function (event) { + assert.ok(event.type = 'Binary'); + assert.ok(areArraysEqual(event.data, buf)); + ws.terminate(); + srv.close(); + done(); + }; + }); + }); + + it('before connect should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + try { + ws.send('hi'); + } + catch (e) { + ws.terminate(); + srv.close(); + done(); + } + }); + }); + + it('before connect should pass error through callback, if present', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.send('hi', function(error) { + assert.ok(error instanceof Error); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('without data should be successful', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send(); + }); + srv.on('message', function(message, flags) { + assert.equal('', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('calls optional callback when flushed', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi', function() { + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + it('with unencoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi'); + }); + srv.on('message', function(message, flags) { + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi', {mask: true}); + }); + srv.on('message', function(message, flags) { + assert.ok(flags.masked); + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with unencoded binary message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.on('open', function() { + ws.send(array, {binary: true}); + }); + srv.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded binary message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.on('open', function() { + ws.send(array, {mask: true, binary: true}); + }); + srv.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(flags.masked); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with binary stream will send fragmented data', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var callbackFired = false; + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.bufferSize = 100; + ws.send(fileStream, {binary: true}, function(error) { + assert.equal(null, error); + callbackFired = true; + }); + }); + srv.on('message', function(data, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile'), data)); + ws.terminate(); + }); + ws.on('close', function() { + assert.ok(callbackFired); + srv.close(); + done(); + }); + }); + }); + + it('with text stream will send fragmented data', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var callbackFired = false; + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream, {binary: false}, function(error) { + assert.equal(null, error); + callbackFired = true; + }); + }); + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + ws.terminate(); + }); + ws.on('close', function() { + assert.ok(callbackFired); + srv.close(); + done(); + }); + }); + }); + + it('will cause intermittent send to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.send('foobar'); + ws.send('baz'); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + } + else { + assert.ok(!flags.binary); + assert.equal('baz', data); + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent stream to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) send('foo'); + else send('bar', true); + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent ping to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.ping('foobar'); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('ping', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent pong to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.pong('foobar'); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('pong', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent close to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.close(1000, 'foobar'); + }); + ws.on('close', function() { + srv.close(); + ws.terminate(); + done(); + }); + ws.on('error', function() { /* That's quite alright -- a send was attempted after close */ }); + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + }); + srv.on('close', function(code, data) { + assert.equal(1000, code); + assert.equal('foobar', data); + }); + }); + }); + }); + + describe('#stream', function() { + it('very long binary data can be streamed', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var buffer = new Buffer(10 * 1024); + for (var i = 0; i < buffer.length; ++i) buffer[i] = i % 0xff; + ws.on('open', function() { + var i = 0; + var blockSize = 800; + var bufLen = buffer.length; + ws.stream({binary: true}, function(error, send) { + assert.ok(!error); + var start = i * blockSize; + var toSend = Math.min(blockSize, bufLen - (i * blockSize)); + var end = start + toSend; + var isFinal = toSend < blockSize; + send(buffer.slice(start, end), isFinal); + i += 1; + }); + }); + srv.on('message', function(data, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(buffer, data)); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('before connect should pass error through callback', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.stream(function(error) { + assert.ok(error instanceof Error); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('without callback should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + try { + ws.stream(); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent send to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + ws.send('foobar'); + ws.send('baz'); + } + else { + send(payload.substr(5, 5), true); + } + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.equal(payload, data); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + } + else { + assert.ok(!flags.binary); + assert.equal('baz', data); + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent stream to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + var i2 = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i2 == 1) send('foo'); + else send('bar', true); + }); + ws.send('baz'); + } + else send(payload.substr(5, 5), true); + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.equal(payload, data); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + } + else if (receivedIndex == 3){ + assert.ok(!flags.binary); + assert.equal('baz', data); + setTimeout(function() { + srv.close(); + ws.terminate(); + done(); + }, 1000); + } + else throw new Error('more messages than we actually sent just arrived'); + }); + }); + }); + + it('will cause intermittent ping to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + ws.ping('foobar'); + } + else { + send(payload.substr(5, 5), true); + } + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.equal(payload, data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('ping', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent pong to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + ws.pong('foobar'); + } + else { + send(payload.substr(5, 5), true); + } + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.equal(payload, data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('pong', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent close to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + var errorGiven = false; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + if (++i == 1) { + send(payload.substr(0, 5)); + ws.close(1000, 'foobar'); + } + else if(i == 2) { + send(payload.substr(5, 5), true); + } + else if (i == 3) { + assert.ok(error); + errorGiven = true; + } + }); + }); + ws.on('close', function() { + assert.ok(errorGiven); + srv.close(); + ws.terminate(); + done(); + }); + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.equal(payload, data); + }); + srv.on('close', function(code, data) { + assert.equal(1000, code); + assert.equal('foobar', data); + }); + }); + }); + }); + + describe('#close', function() { + it('will raise error callback, if any, if called during send stream', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var errorGiven = false; + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream, function(error) { + errorGiven = error != null; + }); + ws.close(1000, 'foobar'); + }); + ws.on('close', function() { + setTimeout(function() { + assert.ok(errorGiven); + srv.close(); + ws.terminate(); + done(); + }, 1000); + }); + }); + }); + + it('without invalid first argument throws exception', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + try { + ws.close('error'); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('without reserved error code 1004 throws exception', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + try { + ws.close(1004); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('without message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.close(1000); + }); + srv.on('close', function(code, message, flags) { + assert.equal('', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.close(1000, 'some reason'); + }); + srv.on('close', function(code, message, flags) { + assert.ok(flags.masked); + assert.equal('some reason', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.close(1000, 'some reason', {mask: true}); + }); + srv.on('close', function(code, message, flags) { + assert.ok(flags.masked); + assert.equal('some reason', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('ends connection to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var connectedOnce = false; + ws.on('open', function() { + connectedOnce = true; + ws.close(1000, 'some reason', {mask: true}); + }); + ws.on('close', function() { + assert.ok(connectedOnce); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + describe('W3C API emulation', function() { + it('should not throw errors when getting and setting', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var listener = function () {}; + + ws.onmessage = listener; + ws.onerror = listener; + ws.onclose = listener; + ws.onopen = listener; + + assert.ok(ws.onopen === listener); + assert.ok(ws.onmessage === listener); + assert.ok(ws.onclose === listener); + assert.ok(ws.onerror === listener); + + srv.close(); + ws.terminate(); + done(); + }); + }); + + it('should work the same as the EventEmitter api', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var listener = function() {}; + var message = 0; + var close = 0; + var open = 0; + + ws.onmessage = function(messageEvent) { + assert.ok(!!messageEvent.data); + ++message; + ws.close(); + }; + + ws.onopen = function() { + ++open; + } + + ws.onclose = function() { + ++close; + } + + ws.on('open', function() { + ws.send('foo'); + }); + + ws.on('close', function() { + process.nextTick(function() { + assert.ok(message === 1); + assert.ok(open === 1); + assert.ok(close === 1); + + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + it('should receive text data wrapped in a MessageEvent when using addEventListener', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('open', function() { + ws.send('hi'); + }); + ws.addEventListener('message', function(messageEvent) { + assert.equal('hi', messageEvent.data); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('should receive valid CloseEvent when server closes with code 1000', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('close', function(closeEvent) { + assert.equal(true, closeEvent.wasClean); + assert.equal(1000, closeEvent.code); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('connection', function(client) { + client.close(1000); + }); + }); + + it('should receive valid CloseEvent when server closes with code 1001', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('close', function(closeEvent) { + assert.equal(false, closeEvent.wasClean); + assert.equal(1001, closeEvent.code); + assert.equal('some daft reason', closeEvent.reason); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('connection', function(client) { + client.close(1001, 'some daft reason'); + }); + }); + + it('should have target set on Events', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('open', function(openEvent) { + assert.equal(ws, openEvent.target); + }); + ws.addEventListener('message', function(messageEvent) { + assert.equal(ws, messageEvent.target); + wss.close(); + }); + ws.addEventListener('close', function(closeEvent) { + assert.equal(ws, closeEvent.target); + ws.emit('error', new Error('forced')); + }); + ws.addEventListener('error', function(errorEvent) { + assert.equal(errorEvent.message, 'forced'); + assert.equal(ws, errorEvent.target); + ws.terminate(); + done(); + }); + }); + wss.on('connection', function(client) { + client.send('hi') + }); + }); + }); + + describe('ssl', function() { + it('can connect to secure websocket server', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + + it('can connect to secure websocket server with client side certificate', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem'), + ca: [fs.readFileSync('test/fixtures/ca1-cert.pem')], + requestCert: true + }; + var clientOptions = { + key: fs.readFileSync('test/fixtures/agent1-key.pem'), + cert: fs.readFileSync('test/fixtures/agent1-cert.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var success = false; + var wss = new WebSocketServer({ + server: app, + verifyClient: function(info) { + success = !!info.req.client.authorized; + return true; + } + }); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port, clientOptions); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + success.should.be.ok; + done(); + }); + }); + + it('cannot connect to secure websocket server via ws://', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() { + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + }); + + it('can send and receive text data', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + ws.on('open', function() { + ws.send('foobar'); + }); + }); + wss.on('connection', function(ws) { + ws.on('message', function(message, flags) { + message.should.eql('foobar'); + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + }); + + it('can send and receive very long binary data', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + } + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + crypto.randomBytes(5 * 1024 * 1024, function(ex, buf) { + if (ex) throw ex; + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + ws.on('open', function() { + ws.send(buf, {binary: true}); + }); + ws.on('message', function(message, flags) { + flags.binary.should.be.ok; + areArraysEqual(buf, message).should.be.ok; + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + ws.on('message', function(message, flags) { + ws.send(message, {binary: true}); + }); + }); + }); + }); + }); + + describe('protocol support discovery', function() { + describe('#supports', function() { + describe('#binary', function() { + it('returns true for hybi transport', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + assert.equal(true, client.supports.binary); + wss.close(); + done(); + }); + }); + + it('returns false for hixie transport', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(client) { + assert.equal(false, client.supports.binary); + wss.close(); + done(); + }); + }); + }); + }); + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/test/WebSocketServer.test.js b/node_modules/dronestream/node_modules/ws/test/WebSocketServer.test.js new file mode 100644 index 0000000..c21fd97 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/WebSocketServer.test.js @@ -0,0 +1,1103 @@ +var http = require('http') + , https = require('https') + , WebSocket = require('../') + , WebSocketServer = WebSocket.Server + , fs = require('fs') + , should = require('should'); + +var port = 8000; + +function getArrayBuffer(buf) { + var l = buf.length; + var arrayBuf = new ArrayBuffer(l); + for (var i = 0; i < l; ++i) { + arrayBuf[i] = buf[i]; + } + return arrayBuf; +} + +function areArraysEqual(x, y) { + if (x.length != y.length) return false; + for (var i = 0, l = x.length; i < l; ++i) { + if (x[i] !== y[i]) return false; + } + return true; +} + +describe('WebSocketServer', function() { + describe('#ctor', function() { + it('throws an error if no option object is passed', function() { + var gotException = false; + try { + var wss = new WebSocketServer(); + } + catch (e) { + gotException = true; + } + gotException.should.be.ok; + }); + + it('throws an error if no port or server is specified', function() { + var gotException = false; + try { + var wss = new WebSocketServer({}); + } + catch (e) { + gotException = true; + } + gotException.should.be.ok; + }); + + it('does not throw an error if no port or server is specified, when the noServer option is true', function() { + var gotException = false; + try { + var wss = new WebSocketServer({noServer: true}); + } + catch (e) { + gotException = true; + } + gotException.should.eql(false); + }); + + it('emits an error if http server bind fails', function(done) { + var wss = new WebSocketServer({port: 1}); + wss.on('error', function() { done(); }); + }); + + it('starts a server on a given port', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + wss.close(); + done(); + }); + }); + + it('uses a precreated http server', function (done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws://localhost:' + port); + + wss.on('connection', function(client) { + wss.close(); + srv.close(); + done(); + }); + }); + }); + + it('uses a precreated http server listening on unix socket', function (done) { + var srv = http.createServer(); + var sockPath = '/tmp/ws_socket_'+new Date().getTime()+'.'+Math.floor(Math.random() * 1000); + srv.listen(sockPath, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws+unix://'+sockPath); + + wss.on('connection', function(client) { + wss.close(); + srv.close(); + done(); + }); + }); + }); + + it('emits path specific connection event', function (done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws://localhost:' + port+'/endpointName'); + + wss.on('connection/endpointName', function(client) { + wss.close(); + srv.close(); + done(); + }); + }); + }); + + it('can have two different instances listening on the same http server with two different paths', function(done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss1 = new WebSocketServer({server: srv, path: '/wss1'}) + , wss2 = new WebSocketServer({server: srv, path: '/wss2'}); + var doneCount = 0; + wss1.on('connection', function(client) { + wss1.close(); + if (++doneCount == 2) { + srv.close(); + done(); + } + }); + wss2.on('connection', function(client) { + wss2.close(); + if (++doneCount == 2) { + srv.close(); + done(); + } + }); + var ws1 = new WebSocket('ws://localhost:' + port + '/wss1'); + var ws2 = new WebSocket('ws://localhost:' + port + '/wss2?foo=1'); + }); + }); + + it('cannot have two different instances listening on the same http server with the same path', function(done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss1 = new WebSocketServer({server: srv, path: '/wss1'}); + try { + var wss2 = new WebSocketServer({server: srv, path: '/wss1'}); + } + catch (e) { + wss1.close(); + srv.close(); + done(); + } + }); + }); + }); + + describe('#close', function() { + it('will close all clients', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('close', function() { + if (++closes == 2) done(); + }); + }); + var closes = 0; + wss.on('connection', function(client) { + client.on('close', function() { + if (++closes == 2) done(); + }); + wss.close(); + }); + }); + + it('does not close a precreated server', function(done) { + var srv = http.createServer(); + var realClose = srv.close; + srv.close = function() { + should.fail('must not close pre-created server'); + } + srv.listen(++port, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws://localhost:' + port); + wss.on('connection', function(client) { + wss.close(); + srv.close = realClose; + srv.close(); + done(); + }); + }); + }); + + it('cleans up websocket data on a precreated server', function(done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss1 = new WebSocketServer({server: srv, path: '/wss1'}) + , wss2 = new WebSocketServer({server: srv, path: '/wss2'}); + (typeof srv._webSocketPaths).should.eql('object'); + Object.keys(srv._webSocketPaths).length.should.eql(2); + wss1.close(); + Object.keys(srv._webSocketPaths).length.should.eql(1); + wss2.close(); + (typeof srv._webSocketPaths).should.eql('undefined'); + srv.close(); + done(); + }); + }); + }); + + describe('#clients', function() { + it('returns a list of connected clients', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + wss.clients.length.should.eql(0); + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + wss.clients.length.should.eql(1); + wss.close(); + done(); + }); + }); + + it('can be disabled', function(done) { + var wss = new WebSocketServer({port: ++port, clientTracking: false}, function() { + wss.clients.length.should.eql(0); + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + wss.clients.length.should.eql(0); + wss.close(); + done(); + }); + }); + + it('is updated when client terminates the connection', function(done) { + var ws; + var wss = new WebSocketServer({port: ++port}, function() { + ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + client.on('close', function() { + wss.clients.length.should.eql(0); + wss.close(); + done(); + }); + ws.terminate(); + }); + }); + + it('is updated when client closes the connection', function(done) { + var ws; + var wss = new WebSocketServer({port: ++port}, function() { + ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + client.on('close', function() { + wss.clients.length.should.eql(0); + wss.close(); + done(); + }); + ws.close(); + }); + }); + }); + + describe('#options', function() { + it('exposes options passed to constructor', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + wss.options.port.should.eql(port); + wss.close(); + done(); + }); + }); + }); + + describe('#handleUpgrade', function() { + it('can be used for a pre-existing server', function (done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss = new WebSocketServer({noServer: true}); + srv.on('upgrade', function(req, socket, upgradeHead) { + wss.handleUpgrade(req, socket, upgradeHead, function(client) { + client.send('hello'); + }); + }); + var ws = new WebSocket('ws://localhost:' + port); + ws.on('message', function(message) { + message.should.eql('hello'); + wss.close(); + srv.close(); + done(); + }); + }); + }); + }); + + describe('hybi mode', function() { + describe('connection establishing', function() { + it('does not accept connections with no sec-websocket-key', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('does not accept connections with no sec-websocket-version', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('does not accept connections with invalid sec-websocket-version', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 12 + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be denied', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 8, + 'Sec-WebSocket-Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets client origin', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.origin.should.eql('http://foobarbaz.com'); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobarbaz.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets original request', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.req.headers['sec-websocket-key'].should.eql('dGhlIHNhbXBsZSBub25jZQ=='); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobarbaz.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('verifyClient has secure:true for ssl connections', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var success = false; + var wss = new WebSocketServer({ + server: app, + verifyClient: function(info) { + success = info.secure === true; + return true; + } + }); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + success.should.be.ok; + done(); + }); + }); + + it('verifyClient has secure:false for non-ssl connections', function(done) { + var app = http.createServer(function (req, res) { + res.writeHead(200); + res.end(); + }); + var success = false; + var wss = new WebSocketServer({ + server: app, + verifyClient: function(info) { + success = info.secure === false; + return true; + } + }); + app.listen(++port, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + success.should.be.ok; + done(); + }); + }); + + it('client can be denied asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + process.nextTick(function() { + cb(false); + }); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 8, + 'Sec-WebSocket-Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + process.nextTick(function() { + cb(true); + }); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('handles messages passed along with the upgrade request (upgrade head)', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.write(new Buffer([0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f], 'binary')); + req.end(); + }); + wss.on('connection', function(ws) { + ws.on('message', function(data) { + data.should.eql('Hello'); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('selects the first protocol by default', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + ws.protocol.should.eql('prot1'); + wss.close(); + done(); + }); + }); + }); + + it('selects the last protocol via protocol handler', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(true, ps[ps.length-1]); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + ws.protocol.should.eql('prot2'); + wss.close(); + done(); + }); + }); + }); + + it('client detects invalid server protocol', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(true, 'prot3'); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + done(new Error('connection must not be established')); + }); + ws.on('error', function() { + done(); + }); + }); + }); + + it('client detects no server protocol', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(true); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + done(new Error('connection must not be established')); + }); + ws.on('error', function() { + done(); + }); + }); + }); + + it('client refuses server protocols', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(false); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + done(new Error('connection must not be established')); + }); + ws.on('error', function() { + done(); + }); + }); + }); + + it('server detects invalid protocol handler', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + // not calling callback is an error and shouldn't timeout + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Sec-WebSocket-Origin': 'http://foobar.com' + } + }; + options.port = port; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(501); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + }); + + describe('messaging', function() { + it('can send and receive data', function(done) { + var data = new Array(65*1024); + for (var i = 0; i < data.length; ++i) { + data[i] = String.fromCharCode(65 + ~~(25 * Math.random())); + } + data = data.join(''); + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('message', function(message, flags) { + ws.send(message); + }); + }); + wss.on('connection', function(client) { + client.on('message', function(message) { + message.should.eql(data); + wss.close(); + done(); + }); + client.send(data); + }); + }); + }); + }); + + describe('hixie mode', function() { + it('can be disabled', function(done) { + var wss = new WebSocketServer({port: ++port, disableHixie: true}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + describe('connection establishing', function() { + it('does not accept connections with no sec-websocket-key1', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('does not accept connections with no sec-websocket-key2', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('accepts connections with valid handshake', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('client can be denied', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets client origin', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.origin.should.eql('http://foobarbaz.com'); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets original request', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.req.headers['sec-websocket-key1'].should.eql('3e6b263 4 17 80'); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('client can be denied asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + cb(false); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + cb(true); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(ws) { + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('handles messages passed along with the upgrade request (upgrade head)', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90', + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.write(new Buffer([0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff], 'binary')); + req.end(); + }); + wss.on('connection', function(ws) { + ws.on('message', function(data) { + data.should.eql('Hello'); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + }); + }); + + describe('client properties', function() { + it('protocol is exposed', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'hi'}); + }); + wss.on('connection', function(client) { + client.protocol.should.eql('hi'); + wss.close(); + done(); + }); + }); + + it('protocolVersion is exposed', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8}); + }); + wss.on('connection', function(client) { + client.protocolVersion.should.eql(8); + wss.close(); + done(); + }); + }); + + it('upgradeReq is the original request object', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8}); + }); + wss.on('connection', function(client) { + client.upgradeReq.httpVersion.should.eql('1.1'); + wss.close(); + done(); + }); + }); + }); + +}); diff --git a/node_modules/dronestream/node_modules/ws/test/autobahn-server.js b/node_modules/dronestream/node_modules/ws/test/autobahn-server.js new file mode 100644 index 0000000..36fe0c2 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/autobahn-server.js @@ -0,0 +1,29 @@ +var WebSocketServer = require('../').Server; + +process.on('uncaughtException', function(err) { + console.log('Caught exception: ', err, err.stack); +}); + +process.on('SIGINT', function () { + try { + console.log('Updating reports and shutting down'); + var ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws'); + ws.on('close', function() { + process.exit(); + }); + } + catch(e) { + process.exit(); + } +}); + +var wss = new WebSocketServer({port: 8181}); +wss.on('connection', function(ws) { + console.log('new connection'); + ws.on('message', function(data, flags) { + ws.send(flags.buffer, {binary: flags.binary === true}); + }); + ws.on('error', function() { + console.log('error', arguments); + }); +}); diff --git a/node_modules/dronestream/node_modules/ws/test/autobahn.js b/node_modules/dronestream/node_modules/ws/test/autobahn.js new file mode 100644 index 0000000..048cc90 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/autobahn.js @@ -0,0 +1,52 @@ +var WebSocket = require('../'); +var currentTest = 1; +var lastTest = -1; +var testCount = null; + +process.on('uncaughtException', function(err) { + console.log('Caught exception: ', err, err.stack); +}); + +process.on('SIGINT', function () { + try { + console.log('Updating reports and shutting down'); + var ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws'); + ws.on('close', function() { + process.exit(); + }); + } + catch(e) { + process.exit(); + } +}); + +function nextTest() { + if (currentTest > testCount || (lastTest != -1 && currentTest > lastTest)) { + console.log('Updating reports and shutting down'); + var ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws'); + ws.on('close', function() { + process.exit(); + }); + return; + }; + console.log('Running test case ' + currentTest + '/' + testCount); + var ws = new WebSocket('ws://localhost:9001/runCase?case=' + currentTest + '&agent=ws'); + ws.on('message', function(data, flags) { + ws.send(flags.buffer, {binary: flags.binary === true, mask: true}); + }); + ws.on('close', function(data) { + currentTest += 1; + process.nextTick(nextTest); + }); + ws.on('error', function(e) {}); +} + +var ws = new WebSocket('ws://localhost:9001/getCaseCount'); +ws.on('message', function(data, flags) { + testCount = parseInt(data); +}); +ws.on('close', function() { + if (testCount > 0) { + nextTest(); + } +}); \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/agent1-cert.pem b/node_modules/dronestream/node_modules/ws/test/fixtures/agent1-cert.pem new file mode 100644 index 0000000..cccb9fb --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/agent1-cert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICbjCCAdcCCQCVvok5oeLpqzANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJV +UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO +BgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlA +dGlueWNsb3Vkcy5vcmcwHhcNMTMwMzA4MDAzMDIyWhcNNDAwNzIzMDAzMDIyWjB9 +MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQK +EwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MTEgMB4G +CSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBAL6GwKosYb0Yc3Qo0OtQVlCJ4208Idw11ij+t2W5sfYbCil5tyQo +jnhGM1CJhEXynQpXXwjKJuIeTQCkeUibTyFKa0bs8+li2FiGoKYbb4G81ovnqkmE +2iDVb8Gw3rrM4zeZ0ZdFnjMsAZac8h6+C4sB/pS9BiMOo6qTl15RQlcJAgMBAAEw +DQYJKoZIhvcNAQEFBQADgYEAOtmLo8DwTPnI4wfQbQ3hWlTS/9itww6IsxH2ODt9 +ggB7wi7N3uAdIWRZ54ke0NEAO5CW1xNTwsWcxQbiHrDOqX1vfVCjIenI76jVEEap +/Ay53ydHNBKdsKkib61Me14Mu0bA3lUul57VXwmH4NUEFB3w973Q60PschUhOEXj +7DY= +-----END CERTIFICATE----- diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/agent1-key.pem b/node_modules/dronestream/node_modules/ws/test/fixtures/agent1-key.pem new file mode 100644 index 0000000..cbd5f0c --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/agent1-key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC+hsCqLGG9GHN0KNDrUFZQieNtPCHcNdYo/rdlubH2Gwopebck +KI54RjNQiYRF8p0KV18IyibiHk0ApHlIm08hSmtG7PPpYthYhqCmG2+BvNaL56pJ +hNog1W/BsN66zOM3mdGXRZ4zLAGWnPIevguLAf6UvQYjDqOqk5deUUJXCQIDAQAB +AoGANu/CBA+SCyVOvRK70u4yRTzNMAUjukxnuSBhH1rg/pajYnwvG6T6F6IeT72n +P0gKkh3JUE6B0bds+p9yPUZTFUXghxjcF33wlIY44H6gFE4K5WutsFJ9c450wtuu +8rXZTsIg7lAXWjTFVmdtOEPetcGlO2Hpi1O7ZzkzHgB2w9ECQQDksCCYx78or1zY +ZSokm8jmpIjG3VLKdvI9HAoJRN40ldnwFoigrFa1AHwsFtWNe8bKyVRPDoLDUjpB +dkPWgweVAkEA1UfgqguQ2KIkbtp9nDBionu3QaajksrRHwIa8vdfRfLxszfHk2fh +NGY3dkRZF8HUAbzYLrd9poVhCBAEjWekpQJASOM6AHfpnXYHCZF01SYx6hEW5wsz +kARJQODm8f1ZNTlttO/5q/xBxn7ZFNRSTD3fJlL05B2j380ddC/Vf1FT4QJAP1BC +GliqnBSuGhZUWYxni3KMeTm9rzL0F29pjpzutHYlWB2D6ndY/FQnvL0XcZ0Bka58 +womIDGnl3x3aLBwLXQJBAJv6h5CHbXHx7VyDJAcNfppAqZGcEaiVg8yf2F33iWy2 +FLthhJucx7df7SO2aw5h06bRDRAhb9br0R9/3mLr7RE= +-----END RSA PRIVATE KEY----- diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/ca1-cert.pem b/node_modules/dronestream/node_modules/ws/test/fixtures/ca1-cert.pem new file mode 100644 index 0000000..1d0c0d6 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/ca1-cert.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICazCCAdQCCQC9/g69HtxXRzANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJV +UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO +BgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlA +dGlueWNsb3Vkcy5vcmcwHhcNMTMwMzA4MDAzMDIyWhcNNDAwNzIzMDAzMDIyWjB6 +MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQK +EwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqG +SIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0A +MIGJAoGBAKxr1mARUcv7zaqx5y4AxJPK6c1jdbSg7StcL4vg8klaPAlfNO6o+/Cl +w5CdQD3ukaVUwUOJ4T/+b3Xf7785XcWBC33GdjVQkfbHATJYcka7j7JDw3qev5Jk +1rAbRw48hF6rYlSGcx1mccAjoLoa3I8jgxCNAYHIjUQXgdmU893rAgMBAAEwDQYJ +KoZIhvcNAQEFBQADgYEAis05yxjCtJRuv8uX/DK6TX/j9C9Lzp1rKDNFTaTZ0iRw +KCw1EcNx4OXSj9gNblW4PWxpDvygrt1AmH9h2cb8K859NSHa9JOBFw6MA5C2A4Sj +NQfNATqUl4T6cdORlcDEZwHtT8b6D4A6Er31G/eJF4Sen0TUFpjdjd+l9RBjHlo= +-----END CERTIFICATE----- diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/ca1-key.pem b/node_modules/dronestream/node_modules/ws/test/fixtures/ca1-key.pem new file mode 100644 index 0000000..df14950 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/ca1-key.pem @@ -0,0 +1,17 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIFeWxJE1BrRECAggA +MBQGCCqGSIb3DQMHBAgu9PlMSQ+BOASCAoDEZN2tX0xWo/N+Jg+PrvCrFDk3P+3x +5xG/PEDjtMCAWPBEwbnaYHDzYmhNcAmxzGqEHGMDiWYs46LbO560VS3uMvFbEWPo +KYYVb13vkxl2poXdonCb5cHZA5GUYzTIVVJFptl4LHwBczHoMHtA4FqAhKlYvlWw +EOrdLB8XcwMmGPFabbbGxno0+EWWM27uNjlogfoxj35mQqSW4rOlhZ460XjOB1Zx +LjXMuZeONojkGYQRG5EUMchBoctQpCOM6cAi9r1B9BvtFCBpDV1c1zEZBzTEUd8o +kLn6tjLmY+QpTdylFjEWc7U3ppLY/pkoTBv4r85a2sEMWqkhSJboLaTboWzDJcU3 +Ke61pMpovt/3yCUd3TKgwduVwwQtDVTlBe0p66aN9QVj3CrFy/bKAGO3vxlli24H +aIjZf+OVoBY21ESlW3jLvNlBf7Ezf///2E7j4SCDLyZSFMTpFoAG/jDRyvi+wTKX +Kh485Bptnip6DCSuoH4u2SkOqwz3gJS/6s02YKe4m311QT4Pzne5/FwOFaS/HhQg +Xvyh2/d00OgJ0Y0PYQsHILPRgTUCKUXvj1O58opn3fxSacsPxIXwj6Z4FYAjUTaV +2B85k1lpant/JJEilDqMjqzx4pHZ/Z3Uto1lSM1JZs9SNL/0UR+6F0TXZTULVU9V +w8jYzz4sPr7LEyrrTbzmjQgnQFVbhAN/eKgRZK/SpLjxpmBV5MfpbPKsPUZqT4UC +4nXa8a/NYUQ9e+QKK8enq9E599c2W442W7Z1uFRZTWReMx/lF8wwA6G8zOPG0bdj +d+T5Gegzd5mvRiXMBklCo8RLxOOvgxun1n3PY4a63aH6mqBhdfhiLp5j +-----END ENCRYPTED PRIVATE KEY----- diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/certificate.pem b/node_modules/dronestream/node_modules/ws/test/fixtures/certificate.pem new file mode 100644 index 0000000..0efc2ef --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/certificate.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICATCCAWoCCQDPufXH86n2QzANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJu +bzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTEyMDEwMTE0NDQwMFoXDTIwMDMxOTE0NDQwMFowRTELMAkG +A1UEBhMCbm8xEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtrQ7 ++r//2iV/B6F+4boH0XqFn7alcV9lpjvAmwRXNKnxAoa0f97AjYPGNLKrjpkNXXhB +JROIdbRbZnCNeC5fzX1a+JCo7KStzBXuGSZr27TtFmcV4H+9gIRIcNHtZmJLnxbJ +sIhkGR8yVYdmJZe4eT5ldk1zoB1adgPF1hZhCBMCAwEAATANBgkqhkiG9w0BAQUF +AAOBgQCeWBEHYJ4mCB5McwSSUox0T+/mJ4W48L/ZUE4LtRhHasU9hiW92xZkTa7E +QLcoJKQiWfiLX2ysAro0NX4+V8iqLziMqvswnPzz5nezaOLE/9U/QvH3l8qqNkXu +rNbsW1h/IO6FV8avWFYVFoutUwOaZ809k7iMh2F2JMgXQ5EymQ== +-----END CERTIFICATE----- diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/key.pem b/node_modules/dronestream/node_modules/ws/test/fixtures/key.pem new file mode 100644 index 0000000..176fe32 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC2tDv6v//aJX8HoX7hugfReoWftqVxX2WmO8CbBFc0qfEChrR/ +3sCNg8Y0squOmQ1deEElE4h1tFtmcI14Ll/NfVr4kKjspK3MFe4ZJmvbtO0WZxXg +f72AhEhw0e1mYkufFsmwiGQZHzJVh2Yll7h5PmV2TXOgHVp2A8XWFmEIEwIDAQAB +AoGAAlVY8sHi/aE+9xT77twWX3mGHV0SzdjfDnly40fx6S1Gc7bOtVdd9DC7pk6l +3ENeJVR02IlgU8iC5lMHq4JEHPE272jtPrLlrpWLTGmHEqoVFv9AITPqUDLhB9Kk +Hjl7h8NYBKbr2JHKICr3DIPKOT+RnXVb1PD4EORbJ3ooYmkCQQDfknUnVxPgxUGs +ouABw1WJIOVgcCY/IFt4Ihf6VWTsxBgzTJKxn3HtgvE0oqTH7V480XoH0QxHhjLq +DrgobWU9AkEA0TRJ8/ouXGnFEPAXjWr9GdPQRZ1Use2MrFjneH2+Sxc0CmYtwwqL +Kr5kS6mqJrxprJeluSjBd+3/ElxURrEXjwJAUvmlN1OPEhXDmRHd92mKnlkyKEeX +OkiFCiIFKih1S5Y/sRJTQ0781nyJjtJqO7UyC3pnQu1oFEePL+UEniRztQJAMfav +AtnpYKDSM+1jcp7uu9BemYGtzKDTTAYfoiNF42EzSJiGrWJDQn4eLgPjY0T0aAf/ +yGz3Z9ErbhMm/Ysl+QJBAL4kBxRT8gM4ByJw4sdOvSeCCANFq8fhbgm8pGWlCPb5 +JGmX3/GHFM8x2tbWMGpyZP1DLtiNEFz7eCGktWK5rqE= +-----END RSA PRIVATE KEY----- diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/request.pem b/node_modules/dronestream/node_modules/ws/test/fixtures/request.pem new file mode 100644 index 0000000..51bc7f6 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/request.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBhDCB7gIBADBFMQswCQYDVQQGEwJubzETMBEGA1UECAwKU29tZS1TdGF0ZTEh +MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC2tDv6v//aJX8HoX7hugfReoWftqVxX2WmO8CbBFc0qfEC +hrR/3sCNg8Y0squOmQ1deEElE4h1tFtmcI14Ll/NfVr4kKjspK3MFe4ZJmvbtO0W +ZxXgf72AhEhw0e1mYkufFsmwiGQZHzJVh2Yll7h5PmV2TXOgHVp2A8XWFmEIEwID +AQABoAAwDQYJKoZIhvcNAQEFBQADgYEAjsUXEARgfxZNkMjuUcudgU2w4JXS0gGI +JQ0U1LmU0vMDSKwqndMlvCbKzEgPbJnGJDI8D4MeINCJHa5Ceyb8c+jaJYUcCabl +lQW5Psn3+eWp8ncKlIycDRj1Qk615XuXtV0fhkrgQM2ZCm9LaQ1O1Gd/CzLihLjF +W0MmgMKMMRk= +-----END CERTIFICATE REQUEST----- diff --git a/node_modules/dronestream/node_modules/ws/test/fixtures/textfile b/node_modules/dronestream/node_modules/ws/test/fixtures/textfile new file mode 100644 index 0000000..a10483b --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/fixtures/textfile @@ -0,0 +1,9 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam egestas, massa at aliquam luctus, sapien erat viverra elit, nec pulvinar turpis eros sagittis urna. Pellentesque imperdiet tempor varius. Pellentesque blandit, ipsum in imperdiet venenatis, mi elit faucibus odio, id condimentum ante enim sed lectus. Aliquam et odio non odio pellentesque pulvinar. Vestibulum a erat dolor. Integer pretium risus sit amet nisl volutpat nec venenatis magna egestas. Ut bibendum felis eu tellus laoreet eleifend. Nam pulvinar auctor tortor, eu iaculis leo vestibulum quis. In euismod risus ac purus vehicula et fermentum ligula consectetur. Vivamus condimentum tempus lacinia. + +Curabitur sodales condimentum urna id dictum. Sed quis justo sit amet quam ultrices tincidunt vel laoreet nulla. Nullam quis ipsum sed nisi mollis bibendum at sit amet nisi. Donec laoreet consequat velit sit amet mollis. Nam sed sapien a massa iaculis dapibus. Sed dui nunc, ultricies et pellentesque ullamcorper, aliquet vitae ligula. Integer eu velit in neque iaculis venenatis. Ut rhoncus cursus est, ac dignissim leo vehicula a. Nulla ullamcorper vulputate mauris id blandit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eleifend, nisi a tempor sollicitudin, odio massa pretium urna, quis congue sapien elit at tortor. Curabitur ipsum orci, vehicula non commodo molestie, laoreet id enim. Pellentesque convallis ultrices congue. Pellentesque nec iaculis lorem. In sagittis pharetra ipsum eget sodales. + +Fusce id nulla odio. Nunc nibh justo, placerat vel tincidunt sed, ornare et enim. Nulla vel urna vel ante commodo bibendum in vitae metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis erat nunc, semper eget sagittis sit amet, ullamcorper eget lacus. Donec hendrerit ipsum vitae eros vestibulum eu gravida neque tincidunt. Ut molestie lacinia nulla. Donec mattis odio at magna egestas at pellentesque eros accumsan. Praesent interdum sem sit amet nibh commodo dignissim. Duis laoreet, enim ultricies fringilla suscipit, enim libero cursus nulla, sollicitudin adipiscing erat velit ut dui. Nulla eleifend mauris at velit fringilla a molestie lorem venenatis. + +Donec sit amet scelerisque metus. Cras ac felis a nulla venenatis vulputate. Duis porttitor eros ac neque rhoncus eget aliquet neque egestas. Quisque sed nunc est, vitae dapibus quam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In vehicula, est vitae posuere ultricies, diam purus pretium sapien, nec rhoncus dolor nisl eget arcu. Aliquam et nisi vitae risus tincidunt auctor. In vehicula, erat a cursus adipiscing, lorem orci congue est, nec ultricies elit dui in nunc. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Duis congue tempus elit sit amet auctor. Duis dignissim, risus ut sollicitudin ultricies, dolor ligula gravida odio, nec congue orci purus ut ligula. Fusce pretium dictum lectus at volutpat. Sed non auctor mauris. Etiam placerat vestibulum massa id blandit. Quisque consequat lacus ut nulla euismod facilisis. Sed aliquet ipsum nec mi imperdiet viverra. Pellentesque ullamcorper, lectus nec varius gravida, odio justo cursus risus, eu sagittis metus arcu quis felis. Phasellus consectetur vehicula libero, at condimentum orci euismod vel. Nunc purus tortor, suscipit nec fringilla nec, vulputate et nibh. Nam porta vehicula neque. Praesent porttitor, sapien eu auctor euismod, arcu quam elementum urna, sed hendrerit magna augue sed quam. \ No newline at end of file diff --git a/node_modules/dronestream/node_modules/ws/test/hybi-common.js b/node_modules/dronestream/node_modules/ws/test/hybi-common.js new file mode 100644 index 0000000..006f9c6 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/hybi-common.js @@ -0,0 +1,99 @@ +/** + * Returns a Buffer from a "ff 00 ff"-type hex string. + */ + +getBufferFromHexString = function(byteStr) { + var bytes = byteStr.split(' '); + var buf = new Buffer(bytes.length); + for (var i = 0; i < bytes.length; ++i) { + buf[i] = parseInt(bytes[i], 16); + } + return buf; +} + +/** + * Returns a hex string from a Buffer. + */ + +getHexStringFromBuffer = function(data) { + var s = ''; + for (var i = 0; i < data.length; ++i) { + s += padl(data[i].toString(16), 2, '0') + ' '; + } + return s.trim(); +} + +/** + * Splits a buffer in two parts. + */ + +splitBuffer = function(buffer) { + var b1 = new Buffer(Math.ceil(buffer.length / 2)); + buffer.copy(b1, 0, 0, b1.length); + var b2 = new Buffer(Math.floor(buffer.length / 2)); + buffer.copy(b2, 0, b1.length, b1.length + b2.length); + return [b1, b2]; +} + +/** + * Performs hybi07+ type masking on a hex string or buffer. + */ + +mask = function(buf, maskString) { + if (typeof buf == 'string') buf = new Buffer(buf); + var mask = getBufferFromHexString(maskString || '34 83 a8 68'); + for (var i = 0; i < buf.length; ++i) { + buf[i] ^= mask[i % 4]; + } + return buf; +} + +/** + * Returns a hex string representing the length of a message + */ + +getHybiLengthAsHexString = function(len, masked) { + if (len < 126) { + var buf = new Buffer(1); + buf[0] = (masked ? 0x80 : 0) | len; + } + else if (len < 65536) { + var buf = new Buffer(3); + buf[0] = (masked ? 0x80 : 0) | 126; + getBufferFromHexString(pack(4, len)).copy(buf, 1); + } + else { + var buf = new Buffer(9); + buf[0] = (masked ? 0x80 : 0) | 127; + getBufferFromHexString(pack(16, len)).copy(buf, 1); + } + return getHexStringFromBuffer(buf); +} + +/** + * Unpacks a Buffer into a number. + */ + +unpack = function(buffer) { + var n = 0; + for (var i = 0; i < buffer.length; ++i) { + n = (i == 0) ? buffer[i] : (n * 256) + buffer[i]; + } + return n; +} + +/** + * Returns a hex string, representing a specific byte count 'length', from a number. + */ + +pack = function(length, number) { + return padl(number.toString(16), length, '0').replace(/([0-9a-f][0-9a-f])/gi, '$1 ').trim(); +} + +/** + * Left pads the string 's' to a total length of 'n' with char 'c'. + */ + +padl = function(s, n, c) { + return new Array(1 + n - s.length).join(c) + s; +} diff --git a/node_modules/dronestream/node_modules/ws/test/testserver.js b/node_modules/dronestream/node_modules/ws/test/testserver.js new file mode 100644 index 0000000..3e7a966 --- /dev/null +++ b/node_modules/dronestream/node_modules/ws/test/testserver.js @@ -0,0 +1,180 @@ +var http = require('http') + , util = require('util') + , crypto = require('crypto') + , events = require('events') + , Sender = require('../lib/Sender') + , Receiver = require('../lib/Receiver'); + +module.exports = { + handlers: { + valid: validServer, + invalidKey: invalidRequestHandler, + closeAfterConnect: closeAfterConnectHandler, + return401: return401 + }, + createServer: function(port, handler, cb) { + if (handler && !cb) { + cb = handler; + handler = null; + } + var webServer = http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('okay'); + }); + var srv = new Server(webServer); + webServer.on('upgrade', function(req, socket) { + webServer._socket = socket; + (handler || validServer)(srv, req, socket); + }); + webServer.listen(port, '127.0.0.1', function() { cb(srv); }); + } +}; + +/** + * Test strategies + */ + +function validServer(server, req, socket) { + if (typeof req.headers.upgrade === 'undefined' || + req.headers.upgrade.toLowerCase() !== 'websocket') { + throw new Error('invalid headers'); + return; + } + + if (!req.headers['sec-websocket-key']) { + socket.end(); + throw new Error('websocket key is missing'); + } + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.setTimeout(0); + socket.setNoDelay(true); + + var sender = new Sender(socket); + var receiver = new Receiver(); + receiver.ontext = function (message, flags) { + server.emit('message', message, flags); + sender.send(message); + }; + receiver.onbinary = function (message, flags) { + flags = flags || {}; + flags.binary = true; + server.emit('message', message, flags); + sender.send(message, {binary: true}); + }; + receiver.onping = function (message, flags) { + flags = flags || {}; + server.emit('ping', message, flags); + }; + receiver.onpong = function (message, flags) { + flags = flags || {}; + server.emit('pong', message, flags); + }; + receiver.onclose = function (code, message, flags) { + flags = flags || {}; + server.emit('close', code, message, flags); + }; + socket.on('data', function (data) { + receiver.add(data); + }); + socket.on('end', function() { + socket.end(); + }); +} + +function invalidRequestHandler(server, req, socket) { + if (typeof req.headers.upgrade === 'undefined' || + req.headers.upgrade.toLowerCase() !== 'websocket') { + throw new Error('invalid headers'); + return; + } + + if (!req.headers['sec-websocket-key']) { + socket.end(); + throw new Error('websocket key is missing'); + } + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "bogus"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.end(); +} + +function closeAfterConnectHandler(server, req, socket) { + if (typeof req.headers.upgrade === 'undefined' || + req.headers.upgrade.toLowerCase() !== 'websocket') { + throw new Error('invalid headers'); + return; + } + + if (!req.headers['sec-websocket-key']) { + socket.end(); + throw new Error('websocket key is missing'); + } + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.end(); +} + + +function return401(server, req, socket) { + var headers = [ + 'HTTP/1.1 401 Unauthorized' + , 'Content-type: text/html' + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.end(); +} + +/** + * Server object, which will do the actual emitting + */ + +function Server(webServer) { + this.webServer = webServer; +} + +util.inherits(Server, events.EventEmitter); + +Server.prototype.close = function() { + this.webServer.close(); + if (this._socket) this._socket.end(); +} diff --git a/node_modules/dronestream/package.json b/node_modules/dronestream/package.json new file mode 100644 index 0000000..84f7be3 --- /dev/null +++ b/node_modules/dronestream/package.json @@ -0,0 +1,49 @@ +{ + "name": "dronestream", + "description": "video live stream from your parrot ar.drone 2.0 to your browser in pure javascript", + "version": "1.1.0", + "repository": { + "type": "git", + "url": "git@github.com:bkw/node-dronestream.git" + }, + "main": "index", + "keywords": [ + "drone", + "nodecopter", + "parrot", + "video", + "stream", + "browser", + "x264" + ], + "dependencies": { + "ws": "~0.4.27", + "ar-drone": "0.1.0", + "buffy": "0.0.5" + }, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-contrib-uglify": "~0.2.2", + "grunt-contrib-jshint": "~0.6.2", + "matchdep": "~0.1.2", + "grunt-contrib-concat": "~0.3.0" + }, + "author": { + "name": "Bernhard K. Weisshuhn", + "email": "bkw@codingforce.com" + }, + "contributors": [ + { + "name": "Karl Westin", + "email": "karl.westin@gmail.com" + } + ], + "license": "BSD", + "readme": "# node-dronestream\n\nGet a realtime live video stream from your\n[Parrot AR Drone 2.0](http://ardrone2.parrot.com/) straight to your browser.\n\n## Requirements\n\nYou'll need a decent and current browser and some cpu horsepower.\nThis code uses web-sockets and the incredibly awesome\n[Broadway.js](https://github.com/mbebenita/Broadway) to render the video frames\nin your browser using a WebGL canvas.\n\n## How to use\n\nPlease see the http.createServer and Express 3.0 examples in the 'examples' dir.\nYou attach the stream to your server like this:\n```javascript\n// in node:\n//\n// note that the 'server' object points to a server instance and NOT an express app.\nrequire(\"dronestream\").listen(server); \n// if your drone is on a different IP\nrequire(\"dronestream\").listen(server, { ip: \"192.168.2.155\" });\n```\n\nWe serve the client in the same manner as Socket.IO. Add a reference to \n**/dronestream/nodecopter-client.js** in your template. Then attach the stream to a DOM node:\n```html\n\n\n\n```\n\n## How it works\n\nThe drone sends a proprietary video feed on 192.168.1.1 port 5555. This is\nmostly a h264 baseline video, but adds custom framing. These frames are parsed\nand mostly disposed of. The remaining h264 payload is split into NAL units and\nsent to the browser via web sockets.\n\nIn the browser broadway takes care of the rendering of the WebGL canvas.\n\n## Status\n\nNode-dronestream has gained some stability in the last release. It attempts \nto recover lost connections to the drone, and it handles multiple clients, \ndisconnections, etc. See \"How to use\" for API.\n\n## Thanks\n\n- Triple high fives to Felix 'felixge' Geisendörfer for getting the whole\n NodeCopter movement started and being extremely helpful in the process of\n getting this together.\n\n- André 'zoddy' Kussmann for supplying the drone and allowing me to keep\n hacking on it, even when he had to cancel the NodeCopter event for himself.\n\n- Michael Bebenita, Alon Zakai, Andreas Gal and Mathieu 'p01' Henri for the\n magic of Broadway.js\n\n- Johann Phillip Strathausen for being a great team mate at NodeCopter 2012\n Berlin.\n\n- Brian Leroux for being not content with the original solution and for\n cleaning up the predecessor, nodecopter-stream.\n\n- @karlwestin for picking up where I was to lazy to actually make this usable.\n\n## Demo\n\nWatch @felixge demoing node-dronestream live at german user group cgnjs:\nhttp://www.youtube.com/watch?v=nwGNNMJt4mE&t=19m52\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/bkw/node-dronestream/issues" + }, + "_id": "dronestream@1.1.0", + "_from": "dronestream@" +} diff --git a/node_modules/express/.npmignore b/node_modules/express/.npmignore new file mode 100644 index 0000000..caf574d --- /dev/null +++ b/node_modules/express/.npmignore @@ -0,0 +1,9 @@ +.git* +docs/ +examples/ +support/ +test/ +testing.js +.DS_Store +coverage.html +lib-cov diff --git a/node_modules/express/.travis.yml b/node_modules/express/.travis.yml new file mode 100644 index 0000000..cc4dba2 --- /dev/null +++ b/node_modules/express/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.8" + - "0.10" diff --git a/node_modules/express/History.md b/node_modules/express/History.md new file mode 100644 index 0000000..1166646 --- /dev/null +++ b/node_modules/express/History.md @@ -0,0 +1,1183 @@ + +3.3.4 / 2013-07-08 +================== + + * update send and connect + +3.3.3 / 2013-07-04 +================== + + * update connect + +3.3.2 / 2013-07-03 +================== + + * update connect + * update send + * remove .version export + +3.3.1 / 2013-06-27 +================== + + * update connect + +3.3.0 / 2013-06-26 +================== + + * update connect + * add support for multiple X-Forwarded-Proto values. Closes #1646 + * change: remove charset from json responses. Closes #1631 + * change: return actual booleans from req.accept* functions + * fix jsonp callback array throw + +3.2.6 / 2013-06-02 +================== + + * update connect + +3.2.5 / 2013-05-21 +================== + + * update connect + * update node-cookie + * add: throw a meaningful error when there is no default engine + * change generation of ETags with res.send() to GET requests only. Closes #1619 + +3.2.4 / 2013-05-09 +================== + + * fix `req.subdomains` when no Host is present + * fix `req.host` when no Host is present, return undefined + +3.2.3 / 2013-05-07 +================== + + * update connect / qs + +3.2.2 / 2013-05-03 +================== + + * update qs + +3.2.1 / 2013-04-29 +================== + + * add app.VERB() paths array deprecation warning + * update connect + * update qs and remove all ~ semver crap + * fix: accept number as value of Signed Cookie + +3.2.0 / 2013-04-15 +================== + + * add "view" constructor setting to override view behaviour + * add req.acceptsEncoding(name) + * add req.acceptedEncodings + * revert cookie signature change causing session race conditions + * fix sorting of Accept values of the same quality + +3.1.2 / 2013-04-12 +================== + + * add support for custom Accept parameters + * update cookie-signature + +3.1.1 / 2013-04-01 +================== + + * add X-Forwarded-Host support to `req.host` + * fix relative redirects + * update mkdirp + * update buffer-crc32 + * remove legacy app.configure() method from app template. + +3.1.0 / 2013-01-25 +================== + + * add support for leading "." in "view engine" setting + * add array support to `res.set()` + * add node 0.8.x to travis.yml + * add "subdomain offset" setting for tweaking `req.subdomains` + * add `res.location(url)` implementing `res.redirect()`-like setting of Location + * use app.get() for x-powered-by setting for inheritance + * fix colons in passwords for `req.auth` + +3.0.6 / 2013-01-04 +================== + + * add http verb methods to Router + * update connect + * fix mangling of the `res.cookie()` options object + * fix jsonp whitespace escape. Closes #1132 + +3.0.5 / 2012-12-19 +================== + + * add throwing when a non-function is passed to a route + * fix: explicitly remove Transfer-Encoding header from 204 and 304 responses + * revert "add 'etag' option" + +3.0.4 / 2012-12-05 +================== + + * add 'etag' option to disable `res.send()` Etags + * add escaping of urls in text/plain in `res.redirect()` + for old browsers interpreting as html + * change crc32 module for a more liberal license + * update connect + +3.0.3 / 2012-11-13 +================== + + * update connect + * update cookie module + * fix cookie max-age + +3.0.2 / 2012-11-08 +================== + + * add OPTIONS to cors example. Closes #1398 + * fix route chaining regression. Closes #1397 + +3.0.1 / 2012-11-01 +================== + + * update connect + +3.0.0 / 2012-10-23 +================== + + * add `make clean` + * add "Basic" check to req.auth + * add `req.auth` test coverage + * add cb && cb(payload) to `res.jsonp()`. Closes #1374 + * add backwards compat for `res.redirect()` status. Closes #1336 + * add support for `res.json()` to retain previously defined Content-Types. Closes #1349 + * update connect + * change `res.redirect()` to utilize a pathname-relative Location again. Closes #1382 + * remove non-primitive string support for `res.send()` + * fix view-locals example. Closes #1370 + * fix route-separation example + +3.0.0rc5 / 2012-09-18 +================== + + * update connect + * add redis search example + * add static-files example + * add "x-powered-by" setting (`app.disable('x-powered-by')`) + * add "application/octet-stream" redirect Accept test case. Closes #1317 + +3.0.0rc4 / 2012-08-30 +================== + + * add `res.jsonp()`. Closes #1307 + * add "verbose errors" option to error-pages example + * add another route example to express(1) so people are not so confused + * add redis online user activity tracking example + * update connect dep + * fix etag quoting. Closes #1310 + * fix error-pages 404 status + * fix jsonp callback char restrictions + * remove old OPTIONS default response + +3.0.0rc3 / 2012-08-13 +================== + + * update connect dep + * fix signed cookies to work with `connect.cookieParser()` ("s:" prefix was missing) [tnydwrds] + * fix `res.render()` clobbering of "locals" + +3.0.0rc2 / 2012-08-03 +================== + + * add CORS example + * update connect dep + * deprecate `.createServer()` & remove old stale examples + * fix: escape `res.redirect()` link + * fix vhost example + +3.0.0rc1 / 2012-07-24 +================== + + * add more examples to view-locals + * add scheme-relative redirects (`res.redirect("//foo.com")`) support + * update cookie dep + * update connect dep + * update send dep + * fix `express(1)` -h flag, use -H for hogan. Closes #1245 + * fix `res.sendfile()` socket error handling regression + +3.0.0beta7 / 2012-07-16 +================== + + * update connect dep for `send()` root normalization regression + +3.0.0beta6 / 2012-07-13 +================== + + * add `err.view` property for view errors. Closes #1226 + * add "jsonp callback name" setting + * add support for "/foo/:bar*" non-greedy matches + * change `res.sendfile()` to use `send()` module + * change `res.send` to use "response-send" module + * remove `app.locals.use` and `res.locals.use`, use regular middleware + +3.0.0beta5 / 2012-07-03 +================== + + * add "make check" support + * add route-map example + * add `res.json(obj, status)` support back for BC + * add "methods" dep, remove internal methods module + * update connect dep + * update auth example to utilize cores pbkdf2 + * updated tests to use "supertest" + +3.0.0beta4 / 2012-06-25 +================== + + * Added `req.auth` + * Added `req.range(size)` + * Added `res.links(obj)` + * Added `res.send(body, status)` support back for backwards compat + * Added `.default()` support to `res.format()` + * Added 2xx / 304 check to `req.fresh` + * Revert "Added + support to the router" + * Fixed `res.send()` freshness check, respect res.statusCode + +3.0.0beta3 / 2012-06-15 +================== + + * Added hogan `--hjs` to express(1) [nullfirm] + * Added another example to content-negotiation + * Added `fresh` dep + * Changed: `res.send()` always checks freshness + * Fixed: expose connects mime module. Cloases #1165 + +3.0.0beta2 / 2012-06-06 +================== + + * Added `+` support to the router + * Added `req.host` + * Changed `req.param()` to check route first + * Update connect dep + +3.0.0beta1 / 2012-06-01 +================== + + * Added `res.format()` callback to override default 406 behaviour + * Fixed `res.redirect()` 406. Closes #1154 + +3.0.0alpha5 / 2012-05-30 +================== + + * Added `req.ip` + * Added `{ signed: true }` option to `res.cookie()` + * Removed `res.signedCookie()` + * Changed: dont reverse `req.ips` + * Fixed "trust proxy" setting check for `req.ips` + +3.0.0alpha4 / 2012-05-09 +================== + + * Added: allow `[]` in jsonp callback. Closes #1128 + * Added `PORT` env var support in generated template. Closes #1118 [benatkin] + * Updated: connect 2.2.2 + +3.0.0alpha3 / 2012-05-04 +================== + + * Added public `app.routes`. Closes #887 + * Added _view-locals_ example + * Added _mvc_ example + * Added `res.locals.use()`. Closes #1120 + * Added conditional-GET support to `res.send()` + * Added: coerce `res.set()` values to strings + * Changed: moved `static()` in generated apps below router + * Changed: `res.send()` only set ETag when not previously set + * Changed connect 2.2.1 dep + * Changed: `make test` now runs unit / acceptance tests + * Fixed req/res proto inheritance + +3.0.0alpha2 / 2012-04-26 +================== + + * Added `make benchmark` back + * Added `res.send()` support for `String` objects + * Added client-side data exposing example + * Added `res.header()` and `req.header()` aliases for BC + * Added `express.createServer()` for BC + * Perf: memoize parsed urls + * Perf: connect 2.2.0 dep + * Changed: make `expressInit()` middleware self-aware + * Fixed: use app.get() for all core settings + * Fixed redis session example + * Fixed session example. Closes #1105 + * Fixed generated express dep. Closes #1078 + +3.0.0alpha1 / 2012-04-15 +================== + + * Added `app.locals.use(callback)` + * Added `app.locals` object + * Added `app.locals(obj)` + * Added `res.locals` object + * Added `res.locals(obj)` + * Added `res.format()` for content-negotiation + * Added `app.engine()` + * Added `res.cookie()` JSON cookie support + * Added "trust proxy" setting + * Added `req.subdomains` + * Added `req.protocol` + * Added `req.secure` + * Added `req.path` + * Added `req.ips` + * Added `req.fresh` + * Added `req.stale` + * Added comma-delmited / array support for `req.accepts()` + * Added debug instrumentation + * Added `res.set(obj)` + * Added `res.set(field, value)` + * Added `res.get(field)` + * Added `app.get(setting)`. Closes #842 + * Added `req.acceptsLanguage()` + * Added `req.acceptsCharset()` + * Added `req.accepted` + * Added `req.acceptedLanguages` + * Added `req.acceptedCharsets` + * Added "json replacer" setting + * Added "json spaces" setting + * Added X-Forwarded-Proto support to `res.redirect()`. Closes #92 + * Added `--less` support to express(1) + * Added `express.response` prototype + * Added `express.request` prototype + * Added `express.application` prototype + * Added `app.path()` + * Added `app.render()` + * Added `res.type()` to replace `res.contentType()` + * Changed: `res.redirect()` to add relative support + * Changed: enable "jsonp callback" by default + * Changed: renamed "case sensitive routes" to "case sensitive routing" + * Rewrite of all tests with mocha + * Removed "root" setting + * Removed `res.redirect('home')` support + * Removed `req.notify()` + * Removed `app.register()` + * Removed `app.redirect()` + * Removed `app.is()` + * Removed `app.helpers()` + * Removed `app.dynamicHelpers()` + * Fixed `res.sendfile()` with non-GET. Closes #723 + * Fixed express(1) public dir for windows. Closes #866 + +2.5.9/ 2012-04-02 +================== + + * Added support for PURGE request method [pbuyle] + * Fixed `express(1)` generated app `app.address()` before `listening` [mmalecki] + +2.5.8 / 2012-02-08 +================== + + * Update mkdirp dep. Closes #991 + +2.5.7 / 2012-02-06 +================== + + * Fixed `app.all` duplicate DELETE requests [mscdex] + +2.5.6 / 2012-01-13 +================== + + * Updated hamljs dev dep. Closes #953 + +2.5.5 / 2012-01-08 +================== + + * Fixed: set `filename` on cached templates [matthewleon] + +2.5.4 / 2012-01-02 +================== + + * Fixed `express(1)` eol on 0.4.x. Closes #947 + +2.5.3 / 2011-12-30 +================== + + * Fixed `req.is()` when a charset is present + +2.5.2 / 2011-12-10 +================== + + * Fixed: express(1) LF -> CRLF for windows + +2.5.1 / 2011-11-17 +================== + + * Changed: updated connect to 1.8.x + * Removed sass.js support from express(1) + +2.5.0 / 2011-10-24 +================== + + * Added ./routes dir for generated app by default + * Added npm install reminder to express(1) app gen + * Added 0.5.x support + * Removed `make test-cov` since it wont work with node 0.5.x + * Fixed express(1) public dir for windows. Closes #866 + +2.4.7 / 2011-10-05 +================== + + * Added mkdirp to express(1). Closes #795 + * Added simple _json-config_ example + * Added shorthand for the parsed request's pathname via `req.path` + * Changed connect dep to 1.7.x to fix npm issue... + * Fixed `res.redirect()` __HEAD__ support. [reported by xerox] + * Fixed `req.flash()`, only escape args + * Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie] + +2.4.6 / 2011-08-22 +================== + + * Fixed multiple param callback regression. Closes #824 [reported by TroyGoode] + +2.4.5 / 2011-08-19 +================== + + * Added support for routes to handle errors. Closes #809 + * Added `app.routes.all()`. Closes #803 + * Added "basepath" setting to work in conjunction with reverse proxies etc. + * Refactored `Route` to use a single array of callbacks + * Added support for multiple callbacks for `app.param()`. Closes #801 +Closes #805 + * Changed: removed .call(self) for route callbacks + * Dependency: `qs >= 0.3.1` + * Fixed `res.redirect()` on windows due to `join()` usage. Closes #808 + +2.4.4 / 2011-08-05 +================== + + * Fixed `res.header()` intention of a set, even when `undefined` + * Fixed `*`, value no longer required + * Fixed `res.send(204)` support. Closes #771 + +2.4.3 / 2011-07-14 +================== + + * Added docs for `status` option special-case. Closes #739 + * Fixed `options.filename`, exposing the view path to template engines + +2.4.2. / 2011-07-06 +================== + + * Revert "removed jsonp stripping" for XSS + +2.4.1 / 2011-07-06 +================== + + * Added `res.json()` JSONP support. Closes #737 + * Added _extending-templates_ example. Closes #730 + * Added "strict routing" setting for trailing slashes + * Added support for multiple envs in `app.configure()` calls. Closes #735 + * Changed: `res.send()` using `res.json()` + * Changed: when cookie `path === null` don't default it + * Changed; default cookie path to "home" setting. Closes #731 + * Removed _pids/logs_ creation from express(1) + +2.4.0 / 2011-06-28 +================== + + * Added chainable `res.status(code)` + * Added `res.json()`, an explicit version of `res.send(obj)` + * Added simple web-service example + +2.3.12 / 2011-06-22 +================== + + * \#express is now on freenode! come join! + * Added `req.get(field, param)` + * Added links to Japanese documentation, thanks @hideyukisaito! + * Added; the `express(1)` generated app outputs the env + * Added `content-negotiation` example + * Dependency: connect >= 1.5.1 < 2.0.0 + * Fixed view layout bug. Closes #720 + * Fixed; ignore body on 304. Closes #701 + +2.3.11 / 2011-06-04 +================== + + * Added `npm test` + * Removed generation of dummy test file from `express(1)` + * Fixed; `express(1)` adds express as a dep + * Fixed; prune on `prepublish` + +2.3.10 / 2011-05-27 +================== + + * Added `req.route`, exposing the current route + * Added _package.json_ generation support to `express(1)` + * Fixed call to `app.param()` function for optional params. Closes #682 + +2.3.9 / 2011-05-25 +================== + + * Fixed bug-ish with `../' in `res.partial()` calls + +2.3.8 / 2011-05-24 +================== + + * Fixed `app.options()` + +2.3.7 / 2011-05-23 +================== + + * Added route `Collection`, ex: `app.get('/user/:id').remove();` + * Added support for `app.param(fn)` to define param logic + * Removed `app.param()` support for callback with return value + * Removed module.parent check from express(1) generated app. Closes #670 + * Refactored router. Closes #639 + +2.3.6 / 2011-05-20 +================== + + * Changed; using devDependencies instead of git submodules + * Fixed redis session example + * Fixed markdown example + * Fixed view caching, should not be enabled in development + +2.3.5 / 2011-05-20 +================== + + * Added export `.view` as alias for `.View` + +2.3.4 / 2011-05-08 +================== + + * Added `./examples/say` + * Fixed `res.sendfile()` bug preventing the transfer of files with spaces + +2.3.3 / 2011-05-03 +================== + + * Added "case sensitive routes" option. + * Changed; split methods supported per rfc [slaskis] + * Fixed route-specific middleware when using the same callback function several times + +2.3.2 / 2011-04-27 +================== + + * Fixed view hints + +2.3.1 / 2011-04-26 +================== + + * Added `app.match()` as `app.match.all()` + * Added `app.lookup()` as `app.lookup.all()` + * Added `app.remove()` for `app.remove.all()` + * Added `app.remove.VERB()` + * Fixed template caching collision issue. Closes #644 + * Moved router over from connect and started refactor + +2.3.0 / 2011-04-25 +================== + + * Added options support to `res.clearCookie()` + * Added `res.helpers()` as alias of `res.locals()` + * Added; json defaults to UTF-8 with `res.send()`. Closes #632. [Daniel * Dependency `connect >= 1.4.0` + * Changed; auto set Content-Type in res.attachement [Aaron Heckmann] + * Renamed "cache views" to "view cache". Closes #628 + * Fixed caching of views when using several apps. Closes #637 + * Fixed gotcha invoking `app.param()` callbacks once per route middleware. +Closes #638 + * Fixed partial lookup precedence. Closes #631 +Shaw] + +2.2.2 / 2011-04-12 +================== + + * Added second callback support for `res.download()` connection errors + * Fixed `filename` option passing to template engine + +2.2.1 / 2011-04-04 +================== + + * Added `layout(path)` helper to change the layout within a view. Closes #610 + * Fixed `partial()` collection object support. + Previously only anything with `.length` would work. + When `.length` is present one must still be aware of holes, + however now `{ collection: {foo: 'bar'}}` is valid, exposes + `keyInCollection` and `keysInCollection`. + + * Performance improved with better view caching + * Removed `request` and `response` locals + * Changed; errorHandler page title is now `Express` instead of `Connect` + +2.2.0 / 2011-03-30 +================== + + * Added `app.lookup.VERB()`, ex `app.lookup.put('/user/:id')`. Closes #606 + * Added `app.match.VERB()`, ex `app.match.put('/user/12')`. Closes #606 + * Added `app.VERB(path)` as alias of `app.lookup.VERB()`. + * Dependency `connect >= 1.2.0` + +2.1.1 / 2011-03-29 +================== + + * Added; expose `err.view` object when failing to locate a view + * Fixed `res.partial()` call `next(err)` when no callback is given [reported by aheckmann] + * Fixed; `res.send(undefined)` responds with 204 [aheckmann] + +2.1.0 / 2011-03-24 +================== + + * Added `/_?` partial lookup support. Closes #447 + * Added `request`, `response`, and `app` local variables + * Added `settings` local variable, containing the app's settings + * Added `req.flash()` exception if `req.session` is not available + * Added `res.send(bool)` support (json response) + * Fixed stylus example for latest version + * Fixed; wrap try/catch around `res.render()` + +2.0.0 / 2011-03-17 +================== + + * Fixed up index view path alternative. + * Changed; `res.locals()` without object returns the locals + +2.0.0rc3 / 2011-03-17 +================== + + * Added `res.locals(obj)` to compliment `res.local(key, val)` + * Added `res.partial()` callback support + * Fixed recursive error reporting issue in `res.render()` + +2.0.0rc2 / 2011-03-17 +================== + + * Changed; `partial()` "locals" are now optional + * Fixed `SlowBuffer` support. Closes #584 [reported by tyrda01] + * Fixed .filename view engine option [reported by drudge] + * Fixed blog example + * Fixed `{req,res}.app` reference when mounting [Ben Weaver] + +2.0.0rc / 2011-03-14 +================== + + * Fixed; expose `HTTPSServer` constructor + * Fixed express(1) default test charset. Closes #579 [reported by secoif] + * Fixed; default charset to utf-8 instead of utf8 for lame IE [reported by NickP] + +2.0.0beta3 / 2011-03-09 +================== + + * Added support for `res.contentType()` literal + The original `res.contentType('.json')`, + `res.contentType('application/json')`, and `res.contentType('json')` + will work now. + * Added `res.render()` status option support back + * Added charset option for `res.render()` + * Added `.charset` support (via connect 1.0.4) + * Added view resolution hints when in development and a lookup fails + * Added layout lookup support relative to the page view. + For example while rendering `./views/user/index.jade` if you create + `./views/user/layout.jade` it will be used in favour of the root layout. + * Fixed `res.redirect()`. RFC states absolute url [reported by unlink] + * Fixed; default `res.send()` string charset to utf8 + * Removed `Partial` constructor (not currently used) + +2.0.0beta2 / 2011-03-07 +================== + + * Added res.render() `.locals` support back to aid in migration process + * Fixed flash example + +2.0.0beta / 2011-03-03 +================== + + * Added HTTPS support + * Added `res.cookie()` maxAge support + * Added `req.header()` _Referrer_ / _Referer_ special-case, either works + * Added mount support for `res.redirect()`, now respects the mount-point + * Added `union()` util, taking place of `merge(clone())` combo + * Added stylus support to express(1) generated app + * Added secret to session middleware used in examples and generated app + * Added `res.local(name, val)` for progressive view locals + * Added default param support to `req.param(name, default)` + * Added `app.disabled()` and `app.enabled()` + * Added `app.register()` support for omitting leading ".", either works + * Added `res.partial()`, using the same interface as `partial()` within a view. Closes #539 + * Added `app.param()` to map route params to async/sync logic + * Added; aliased `app.helpers()` as `app.locals()`. Closes #481 + * Added extname with no leading "." support to `res.contentType()` + * Added `cache views` setting, defaulting to enabled in "production" env + * Added index file partial resolution, eg: partial('user') may try _views/user/index.jade_. + * Added `req.accepts()` support for extensions + * Changed; `res.download()` and `res.sendfile()` now utilize Connect's + static file server `connect.static.send()`. + * Changed; replaced `connect.utils.mime()` with npm _mime_ module + * Changed; allow `req.query` to be pre-defined (via middleware or other parent + * Changed view partial resolution, now relative to parent view + * Changed view engine signature. no longer `engine.render(str, options, callback)`, now `engine.compile(str, options) -> Function`, the returned function accepts `fn(locals)`. + * Fixed `req.param()` bug returning Array.prototype methods. Closes #552 + * Fixed; using `Stream#pipe()` instead of `sys.pump()` in `res.sendfile()` + * Fixed; using _qs_ module instead of _querystring_ + * Fixed; strip unsafe chars from jsonp callbacks + * Removed "stream threshold" setting + +1.0.8 / 2011-03-01 +================== + + * Allow `req.query` to be pre-defined (via middleware or other parent app) + * "connect": ">= 0.5.0 < 1.0.0". Closes #547 + * Removed the long deprecated __EXPRESS_ENV__ support + +1.0.7 / 2011-02-07 +================== + + * Fixed `render()` setting inheritance. + Mounted apps would not inherit "view engine" + +1.0.6 / 2011-02-07 +================== + + * Fixed `view engine` setting bug when period is in dirname + +1.0.5 / 2011-02-05 +================== + + * Added secret to generated app `session()` call + +1.0.4 / 2011-02-05 +================== + + * Added `qs` dependency to _package.json_ + * Fixed namespaced `require()`s for latest connect support + +1.0.3 / 2011-01-13 +================== + + * Remove unsafe characters from JSONP callback names [Ryan Grove] + +1.0.2 / 2011-01-10 +================== + + * Removed nested require, using `connect.router` + +1.0.1 / 2010-12-29 +================== + + * Fixed for middleware stacked via `createServer()` + previously the `foo` middleware passed to `createServer(foo)` + would not have access to Express methods such as `res.send()` + or props like `req.query` etc. + +1.0.0 / 2010-11-16 +================== + + * Added; deduce partial object names from the last segment. + For example by default `partial('forum/post', postObject)` will + give you the _post_ object, providing a meaningful default. + * Added http status code string representation to `res.redirect()` body + * Added; `res.redirect()` supporting _text/plain_ and _text/html_ via __Accept__. + * Added `req.is()` to aid in content negotiation + * Added partial local inheritance [suggested by masylum]. Closes #102 + providing access to parent template locals. + * Added _-s, --session[s]_ flag to express(1) to add session related middleware + * Added _--template_ flag to express(1) to specify the + template engine to use. + * Added _--css_ flag to express(1) to specify the + stylesheet engine to use (or just plain css by default). + * Added `app.all()` support [thanks aheckmann] + * Added partial direct object support. + You may now `partial('user', user)` providing the "user" local, + vs previously `partial('user', { object: user })`. + * Added _route-separation_ example since many people question ways + to do this with CommonJS modules. Also view the _blog_ example for + an alternative. + * Performance; caching view path derived partial object names + * Fixed partial local inheritance precedence. [reported by Nick Poulden] Closes #454 + * Fixed jsonp support; _text/javascript_ as per mailinglist discussion + +1.0.0rc4 / 2010-10-14 +================== + + * Added _NODE_ENV_ support, _EXPRESS_ENV_ is deprecated and will be removed in 1.0.0 + * Added route-middleware support (very helpful, see the [docs](http://expressjs.com/guide.html#Route-Middleware)) + * Added _jsonp callback_ setting to enable/disable jsonp autowrapping [Dav Glass] + * Added callback query check on response.send to autowrap JSON objects for simple webservice implementations [Dav Glass] + * Added `partial()` support for array-like collections. Closes #434 + * Added support for swappable querystring parsers + * Added session usage docs. Closes #443 + * Added dynamic helper caching. Closes #439 [suggested by maritz] + * Added authentication example + * Added basic Range support to `res.sendfile()` (and `res.download()` etc) + * Changed; `express(1)` generated app using 2 spaces instead of 4 + * Default env to "development" again [aheckmann] + * Removed _context_ option is no more, use "scope" + * Fixed; exposing _./support_ libs to examples so they can run without installs + * Fixed mvc example + +1.0.0rc3 / 2010-09-20 +================== + + * Added confirmation for `express(1)` app generation. Closes #391 + * Added extending of flash formatters via `app.flashFormatters` + * Added flash formatter support. Closes #411 + * Added streaming support to `res.sendfile()` using `sys.pump()` when >= "stream threshold" + * Added _stream threshold_ setting for `res.sendfile()` + * Added `res.send()` __HEAD__ support + * Added `res.clearCookie()` + * Added `res.cookie()` + * Added `res.render()` headers option + * Added `res.redirect()` response bodies + * Added `res.render()` status option support. Closes #425 [thanks aheckmann] + * Fixed `res.sendfile()` responding with 403 on malicious path + * Fixed `res.download()` bug; when an error occurs remove _Content-Disposition_ + * Fixed; mounted apps settings now inherit from parent app [aheckmann] + * Fixed; stripping Content-Length / Content-Type when 204 + * Fixed `res.send()` 204. Closes #419 + * Fixed multiple _Set-Cookie_ headers via `res.header()`. Closes #402 + * Fixed bug messing with error handlers when `listenFD()` is called instead of `listen()`. [thanks guillermo] + + +1.0.0rc2 / 2010-08-17 +================== + + * Added `app.register()` for template engine mapping. Closes #390 + * Added `res.render()` callback support as second argument (no options) + * Added callback support to `res.download()` + * Added callback support for `res.sendfile()` + * Added support for middleware access via `express.middlewareName()` vs `connect.middlewareName()` + * Added "partials" setting to docs + * Added default expresso tests to `express(1)` generated app. Closes #384 + * Fixed `res.sendfile()` error handling, defer via `next()` + * Fixed `res.render()` callback when a layout is used [thanks guillermo] + * Fixed; `make install` creating ~/.node_libraries when not present + * Fixed issue preventing error handlers from being defined anywhere. Closes #387 + +1.0.0rc / 2010-07-28 +================== + + * Added mounted hook. Closes #369 + * Added connect dependency to _package.json_ + + * Removed "reload views" setting and support code + development env never caches, production always caches. + + * Removed _param_ in route callbacks, signature is now + simply (req, res, next), previously (req, res, params, next). + Use _req.params_ for path captures, _req.query_ for GET params. + + * Fixed "home" setting + * Fixed middleware/router precedence issue. Closes #366 + * Fixed; _configure()_ callbacks called immediately. Closes #368 + +1.0.0beta2 / 2010-07-23 +================== + + * Added more examples + * Added; exporting `Server` constructor + * Added `Server#helpers()` for view locals + * Added `Server#dynamicHelpers()` for dynamic view locals. Closes #349 + * Added support for absolute view paths + * Added; _home_ setting defaults to `Server#route` for mounted apps. Closes #363 + * Added Guillermo Rauch to the contributor list + * Added support for "as" for non-collection partials. Closes #341 + * Fixed _install.sh_, ensuring _~/.node_libraries_ exists. Closes #362 [thanks jf] + * Fixed `res.render()` exceptions, now passed to `next()` when no callback is given [thanks guillermo] + * Fixed instanceof `Array` checks, now `Array.isArray()` + * Fixed express(1) expansion of public dirs. Closes #348 + * Fixed middleware precedence. Closes #345 + * Fixed view watcher, now async [thanks aheckmann] + +1.0.0beta / 2010-07-15 +================== + + * Re-write + - much faster + - much lighter + - Check [ExpressJS.com](http://expressjs.com) for migration guide and updated docs + +0.14.0 / 2010-06-15 +================== + + * Utilize relative requires + * Added Static bufferSize option [aheckmann] + * Fixed caching of view and partial subdirectories [aheckmann] + * Fixed mime.type() comments now that ".ext" is not supported + * Updated haml submodule + * Updated class submodule + * Removed bin/express + +0.13.0 / 2010-06-01 +================== + + * Added node v0.1.97 compatibility + * Added support for deleting cookies via Request#cookie('key', null) + * Updated haml submodule + * Fixed not-found page, now using using charset utf-8 + * Fixed show-exceptions page, now using using charset utf-8 + * Fixed view support due to fs.readFile Buffers + * Changed; mime.type() no longer accepts ".type" due to node extname() changes + +0.12.0 / 2010-05-22 +================== + + * Added node v0.1.96 compatibility + * Added view `helpers` export which act as additional local variables + * Updated haml submodule + * Changed ETag; removed inode, modified time only + * Fixed LF to CRLF for setting multiple cookies + * Fixed cookie complation; values are now urlencoded + * Fixed cookies parsing; accepts quoted values and url escaped cookies + +0.11.0 / 2010-05-06 +================== + + * Added support for layouts using different engines + - this.render('page.html.haml', { layout: 'super-cool-layout.html.ejs' }) + - this.render('page.html.haml', { layout: 'foo' }) // assumes 'foo.html.haml' + - this.render('page.html.haml', { layout: false }) // no layout + * Updated ext submodule + * Updated haml submodule + * Fixed EJS partial support by passing along the context. Issue #307 + +0.10.1 / 2010-05-03 +================== + + * Fixed binary uploads. + +0.10.0 / 2010-04-30 +================== + + * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s + encoding is set to 'utf8' or 'utf-8'. + * Added "encoding" option to Request#render(). Closes #299 + * Added "dump exceptions" setting, which is enabled by default. + * Added simple ejs template engine support + * Added error reponse support for text/plain, application/json. Closes #297 + * Added callback function param to Request#error() + * Added Request#sendHead() + * Added Request#stream() + * Added support for Request#respond(304, null) for empty response bodies + * Added ETag support to Request#sendfile() + * Added options to Request#sendfile(), passed to fs.createReadStream() + * Added filename arg to Request#download() + * Performance enhanced due to pre-reversing plugins so that plugins.reverse() is not called on each request + * Performance enhanced by preventing several calls to toLowerCase() in Router#match() + * Changed; Request#sendfile() now streams + * Changed; Renamed Request#halt() to Request#respond(). Closes #289 + * Changed; Using sys.inspect() instead of JSON.encode() for error output + * Changed; run() returns the http.Server instance. Closes #298 + * Changed; Defaulting Server#host to null (INADDR_ANY) + * Changed; Logger "common" format scale of 0.4f + * Removed Logger "request" format + * Fixed; Catching ENOENT in view caching, preventing error when "views/partials" is not found + * Fixed several issues with http client + * Fixed Logger Content-Length output + * Fixed bug preventing Opera from retaining the generated session id. Closes #292 + +0.9.0 / 2010-04-14 +================== + + * Added DSL level error() route support + * Added DSL level notFound() route support + * Added Request#error() + * Added Request#notFound() + * Added Request#render() callback function. Closes #258 + * Added "max upload size" setting + * Added "magic" variables to collection partials (\_\_index\_\_, \_\_length\_\_, \_\_isFirst\_\_, \_\_isLast\_\_). Closes #254 + * Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js + * Added callback function support to Request#halt() as 3rd/4th arg + * Added preprocessing of route param wildcards using param(). Closes #251 + * Added view partial support (with collections etc) + * Fixed bug preventing falsey params (such as ?page=0). Closes #286 + * Fixed setting of multiple cookies. Closes #199 + * Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml) + * Changed; session cookie is now httpOnly + * Changed; Request is no longer global + * Changed; Event is no longer global + * Changed; "sys" module is no longer global + * Changed; moved Request#download to Static plugin where it belongs + * Changed; Request instance created before body parsing. Closes #262 + * Changed; Pre-caching views in memory when "cache view contents" is enabled. Closes #253 + * Changed; Pre-caching view partials in memory when "cache view partials" is enabled + * Updated support to node --version 0.1.90 + * Updated dependencies + * Removed set("session cookie") in favour of use(Session, { cookie: { ... }}) + * Removed utils.mixin(); use Object#mergeDeep() + +0.8.0 / 2010-03-19 +================== + + * Added coffeescript example app. Closes #242 + * Changed; cache api now async friendly. Closes #240 + * Removed deprecated 'express/static' support. Use 'express/plugins/static' + +0.7.6 / 2010-03-19 +================== + + * Added Request#isXHR. Closes #229 + * Added `make install` (for the executable) + * Added `express` executable for setting up simple app templates + * Added "GET /public/*" to Static plugin, defaulting to /public + * Added Static plugin + * Fixed; Request#render() only calls cache.get() once + * Fixed; Namespacing View caches with "view:" + * Fixed; Namespacing Static caches with "static:" + * Fixed; Both example apps now use the Static plugin + * Fixed set("views"). Closes #239 + * Fixed missing space for combined log format + * Deprecated Request#sendfile() and 'express/static' + * Removed Server#running + +0.7.5 / 2010-03-16 +================== + + * Added Request#flash() support without args, now returns all flashes + * Updated ext submodule + +0.7.4 / 2010-03-16 +================== + + * Fixed session reaper + * Changed; class.js replacing js-oo Class implementation (quite a bit faster, no browser cruft) + +0.7.3 / 2010-03-16 +================== + + * Added package.json + * Fixed requiring of haml / sass due to kiwi removal + +0.7.2 / 2010-03-16 +================== + + * Fixed GIT submodules (HAH!) + +0.7.1 / 2010-03-16 +================== + + * Changed; Express now using submodules again until a PM is adopted + * Changed; chat example using millisecond conversions from ext + +0.7.0 / 2010-03-15 +================== + + * Added Request#pass() support (finds the next matching route, or the given path) + * Added Logger plugin (default "common" format replaces CommonLogger) + * Removed Profiler plugin + * Removed CommonLogger plugin + +0.6.0 / 2010-03-11 +================== + + * Added seed.yml for kiwi package management support + * Added HTTP client query string support when method is GET. Closes #205 + + * Added support for arbitrary view engines. + For example "foo.engine.html" will now require('engine'), + the exports from this module are cached after the first require(). + + * Added async plugin support + + * Removed usage of RESTful route funcs as http client + get() etc, use http.get() and friends + + * Removed custom exceptions + +0.5.0 / 2010-03-10 +================== + + * Added ext dependency (library of js extensions) + * Removed extname() / basename() utils. Use path module + * Removed toArray() util. Use arguments.values + * Removed escapeRegexp() util. Use RegExp.escape() + * Removed process.mixin() dependency. Use utils.mixin() + * Removed Collection + * Removed ElementCollection + * Shameless self promotion of ebook "Advanced JavaScript" (http://dev-mag.com) ;) + +0.4.0 / 2010-02-11 +================== + + * Added flash() example to sample upload app + * Added high level restful http client module (express/http) + * Changed; RESTful route functions double as HTTP clients. Closes #69 + * Changed; throwing error when routes are added at runtime + * Changed; defaulting render() context to the current Request. Closes #197 + * Updated haml submodule + +0.3.0 / 2010-02-11 +================== + + * Updated haml / sass submodules. Closes #200 + * Added flash message support. Closes #64 + * Added accepts() now allows multiple args. fixes #117 + * Added support for plugins to halt. Closes #189 + * Added alternate layout support. Closes #119 + * Removed Route#run(). Closes #188 + * Fixed broken specs due to use(Cookie) missing + +0.2.1 / 2010-02-05 +================== + + * Added "plot" format option for Profiler (for gnuplot processing) + * Added request number to Profiler plugin + * Fixed binary encoding for multi-part file uploads, was previously defaulting to UTF8 + * Fixed issue with routes not firing when not files are present. Closes #184 + * Fixed process.Promise -> events.Promise + +0.2.0 / 2010-02-03 +================== + + * Added parseParam() support for name[] etc. (allows for file inputs with "multiple" attr) Closes #180 + * Added Both Cache and Session option "reapInterval" may be "reapEvery". Closes #174 + * Added expiration support to cache api with reaper. Closes #133 + * Added cache Store.Memory#reap() + * Added Cache; cache api now uses first class Cache instances + * Added abstract session Store. Closes #172 + * Changed; cache Memory.Store#get() utilizing Collection + * Renamed MemoryStore -> Store.Memory + * Fixed use() of the same plugin several time will always use latest options. Closes #176 + +0.1.0 / 2010-02-03 +================== + + * Changed; Hooks (before / after) pass request as arg as well as evaluated in their context + * Updated node support to 0.1.27 Closes #169 + * Updated dirname(__filename) -> __dirname + * Updated libxmljs support to v0.2.0 + * Added session support with memory store / reaping + * Added quick uid() helper + * Added multi-part upload support + * Added Sass.js support / submodule + * Added production env caching view contents and static files + * Added static file caching. Closes #136 + * Added cache plugin with memory stores + * Added support to StaticFile so that it works with non-textual files. + * Removed dirname() helper + * Removed several globals (now their modules must be required) + +0.0.2 / 2010-01-10 +================== + + * Added view benchmarks; currently haml vs ejs + * Added Request#attachment() specs. Closes #116 + * Added use of node's parseQuery() util. Closes #123 + * Added `make init` for submodules + * Updated Haml + * Updated sample chat app to show messages on load + * Updated libxmljs parseString -> parseHtmlString + * Fixed `make init` to work with older versions of git + * Fixed specs can now run independant specs for those who cant build deps. Closes #127 + * Fixed issues introduced by the node url module changes. Closes 126. + * Fixed two assertions failing due to Collection#keys() returning strings + * Fixed faulty Collection#toArray() spec due to keys() returning strings + * Fixed `make test` now builds libxmljs.node before testing + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/LICENSE b/node_modules/express/LICENSE new file mode 100644 index 0000000..36075a3 --- /dev/null +++ b/node_modules/express/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2009-2011 TJ Holowaychuk + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/Makefile b/node_modules/express/Makefile new file mode 100644 index 0000000..228f299 --- /dev/null +++ b/node_modules/express/Makefile @@ -0,0 +1,33 @@ + +MOCHA_OPTS= --check-leaks +REPORTER = dot + +check: test + +test: test-unit test-acceptance + +test-unit: + @NODE_ENV=test ./node_modules/.bin/mocha \ + --reporter $(REPORTER) \ + $(MOCHA_OPTS) + +test-acceptance: + @NODE_ENV=test ./node_modules/.bin/mocha \ + --reporter $(REPORTER) \ + --bail \ + test/acceptance/*.js + +test-cov: lib-cov + @EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html + +lib-cov: + @jscoverage lib lib-cov + +benchmark: + @./support/bench + +clean: + rm -f coverage.html + rm -fr lib-cov + +.PHONY: test test-unit test-acceptance benchmark clean diff --git a/node_modules/express/Readme.md b/node_modules/express/Readme.md new file mode 100644 index 0000000..00158b8 --- /dev/null +++ b/node_modules/express/Readme.md @@ -0,0 +1,179 @@ +![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png) + + Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Dependency Status](https://gemnasium.com/visionmedia/express.png)](https://gemnasium.com/visionmedia/express) + +```js +var express = require('express'); +var app = express(); + +app.get('/', function(req, res){ + res.send('Hello World'); +}); + +app.listen(3000); +``` + +## Installation + + $ npm install -g express + +## Quick Start + + The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below: + + Create the app: + + $ npm install -g express + $ express /tmp/foo && cd /tmp/foo + + Install dependencies: + + $ npm install + + Start the server: + + $ node app + +## Features + + * Built on [Connect](http://github.com/senchalabs/connect) + * Robust routing + * HTTP helpers (redirection, caching, etc) + * View system supporting 14+ template engines + * Content negotiation + * Focus on high performance + * Environment based configuration + * Executable for generating applications quickly + * High test coverage + +## Philosophy + + The Express philosophy is to provide small, robust tooling for HTTP servers. Making + it a great solution for single page applications, web sites, hybrids, or public + HTTP APIs. + + Built on Connect you can use _only_ what you need, and nothing more, applications + can be as big or as small as you like, even a single file. Express does + not force you to use any specific ORM or template engine. With support for over + 14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js) + you can quickly craft your perfect framework. + +## More Information + + * Join #express on freenode + * [Google Group](http://groups.google.com/group/express-js) for discussion + * Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates + * Visit the [Wiki](http://github.com/visionmedia/express/wiki) + * [Русскоязычная документация](http://jsman.ru/express/) + * Run express examples [online](https://runnable.com/express) + +## Viewing Examples + +Clone the Express repo, then install the dev dependencies to install all the example / test suite deps: + + $ git clone git://github.com/visionmedia/express.git --depth 1 + $ cd express + $ npm install + +then run whichever tests you want: + + $ node examples/content-negotiation + +## Running Tests + +To run the test suite first invoke the following command within the repo, installing the development dependencies: + + $ npm install + +then run the tests: + + $ make test + +## Contributors + +``` +project: express +commits: 3559 +active : 468 days +files : 237 +authors: + 1891 Tj Holowaychuk 53.1% + 1285 visionmedia 36.1% + 182 TJ Holowaychuk 5.1% + 54 Aaron Heckmann 1.5% + 34 csausdev 1.0% + 26 ciaranj 0.7% + 21 Robert Sköld 0.6% + 6 Guillermo Rauch 0.2% + 3 Dav Glass 0.1% + 3 Nick Poulden 0.1% + 2 Randy Merrill 0.1% + 2 Benny Wong 0.1% + 2 Hunter Loftis 0.1% + 2 Jake Gordon 0.1% + 2 Brian McKinney 0.1% + 2 Roman Shtylman 0.1% + 2 Ben Weaver 0.1% + 2 Dave Hoover 0.1% + 2 Eivind Fjeldstad 0.1% + 2 Daniel Shaw 0.1% + 1 Matt Colyer 0.0% + 1 Pau Ramon 0.0% + 1 Pero Pejovic 0.0% + 1 Peter Rekdal Sunde 0.0% + 1 Raynos 0.0% + 1 Teng Siong Ong 0.0% + 1 Viktor Kelemen 0.0% + 1 ctide 0.0% + 1 8bitDesigner 0.0% + 1 isaacs 0.0% + 1 mgutz 0.0% + 1 pikeas 0.0% + 1 shuwatto 0.0% + 1 tstrimple 0.0% + 1 ewoudj 0.0% + 1 Adam Sanderson 0.0% + 1 Andrii Kostenko 0.0% + 1 Andy Hiew 0.0% + 1 Arpad Borsos 0.0% + 1 Ashwin Purohit 0.0% + 1 Benjen 0.0% + 1 Darren Torpey 0.0% + 1 Greg Ritter 0.0% + 1 Gregory Ritter 0.0% + 1 James Herdman 0.0% + 1 Jim Snodgrass 0.0% + 1 Joe McCann 0.0% + 1 Jonathan Dumaine 0.0% + 1 Jonathan Palardy 0.0% + 1 Jonathan Zacsh 0.0% + 1 Justin Lilly 0.0% + 1 Ken Sato 0.0% + 1 Maciej Małecki 0.0% + 1 Masahiro Hayashi 0.0% +``` + +## License + +(The MIT License) + +Copyright (c) 2009-2012 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/bin/express b/node_modules/express/bin/express new file mode 100755 index 0000000..b2b98c8 --- /dev/null +++ b/node_modules/express/bin/express @@ -0,0 +1,422 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var exec = require('child_process').exec + , program = require('commander') + , mkdirp = require('mkdirp') + , pkg = require('../package.json') + , version = pkg.version + , os = require('os') + , fs = require('fs'); + +// CLI + +program + .version(version) + .option('-s, --sessions', 'add session support') + .option('-e, --ejs', 'add ejs engine support (defaults to jade)') + .option('-J, --jshtml', 'add jshtml engine support (defaults to jade)') + .option('-H, --hogan', 'add hogan.js engine support') + .option('-c, --css ', 'add stylesheet support (less|stylus) (defaults to plain css)') + .option('-f, --force', 'force on non-empty directory') + .parse(process.argv); + +// Path + +var path = program.args.shift() || '.'; + +// end-of-line code + +var eol = os.EOL + +// Template engine + +program.template = 'jade'; +if (program.ejs) program.template = 'ejs'; +if (program.jshtml) program.template = 'jshtml'; +if (program.hogan) program.template = 'hjs'; + +/** + * Routes index template. + */ + +var index = [ + '' + , '/*' + , ' * GET home page.' + , ' */' + , '' + , 'exports.index = function(req, res){' + , ' res.render(\'index\', { title: \'Express\' });' + , '};' +].join(eol); + +/** + * Routes users template. + */ + +var users = [ + '' + , '/*' + , ' * GET users listing.' + , ' */' + , '' + , 'exports.list = function(req, res){' + , ' res.send("respond with a resource");' + , '};' +].join(eol); + +/** + * Jade layout template. + */ + +var jadeLayout = [ + 'doctype 5' + , 'html' + , ' head' + , ' title= title' + , ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')' + , ' body' + , ' block content' +].join(eol); + +/** + * Jade index template. + */ + +var jadeIndex = [ + 'extends layout' + , '' + , 'block content' + , ' h1= title' + , ' p Welcome to #{title}' +].join(eol); + +/** + * EJS index template. + */ + +var ejsIndex = [ + '' + , '' + , ' ' + , ' <%= title %>' + , ' ' + , ' ' + , ' ' + , '

<%= title %>

' + , '

Welcome to <%= title %>

' + , ' ' + , '' +].join(eol); + +/** + * JSHTML layout template. + */ + +var jshtmlLayout = [ + '' + , '' + , ' ' + , ' @write(title) ' + , ' ' + , ' ' + , ' ' + , ' @write(body)' + , ' ' + , '' +].join(eol); + +/** + * JSHTML index template. + */ + +var jshtmlIndex = [ + '

@write(title)

' + , '

Welcome to @write(title)

' +].join(eol); + +/** + * Hogan.js index template. + */ +var hoganIndex = [ + '' + , '' + , ' ' + , ' {{ title }}' + , ' ' + , ' ' + , ' ' + , '

{{ title }}

' + , '

Welcome to {{ title }}

' + , ' ' + , '' +].join(eol); + +/** + * Default css template. + */ + +var css = [ + 'body {' + , ' padding: 50px;' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;' + , '}' + , '' + , 'a {' + , ' color: #00B7FF;' + , '}' +].join(eol); + +/** + * Default less template. + */ + +var less = [ + 'body {' + , ' padding: 50px;' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;' + , '}' + , '' + , 'a {' + , ' color: #00B7FF;' + , '}' +].join(eol); + +/** + * Default stylus template. + */ + +var stylus = [ + 'body' + , ' padding: 50px' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif' + , 'a' + , ' color: #00B7FF' +].join(eol); + +/** + * App template. + */ + +var app = [ + '' + , '/**' + , ' * Module dependencies.' + , ' */' + , '' + , 'var express = require(\'express\')' + , ' , routes = require(\'./routes\')' + , ' , user = require(\'./routes/user\')' + , ' , http = require(\'http\')' + , ' , path = require(\'path\');' + , '' + , 'var app = express();' + , '' + , '// all environments' + , 'app.set(\'port\', process.env.PORT || 3000);' + , 'app.set(\'views\', __dirname + \'/views\');' + , 'app.set(\'view engine\', \':TEMPLATE\');' + , 'app.use(express.favicon());' + , 'app.use(express.logger(\'dev\'));' + , 'app.use(express.bodyParser());' + , 'app.use(express.methodOverride());{sess}' + , 'app.use(app.router);{css}' + , 'app.use(express.static(path.join(__dirname, \'public\')));' + , '' + , '// development only' + , 'if (\'development\' == app.get(\'env\')) {' + , ' app.use(express.errorHandler());' + , '}' + , '' + , 'app.get(\'/\', routes.index);' + , 'app.get(\'/users\', user.list);' + , '' + , 'http.createServer(app).listen(app.get(\'port\'), function(){' + , ' console.log(\'Express server listening on port \' + app.get(\'port\'));' + , '});' + , '' +].join(eol); + +// Generate application + +(function createApplication(path) { + emptyDirectory(path, function(empty){ + if (empty || program.force) { + createApplicationAt(path); + } else { + program.confirm('destination is not empty, continue? ', function(ok){ + if (ok) { + process.stdin.destroy(); + createApplicationAt(path); + } else { + abort('aborting'); + } + }); + } + }); +})(path); + +/** + * Create application at the given directory `path`. + * + * @param {String} path + */ + +function createApplicationAt(path) { + console.log(); + process.on('exit', function(){ + console.log(); + console.log(' install dependencies:'); + console.log(' $ cd %s && npm install', path); + console.log(); + console.log(' run the app:'); + console.log(' $ node app'); + console.log(); + }); + + mkdir(path, function(){ + mkdir(path + '/public'); + mkdir(path + '/public/javascripts'); + mkdir(path + '/public/images'); + mkdir(path + '/public/stylesheets', function(){ + switch (program.css) { + case 'less': + write(path + '/public/stylesheets/style.less', less); + break; + case 'stylus': + write(path + '/public/stylesheets/style.styl', stylus); + break; + default: + write(path + '/public/stylesheets/style.css', css); + } + }); + + mkdir(path + '/routes', function(){ + write(path + '/routes/index.js', index); + write(path + '/routes/user.js', users); + }); + + mkdir(path + '/views', function(){ + switch (program.template) { + case 'ejs': + write(path + '/views/index.ejs', ejsIndex); + break; + case 'jade': + write(path + '/views/layout.jade', jadeLayout); + write(path + '/views/index.jade', jadeIndex); + break; + case 'jshtml': + write(path + '/views/layout.jshtml', jshtmlLayout); + write(path + '/views/index.jshtml', jshtmlIndex); + break; + case 'hjs': + write(path + '/views/index.hjs', hoganIndex); + break; + + } + }); + + // CSS Engine support + switch (program.css) { + case 'less': + app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));'); + break; + case 'stylus': + app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(__dirname + \'/public\'));'); + break; + default: + app = app.replace('{css}', ''); + } + + // Session support + app = app.replace('{sess}', program.sessions + ? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());' + : ''); + + // Template support + app = app.replace(':TEMPLATE', program.template); + + // package.json + var pkg = { + name: 'application-name' + , version: '0.0.1' + , private: true + , scripts: { start: 'node app.js' } + , dependencies: { + express: version + } + } + + if (program.template) pkg.dependencies[program.template] = '*'; + + // CSS Engine support + switch (program.css) { + case 'less': + pkg.dependencies['less-middleware'] = '*'; + break; + default: + if (program.css) { + pkg.dependencies[program.css] = '*'; + } + } + + write(path + '/package.json', JSON.stringify(pkg, null, 2)); + write(path + '/app.js', app); + }); +} + +/** + * Check if the given directory `path` is empty. + * + * @param {String} path + * @param {Function} fn + */ + +function emptyDirectory(path, fn) { + fs.readdir(path, function(err, files){ + if (err && 'ENOENT' != err.code) throw err; + fn(!files || !files.length); + }); +} + +/** + * echo str > path. + * + * @param {String} path + * @param {String} str + */ + +function write(path, str) { + fs.writeFile(path, str); + console.log(' \x1b[36mcreate\x1b[0m : ' + path); +} + +/** + * Mkdir -p. + * + * @param {String} path + * @param {Function} fn + */ + +function mkdir(path, fn) { + mkdirp(path, 0755, function(err){ + if (err) throw err; + console.log(' \033[36mcreate\033[0m : ' + path); + fn && fn(); + }); +} + +/** + * Exit with the given `str`. + * + * @param {String} str + */ + +function abort(str) { + console.error(str); + process.exit(1); +} diff --git a/node_modules/express/index.js b/node_modules/express/index.js new file mode 100644 index 0000000..bfe9934 --- /dev/null +++ b/node_modules/express/index.js @@ -0,0 +1,4 @@ + +module.exports = process.env.EXPRESS_COV + ? require('./lib-cov/express') + : require('./lib/express'); \ No newline at end of file diff --git a/node_modules/express/lib/application.js b/node_modules/express/lib/application.js new file mode 100644 index 0000000..5500655 --- /dev/null +++ b/node_modules/express/lib/application.js @@ -0,0 +1,535 @@ +/** + * Module dependencies. + */ + +var connect = require('connect') + , Router = require('./router') + , methods = require('methods') + , middleware = require('./middleware') + , debug = require('debug')('express:application') + , locals = require('./utils').locals + , View = require('./view') + , utils = connect.utils + , path = require('path') + , http = require('http') + , join = path.join; + +/** + * Application prototype. + */ + +var app = exports = module.exports = {}; + +/** + * Initialize the server. + * + * - setup default configuration + * - setup default middleware + * - setup route reflection methods + * + * @api private + */ + +app.init = function(){ + this.cache = {}; + this.settings = {}; + this.engines = {}; + this.defaultConfiguration(); +}; + +/** + * Initialize application configuration. + * + * @api private + */ + +app.defaultConfiguration = function(){ + // default settings + this.enable('x-powered-by'); + this.set('env', process.env.NODE_ENV || 'development'); + this.set('subdomain offset', 2); + debug('booting in %s mode', this.get('env')); + + // implicit middleware + this.use(connect.query()); + this.use(middleware.init(this)); + + // inherit protos + this.on('mount', function(parent){ + this.request.__proto__ = parent.request; + this.response.__proto__ = parent.response; + this.engines.__proto__ = parent.engines; + this.settings.__proto__ = parent.settings; + }); + + // router + this._router = new Router(this); + this.routes = this._router.map; + this.__defineGetter__('router', function(){ + this._usedRouter = true; + this._router.caseSensitive = this.enabled('case sensitive routing'); + this._router.strict = this.enabled('strict routing'); + return this._router.middleware; + }); + + // setup locals + this.locals = locals(this); + + // default locals + this.locals.settings = this.settings; + + // default configuration + this.set('view', View); + this.set('views', process.cwd() + '/views'); + this.set('jsonp callback name', 'callback'); + + this.configure('development', function(){ + this.set('json spaces', 2); + }); + + this.configure('production', function(){ + this.enable('view cache'); + }); +}; + +/** + * Proxy `connect#use()` to apply settings to + * mounted applications. + * + * @param {String|Function|Server} route + * @param {Function|Server} fn + * @return {app} for chaining + * @api public + */ + +app.use = function(route, fn){ + var app; + + // default route to '/' + if ('string' != typeof route) fn = route, route = '/'; + + // express app + if (fn.handle && fn.set) app = fn; + + // restore .app property on req and res + if (app) { + app.route = route; + fn = function(req, res, next) { + var orig = req.app; + app.handle(req, res, function(err){ + req.__proto__ = orig.request; + res.__proto__ = orig.response; + next(err); + }); + }; + } + + connect.proto.use.call(this, route, fn); + + // mounted an app + if (app) { + app.parent = this; + app.emit('mount', this); + } + + return this; +}; + +/** + * Register the given template engine callback `fn` + * as `ext`. + * + * By default will `require()` the engine based on the + * file extension. For example if you try to render + * a "foo.jade" file Express will invoke the following internally: + * + * app.engine('jade', require('jade').__express); + * + * For engines that do not provide `.__express` out of the box, + * or if you wish to "map" a different extension to the template engine + * you may use this method. For example mapping the EJS template engine to + * ".html" files: + * + * app.engine('html', require('ejs').renderFile); + * + * In this case EJS provides a `.renderFile()` method with + * the same signature that Express expects: `(path, options, callback)`, + * though note that it aliases this method as `ejs.__express` internally + * so if you're using ".ejs" extensions you dont need to do anything. + * + * Some template engines do not follow this convention, the + * [Consolidate.js](https://github.com/visionmedia/consolidate.js) + * library was created to map all of node's popular template + * engines to follow this convention, thus allowing them to + * work seamlessly within Express. + * + * @param {String} ext + * @param {Function} fn + * @return {app} for chaining + * @api public + */ + +app.engine = function(ext, fn){ + if ('function' != typeof fn) throw new Error('callback function required'); + if ('.' != ext[0]) ext = '.' + ext; + this.engines[ext] = fn; + return this; +}; + +/** + * Map the given param placeholder `name`(s) to the given callback(s). + * + * Parameter mapping is used to provide pre-conditions to routes + * which use normalized placeholders. For example a _:user_id_ parameter + * could automatically load a user's information from the database without + * any additional code, + * + * The callback uses the samesignature as middleware, the only differencing + * being that the value of the placeholder is passed, in this case the _id_ + * of the user. Once the `next()` function is invoked, just like middleware + * it will continue on to execute the route, or subsequent parameter functions. + * + * app.param('user_id', function(req, res, next, id){ + * User.find(id, function(err, user){ + * if (err) { + * next(err); + * } else if (user) { + * req.user = user; + * next(); + * } else { + * next(new Error('failed to load user')); + * } + * }); + * }); + * + * @param {String|Array} name + * @param {Function} fn + * @return {app} for chaining + * @api public + */ + +app.param = function(name, fn){ + var self = this + , fns = [].slice.call(arguments, 1); + + // array + if (Array.isArray(name)) { + name.forEach(function(name){ + fns.forEach(function(fn){ + self.param(name, fn); + }); + }); + // param logic + } else if ('function' == typeof name) { + this._router.param(name); + // single + } else { + if (':' == name[0]) name = name.substr(1); + fns.forEach(function(fn){ + self._router.param(name, fn); + }); + } + + return this; +}; + +/** + * Assign `setting` to `val`, or return `setting`'s value. + * + * app.set('foo', 'bar'); + * app.get('foo'); + * // => "bar" + * + * Mounted servers inherit their parent server's settings. + * + * @param {String} setting + * @param {String} val + * @return {Server} for chaining + * @api public + */ + +app.set = function(setting, val){ + if (1 == arguments.length) { + return this.settings[setting]; + } else { + this.settings[setting] = val; + return this; + } +}; + +/** + * Return the app's absolute pathname + * based on the parent(s) that have + * mounted it. + * + * For example if the application was + * mounted as "/admin", which itself + * was mounted as "/blog" then the + * return value would be "/blog/admin". + * + * @return {String} + * @api private + */ + +app.path = function(){ + return this.parent + ? this.parent.path() + this.route + : ''; +}; + +/** + * Check if `setting` is enabled (truthy). + * + * app.enabled('foo') + * // => false + * + * app.enable('foo') + * app.enabled('foo') + * // => true + * + * @param {String} setting + * @return {Boolean} + * @api public + */ + +app.enabled = function(setting){ + return !!this.set(setting); +}; + +/** + * Check if `setting` is disabled. + * + * app.disabled('foo') + * // => true + * + * app.enable('foo') + * app.disabled('foo') + * // => false + * + * @param {String} setting + * @return {Boolean} + * @api public + */ + +app.disabled = function(setting){ + return !this.set(setting); +}; + +/** + * Enable `setting`. + * + * @param {String} setting + * @return {app} for chaining + * @api public + */ + +app.enable = function(setting){ + return this.set(setting, true); +}; + +/** + * Disable `setting`. + * + * @param {String} setting + * @return {app} for chaining + * @api public + */ + +app.disable = function(setting){ + return this.set(setting, false); +}; + +/** + * Configure callback for zero or more envs, + * when no `env` is specified that callback will + * be invoked for all environments. Any combination + * can be used multiple times, in any order desired. + * + * Examples: + * + * app.configure(function(){ + * // executed for all envs + * }); + * + * app.configure('stage', function(){ + * // executed staging env + * }); + * + * app.configure('stage', 'production', function(){ + * // executed for stage and production + * }); + * + * Note: + * + * These callbacks are invoked immediately, and + * are effectively sugar for the following: + * + * var env = process.env.NODE_ENV || 'development'; + * + * switch (env) { + * case 'development': + * ... + * break; + * case 'stage': + * ... + * break; + * case 'production': + * ... + * break; + * } + * + * @param {String} env... + * @param {Function} fn + * @return {app} for chaining + * @api public + */ + +app.configure = function(env, fn){ + var envs = 'all' + , args = [].slice.call(arguments); + fn = args.pop(); + if (args.length) envs = args; + if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this); + return this; +}; + +/** + * Delegate `.VERB(...)` calls to `router.VERB(...)`. + */ + +methods.forEach(function(method){ + app[method] = function(path){ + if ('get' == method && 1 == arguments.length) return this.set(path); + + // deprecated + if (Array.isArray(path)) { + console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0'); + } + + // if no router attached yet, attach the router + if (!this._usedRouter) this.use(this.router); + + // setup route + this._router[method].apply(this._router, arguments); + return this; + }; +}); + +/** + * Special-cased "all" method, applying the given route `path`, + * middleware, and callback to _every_ HTTP method. + * + * @param {String} path + * @param {Function} ... + * @return {app} for chaining + * @api public + */ + +app.all = function(path){ + var args = arguments; + methods.forEach(function(method){ + app[method].apply(this, args); + }, this); + return this; +}; + +// del -> delete alias + +app.del = app.delete; + +/** + * Render the given view `name` name with `options` + * and a callback accepting an error and the + * rendered template string. + * + * Example: + * + * app.render('email', { name: 'Tobi' }, function(err, html){ + * // ... + * }) + * + * @param {String} name + * @param {String|Function} options or fn + * @param {Function} fn + * @api public + */ + +app.render = function(name, options, fn){ + var opts = {} + , cache = this.cache + , engines = this.engines + , view; + + // support callback function as second arg + if ('function' == typeof options) { + fn = options, options = {}; + } + + // merge app.locals + utils.merge(opts, this.locals); + + // merge options._locals + if (options._locals) utils.merge(opts, options._locals); + + // merge options + utils.merge(opts, options); + + // set .cache unless explicitly provided + opts.cache = null == opts.cache + ? this.enabled('view cache') + : opts.cache; + + // primed cache + if (opts.cache) view = cache[name]; + + // view + if (!view) { + view = new (this.get('view'))(name, { + defaultEngine: this.get('view engine'), + root: this.get('views'), + engines: engines + }); + + if (!view.path) { + var err = new Error('Failed to lookup view "' + name + '"'); + err.view = view; + return fn(err); + } + + // prime the cache + if (opts.cache) cache[name] = view; + } + + // render + try { + view.render(opts, fn); + } catch (err) { + fn(err); + } +}; + +/** + * Listen for connections. + * + * A node `http.Server` is returned, with this + * application (which is a `Function`) as its + * callback. If you wish to create both an HTTP + * and HTTPS server you may do so with the "http" + * and "https" modules as shown here: + * + * var http = require('http') + * , https = require('https') + * , express = require('express') + * , app = express(); + * + * http.createServer(app).listen(80); + * https.createServer({ ... }, app).listen(443); + * + * @return {http.Server} + * @api public + */ + +app.listen = function(){ + var server = http.createServer(this); + return server.listen.apply(server, arguments); +}; diff --git a/node_modules/express/lib/express.js b/node_modules/express/lib/express.js new file mode 100644 index 0000000..c204849 --- /dev/null +++ b/node_modules/express/lib/express.js @@ -0,0 +1,86 @@ +/** + * Module dependencies. + */ + +var connect = require('connect') + , proto = require('./application') + , Route = require('./router/route') + , Router = require('./router') + , req = require('./request') + , res = require('./response') + , utils = connect.utils; + +/** + * Expose `createApplication()`. + */ + +exports = module.exports = createApplication; + +/** + * Expose mime. + */ + +exports.mime = connect.mime; + +/** + * Create an express application. + * + * @return {Function} + * @api public + */ + +function createApplication() { + var app = connect(); + utils.merge(app, proto); + app.request = { __proto__: req, app: app }; + app.response = { __proto__: res, app: app }; + app.init(); + return app; +} + +/** + * Expose connect.middleware as express.* + * for example `express.logger` etc. + */ + +for (var key in connect.middleware) { + Object.defineProperty( + exports + , key + , Object.getOwnPropertyDescriptor(connect.middleware, key)); +} + +/** + * Error on createServer(). + */ + +exports.createServer = function(){ + console.warn('Warning: express.createServer() is deprecated, express'); + console.warn('applications no longer inherit from http.Server,'); + console.warn('please use:'); + console.warn(''); + console.warn(' var express = require("express");'); + console.warn(' var app = express();'); + console.warn(''); + return createApplication(); +}; + +/** + * Expose the prototypes. + */ + +exports.application = proto; +exports.request = req; +exports.response = res; + +/** + * Expose constructors. + */ + +exports.Route = Route; +exports.Router = Router; + +// Error handler title + +exports.errorHandler.title = 'Express'; + diff --git a/node_modules/express/lib/middleware.js b/node_modules/express/lib/middleware.js new file mode 100644 index 0000000..e07dd4c --- /dev/null +++ b/node_modules/express/lib/middleware.js @@ -0,0 +1,32 @@ + +/** + * Module dependencies. + */ + +var utils = require('./utils'); + +/** + * Initialization middleware, exposing the + * request and response to eachother, as well + * as defaulting the X-Powered-By header field. + * + * @param {Function} app + * @return {Function} + * @api private + */ + +exports.init = function(app){ + return function expressInit(req, res, next){ + if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express'); + req.res = res; + res.req = req; + req.next = next; + + req.__proto__ = app.request; + res.__proto__ = app.response; + + res.locals = res.locals || utils.locals(res); + + next(); + } +}; diff --git a/node_modules/express/lib/request.js b/node_modules/express/lib/request.js new file mode 100644 index 0000000..6fc09ee --- /dev/null +++ b/node_modules/express/lib/request.js @@ -0,0 +1,526 @@ + +/** + * Module dependencies. + */ + +var http = require('http') + , utils = require('./utils') + , connect = require('connect') + , fresh = require('fresh') + , parseRange = require('range-parser') + , parse = connect.utils.parseUrl + , mime = connect.mime; + +/** + * Request prototype. + */ + +var req = exports = module.exports = { + __proto__: http.IncomingMessage.prototype +}; + +/** + * Return request header. + * + * The `Referrer` header field is special-cased, + * both `Referrer` and `Referer` are interchangeable. + * + * Examples: + * + * req.get('Content-Type'); + * // => "text/plain" + * + * req.get('content-type'); + * // => "text/plain" + * + * req.get('Something'); + * // => undefined + * + * Aliased as `req.header()`. + * + * @param {String} name + * @return {String} + * @api public + */ + +req.get = +req.header = function(name){ + switch (name = name.toLowerCase()) { + case 'referer': + case 'referrer': + return this.headers.referrer + || this.headers.referer; + default: + return this.headers[name]; + } +}; + +/** + * Check if the given `type(s)` is acceptable, returning + * the best match when true, otherwise `undefined`, in which + * case you should respond with 406 "Not Acceptable". + * + * The `type` value may be a single mime type string + * such as "application/json", the extension name + * such as "json", a comma-delimted list such as "json, html, text/plain", + * or an array `["json", "html", "text/plain"]`. When a list + * or array is given the _best_ match, if any is returned. + * + * Examples: + * + * // Accept: text/html + * req.accepts('html'); + * // => "html" + * + * // Accept: text/*, application/json + * req.accepts('html'); + * // => "html" + * req.accepts('text/html'); + * // => "text/html" + * req.accepts('json, text'); + * // => "json" + * req.accepts('application/json'); + * // => "application/json" + * + * // Accept: text/*, application/json + * req.accepts('image/png'); + * req.accepts('png'); + * // => undefined + * + * // Accept: text/*;q=.5, application/json + * req.accepts(['html', 'json']); + * req.accepts('html, json'); + * // => "json" + * + * @param {String|Array} type(s) + * @return {String} + * @api public + */ + +req.accepts = function(type){ + return utils.accepts(type, this.get('Accept')); +}; + +/** + * Check if the given `encoding` is accepted. + * + * @param {String} encoding + * @return {Boolean} + * @api public + */ + +req.acceptsEncoding = function(encoding){ + return !! ~this.acceptedEncodings.indexOf(encoding); +}; + +/** + * Check if the given `charset` is acceptable, + * otherwise you should respond with 406 "Not Acceptable". + * + * @param {String} charset + * @return {Boolean} + * @api public + */ + +req.acceptsCharset = function(charset){ + var accepted = this.acceptedCharsets; + return accepted.length + ? !! ~accepted.indexOf(charset) + : true; +}; + +/** + * Check if the given `lang` is acceptable, + * otherwise you should respond with 406 "Not Acceptable". + * + * @param {String} lang + * @return {Boolean} + * @api public + */ + +req.acceptsLanguage = function(lang){ + var accepted = this.acceptedLanguages; + return accepted.length + ? !! ~accepted.indexOf(lang) + : true; +}; + +/** + * Parse Range header field, + * capping to the given `size`. + * + * Unspecified ranges such as "0-" require + * knowledge of your resource length. In + * the case of a byte range this is of course + * the total number of bytes. If the Range + * header field is not given `null` is returned, + * `-1` when unsatisfiable, `-2` when syntactically invalid. + * + * NOTE: remember that ranges are inclusive, so + * for example "Range: users=0-3" should respond + * with 4 users when available, not 3. + * + * @param {Number} size + * @return {Array} + * @api public + */ + +req.range = function(size){ + var range = this.get('Range'); + if (!range) return; + return parseRange(size, range); +}; + +/** + * Return an array of encodings. + * + * Examples: + * + * ['gzip', 'deflate'] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('acceptedEncodings', function(){ + var accept = this.get('Accept-Encoding'); + return accept + ? accept.trim().split(/ *, */) + : []; +}); + +/** + * Return an array of Accepted media types + * ordered from highest quality to lowest. + * + * Examples: + * + * [ { value: 'application/json', + * quality: 1, + * type: 'application', + * subtype: 'json' }, + * { value: 'text/html', + * quality: 0.5, + * type: 'text', + * subtype: 'html' } ] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('accepted', function(){ + var accept = this.get('Accept'); + return accept + ? utils.parseAccept(accept) + : []; +}); + +/** + * Return an array of Accepted languages + * ordered from highest quality to lowest. + * + * Examples: + * + * Accept-Language: en;q=.5, en-us + * ['en-us', 'en'] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('acceptedLanguages', function(){ + var accept = this.get('Accept-Language'); + return accept + ? utils + .parseParams(accept) + .map(function(obj){ + return obj.value; + }) + : []; +}); + +/** + * Return an array of Accepted charsets + * ordered from highest quality to lowest. + * + * Examples: + * + * Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8 + * ['unicode-1-1', 'iso-8859-5'] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('acceptedCharsets', function(){ + var accept = this.get('Accept-Charset'); + return accept + ? utils + .parseParams(accept) + .map(function(obj){ + return obj.value; + }) + : []; +}); + +/** + * Return the value of param `name` when present or `defaultValue`. + * + * - Checks route placeholders, ex: _/user/:id_ + * - Checks body params, ex: id=12, {"id":12} + * - Checks query string params, ex: ?id=12 + * + * To utilize request bodies, `req.body` + * should be an object. This can be done by using + * the `connect.bodyParser()` middleware. + * + * @param {String} name + * @param {Mixed} [defaultValue] + * @return {String} + * @api public + */ + +req.param = function(name, defaultValue){ + var params = this.params || {}; + var body = this.body || {}; + var query = this.query || {}; + if (null != params[name] && params.hasOwnProperty(name)) return params[name]; + if (null != body[name]) return body[name]; + if (null != query[name]) return query[name]; + return defaultValue; +}; + +/** + * Check if the incoming request contains the "Content-Type" + * header field, and it contains the give mime `type`. + * + * Examples: + * + * // With Content-Type: text/html; charset=utf-8 + * req.is('html'); + * req.is('text/html'); + * req.is('text/*'); + * // => true + * + * // When Content-Type is application/json + * req.is('json'); + * req.is('application/json'); + * req.is('application/*'); + * // => true + * + * req.is('html'); + * // => false + * + * @param {String} type + * @return {Boolean} + * @api public + */ + +req.is = function(type){ + var ct = this.get('Content-Type'); + if (!ct) return false; + ct = ct.split(';')[0]; + if (!~type.indexOf('/')) type = mime.lookup(type); + if (~type.indexOf('*')) { + type = type.split('/'); + ct = ct.split('/'); + if ('*' == type[0] && type[1] == ct[1]) return true; + if ('*' == type[1] && type[0] == ct[0]) return true; + return false; + } + return !! ~ct.indexOf(type); +}; + +/** + * Return the protocol string "http" or "https" + * when requested with TLS. When the "trust proxy" + * setting is enabled the "X-Forwarded-Proto" header + * field will be trusted. If you're running behind + * a reverse proxy that supplies https for you this + * may be enabled. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('protocol', function(){ + var trustProxy = this.app.get('trust proxy'); + if (this.connection.encrypted) return 'https'; + if (!trustProxy) return 'http'; + var proto = this.get('X-Forwarded-Proto') || 'http'; + return proto.split(/\s*,\s*/)[0]; +}); + +/** + * Short-hand for: + * + * req.protocol == 'https' + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('secure', function(){ + return 'https' == this.protocol; +}); + +/** + * Return the remote address, or when + * "trust proxy" is `true` return + * the upstream addr. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('ip', function(){ + return this.ips[0] || this.connection.remoteAddress; +}); + +/** + * When "trust proxy" is `true`, parse + * the "X-Forwarded-For" ip address list. + * + * For example if the value were "client, proxy1, proxy2" + * you would receive the array `["client", "proxy1", "proxy2"]` + * where "proxy2" is the furthest down-stream. + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('ips', function(){ + var trustProxy = this.app.get('trust proxy'); + var val = this.get('X-Forwarded-For'); + return trustProxy && val + ? val.split(/ *, */) + : []; +}); + +/** + * Return basic auth credentials. + * + * Examples: + * + * // http://tobi:hello@example.com + * req.auth + * // => { username: 'tobi', password: 'hello' } + * + * @return {Object} or undefined + * @api public + */ + +req.__defineGetter__('auth', function(){ + // missing + var auth = this.get('Authorization'); + if (!auth) return; + + // malformed + var parts = auth.split(' '); + if ('basic' != parts[0].toLowerCase()) return; + if (!parts[1]) return; + auth = parts[1]; + + // credentials + auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/); + if (!auth) return; + return { username: auth[1], password: auth[2] }; +}); + +/** + * Return subdomains as an array. + * + * Subdomains are the dot-separated parts of the host before the main domain of + * the app. By default, the domain of the app is assumed to be the last two + * parts of the host. This can be changed by setting "subdomain offset". + * + * For example, if the domain is "tobi.ferrets.example.com": + * If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`. + * If "subdomain offset" is 3, req.subdomains is `["tobi"]`. + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('subdomains', function(){ + var offset = this.app.get('subdomain offset'); + return (this.host || '') + .split('.') + .reverse() + .slice(offset); +}); + +/** + * Short-hand for `url.parse(req.url).pathname`. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('path', function(){ + return parse(this).pathname; +}); + +/** + * Parse the "Host" header field hostname. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('host', function(){ + var trustProxy = this.app.get('trust proxy'); + var host = trustProxy && this.get('X-Forwarded-Host'); + host = host || this.get('Host'); + if (!host) return; + return host.split(':')[0]; +}); + +/** + * Check if the request is fresh, aka + * Last-Modified and/or the ETag + * still match. + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('fresh', function(){ + var method = this.method; + var s = this.res.statusCode; + + // GET or HEAD for weak freshness validation only + if ('GET' != method && 'HEAD' != method) return false; + + // 2xx or 304 as per rfc2616 14.26 + if ((s >= 200 && s < 300) || 304 == s) { + return fresh(this.headers, this.res._headers); + } + + return false; +}); + +/** + * Check if the request is stale, aka + * "Last-Modified" and / or the "ETag" for the + * resource has changed. + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('stale', function(){ + return !this.fresh; +}); + +/** + * Check if the request was an _XMLHttpRequest_. + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('xhr', function(){ + var val = this.get('X-Requested-With') || ''; + return 'xmlhttprequest' == val.toLowerCase(); +}); diff --git a/node_modules/express/lib/response.js b/node_modules/express/lib/response.js new file mode 100644 index 0000000..f6b7144 --- /dev/null +++ b/node_modules/express/lib/response.js @@ -0,0 +1,757 @@ +/** + * Module dependencies. + */ + +var http = require('http') + , path = require('path') + , connect = require('connect') + , utils = connect.utils + , sign = require('cookie-signature').sign + , normalizeType = require('./utils').normalizeType + , normalizeTypes = require('./utils').normalizeTypes + , etag = require('./utils').etag + , statusCodes = http.STATUS_CODES + , cookie = require('cookie') + , send = require('send') + , mime = connect.mime + , basename = path.basename + , extname = path.extname + , join = path.join; + +/** + * Response prototype. + */ + +var res = module.exports = { + __proto__: http.ServerResponse.prototype +}; + +/** + * Set status `code`. + * + * @param {Number} code + * @return {ServerResponse} + * @api public + */ + +res.status = function(code){ + this.statusCode = code; + return this; +}; + +/** + * Set Link header field with the given `links`. + * + * Examples: + * + * res.links({ + * next: 'http://api.example.com/users?page=2', + * last: 'http://api.example.com/users?page=5' + * }); + * + * @param {Object} links + * @return {ServerResponse} + * @api public + */ + +res.links = function(links){ + return this.set('Link', Object.keys(links).map(function(rel){ + return '<' + links[rel] + '>; rel="' + rel + '"'; + }).join(', ')); +}; + +/** + * Send a response. + * + * Examples: + * + * res.send(new Buffer('wahoo')); + * res.send({ some: 'json' }); + * res.send('

some html

'); + * res.send(404, 'Sorry, cant find that'); + * res.send(404); + * + * @param {Mixed} body or status + * @param {Mixed} body + * @return {ServerResponse} + * @api public + */ + +res.send = function(body){ + var req = this.req; + var head = 'HEAD' == req.method; + var len; + + // allow status / body + if (2 == arguments.length) { + // res.send(body, status) backwards compat + if ('number' != typeof body && 'number' == typeof arguments[1]) { + this.statusCode = arguments[1]; + } else { + this.statusCode = body; + body = arguments[1]; + } + } + + switch (typeof body) { + // response status + case 'number': + this.get('Content-Type') || this.type('txt'); + this.statusCode = body; + body = http.STATUS_CODES[body]; + break; + // string defaulting to html + case 'string': + if (!this.get('Content-Type')) { + this.charset = this.charset || 'utf-8'; + this.type('html'); + } + break; + case 'boolean': + case 'object': + if (null == body) { + body = ''; + } else if (Buffer.isBuffer(body)) { + this.get('Content-Type') || this.type('bin'); + } else { + return this.json(body); + } + break; + } + + // populate Content-Length + if (undefined !== body && !this.get('Content-Length')) { + this.set('Content-Length', len = Buffer.isBuffer(body) + ? body.length + : Buffer.byteLength(body)); + } + + // ETag support + // TODO: W/ support + if (len > 1024 && 'GET' == req.method) { + if (!this.get('ETag')) { + this.set('ETag', etag(body)); + } + } + + // freshness + if (req.fresh) this.statusCode = 304; + + // strip irrelevant headers + if (204 == this.statusCode || 304 == this.statusCode) { + this.removeHeader('Content-Type'); + this.removeHeader('Content-Length'); + this.removeHeader('Transfer-Encoding'); + body = ''; + } + + // respond + this.end(head ? null : body); + return this; +}; + +/** + * Send JSON response. + * + * Examples: + * + * res.json(null); + * res.json({ user: 'tj' }); + * res.json(500, 'oh noes!'); + * res.json(404, 'I dont have that'); + * + * @param {Mixed} obj or status + * @param {Mixed} obj + * @return {ServerResponse} + * @api public + */ + +res.json = function(obj){ + // allow status / body + if (2 == arguments.length) { + // res.json(body, status) backwards compat + if ('number' == typeof arguments[1]) { + this.statusCode = arguments[1]; + } else { + this.statusCode = obj; + obj = arguments[1]; + } + } + + // settings + var app = this.app; + var replacer = app.get('json replacer'); + var spaces = app.get('json spaces'); + var body = JSON.stringify(obj, replacer, spaces); + + // content-type + this.get('Content-Type') || this.set('Content-Type', 'application/json'); + + return this.send(body); +}; + +/** + * Send JSON response with JSONP callback support. + * + * Examples: + * + * res.jsonp(null); + * res.jsonp({ user: 'tj' }); + * res.jsonp(500, 'oh noes!'); + * res.jsonp(404, 'I dont have that'); + * + * @param {Mixed} obj or status + * @param {Mixed} obj + * @return {ServerResponse} + * @api public + */ + +res.jsonp = function(obj){ + // allow status / body + if (2 == arguments.length) { + // res.json(body, status) backwards compat + if ('number' == typeof arguments[1]) { + this.statusCode = arguments[1]; + } else { + this.statusCode = obj; + obj = arguments[1]; + } + } + + // settings + var app = this.app; + var replacer = app.get('json replacer'); + var spaces = app.get('json spaces'); + var body = JSON.stringify(obj, replacer, spaces) + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029'); + var callback = this.req.query[app.get('jsonp callback name')]; + + // content-type + this.charset = this.charset || 'utf-8'; + this.set('Content-Type', 'application/json'); + + // jsonp + if (callback) { + if (callback instanceof Array) callback = callback[0]; + this.set('Content-Type', 'text/javascript'); + var cb = callback.replace(/[^\[\]\w$.]/g, ''); + body = cb + ' && ' + cb + '(' + body + ');'; + } + + return this.send(body); +}; + +/** + * Transfer the file at the given `path`. + * + * Automatically sets the _Content-Type_ response header field. + * The callback `fn(err)` is invoked when the transfer is complete + * or when an error occurs. Be sure to check `res.sentHeader` + * if you wish to attempt responding, as the header and some data + * may have already been transferred. + * + * Options: + * + * - `maxAge` defaulting to 0 + * - `root` root directory for relative filenames + * + * Examples: + * + * The following example illustrates how `res.sendfile()` may + * be used as an alternative for the `static()` middleware for + * dynamic situations. The code backing `res.sendfile()` is actually + * the same code, so HTTP cache support etc is identical. + * + * app.get('/user/:uid/photos/:file', function(req, res){ + * var uid = req.params.uid + * , file = req.params.file; + * + * req.user.mayViewFilesFrom(uid, function(yes){ + * if (yes) { + * res.sendfile('/uploads/' + uid + '/' + file); + * } else { + * res.send(403, 'Sorry! you cant see that.'); + * } + * }); + * }); + * + * @param {String} path + * @param {Object|Function} options or fn + * @param {Function} fn + * @api public + */ + +res.sendfile = function(path, options, fn){ + var self = this + , req = self.req + , next = this.req.next + , options = options || {} + , done; + + // support function as second arg + if ('function' == typeof options) { + fn = options; + options = {}; + } + + // socket errors + req.socket.on('error', error); + + // errors + function error(err) { + if (done) return; + done = true; + + // clean up + cleanup(); + if (!self.headerSent) self.removeHeader('Content-Disposition'); + + // callback available + if (fn) return fn(err); + + // list in limbo if there's no callback + if (self.headerSent) return; + + // delegate + next(err); + } + + // streaming + function stream() { + if (done) return; + cleanup(); + if (fn) self.on('finish', fn); + } + + // cleanup + function cleanup() { + req.socket.removeListener('error', error); + } + + // transfer + var file = send(req, path); + if (options.root) file.root(options.root); + file.maxage(options.maxAge || 0); + file.on('error', error); + file.on('directory', next); + file.on('stream', stream); + file.pipe(this); + this.on('finish', cleanup); +}; + +/** + * Transfer the file at the given `path` as an attachment. + * + * Optionally providing an alternate attachment `filename`, + * and optional callback `fn(err)`. The callback is invoked + * when the data transfer is complete, or when an error has + * ocurred. Be sure to check `res.headerSent` if you plan to respond. + * + * This method uses `res.sendfile()`. + * + * @param {String} path + * @param {String|Function} filename or fn + * @param {Function} fn + * @api public + */ + +res.download = function(path, filename, fn){ + // support function as second arg + if ('function' == typeof filename) { + fn = filename; + filename = null; + } + + filename = filename || path; + this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"'); + return this.sendfile(path, fn); +}; + +/** + * Set _Content-Type_ response header with `type` through `mime.lookup()` + * when it does not contain "/", or set the Content-Type to `type` otherwise. + * + * Examples: + * + * res.type('.html'); + * res.type('html'); + * res.type('json'); + * res.type('application/json'); + * res.type('png'); + * + * @param {String} type + * @return {ServerResponse} for chaining + * @api public + */ + +res.contentType = +res.type = function(type){ + return this.set('Content-Type', ~type.indexOf('/') + ? type + : mime.lookup(type)); +}; + +/** + * Respond to the Acceptable formats using an `obj` + * of mime-type callbacks. + * + * This method uses `req.accepted`, an array of + * acceptable types ordered by their quality values. + * When "Accept" is not present the _first_ callback + * is invoked, otherwise the first match is used. When + * no match is performed the server responds with + * 406 "Not Acceptable". + * + * Content-Type is set for you, however if you choose + * you may alter this within the callback using `res.type()` + * or `res.set('Content-Type', ...)`. + * + * res.format({ + * 'text/plain': function(){ + * res.send('hey'); + * }, + * + * 'text/html': function(){ + * res.send('

hey

'); + * }, + * + * 'appliation/json': function(){ + * res.send({ message: 'hey' }); + * } + * }); + * + * In addition to canonicalized MIME types you may + * also use extnames mapped to these types: + * + * res.format({ + * text: function(){ + * res.send('hey'); + * }, + * + * html: function(){ + * res.send('

hey

'); + * }, + * + * json: function(){ + * res.send({ message: 'hey' }); + * } + * }); + * + * By default Express passes an `Error` + * with a `.status` of 406 to `next(err)` + * if a match is not made. If you provide + * a `.default` callback it will be invoked + * instead. + * + * @param {Object} obj + * @return {ServerResponse} for chaining + * @api public + */ + +res.format = function(obj){ + var req = this.req + , next = req.next; + + var fn = obj.default; + if (fn) delete obj.default; + var keys = Object.keys(obj); + + var key = req.accepts(keys); + + this.set('Vary', 'Accept'); + + if (key) { + this.set('Content-Type', normalizeType(key).value); + obj[key](req, this, next); + } else if (fn) { + fn(); + } else { + var err = new Error('Not Acceptable'); + err.status = 406; + err.types = normalizeTypes(keys).map(function(o){ return o.value }); + next(err); + } + + return this; +}; + +/** + * Set _Content-Disposition_ header to _attachment_ with optional `filename`. + * + * @param {String} filename + * @return {ServerResponse} + * @api public + */ + +res.attachment = function(filename){ + if (filename) this.type(extname(filename)); + this.set('Content-Disposition', filename + ? 'attachment; filename="' + basename(filename) + '"' + : 'attachment'); + return this; +}; + +/** + * Set header `field` to `val`, or pass + * an object of header fields. + * + * Examples: + * + * res.set('Foo', ['bar', 'baz']); + * res.set('Accept', 'application/json'); + * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); + * + * Aliased as `res.header()`. + * + * @param {String|Object|Array} field + * @param {String} val + * @return {ServerResponse} for chaining + * @api public + */ + +res.set = +res.header = function(field, val){ + if (2 == arguments.length) { + if (Array.isArray(val)) val = val.map(String); + else val = String(val); + this.setHeader(field, val); + } else { + for (var key in field) { + this.set(key, field[key]); + } + } + return this; +}; + +/** + * Get value for header `field`. + * + * @param {String} field + * @return {String} + * @api public + */ + +res.get = function(field){ + return this.getHeader(field); +}; + +/** + * Clear cookie `name`. + * + * @param {String} name + * @param {Object} options + * @param {ServerResponse} for chaining + * @api public + */ + +res.clearCookie = function(name, options){ + var opts = { expires: new Date(1), path: '/' }; + return this.cookie(name, '', options + ? utils.merge(opts, options) + : opts); +}; + +/** + * Set cookie `name` to `val`, with the given `options`. + * + * Options: + * + * - `maxAge` max-age in milliseconds, converted to `expires` + * - `signed` sign the cookie + * - `path` defaults to "/" + * + * Examples: + * + * // "Remember Me" for 15 minutes + * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); + * + * // save as above + * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) + * + * @param {String} name + * @param {String|Object} val + * @param {Options} options + * @api public + */ + +res.cookie = function(name, val, options){ + options = utils.merge({}, options); + var secret = this.req.secret; + var signed = options.signed; + if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies'); + if ('number' == typeof val) val = val.toString(); + if ('object' == typeof val) val = 'j:' + JSON.stringify(val); + if (signed) val = 's:' + sign(val, secret); + if ('maxAge' in options) { + options.expires = new Date(Date.now() + options.maxAge); + options.maxAge /= 1000; + } + if (null == options.path) options.path = '/'; + this.set('Set-Cookie', cookie.serialize(name, String(val), options)); + return this; +}; + + +/** + * Set the location header to `url`. + * + * The given `url` can also be the name of a mapped url, for + * example by default express supports "back" which redirects + * to the _Referrer_ or _Referer_ headers or "/". + * + * Examples: + * + * res.location('/foo/bar').; + * res.location('http://example.com'); + * res.location('../login'); // /blog/post/1 -> /blog/login + * + * Mounting: + * + * When an application is mounted and `res.location()` + * is given a path that does _not_ lead with "/" it becomes + * relative to the mount-point. For example if the application + * is mounted at "/blog", the following would become "/blog/login". + * + * res.location('login'); + * + * While the leading slash would result in a location of "/login": + * + * res.location('/login'); + * + * @param {String} url + * @api public + */ + +res.location = function(url){ + var app = this.app + , req = this.req; + + // setup redirect map + var map = { back: req.get('Referrer') || '/' }; + + // perform redirect + url = map[url] || url; + + // relative + if (!~url.indexOf('://') && 0 != url.indexOf('//')) { + var path + + // relative to path + if ('.' == url[0]) { + path = req.originalUrl.split('?')[0] + url = path + ('/' == path[path.length - 1] ? '' : '/') + url; + // relative to mount-point + } else if ('/' != url[0]) { + path = app.path(); + url = path + '/' + url; + } + } + + // Respond + this.set('Location', url); + return this; +}; + +/** + * Redirect to the given `url` with optional response `status` + * defaulting to 302. + * + * The resulting `url` is determined by `res.location()`, so + * it will play nicely with mounted apps, relative paths, + * `"back"` etc. + * + * Examples: + * + * res.redirect('/foo/bar'); + * res.redirect('http://example.com'); + * res.redirect(301, 'http://example.com'); + * res.redirect('http://example.com', 301); + * res.redirect('../login'); // /blog/post/1 -> /blog/login + * + * @param {String} url + * @param {Number} code + * @api public + */ + +res.redirect = function(url){ + var app = this.app + , head = 'HEAD' == this.req.method + , status = 302 + , body; + + // allow status / url + if (2 == arguments.length) { + if ('number' == typeof url) { + status = url; + url = arguments[1]; + } else { + status = arguments[1]; + } + } + + // Set location header + this.location(url); + url = this.get('Location'); + + // Support text/{plain,html} by default + this.format({ + text: function(){ + body = statusCodes[status] + '. Redirecting to ' + encodeURI(url); + }, + + html: function(){ + var u = utils.escape(url); + body = '

' + statusCodes[status] + '. Redirecting to ' + u + '

'; + }, + + default: function(){ + body = ''; + } + }); + + // Respond + this.statusCode = status; + this.set('Content-Length', Buffer.byteLength(body)); + this.end(head ? null : body); +}; + +/** + * Render `view` with the given `options` and optional callback `fn`. + * When a callback function is given a response will _not_ be made + * automatically, otherwise a response of _200_ and _text/html_ is given. + * + * Options: + * + * - `cache` boolean hinting to the engine it should cache + * - `filename` filename of the view being rendered + * + * @param {String} view + * @param {Object|Function} options or callback function + * @param {Function} fn + * @api public + */ + +res.render = function(view, options, fn){ + var self = this + , options = options || {} + , req = this.req + , app = req.app; + + // support callback function as second arg + if ('function' == typeof options) { + fn = options, options = {}; + } + + // merge res.locals + options._locals = self.locals; + + // default callback to respond + fn = fn || function(err, str){ + if (err) return req.next(err); + self.send(str); + }; + + // render + app.render(view, options, fn); +}; diff --git a/node_modules/express/lib/router/index.js b/node_modules/express/lib/router/index.js new file mode 100644 index 0000000..662dc29 --- /dev/null +++ b/node_modules/express/lib/router/index.js @@ -0,0 +1,273 @@ +/** + * Module dependencies. + */ + +var Route = require('./route') + , utils = require('../utils') + , methods = require('methods') + , debug = require('debug')('express:router') + , parse = require('connect').utils.parseUrl; + +/** + * Expose `Router` constructor. + */ + +exports = module.exports = Router; + +/** + * Initialize a new `Router` with the given `options`. + * + * @param {Object} options + * @api private + */ + +function Router(options) { + options = options || {}; + var self = this; + this.map = {}; + this.params = {}; + this._params = []; + this.caseSensitive = options.caseSensitive; + this.strict = options.strict; + this.middleware = function router(req, res, next){ + self._dispatch(req, res, next); + }; +} + +/** + * Register a param callback `fn` for the given `name`. + * + * @param {String|Function} name + * @param {Function} fn + * @return {Router} for chaining + * @api public + */ + +Router.prototype.param = function(name, fn){ + // param logic + if ('function' == typeof name) { + this._params.push(name); + return; + } + + // apply param functions + var params = this._params + , len = params.length + , ret; + + for (var i = 0; i < len; ++i) { + if (ret = params[i](name, fn)) { + fn = ret; + } + } + + // ensure we end up with a + // middleware function + if ('function' != typeof fn) { + throw new Error('invalid param() call for ' + name + ', got ' + fn); + } + + (this.params[name] = this.params[name] || []).push(fn); + return this; +}; + +/** + * Route dispatcher aka the route "middleware". + * + * @param {IncomingMessage} req + * @param {ServerResponse} res + * @param {Function} next + * @api private + */ + +Router.prototype._dispatch = function(req, res, next){ + var params = this.params + , self = this; + + debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl); + + // route dispatch + (function pass(i, err){ + var paramCallbacks + , paramIndex = 0 + , paramVal + , route + , keys + , key; + + // match next route + function nextRoute(err) { + pass(req._route_index + 1, err); + } + + // match route + req.route = route = self.matchRequest(req, i); + + // no route + if (!route) return next(err); + debug('matched %s %s', route.method, route.path); + + // we have a route + // start at param 0 + req.params = route.params; + keys = route.keys; + i = 0; + + // param callbacks + function param(err) { + paramIndex = 0; + key = keys[i++]; + paramVal = key && req.params[key.name]; + paramCallbacks = key && params[key.name]; + + try { + if ('route' == err) { + nextRoute(); + } else if (err) { + i = 0; + callbacks(err); + } else if (paramCallbacks && undefined !== paramVal) { + paramCallback(); + } else if (key) { + param(); + } else { + i = 0; + callbacks(); + } + } catch (err) { + param(err); + } + }; + + param(err); + + // single param callbacks + function paramCallback(err) { + var fn = paramCallbacks[paramIndex++]; + if (err || !fn) return param(err); + fn(req, res, paramCallback, paramVal, key.name); + } + + // invoke route callbacks + function callbacks(err) { + var fn = route.callbacks[i++]; + try { + if ('route' == err) { + nextRoute(); + } else if (err && fn) { + if (fn.length < 4) return callbacks(err); + fn(err, req, res, callbacks); + } else if (fn) { + if (fn.length < 4) return fn(req, res, callbacks); + callbacks(); + } else { + nextRoute(err); + } + } catch (err) { + callbacks(err); + } + } + })(0); +}; + +/** + * Attempt to match a route for `req` + * with optional starting index of `i` + * defaulting to 0. + * + * @param {IncomingMessage} req + * @param {Number} i + * @return {Route} + * @api private + */ + +Router.prototype.matchRequest = function(req, i, head){ + var method = req.method.toLowerCase() + , url = parse(req) + , path = url.pathname + , routes = this.map + , i = i || 0 + , route; + + // HEAD support + if (!head && 'head' == method) { + route = this.matchRequest(req, i, true); + if (route) return route; + method = 'get'; + } + + // routes for this method + if (routes = routes[method]) { + + // matching routes + for (var len = routes.length; i < len; ++i) { + route = routes[i]; + if (route.match(path)) { + req._route_index = i; + return route; + } + } + } +}; + +/** + * Attempt to match a route for `method` + * and `url` with optional starting + * index of `i` defaulting to 0. + * + * @param {String} method + * @param {String} url + * @param {Number} i + * @return {Route} + * @api private + */ + +Router.prototype.match = function(method, url, i, head){ + var req = { method: method, url: url }; + return this.matchRequest(req, i, head); +}; + +/** + * Route `method`, `path`, and one or more callbacks. + * + * @param {String} method + * @param {String} path + * @param {Function} callback... + * @return {Router} for chaining + * @api private + */ + +Router.prototype.route = function(method, path, callbacks){ + var method = method.toLowerCase() + , callbacks = utils.flatten([].slice.call(arguments, 2)); + + // ensure path was given + if (!path) throw new Error('Router#' + method + '() requires a path'); + + // ensure all callbacks are functions + callbacks.forEach(function(fn, i){ + if ('function' == typeof fn) return; + var type = {}.toString.call(fn); + var msg = '.' + method + '() requires callback functions but got a ' + type; + throw new Error(msg); + }); + + // create the route + debug('defined %s %s', method, path); + var route = new Route(method, path, callbacks, { + sensitive: this.caseSensitive, + strict: this.strict + }); + + // add it + (this.map[method] = this.map[method] || []).push(route); + return this; +}; + +methods.forEach(function(method){ + Router.prototype[method] = function(path){ + var args = [method].concat([].slice.call(arguments)); + this.route.apply(this, args); + return this; + }; +}); diff --git a/node_modules/express/lib/router/route.js b/node_modules/express/lib/router/route.js new file mode 100644 index 0000000..c1a0b5e --- /dev/null +++ b/node_modules/express/lib/router/route.js @@ -0,0 +1,72 @@ + +/** + * Module dependencies. + */ + +var utils = require('../utils'); + +/** + * Expose `Route`. + */ + +module.exports = Route; + +/** + * Initialize `Route` with the given HTTP `method`, `path`, + * and an array of `callbacks` and `options`. + * + * Options: + * + * - `sensitive` enable case-sensitive routes + * - `strict` enable strict matching for trailing slashes + * + * @param {String} method + * @param {String} path + * @param {Array} callbacks + * @param {Object} options. + * @api private + */ + +function Route(method, path, callbacks, options) { + options = options || {}; + this.path = path; + this.method = method; + this.callbacks = callbacks; + this.regexp = utils.pathRegexp(path + , this.keys = [] + , options.sensitive + , options.strict); +} + +/** + * Check if this route matches `path`, if so + * populate `.params`. + * + * @param {String} path + * @return {Boolean} + * @api private + */ + +Route.prototype.match = function(path){ + var keys = this.keys + , params = this.params = [] + , m = this.regexp.exec(path); + + if (!m) return false; + + for (var i = 1, len = m.length; i < len; ++i) { + var key = keys[i - 1]; + + var val = 'string' == typeof m[i] + ? decodeURIComponent(m[i]) + : m[i]; + + if (key) { + params[key.name] = val; + } else { + params.push(val); + } + } + + return true; +}; diff --git a/node_modules/express/lib/utils.js b/node_modules/express/lib/utils.js new file mode 100644 index 0000000..fd245a8 --- /dev/null +++ b/node_modules/express/lib/utils.js @@ -0,0 +1,313 @@ + +/** + * Module dependencies. + */ + +var mime = require('connect').mime + , crc32 = require('buffer-crc32'); + +/** + * toString ref. + */ + +var toString = {}.toString; + +/** + * Return ETag for `body`. + * + * @param {String|Buffer} body + * @return {String} + * @api private + */ + +exports.etag = function(body){ + return '"' + crc32.signed(body) + '"'; +}; + +/** + * Make `locals()` bound to the given `obj`. + * + * This is used for `app.locals` and `res.locals`. + * + * @param {Object} obj + * @return {Function} + * @api private + */ + +exports.locals = function(obj){ + function locals(obj){ + for (var key in obj) locals[key] = obj[key]; + return obj; + }; + + return locals; +}; + +/** + * Check if `path` looks absolute. + * + * @param {String} path + * @return {Boolean} + * @api private + */ + +exports.isAbsolute = function(path){ + if ('/' == path[0]) return true; + if (':' == path[1] && '\\' == path[2]) return true; +}; + +/** + * Flatten the given `arr`. + * + * @param {Array} arr + * @return {Array} + * @api private + */ + +exports.flatten = function(arr, ret){ + var ret = ret || [] + , len = arr.length; + for (var i = 0; i < len; ++i) { + if (Array.isArray(arr[i])) { + exports.flatten(arr[i], ret); + } else { + ret.push(arr[i]); + } + } + return ret; +}; + +/** + * Normalize the given `type`, for example "html" becomes "text/html". + * + * @param {String} type + * @return {Object} + * @api private + */ + +exports.normalizeType = function(type){ + return ~type.indexOf('/') + ? acceptParams(type) + : { value: mime.lookup(type), params: {} }; +}; + +/** + * Normalize `types`, for example "html" becomes "text/html". + * + * @param {Array} types + * @return {Array} + * @api private + */ + +exports.normalizeTypes = function(types){ + var ret = []; + + for (var i = 0; i < types.length; ++i) { + ret.push(exports.normalizeType(types[i])); + } + + return ret; +}; + +/** + * Return the acceptable type in `types`, if any. + * + * @param {Array} types + * @param {String} str + * @return {String} + * @api private + */ + +exports.acceptsArray = function(types, str){ + // accept anything when Accept is not present + if (!str) return types[0]; + + // parse + var accepted = exports.parseAccept(str) + , normalized = exports.normalizeTypes(types) + , len = accepted.length; + + for (var i = 0; i < len; ++i) { + for (var j = 0, jlen = types.length; j < jlen; ++j) { + if (exports.accept(normalized[j], accepted[i])) { + return types[j]; + } + } + } +}; + +/** + * Check if `type(s)` are acceptable based on + * the given `str`. + * + * @param {String|Array} type(s) + * @param {String} str + * @return {Boolean|String} + * @api private + */ + +exports.accepts = function(type, str){ + if ('string' == typeof type) type = type.split(/ *, */); + return exports.acceptsArray(type, str); +}; + +/** + * Check if `type` array is acceptable for `other`. + * + * @param {Object} type + * @param {Object} other + * @return {Boolean} + * @api private + */ + +exports.accept = function(type, other){ + var t = type.value.split('/'); + return (t[0] == other.type || '*' == other.type) + && (t[1] == other.subtype || '*' == other.subtype) + && paramsEqual(type.params, other.params); +}; + +/** + * Check if accept params are equal. + * + * @param {Object} a + * @param {Object} b + * @return {Boolean} + * @api private + */ + +function paramsEqual(a, b){ + return !Object.keys(a).some(function(k) { + return a[k] != b[k]; + }); +} + +/** + * Parse accept `str`, returning + * an array objects containing + * `.type` and `.subtype` along + * with the values provided by + * `parseQuality()`. + * + * @param {Type} name + * @return {Type} + * @api private + */ + +exports.parseAccept = function(str){ + return exports + .parseParams(str) + .map(function(obj){ + var parts = obj.value.split('/'); + obj.type = parts[0]; + obj.subtype = parts[1]; + return obj; + }); +}; + +/** + * Parse quality `str`, returning an + * array of objects with `.value`, + * `.quality` and optional `.params` + * + * @param {String} str + * @return {Array} + * @api private + */ + +exports.parseParams = function(str){ + return str + .split(/ *, */) + .map(acceptParams) + .filter(function(obj){ + return obj.quality; + }) + .sort(function(a, b){ + if (a.quality === b.quality) { + return a.originalIndex - b.originalIndex; + } else { + return b.quality - a.quality; + } + }); +}; + +/** + * Parse accept params `str` returning an + * object with `.value`, `.quality` and `.params`. + * also includes `.originalIndex` for stable sorting + * + * @param {String} str + * @return {Object} + * @api private + */ + +function acceptParams(str, index) { + var parts = str.split(/ *; */); + var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index }; + + for (var i = 1; i < parts.length; ++i) { + var pms = parts[i].split(/ *= */); + if ('q' == pms[0]) { + ret.quality = parseFloat(pms[1]); + } else { + ret.params[pms[0]] = pms[1]; + } + } + + return ret; +} + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html) { + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +}; + +/** + * Normalize the given path string, + * returning a regular expression. + * + * An empty array should be passed, + * which will contain the placeholder + * key names. For example "/user/:id" will + * then contain ["id"]. + * + * @param {String|RegExp|Array} path + * @param {Array} keys + * @param {Boolean} sensitive + * @param {Boolean} strict + * @return {RegExp} + * @api private + */ + +exports.pathRegexp = function(path, keys, sensitive, strict) { + if (toString.call(path) == '[object RegExp]') return path; + if (Array.isArray(path)) path = '(' + path.join('|') + ')'; + path = path + .concat(strict ? '' : '/?') + .replace(/\/\(/g, '(?:/') + .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){ + keys.push({ name: key, optional: !! optional }); + slash = slash || ''; + return '' + + (optional ? '' : slash) + + '(?:' + + (optional ? slash : '') + + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' + + (optional || '') + + (star ? '(/*)?' : ''); + }) + .replace(/([\/.])/g, '\\$1') + .replace(/\*/g, '(.*)'); + return new RegExp('^' + path + '$', sensitive ? '' : 'i'); +} diff --git a/node_modules/express/lib/view.js b/node_modules/express/lib/view.js new file mode 100644 index 0000000..b9dc69e --- /dev/null +++ b/node_modules/express/lib/view.js @@ -0,0 +1,77 @@ +/** + * Module dependencies. + */ + +var path = require('path') + , fs = require('fs') + , utils = require('./utils') + , dirname = path.dirname + , basename = path.basename + , extname = path.extname + , exists = fs.existsSync || path.existsSync + , join = path.join; + +/** + * Expose `View`. + */ + +module.exports = View; + +/** + * Initialize a new `View` with the given `name`. + * + * Options: + * + * - `defaultEngine` the default template engine name + * - `engines` template engine require() cache + * - `root` root path for view lookup + * + * @param {String} name + * @param {Object} options + * @api private + */ + +function View(name, options) { + options = options || {}; + this.name = name; + this.root = options.root; + var engines = options.engines; + this.defaultEngine = options.defaultEngine; + var ext = this.ext = extname(name); + if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.'); + if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine); + this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express); + this.path = this.lookup(name); +} + +/** + * Lookup view by the given `path` + * + * @param {String} path + * @return {String} + * @api private + */ + +View.prototype.lookup = function(path){ + var ext = this.ext; + + // . + if (!utils.isAbsolute(path)) path = join(this.root, path); + if (exists(path)) return path; + + // /index. + path = join(dirname(path), basename(path, ext), 'index' + ext); + if (exists(path)) return path; +}; + +/** + * Render with the given `options` and callback `fn(err, str)`. + * + * @param {Object} options + * @param {Function} fn + * @api private + */ + +View.prototype.render = function(options, fn){ + this.engine(this.path, options, fn); +}; diff --git a/node_modules/express/node_modules/buffer-crc32/.npmignore b/node_modules/express/node_modules/buffer-crc32/.npmignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/.npmignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/node_modules/express/node_modules/buffer-crc32/.travis.yml b/node_modules/express/node_modules/buffer-crc32/.travis.yml new file mode 100644 index 0000000..7a902e8 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: + - 0.6 + - 0.8 +notifications: + email: + recipients: + - brianloveswords@gmail.com \ No newline at end of file diff --git a/node_modules/express/node_modules/buffer-crc32/README.md b/node_modules/express/node_modules/buffer-crc32/README.md new file mode 100644 index 0000000..0d9d8b8 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/README.md @@ -0,0 +1,47 @@ +# buffer-crc32 + +[![Build Status](https://secure.travis-ci.org/brianloveswords/buffer-crc32.png?branch=master)](http://travis-ci.org/brianloveswords/buffer-crc32) + +crc32 that works with binary data and fancy character sets, outputs +buffer, signed or unsigned data and has tests. + +Derived from the sample CRC implementation in the PNG specification: http://www.w3.org/TR/PNG/#D-CRCAppendix + +# install +``` +npm install buffer-crc32 +``` + +# example +```js +var crc32 = require('buffer-crc32'); +// works with buffers +var buf = Buffer([0x00, 0x73, 0x75, 0x70, 0x20, 0x62, 0x72, 0x6f, 0x00]) +crc32(buf) // -> + +// has convenience methods for getting signed or unsigned ints +crc32.signed(buf) // -> -1805997238 +crc32.unsigned(buf) // -> 2488970058 + +// will cast to buffer if given a string, so you can +// directly use foreign characters safely +crc32('自動販売機') // -> + +// and works in append mode too +var partialCrc = crc32('hey'); +var partialCrc = crc32(' ', partialCrc); +var partialCrc = crc32('sup', partialCrc); +var partialCrc = crc32(' ', partialCrc); +var finalCrc = crc32('bros', partialCrc); // -> +``` + +# tests +This was tested against the output of zlib's crc32 method. You can run +the tests with`npm test` (requires tap) + +# see also +https://github.com/alexgorbatchev/node-crc, `crc.buffer.crc32` also +supports buffer inputs and return unsigned ints (thanks @tjholowaychuk). + +# license +MIT/X11 diff --git a/node_modules/express/node_modules/buffer-crc32/index.js b/node_modules/express/node_modules/buffer-crc32/index.js new file mode 100644 index 0000000..e29ce3e --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/index.js @@ -0,0 +1,88 @@ +var Buffer = require('buffer').Buffer; + +var CRC_TABLE = [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +]; + +function bufferizeInt(num) { + var tmp = Buffer(4); + tmp.writeInt32BE(num, 0); + return tmp; +} + +function _crc32(buf, previous) { + if (!Buffer.isBuffer(buf)) { + buf = Buffer(buf); + } + if (Buffer.isBuffer(previous)) { + previous = previous.readUInt32BE(0); + } + var crc = ~~previous ^ -1; + for (var n = 0; n < buf.length; n++) { + crc = CRC_TABLE[(crc ^ buf[n]) & 0xff] ^ (crc >>> 8); + } + return (crc ^ -1); +} + +function crc32() { + return bufferizeInt(_crc32.apply(null, arguments)); +} +crc32.signed = function () { + return _crc32.apply(null, arguments); +}; +crc32.unsigned = function () { + return _crc32.apply(null, arguments) >>> 0; +}; + +module.exports = crc32; diff --git a/node_modules/express/node_modules/buffer-crc32/package.json b/node_modules/express/node_modules/buffer-crc32/package.json new file mode 100644 index 0000000..c702600 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/package.json @@ -0,0 +1,43 @@ +{ + "author": { + "name": "Brian J. Brennan", + "email": "brianloveswords@gmail.com", + "url": "http://bjb.io" + }, + "name": "buffer-crc32", + "description": "A pure javascript CRC32 algorithm that plays nice with binary data", + "version": "0.2.1", + "contributors": [ + { + "name": "Vladimir Kuznetsov" + } + ], + "homepage": "https://github.com/brianloveswords/buffer-crc32", + "repository": { + "type": "git", + "url": "git://github.com/brianloveswords/buffer-crc32.git" + }, + "main": "index.js", + "scripts": { + "test": "./node_modules/.bin/tap tests/*.test.js" + }, + "dependencies": {}, + "devDependencies": { + "tap": "~0.2.5" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "readme": "# buffer-crc32\n\n[![Build Status](https://secure.travis-ci.org/brianloveswords/buffer-crc32.png?branch=master)](http://travis-ci.org/brianloveswords/buffer-crc32)\n\ncrc32 that works with binary data and fancy character sets, outputs\nbuffer, signed or unsigned data and has tests.\n\nDerived from the sample CRC implementation in the PNG specification: http://www.w3.org/TR/PNG/#D-CRCAppendix\n\n# install\n```\nnpm install buffer-crc32\n```\n\n# example\n```js\nvar crc32 = require('buffer-crc32');\n// works with buffers\nvar buf = Buffer([0x00, 0x73, 0x75, 0x70, 0x20, 0x62, 0x72, 0x6f, 0x00])\ncrc32(buf) // -> \n\n// has convenience methods for getting signed or unsigned ints\ncrc32.signed(buf) // -> -1805997238\ncrc32.unsigned(buf) // -> 2488970058\n\n// will cast to buffer if given a string, so you can\n// directly use foreign characters safely\ncrc32('自動販売機') // -> \n\n// and works in append mode too\nvar partialCrc = crc32('hey');\nvar partialCrc = crc32(' ', partialCrc);\nvar partialCrc = crc32('sup', partialCrc);\nvar partialCrc = crc32(' ', partialCrc);\nvar finalCrc = crc32('bros', partialCrc); // -> \n```\n\n# tests\nThis was tested against the output of zlib's crc32 method. You can run\nthe tests with`npm test` (requires tap)\n\n# see also\nhttps://github.com/alexgorbatchev/node-crc, `crc.buffer.crc32` also\nsupports buffer inputs and return unsigned ints (thanks @tjholowaychuk).\n\n# license\nMIT/X11\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/brianloveswords/buffer-crc32/issues" + }, + "_id": "buffer-crc32@0.2.1", + "dist": { + "shasum": "be3e5382fc02b6d6324956ac1af98aa98b08534c" + }, + "_from": "buffer-crc32@0.2.1", + "_resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz" +} diff --git a/node_modules/express/node_modules/buffer-crc32/tests/crc.test.js b/node_modules/express/node_modules/buffer-crc32/tests/crc.test.js new file mode 100644 index 0000000..bb0f9ef --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/tests/crc.test.js @@ -0,0 +1,89 @@ +var crc32 = require('..'); +var test = require('tap').test; + +test('simple crc32 is no problem', function (t) { + var input = Buffer('hey sup bros'); + var expected = Buffer([0x47, 0xfa, 0x55, 0x70]); + t.same(crc32(input), expected); + t.end(); +}); + +test('another simple one', function (t) { + var input = Buffer('IEND'); + var expected = Buffer([0xae, 0x42, 0x60, 0x82]); + t.same(crc32(input), expected); + t.end(); +}); + +test('slightly more complex', function (t) { + var input = Buffer([0x00, 0x00, 0x00]); + var expected = Buffer([0xff, 0x41, 0xd9, 0x12]); + t.same(crc32(input), expected); + t.end(); +}); + +test('complex crc32 gets calculated like a champ', function (t) { + var input = Buffer('शीर्षक'); + var expected = Buffer([0x17, 0xb8, 0xaf, 0xf1]); + t.same(crc32(input), expected); + t.end(); +}); + +test('casts to buffer if necessary', function (t) { + var input = 'शीर्षक'; + var expected = Buffer([0x17, 0xb8, 0xaf, 0xf1]); + t.same(crc32(input), expected); + t.end(); +}); + +test('can do signed', function (t) { + var input = 'ham sandwich'; + var expected = -1891873021; + t.same(crc32.signed(input), expected); + t.end(); +}); + +test('can do unsigned', function (t) { + var input = 'bear sandwich'; + var expected = 3711466352; + t.same(crc32.unsigned(input), expected); + t.end(); +}); + + +test('simple crc32 in append mode', function (t) { + var input = [Buffer('hey'), Buffer(' '), Buffer('sup'), Buffer(' '), Buffer('bros')]; + var expected = Buffer([0x47, 0xfa, 0x55, 0x70]); + for (var crc = 0, i = 0; i < input.length; i++) { + crc = crc32(input[i], crc); + } + t.same(crc, expected); + t.end(); +}); + + +test('can do signed in append mode', function (t) { + var input1 = 'ham'; + var input2 = ' '; + var input3 = 'sandwich'; + var expected = -1891873021; + + var crc = crc32.signed(input1); + crc = crc32.signed(input2, crc); + crc = crc32.signed(input3, crc); + + t.same(crc, expected); + t.end(); +}); + +test('can do unsigned in append mode', function (t) { + var input1 = 'bear san'; + var input2 = 'dwich'; + var expected = 3711466352; + + var crc = crc32.unsigned(input1); + crc = crc32.unsigned(input2, crc); + t.same(crc, expected); + t.end(); +}); + diff --git a/node_modules/express/node_modules/commander/History.md b/node_modules/express/node_modules/commander/History.md new file mode 100644 index 0000000..7cda70f --- /dev/null +++ b/node_modules/express/node_modules/commander/History.md @@ -0,0 +1,158 @@ + +1.2.0 / 2013-06-13 +================== + + * allow "-" hyphen as an option argument + * support for RegExp coercion + +1.1.1 / 2012-11-20 +================== + + * add more sub-command padding + * fix .usage() when args are present. Closes #106 + +1.1.0 / 2012-11-16 +================== + + * add git-style executable subcommand support. Closes #94 + +1.0.5 / 2012-10-09 +================== + + * fix `--name` clobbering. Closes #92 + * fix examples/help. Closes #89 + +1.0.4 / 2012-09-03 +================== + + * add `outputHelp()` method. + +1.0.3 / 2012-08-30 +================== + + * remove invalid .version() defaulting + +1.0.2 / 2012-08-24 +================== + + * add `--foo=bar` support [arv] + * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus] + +1.0.1 / 2012-08-03 +================== + + * fix issue #56 + * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode()) + +1.0.0 / 2012-07-05 +================== + + * add support for optional option descriptions + * add defaulting of `.version()` to package.json's version + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/commander/Readme.md b/node_modules/express/node_modules/commander/Readme.md new file mode 100644 index 0000000..107932a --- /dev/null +++ b/node_modules/express/node_modules/commander/Readme.md @@ -0,0 +1,276 @@ +# Commander.js + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). + + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) + +## Installation + + $ npm install commander + +## Option parsing + + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.0.1') + .option('-p, --peppers', 'Add peppers') + .option('-P, --pineapple', 'Add pineapple') + .option('-b, --bbq', 'Add bbq sauce') + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') + .parse(process.argv); + +console.log('you ordered a pizza with:'); +if (program.peppers) console.log(' - peppers'); +if (program.pineapple) console.log(' - pineappe'); +if (program.bbq) console.log(' - bbq'); +console.log(' - %s cheese', program.cheese); +``` + + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + Options: + + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineappe + -b, --bbq Add bbq sauce + -c, --cheese Add the specified type of cheese [marble] + -h, --help output usage information + +``` + +## Coercion + +```js +function range(val) { + return val.split('..').map(Number); +} + +function list(val) { + return val.split(','); +} + +program + .version('0.0.1') + .usage('[options] ') + .option('-i, --integer ', 'An integer argument', parseInt) + .option('-f, --float ', 'A float argument', parseFloat) + .option('-r, --range ..', 'A range', range) + .option('-l, --list ', 'A list', list) + .option('-o, --optional [value]', 'An optional value') + .parse(process.argv); + +console.log(' int: %j', program.integer); +console.log(' float: %j', program.float); +console.log(' optional: %j', program.optional); +program.range = program.range || []; +console.log(' range: %j..%j', program.range[0], program.range[1]); +console.log(' list: %j', program.list); +console.log(' args: %j', program.args); +``` + +## Custom help + + You can display arbitrary `-h, --help` information + by listening for "--help". Commander will automatically + exit once you are done so that the remainder of your program + does not execute causing undesired behaviours, for example + in the following executable "stuff" will not output when + `--help` is used. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('../'); + +function list(val) { + return val.split(',').map(Number); +} + +program + .version('0.0.1') + .option('-f, --foo', 'enable some foo') + .option('-b, --bar', 'enable some bar') + .option('-B, --baz', 'enable some baz'); + +// must be before .parse() since +// node's emit() is immediate + +program.on('--help', function(){ + console.log(' Examples:'); + console.log(''); + console.log(' $ custom-help --help'); + console.log(' $ custom-help -h'); + console.log(''); +}); + +program.parse(process.argv); + +console.log('stuff'); +``` + +yielding the following help output: + +``` + +Usage: custom-help [options] + +Options: + + -h, --help output usage information + -V, --version output the version number + -f, --foo enable some foo + -b, --bar enable some bar + -B, --baz enable some baz + +Examples: + + $ custom-help --help + $ custom-help -h + +``` + +## .prompt(msg, fn) + + Single-line prompt: + +```js +program.prompt('name: ', function(name){ + console.log('hi %s', name); +}); +``` + + Multi-line prompt: + +```js +program.prompt('description:', function(name){ + console.log('hi %s', name); +}); +``` + + Coercion: + +```js +program.prompt('Age: ', Number, function(age){ + console.log('age: %j', age); +}); +``` + +```js +program.prompt('Birthdate: ', Date, function(date){ + console.log('date: %s', date); +}); +``` + +```js +program.prompt('Email: ', /^.+@.+\..+$/, function(email){ + console.log('email: %j', email); +}); +``` + +## .password(msg[, mask], fn) + +Prompt for password without echoing: + +```js +program.password('Password: ', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +Prompt for password with mask char "*": + +```js +program.password('Password: ', '*', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +## .confirm(msg, fn) + + Confirm with the given `msg`: + +```js +program.confirm('continue? ', function(ok){ + console.log(' got %j', ok); +}); +``` + +## .choose(list, fn) + + Let the user choose from a `list`: + +```js +var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + +console.log('Choose the coolest pet:'); +program.choose(list, function(i){ + console.log('you chose %d "%s"', i, list[i]); +}); +``` + +## .outputHelp() + + Output help information without exiting. + +## .help() + + Output help information and exit immediately. + +## Links + + - [API documentation](http://visionmedia.github.com/commander.js/) + - [ascii tables](https://github.com/LearnBoost/cli-table) + - [progress bars](https://github.com/visionmedia/node-progress) + - [more progress bars](https://github.com/substack/node-multimeter) + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) + +## License + +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/commander/index.js b/node_modules/express/node_modules/commander/index.js new file mode 100644 index 0000000..0ceaf18 --- /dev/null +++ b/node_modules/express/node_modules/commander/index.js @@ -0,0 +1,1152 @@ +/*! + * commander + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , spawn = require('child_process').spawn + , keypress = require('keypress') + , fs = require('fs') + , exists = fs.existsSync + , path = require('path') + , tty = require('tty') + , dirname = path.dirname + , basename = path.basename; + +/** + * Expose the root command. + */ + +exports = module.exports = new Command; + +/** + * Expose `Command`. + */ + +exports.Command = Command; + +/** + * Expose `Option`. + */ + +exports.Option = Option; + +/** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {String} flags + * @param {String} description + * @api public + */ + +function Option(flags, description) { + this.flags = flags; + this.required = ~flags.indexOf('<'); + this.optional = ~flags.indexOf('['); + this.bool = !~flags.indexOf('-no-'); + flags = flags.split(/[ ,|]+/); + if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); + this.long = flags.shift(); + this.description = description || ''; +} + +/** + * Return option name. + * + * @return {String} + * @api private + */ + +Option.prototype.name = function(){ + return this.long + .replace('--', '') + .replace('no-', ''); +}; + +/** + * Check if `arg` matches the short or long flag. + * + * @param {String} arg + * @return {Boolean} + * @api private + */ + +Option.prototype.is = function(arg){ + return arg == this.short + || arg == this.long; +}; + +/** + * Initialize a new `Command`. + * + * @param {String} name + * @api public + */ + +function Command(name) { + this.commands = []; + this.options = []; + this._args = []; + this._name = name; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Command.prototype.__proto__ = EventEmitter.prototype; + +/** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * Examples: + * + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function(){ + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd){ + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env){ + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {String} name + * @param {String} [desc] + * @return {Command} the new command + * @api public + */ + +Command.prototype.command = function(name, desc){ + var args = name.split(/ +/); + var cmd = new Command(args.shift()); + if (desc) cmd.description(desc); + if (desc) this.executables = true; + this.commands.push(cmd); + cmd.parseExpectedArgs(args); + cmd.parent = this; + if (desc) return this; + return cmd; +}; + +/** + * Add an implicit `help [cmd]` subcommand + * which invokes `--help` for the given command. + * + * @api private + */ + +Command.prototype.addImplicitHelpCommand = function() { + this.command('help [cmd]', 'display help for [cmd]'); +}; + +/** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {Array} args + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parseExpectedArgs = function(args){ + if (!args.length) return; + var self = this; + args.forEach(function(arg){ + switch (arg[0]) { + case '<': + self._args.push({ required: true, name: arg.slice(1, -1) }); + break; + case '[': + self._args.push({ required: false, name: arg.slice(1, -1) }); + break; + } + }); + return this; +}; + +/** + * Register callback `fn` for the command. + * + * Examples: + * + * program + * .command('help') + * .description('display verbose help') + * .action(function(){ + * // output help here + * }); + * + * @param {Function} fn + * @return {Command} for chaining + * @api public + */ + +Command.prototype.action = function(fn){ + var self = this; + this.parent.on(this._name, function(args, unknown){ + // Parse any so-far unknown options + unknown = unknown || []; + var parsed = self.parseOptions(unknown); + + // Output help if necessary + outputHelpIfNecessary(self, parsed.unknown); + + // If there are still any unknown options, then we simply + // die, unless someone asked for help, in which case we give it + // to them, and then we die. + if (parsed.unknown.length > 0) { + self.unknownOption(parsed.unknown[0]); + } + + // Leftover arguments need to be pushed back. Fixes issue #56 + if (parsed.args.length) args = parsed.args.concat(args); + + self._args.forEach(function(arg, i){ + if (arg.required && null == args[i]) { + self.missingArgument(arg.name); + } + }); + + // Always append ourselves to the end of the arguments, + // to make sure we match the number of arguments the user + // expects + if (self._args.length) { + args[self._args.length] = self; + } else { + args.push(self); + } + + fn.apply(this, args); + }); + return this; +}; + +/** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * Examples: + * + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to false + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => true + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {String} flags + * @param {String} description + * @param {Function|Mixed} fn or default + * @param {Mixed} defaultValue + * @return {Command} for chaining + * @api public + */ + +Command.prototype.option = function(flags, description, fn, defaultValue){ + var self = this + , option = new Option(flags, description) + , oname = option.name() + , name = camelcase(oname); + + // default as 3rd arg + if ('function' != typeof fn) defaultValue = fn, fn = null; + + // preassign default value only for --no-*, [optional], or + if (false == option.bool || option.optional || option.required) { + // when --no-* we make sure default is true + if (false == option.bool) defaultValue = true; + // preassign only if we have a default + if (undefined !== defaultValue) self[name] = defaultValue; + } + + // register the option + this.options.push(option); + + // when it's passed assign the value + // and conditionally invoke the callback + this.on(oname, function(val){ + // coercion + if (null != val && fn) val = fn(val); + + // unassigned or bool + if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { + // if no value, bool true, and we have a default, then use it! + if (null == val) { + self[name] = option.bool + ? defaultValue || true + : false; + } else { + self[name] = val; + } + } else if (null !== val) { + // reassign + self[name] = val; + } + }); + + return this; +}; + +/** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {Array} argv + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parse = function(argv){ + // implicit help + if (this.executables) this.addImplicitHelpCommand(); + + // store raw args + this.rawArgs = argv; + + // guess name + this._name = this._name || basename(argv[1]); + + // process argv + var parsed = this.parseOptions(this.normalize(argv.slice(2))); + var args = this.args = parsed.args; + + // executable sub-commands, skip .parseArgs() + if (this.executables) return this.executeSubCommand(argv, args, parsed.unknown); + + return this.parseArgs(this.args, parsed.unknown); +}; + +/** + * Execute a sub-command executable. + * + * @param {Array} argv + * @param {Array} args + * @param {Array} unknown + * @api private + */ + +Command.prototype.executeSubCommand = function(argv, args, unknown) { + args = args.concat(unknown); + + if (!args.length) this.help(); + if ('help' == args[0] && 1 == args.length) this.help(); + + // --help + if ('help' == args[0]) { + args[0] = args[1]; + args[1] = '--help'; + } + + // executable + var dir = dirname(argv[1]); + var bin = basename(argv[1]) + '-' + args[0]; + + // check for ./ first + var local = path.join(dir, bin); + if (exists(local)) bin = local; + + // run it + args = args.slice(1); + var proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] }); + proc.on('exit', function(code){ + if (code == 127) { + console.error('\n %s(1) does not exist\n', bin); + } + }); +}; + +/** + * Normalize `args`, splitting joined short flags. For example + * the arg "-abc" is equivalent to "-a -b -c". + * This also normalizes equal sign and splits "--abc=def" into "--abc def". + * + * @param {Array} args + * @return {Array} + * @api private + */ + +Command.prototype.normalize = function(args){ + var ret = [] + , arg + , index; + + for (var i = 0, len = args.length; i < len; ++i) { + arg = args[i]; + if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { + arg.slice(1).split('').forEach(function(c){ + ret.push('-' + c); + }); + } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { + ret.push(arg.slice(0, index), arg.slice(index + 1)); + } else { + ret.push(arg); + } + } + + return ret; +}; + +/** + * Parse command `args`. + * + * When listener(s) are available those + * callbacks are invoked, otherwise the "*" + * event is emitted and those actions are invoked. + * + * @param {Array} args + * @return {Command} for chaining + * @api private + */ + +Command.prototype.parseArgs = function(args, unknown){ + var cmds = this.commands + , len = cmds.length + , name; + + if (args.length) { + name = args[0]; + if (this.listeners(name).length) { + this.emit(args.shift(), args, unknown); + } else { + this.emit('*', args); + } + } else { + outputHelpIfNecessary(this, unknown); + + // If there were no args and we have unknown options, + // then they are extraneous and we need to error. + if (unknown.length > 0) { + this.unknownOption(unknown[0]); + } + } + + return this; +}; + +/** + * Return an option matching `arg` if any. + * + * @param {String} arg + * @return {Option} + * @api private + */ + +Command.prototype.optionFor = function(arg){ + for (var i = 0, len = this.options.length; i < len; ++i) { + if (this.options[i].is(arg)) { + return this.options[i]; + } + } +}; + +/** + * Parse options from `argv` returning `argv` + * void of these options. + * + * @param {Array} argv + * @return {Array} + * @api public + */ + +Command.prototype.parseOptions = function(argv){ + var args = [] + , len = argv.length + , literal + , option + , arg; + + var unknownOptions = []; + + // parse options + for (var i = 0; i < len; ++i) { + arg = argv[i]; + + // literal args after -- + if ('--' == arg) { + literal = true; + continue; + } + + if (literal) { + args.push(arg); + continue; + } + + // find matching Option + option = this.optionFor(arg); + + // option is defined + if (option) { + // requires arg + if (option.required) { + arg = argv[++i]; + if (null == arg) return this.optionMissingArgument(option); + if ('-' == arg[0] && '-' != arg) return this.optionMissingArgument(option, arg); + this.emit(option.name(), arg); + // optional arg + } else if (option.optional) { + arg = argv[i+1]; + if (null == arg || ('-' == arg[0] && '-' != arg)) { + arg = null; + } else { + ++i; + } + this.emit(option.name(), arg); + // bool + } else { + this.emit(option.name()); + } + continue; + } + + // looks like an option + if (arg.length > 1 && '-' == arg[0]) { + unknownOptions.push(arg); + + // If the next argument looks like it might be + // an argument for this option, we pass it on. + // If it isn't, then it'll simply be ignored + if (argv[i+1] && '-' != argv[i+1][0]) { + unknownOptions.push(argv[++i]); + } + continue; + } + + // arg + args.push(arg); + } + + return { args: args, unknown: unknownOptions }; +}; + +/** + * Argument `name` is missing. + * + * @param {String} name + * @api private + */ + +Command.prototype.missingArgument = function(name){ + console.error(); + console.error(" error: missing required argument `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * `Option` is missing an argument, but received `flag` or nothing. + * + * @param {String} option + * @param {String} flag + * @api private + */ + +Command.prototype.optionMissingArgument = function(option, flag){ + console.error(); + if (flag) { + console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + } else { + console.error(" error: option `%s' argument missing", option.flags); + } + console.error(); + process.exit(1); +}; + +/** + * Unknown option `flag`. + * + * @param {String} flag + * @api private + */ + +Command.prototype.unknownOption = function(flag){ + console.error(); + console.error(" error: unknown option `%s'", flag); + console.error(); + process.exit(1); +}; + + +/** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {String} str + * @param {String} flags + * @return {Command} for chaining + * @api public + */ + +Command.prototype.version = function(str, flags){ + if (0 == arguments.length) return this._version; + this._version = str; + flags = flags || '-V, --version'; + this.option(flags, 'output the version number'); + this.on('version', function(){ + console.log(str); + process.exit(0); + }); + return this; +}; + +/** + * Set the description `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.description = function(str){ + if (0 == arguments.length) return this._description; + this._description = str; + return this; +}; + +/** + * Set / get the command usage `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.usage = function(str){ + var args = this._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }); + + var usage = '[options' + + (this.commands.length ? '] [command' : '') + + ']' + + (this._args.length ? ' ' + args : ''); + + if (0 == arguments.length) return this._usage || usage; + this._usage = str; + + return this; +}; + +/** + * Return the largest option length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestOptionLength = function(){ + return this.options.reduce(function(max, option){ + return Math.max(max, option.flags.length); + }, 0); +}; + +/** + * Return help for options. + * + * @return {String} + * @api private + */ + +Command.prototype.optionHelp = function(){ + var width = this.largestOptionLength(); + + // Prepend the help information + return [pad('-h, --help', width) + ' ' + 'output usage information'] + .concat(this.options.map(function(option){ + return pad(option.flags, width) + + ' ' + option.description; + })) + .join('\n'); +}; + +/** + * Return command help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.commandHelp = function(){ + if (!this.commands.length) return ''; + return [ + '' + , ' Commands:' + , '' + , this.commands.map(function(cmd){ + var args = cmd._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }).join(' '); + + return pad(cmd._name + + (cmd.options.length + ? ' [options]' + : '') + ' ' + args, 22) + + (cmd.description() + ? ' ' + cmd.description() + : ''); + }).join('\n').replace(/^/gm, ' ') + , '' + ].join('\n'); +}; + +/** + * Return program help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.helpInformation = function(){ + return [ + '' + , ' Usage: ' + this._name + ' ' + this.usage() + , '' + this.commandHelp() + , ' Options:' + , '' + , '' + this.optionHelp().replace(/^/gm, ' ') + , '' + , '' + ].join('\n'); +}; + +/** + * Prompt for a `Number`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForNumber = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseNumber(val){ + val = Number(val); + if (isNaN(val)) return self.promptSingleLine(str + '(must be a number) ', parseNumber); + fn(val); + }); +}; + +/** + * Prompt for a `Date`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForDate = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseDate(val){ + val = new Date(val); + if (isNaN(val.getTime())) return self.promptSingleLine(str + '(must be a date) ', parseDate); + fn(val); + }); +}; + + +/** + * Prompt for a `Regular Expression`. + * + * @param {String} str + * @param {Object} pattern regular expression object to test + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForRegexp = function(str, pattern, fn){ + var self = this; + this.promptSingleLine(str, function parseRegexp(val){ + if(!pattern.test(val)) return self.promptSingleLine(str + '(regular expression mismatch) ', parseRegexp); + fn(val); + }); +}; + + +/** + * Single-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptSingleLine = function(str, fn){ + // determine if the 2nd argument is a regular expression + if (arguments[1].global !== undefined && arguments[1].multiline !== undefined) { + return this.promptForRegexp(str, arguments[1], arguments[2]); + } else if ('function' == typeof arguments[2]) { + return this['promptFor' + (fn.name || fn)](str, arguments[2]); + } + + process.stdout.write(str); + process.stdin.setEncoding('utf8'); + process.stdin.once('data', function(val){ + fn(val.trim()); + }).resume(); +}; + +/** + * Multi-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptMultiLine = function(str, fn){ + var buf = []; + console.log(str); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function(val){ + if ('\n' == val || '\r\n' == val) { + process.stdin.removeAllListeners('data'); + fn(buf.join('\n')); + } else { + buf.push(val.trimRight()); + } + }).resume(); +}; + +/** + * Prompt `str` and callback `fn(val)` + * + * Commander supports single-line and multi-line prompts. + * To issue a single-line prompt simply add white-space + * to the end of `str`, something like "name: ", whereas + * for a multi-line prompt omit this "description:". + * + * + * Examples: + * + * program.prompt('Username: ', function(name){ + * console.log('hi %s', name); + * }); + * + * program.prompt('Description:', function(desc){ + * console.log('description was "%s"', desc.trim()); + * }); + * + * @param {String|Object} str + * @param {Function} fn + * @api public + */ + +Command.prototype.prompt = function(str, fn){ + var self = this; + if ('string' == typeof str) { + if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments); + this.promptMultiLine(str, fn); + } else { + var keys = Object.keys(str) + , obj = {}; + + function next() { + var key = keys.shift() + , label = str[key]; + + if (!key) return fn(obj); + self.prompt(label, function(val){ + obj[key] = val; + next(); + }); + } + + next(); + } +}; + +/** + * Prompt for password with `str`, `mask` char and callback `fn(val)`. + * + * The mask string defaults to '', aka no output is + * written while typing, you may want to use "*" etc. + * + * Examples: + * + * program.password('Password: ', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * program.password('Password: ', '*', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {String} mask + * @param {Function} fn + * @api public + */ + +Command.prototype.password = function(str, mask, fn){ + var self = this + , buf = ''; + + // default mask + if ('function' == typeof mask) { + fn = mask; + mask = ''; + } + + keypress(process.stdin); + + function setRawMode(mode) { + if (process.stdin.setRawMode) { + process.stdin.setRawMode(mode); + } else { + tty.setRawMode(mode); + } + }; + setRawMode(true); + process.stdout.write(str); + + // keypress + process.stdin.on('keypress', function(c, key){ + if (key && 'enter' == key.name) { + console.log(); + process.stdin.pause(); + process.stdin.removeAllListeners('keypress'); + setRawMode(false); + if (!buf.trim().length) return self.password(str, mask, fn); + fn(buf); + return; + } + + if (key && key.ctrl && 'c' == key.name) { + console.log('%s', buf); + process.exit(); + } + + process.stdout.write(mask); + buf += c; + }).resume(); +}; + +/** + * Confirmation prompt with `str` and callback `fn(bool)` + * + * Examples: + * + * program.confirm('continue? ', function(ok){ + * console.log(' got %j', ok); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {Function} fn + * @api public + */ + + +Command.prototype.confirm = function(str, fn, verbose){ + var self = this; + this.prompt(str, function(ok){ + if (!ok.trim()) { + if (!verbose) str += '(yes or no) '; + return self.confirm(str, fn, true); + } + fn(parseBool(ok)); + }); +}; + +/** + * Choice prompt with `list` of items and callback `fn(index, item)` + * + * Examples: + * + * var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + * + * console.log('Choose the coolest pet:'); + * program.choose(list, function(i){ + * console.log('you chose %d "%s"', i, list[i]); + * process.stdin.destroy(); + * }); + * + * @param {Array} list + * @param {Number|Function} index or fn + * @param {Function} fn + * @api public + */ + +Command.prototype.choose = function(list, index, fn){ + var self = this + , hasDefault = 'number' == typeof index; + + if (!hasDefault) { + fn = index; + index = null; + } + + list.forEach(function(item, i){ + if (hasDefault && i == index) { + console.log('* %d) %s', i + 1, item); + } else { + console.log(' %d) %s', i + 1, item); + } + }); + + function again() { + self.prompt(' : ', function(val){ + val = parseInt(val, 10) - 1; + if (hasDefault && isNaN(val)) val = index; + + if (null == list[val]) { + again(); + } else { + fn(val, list[val]); + } + }); + } + + again(); +}; + + +/** + * Output help information for this command + * + * @api public + */ + +Command.prototype.outputHelp = function(){ + process.stdout.write(this.helpInformation()); + this.emit('--help'); +}; + +/** + * Output help information and exit. + * + * @api public + */ + +Command.prototype.help = function(){ + this.outputHelp(); + process.exit(); +}; + +/** + * Camel-case the given `flag` + * + * @param {String} flag + * @return {String} + * @api private + */ + +function camelcase(flag) { + return flag.split('-').reduce(function(str, word){ + return str + word[0].toUpperCase() + word.slice(1); + }); +} + +/** + * Parse a boolean `str`. + * + * @param {String} str + * @return {Boolean} + * @api private + */ + +function parseBool(str) { + return /^y|yes|ok|true$/i.test(str); +} + +/** + * Pad `str` to `width`. + * + * @param {String} str + * @param {Number} width + * @return {String} + * @api private + */ + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +/** + * Output help information if necessary + * + * @param {Command} command to output help for + * @param {Array} array of options to search for -h or --help + * @api private + */ + +function outputHelpIfNecessary(cmd, options) { + options = options || []; + for (var i = 0; i < options.length; i++) { + if (options[i] == '--help' || options[i] == '-h') { + cmd.outputHelp(); + process.exit(0); + } + } +} diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/README.md b/node_modules/express/node_modules/commander/node_modules/keypress/README.md new file mode 100644 index 0000000..a768e8f --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/README.md @@ -0,0 +1,101 @@ +keypress +======== +### Make any Node ReadableStream emit "keypress" events + + +Previous to Node `v0.8.x`, there was an undocumented `"keypress"` event that +`process.stdin` would emit when it was a TTY. Some people discovered this hidden +gem, and started using it in their own code. + +Now in Node `v0.8.x`, this `"keypress"` event does not get emitted by default, +but rather only when it is being used in conjuction with the `readline` (or by +extension, the `repl`) module. + +This module is the exact logic from the node `v0.8.x` releases ripped out into its +own module. + +__Bonus:__ Now with mouse support! + +Installation +------------ + +Install with `npm`: + +``` bash +$ npm install keypress +``` + +Or add it to the `"dependencies"` section of your _package.json_ file. + + +Example +------- + +#### Listening for "keypress" events + +``` js +var keypress = require('keypress'); + +// make `process.stdin` begin emitting "keypress" events +keypress(process.stdin); + +// listen for the "keypress" event +process.stdin.on('keypress', function (ch, key) { + console.log('got "keypress"', key); + if (key && key.ctrl && key.name == 'c') { + process.stdin.pause(); + } +}); + +process.stdin.setRawMode(true); +process.stdin.resume(); +``` + +#### Listening for "mousepress" events + +``` js +var keypress = require('keypress'); + +// make `process.stdin` begin emitting "mousepress" (and "keypress") events +keypress(process.stdin); + +// you must enable the mouse events before they will begin firing +keypress.enableMouse(process.stdout); + +process.stdin.on('mousepress', function (info) { + console.log('got "mousepress" event at %d x %d', info.x, info.y); +}); + +process.on('exit', function () { + // disable mouse on exit, so that the state + // is back to normal for the terminal + keypress.disableMouse(process.stdout); +}); +``` + + +License +------- + +(The MIT License) + +Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/index.js b/node_modules/express/node_modules/commander/node_modules/keypress/index.js new file mode 100644 index 0000000..c2ba488 --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/index.js @@ -0,0 +1,346 @@ + +/** + * This module offers the internal "keypress" functionality from node-core's + * `readline` module, for your own programs and modules to use. + * + * Usage: + * + * require('keypress')(process.stdin); + * + * process.stdin.on('keypress', function (ch, key) { + * console.log(ch, key); + * if (key.ctrl && key.name == 'c') { + * process.stdin.pause(); + * } + * }); + * proces.stdin.resume(); + */ +var exports = module.exports = keypress; + +exports.enableMouse = function (stream) { + stream.write('\x1b' +'[?1000h') +} + +exports.disableMouse = function (stream) { + stream.write('\x1b' +'[?1000l') +} + + +/** + * accepts a readable Stream instance and makes it emit "keypress" events + */ + +function keypress(stream) { + if (isEmittingKeypress(stream)) return; + stream._emitKeypress = true; + + function onData(b) { + if (stream.listeners('keypress').length > 0) { + emitKey(stream, b); + } else { + // Nobody's watching anyway + stream.removeListener('data', onData); + stream.on('newListener', onNewListener); + } + } + + function onNewListener(event) { + if (event == 'keypress') { + stream.on('data', onData); + stream.removeListener('newListener', onNewListener); + } + } + + if (stream.listeners('keypress').length > 0) { + stream.on('data', onData); + } else { + stream.on('newListener', onNewListener); + } +} + +/** + * Returns `true` if the stream is already emitting "keypress" events. + * `false` otherwise. + */ + +function isEmittingKeypress(stream) { + var rtn = stream._emitKeypress; + if (!rtn) { + // hack: check for the v0.6.x "data" event + stream.listeners('data').forEach(function (l) { + if (l.name == 'onData' && /emitKey/.test(l.toString())) { + rtn = true; + stream._emitKeypress = true; + } + }); + } + if (!rtn) { + // hack: check for the v0.6.x "newListener" event + stream.listeners('newListener').forEach(function (l) { + if (l.name == 'onNewListener' && /keypress/.test(l.toString())) { + rtn = true; + stream._emitKeypress = true; + } + }); + } + return rtn; +} + + +/* + Some patterns seen in terminal key escape codes, derived from combos seen + at http://www.midnight-commander.org/browser/lib/tty/key.c + + ESC letter + ESC [ letter + ESC [ modifier letter + ESC [ 1 ; modifier letter + ESC [ num char + ESC [ num ; modifier char + ESC O letter + ESC O modifier letter + ESC O 1 ; modifier letter + ESC N letter + ESC [ [ num ; modifier char + ESC [ [ 1 ; modifier letter + ESC ESC [ num char + ESC ESC O letter + + - char is usually ~ but $ and ^ also happen with rxvt + - modifier is 1 + + (shift * 1) + + (left_alt * 2) + + (ctrl * 4) + + (right_alt * 8) + - two leading ESCs apparently mean the same as one leading ESC +*/ + +// Regexes used for ansi escape code splitting +var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/; +var functionKeyCodeRe = + /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/; + +function emitKey(stream, s) { + var ch, + key = { + name: undefined, + ctrl: false, + meta: false, + shift: false + }, + parts; + + if (Buffer.isBuffer(s)) { + if (s[0] > 127 && s[1] === undefined) { + s[0] -= 128; + s = '\x1b' + s.toString(stream.encoding || 'utf-8'); + } else { + s = s.toString(stream.encoding || 'utf-8'); + } + } + + key.sequence = s; + + if (s === '\r' || s === '\n') { + // enter + key.name = 'enter'; + + } else if (s === '\t') { + // tab + key.name = 'tab'; + + } else if (s === '\b' || s === '\x7f' || + s === '\x1b\x7f' || s === '\x1b\b') { + // backspace or ctrl+h + key.name = 'backspace'; + key.meta = (s.charAt(0) === '\x1b'); + + } else if (s === '\x1b' || s === '\x1b\x1b') { + // escape key + key.name = 'escape'; + key.meta = (s.length === 2); + + } else if (s === ' ' || s === '\x1b ') { + key.name = 'space'; + key.meta = (s.length === 2); + + } else if (s <= '\x1a') { + // ctrl+letter + key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1); + key.ctrl = true; + + } else if (s.length === 1 && s >= 'a' && s <= 'z') { + // lowercase letter + key.name = s; + + } else if (s.length === 1 && s >= 'A' && s <= 'Z') { + // shift+letter + key.name = s.toLowerCase(); + key.shift = true; + + } else if (parts = metaKeyCodeRe.exec(s)) { + // meta+character key + key.name = parts[1].toLowerCase(); + key.meta = true; + key.shift = /^[A-Z]$/.test(parts[1]); + + } else if (parts = functionKeyCodeRe.exec(s)) { + // ansi escape sequence + + // reassemble the key code leaving out leading \x1b's, + // the modifier key bitflag and any meaningless "1;" sequence + var code = (parts[1] || '') + (parts[2] || '') + + (parts[4] || '') + (parts[6] || ''), + modifier = (parts[3] || parts[5] || 1) - 1; + + // Parse the key modifier + key.ctrl = !!(modifier & 4); + key.meta = !!(modifier & 10); + key.shift = !!(modifier & 1); + key.code = code; + + // Parse the key itself + switch (code) { + /* xterm/gnome ESC O letter */ + case 'OP': key.name = 'f1'; break; + case 'OQ': key.name = 'f2'; break; + case 'OR': key.name = 'f3'; break; + case 'OS': key.name = 'f4'; break; + + /* xterm/rxvt ESC [ number ~ */ + case '[11~': key.name = 'f1'; break; + case '[12~': key.name = 'f2'; break; + case '[13~': key.name = 'f3'; break; + case '[14~': key.name = 'f4'; break; + + /* from Cygwin and used in libuv */ + case '[[A': key.name = 'f1'; break; + case '[[B': key.name = 'f2'; break; + case '[[C': key.name = 'f3'; break; + case '[[D': key.name = 'f4'; break; + case '[[E': key.name = 'f5'; break; + + /* common */ + case '[15~': key.name = 'f5'; break; + case '[17~': key.name = 'f6'; break; + case '[18~': key.name = 'f7'; break; + case '[19~': key.name = 'f8'; break; + case '[20~': key.name = 'f9'; break; + case '[21~': key.name = 'f10'; break; + case '[23~': key.name = 'f11'; break; + case '[24~': key.name = 'f12'; break; + + /* xterm ESC [ letter */ + case '[A': key.name = 'up'; break; + case '[B': key.name = 'down'; break; + case '[C': key.name = 'right'; break; + case '[D': key.name = 'left'; break; + case '[E': key.name = 'clear'; break; + case '[F': key.name = 'end'; break; + case '[H': key.name = 'home'; break; + + /* xterm/gnome ESC O letter */ + case 'OA': key.name = 'up'; break; + case 'OB': key.name = 'down'; break; + case 'OC': key.name = 'right'; break; + case 'OD': key.name = 'left'; break; + case 'OE': key.name = 'clear'; break; + case 'OF': key.name = 'end'; break; + case 'OH': key.name = 'home'; break; + + /* xterm/rxvt ESC [ number ~ */ + case '[1~': key.name = 'home'; break; + case '[2~': key.name = 'insert'; break; + case '[3~': key.name = 'delete'; break; + case '[4~': key.name = 'end'; break; + case '[5~': key.name = 'pageup'; break; + case '[6~': key.name = 'pagedown'; break; + + /* putty */ + case '[[5~': key.name = 'pageup'; break; + case '[[6~': key.name = 'pagedown'; break; + + /* rxvt */ + case '[7~': key.name = 'home'; break; + case '[8~': key.name = 'end'; break; + + /* rxvt keys with modifiers */ + case '[a': key.name = 'up'; key.shift = true; break; + case '[b': key.name = 'down'; key.shift = true; break; + case '[c': key.name = 'right'; key.shift = true; break; + case '[d': key.name = 'left'; key.shift = true; break; + case '[e': key.name = 'clear'; key.shift = true; break; + + case '[2$': key.name = 'insert'; key.shift = true; break; + case '[3$': key.name = 'delete'; key.shift = true; break; + case '[5$': key.name = 'pageup'; key.shift = true; break; + case '[6$': key.name = 'pagedown'; key.shift = true; break; + case '[7$': key.name = 'home'; key.shift = true; break; + case '[8$': key.name = 'end'; key.shift = true; break; + + case 'Oa': key.name = 'up'; key.ctrl = true; break; + case 'Ob': key.name = 'down'; key.ctrl = true; break; + case 'Oc': key.name = 'right'; key.ctrl = true; break; + case 'Od': key.name = 'left'; key.ctrl = true; break; + case 'Oe': key.name = 'clear'; key.ctrl = true; break; + + case '[2^': key.name = 'insert'; key.ctrl = true; break; + case '[3^': key.name = 'delete'; key.ctrl = true; break; + case '[5^': key.name = 'pageup'; key.ctrl = true; break; + case '[6^': key.name = 'pagedown'; key.ctrl = true; break; + case '[7^': key.name = 'home'; key.ctrl = true; break; + case '[8^': key.name = 'end'; key.ctrl = true; break; + + /* misc. */ + case '[Z': key.name = 'tab'; key.shift = true; break; + default: key.name = 'undefined'; break; + + } + } else if (s.length > 1 && s[0] !== '\x1b') { + // Got a longer-than-one string of characters. + // Probably a paste, since it wasn't a control sequence. + Array.prototype.forEach.call(s, function(c) { + emitKey(stream, c); + }); + return; + } + + if (key.code == '[M') { + key.name = 'mouse'; + var s = key.sequence; + var b = s.charCodeAt(3); + key.x = s.charCodeAt(4) - 040; + key.y = s.charCodeAt(5) - 040; + + key.scroll = 0; + + key.ctrl = !!(1<<4 & b); + key.meta = !!(1<<3 & b); + key.shift = !!(1<<2 & b); + + key.release = (3 & b) === 3; + + if (1<<6 & b) { //scroll + key.scroll = 1 & b ? 1 : -1; + } + + if (!key.release && !key.scroll) { + key.button = b & 3; + } + } + + // Don't emit a key if no name was found + if (key.name === undefined) { + key = undefined; + } + + if (s.length === 1) { + ch = s; + } + + if (key && key.name == 'mouse') { + stream.emit('mousepress', key) + } else if (key || ch) { + stream.emit('keypress', ch, key); + } +} diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/package.json b/node_modules/express/node_modules/commander/node_modules/keypress/package.json new file mode 100644 index 0000000..19c0214 --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/package.json @@ -0,0 +1,35 @@ +{ + "name": "keypress", + "version": "0.1.0", + "description": "Make any Node ReadableStream emit \"keypress\" events", + "author": { + "name": "Nathan Rajlich", + "email": "nathan@tootallnate.net", + "url": "http://tootallnate.net" + }, + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git://github.com/TooTallNate/keypress.git" + }, + "keywords": [ + "keypress", + "readline", + "core" + ], + "license": "MIT", + "readme": "keypress\n========\n### Make any Node ReadableStream emit \"keypress\" events\n\n\nPrevious to Node `v0.8.x`, there was an undocumented `\"keypress\"` event that\n`process.stdin` would emit when it was a TTY. Some people discovered this hidden\ngem, and started using it in their own code.\n\nNow in Node `v0.8.x`, this `\"keypress\"` event does not get emitted by default,\nbut rather only when it is being used in conjuction with the `readline` (or by\nextension, the `repl`) module.\n\nThis module is the exact logic from the node `v0.8.x` releases ripped out into its\nown module.\n\n__Bonus:__ Now with mouse support!\n\nInstallation\n------------\n\nInstall with `npm`:\n\n``` bash\n$ npm install keypress\n```\n\nOr add it to the `\"dependencies\"` section of your _package.json_ file.\n\n\nExample\n-------\n\n#### Listening for \"keypress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"keypress\" events\nkeypress(process.stdin);\n\n// listen for the \"keypress\" event\nprocess.stdin.on('keypress', function (ch, key) {\n console.log('got \"keypress\"', key);\n if (key && key.ctrl && key.name == 'c') {\n process.stdin.pause();\n }\n});\n\nprocess.stdin.setRawMode(true);\nprocess.stdin.resume();\n```\n\n#### Listening for \"mousepress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"mousepress\" (and \"keypress\") events\nkeypress(process.stdin);\n\n// you must enable the mouse events before they will begin firing\nkeypress.enableMouse(process.stdout);\n\nprocess.stdin.on('mousepress', function (info) {\n console.log('got \"mousepress\" event at %d x %d', info.x, info.y);\n});\n\nprocess.on('exit', function () {\n // disable mouse on exit, so that the state\n // is back to normal for the terminal\n keypress.disableMouse(process.stdout);\n});\n```\n\n\nLicense\n-------\n\n(The MIT License)\n\nCopyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/TooTallNate/keypress/issues" + }, + "_id": "keypress@0.1.0", + "dist": { + "shasum": "4a3188d4291b66b4f65edb99f806aa9ae293592a" + }, + "_from": "keypress@0.1.x", + "_resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz" +} diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/test.js b/node_modules/express/node_modules/commander/node_modules/keypress/test.js new file mode 100644 index 0000000..c3f61d7 --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/test.js @@ -0,0 +1,28 @@ + +var keypress = require('./') +keypress(process.stdin) + +if (process.stdin.setRawMode) + process.stdin.setRawMode(true) +else + require('tty').setRawMode(true) + +process.stdin.on('keypress', function (c, key) { + console.log(0, c, key) + if (key && key.ctrl && key.name == 'c') { + process.stdin.pause() + } +}) +process.stdin.on('mousepress', function (mouse) { + console.log(mouse) +}) + +keypress.enableMouse(process.stdout) +process.on('exit', function () { + //disable mouse on exit, so that the state is back to normal + //for the terminal. + keypress.disableMouse(process.stdout) +}) + +process.stdin.resume() + diff --git a/node_modules/express/node_modules/commander/package.json b/node_modules/express/node_modules/commander/package.json new file mode 100644 index 0000000..210e7f6 --- /dev/null +++ b/node_modules/express/node_modules/commander/package.json @@ -0,0 +1,44 @@ +{ + "name": "commander", + "version": "1.2.0", + "description": "the complete solution for node.js command-line programs", + "keywords": [ + "command", + "option", + "parser", + "prompt", + "stdin" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "https://github.com/visionmedia/commander.js.git" + }, + "dependencies": { + "keypress": "0.1.x" + }, + "devDependencies": { + "should": ">= 0.0.1" + }, + "scripts": { + "test": "make test" + }, + "main": "index", + "engines": { + "node": ">= 0.6.x" + }, + "readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineappe');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineappe\n -b, --bbq Add bbq sauce\n -c, --cheese Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] ')\n .option('-i, --integer ', 'An integer argument', parseInt)\n .option('-f, --float ', 'A float argument', parseFloat)\n .option('-r, --range ..', 'A range', range)\n .option('-l, --list ', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .prompt(msg, fn)\n\n Single-line prompt:\n\n```js\nprogram.prompt('name: ', function(name){\n console.log('hi %s', name);\n});\n```\n\n Multi-line prompt:\n\n```js\nprogram.prompt('description:', function(name){\n console.log('hi %s', name);\n});\n```\n\n Coercion:\n\n```js\nprogram.prompt('Age: ', Number, function(age){\n console.log('age: %j', age);\n});\n```\n\n```js\nprogram.prompt('Birthdate: ', Date, function(date){\n console.log('date: %s', date);\n});\n```\n\n```js\nprogram.prompt('Email: ', /^.+@.+\\..+$/, function(email){\n console.log('email: %j', email);\n});\n```\n\n## .password(msg[, mask], fn)\n\nPrompt for password without echoing:\n\n```js\nprogram.password('Password: ', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\nPrompt for password with mask char \"*\":\n\n```js\nprogram.password('Password: ', '*', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\n## .confirm(msg, fn)\n\n Confirm with the given `msg`:\n\n```js\nprogram.confirm('continue? ', function(ok){\n console.log(' got %j', ok);\n});\n```\n\n## .choose(list, fn)\n\n Let the user choose from a `list`:\n\n```js\nvar list = ['tobi', 'loki', 'jane', 'manny', 'luna'];\n\nconsole.log('Choose the coolest pet:');\nprogram.choose(list, function(i){\n console.log('you chose %d \"%s\"', i, list[i]);\n});\n```\n\n## .outputHelp()\n\n Output help information without exiting.\n\n## .help()\n\n Output help information and exit immediately.\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/commander.js/issues" + }, + "_id": "commander@1.2.0", + "dist": { + "shasum": "fd5713bfa153c7d6cc599378a5ab4c45c535029e" + }, + "_from": "commander@1.2.0", + "_resolved": "https://registry.npmjs.org/commander/-/commander-1.2.0.tgz" +} diff --git a/node_modules/express/node_modules/connect/.npmignore b/node_modules/express/node_modules/connect/.npmignore new file mode 100644 index 0000000..9046dde --- /dev/null +++ b/node_modules/express/node_modules/connect/.npmignore @@ -0,0 +1,12 @@ +*.markdown +*.md +.git* +Makefile +benchmarks/ +docs/ +examples/ +install.sh +support/ +test/ +.DS_Store +coverage.html diff --git a/node_modules/express/node_modules/connect/.travis.yml b/node_modules/express/node_modules/connect/.travis.yml new file mode 100644 index 0000000..a12e3f0 --- /dev/null +++ b/node_modules/express/node_modules/connect/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.8" + - "0.10" \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/LICENSE b/node_modules/express/node_modules/connect/LICENSE new file mode 100644 index 0000000..0c5d22d --- /dev/null +++ b/node_modules/express/node_modules/connect/LICENSE @@ -0,0 +1,24 @@ +(The MIT License) + +Copyright (c) 2010 Sencha Inc. +Copyright (c) 2011 LearnBoost +Copyright (c) 2011 TJ Holowaychuk + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/Readme.md b/node_modules/express/node_modules/connect/Readme.md new file mode 100644 index 0000000..7d65f9c --- /dev/null +++ b/node_modules/express/node_modules/connect/Readme.md @@ -0,0 +1,133 @@ +[![build status](https://secure.travis-ci.org/senchalabs/connect.png)](http://travis-ci.org/senchalabs/connect) +# Connect + + Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance "plugins" known as _middleware_. + + Connect is bundled with over _20_ commonly used middleware, including + a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://senchalabs.github.com/connect/). + +```js +var connect = require('connect') + , http = require('http'); + +var app = connect() + .use(connect.favicon()) + .use(connect.logger('dev')) + .use(connect.static('public')) + .use(connect.directory('public')) + .use(connect.cookieParser()) + .use(connect.session({ secret: 'my secret here' })) + .use(function(req, res){ + res.end('Hello from Connect!\n'); + }); + +http.createServer(app).listen(3000); +``` + +## Middleware + + - [csrf](http://www.senchalabs.org/connect/csrf.html) + - [basicAuth](http://www.senchalabs.org/connect/basicAuth.html) + - [bodyParser](http://www.senchalabs.org/connect/bodyParser.html) + - [json](http://www.senchalabs.org/connect/json.html) + - [multipart](http://www.senchalabs.org/connect/multipart.html) + - [urlencoded](http://www.senchalabs.org/connect/urlencoded.html) + - [cookieParser](http://www.senchalabs.org/connect/cookieParser.html) + - [directory](http://www.senchalabs.org/connect/directory.html) + - [compress](http://www.senchalabs.org/connect/compress.html) + - [errorHandler](http://www.senchalabs.org/connect/errorHandler.html) + - [favicon](http://www.senchalabs.org/connect/favicon.html) + - [limit](http://www.senchalabs.org/connect/limit.html) + - [logger](http://www.senchalabs.org/connect/logger.html) + - [methodOverride](http://www.senchalabs.org/connect/methodOverride.html) + - [query](http://www.senchalabs.org/connect/query.html) + - [responseTime](http://www.senchalabs.org/connect/responseTime.html) + - [session](http://www.senchalabs.org/connect/session.html) + - [static](http://www.senchalabs.org/connect/static.html) + - [staticCache](http://www.senchalabs.org/connect/staticCache.html) + - [vhost](http://www.senchalabs.org/connect/vhost.html) + - [subdomains](http://www.senchalabs.org/connect/subdomains.html) + - [cookieSession](http://www.senchalabs.org/connect/cookieSession.html) + +## Running Tests + +first: + + $ npm install -d + +then: + + $ make test + +## Authors + + Below is the output from [git-summary](http://github.com/visionmedia/git-extras). + + + project: connect + commits: 2033 + active : 301 days + files : 171 + authors: + 1414 Tj Holowaychuk 69.6% + 298 visionmedia 14.7% + 191 Tim Caswell 9.4% + 51 TJ Holowaychuk 2.5% + 10 Ryan Olds 0.5% + 8 Astro 0.4% + 5 Nathan Rajlich 0.2% + 5 Jakub Nešetřil 0.2% + 3 Daniel Dickison 0.1% + 3 David Rio Deiros 0.1% + 3 Alexander Simmerl 0.1% + 3 Andreas Lind Petersen 0.1% + 2 Aaron Heckmann 0.1% + 2 Jacques Crocker 0.1% + 2 Fabian Jakobs 0.1% + 2 Brian J Brennan 0.1% + 2 Adam Malcontenti-Wilson 0.1% + 2 Glen Mailer 0.1% + 2 James Campos 0.1% + 1 Trent Mick 0.0% + 1 Troy Kruthoff 0.0% + 1 Wei Zhu 0.0% + 1 comerc 0.0% + 1 darobin 0.0% + 1 nateps 0.0% + 1 Marco Sanson 0.0% + 1 Arthur Taylor 0.0% + 1 Aseem Kishore 0.0% + 1 Bart Teeuwisse 0.0% + 1 Cameron Howey 0.0% + 1 Chad Weider 0.0% + 1 Craig Barnes 0.0% + 1 Eran Hammer-Lahav 0.0% + 1 Gregory McWhirter 0.0% + 1 Guillermo Rauch 0.0% + 1 Jae Kwon 0.0% + 1 Jakub Nesetril 0.0% + 1 Joshua Peek 0.0% + 1 Jxck 0.0% + 1 AJ ONeal 0.0% + 1 Michael Hemesath 0.0% + 1 Morten Siebuhr 0.0% + 1 Samori Gorse 0.0% + 1 Tom Jensen 0.0% + +## Node Compatibility + + Connect `< 1.x` is compatible with node 0.2.x + + + Connect `1.x` is compatible with node 0.4.x + + + Connect (_master_) `2.x` is compatible with node 0.6.x + +## CLA + + [http://sencha.com/cla](http://sencha.com/cla) + +## License + +View the [LICENSE](https://github.com/senchalabs/connect/blob/master/LICENSE) file. The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons used by the `directory` middleware created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/). diff --git a/node_modules/express/node_modules/connect/index.js b/node_modules/express/node_modules/connect/index.js new file mode 100644 index 0000000..23240ee --- /dev/null +++ b/node_modules/express/node_modules/connect/index.js @@ -0,0 +1,4 @@ + +module.exports = process.env.CONNECT_COV + ? require('./lib-cov/connect') + : require('./lib/connect'); \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/cache.js b/node_modules/express/node_modules/connect/lib/cache.js new file mode 100644 index 0000000..052fcdb --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/cache.js @@ -0,0 +1,81 @@ + +/*! + * Connect - Cache + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Expose `Cache`. + */ + +module.exports = Cache; + +/** + * LRU cache store. + * + * @param {Number} limit + * @api private + */ + +function Cache(limit) { + this.store = {}; + this.keys = []; + this.limit = limit; +} + +/** + * Touch `key`, promoting the object. + * + * @param {String} key + * @param {Number} i + * @api private + */ + +Cache.prototype.touch = function(key, i){ + this.keys.splice(i,1); + this.keys.push(key); +}; + +/** + * Remove `key`. + * + * @param {String} key + * @api private + */ + +Cache.prototype.remove = function(key){ + delete this.store[key]; +}; + +/** + * Get the object stored for `key`. + * + * @param {String} key + * @return {Array} + * @api private + */ + +Cache.prototype.get = function(key){ + return this.store[key]; +}; + +/** + * Add a cache `key`. + * + * @param {String} key + * @return {Array} + * @api private + */ + +Cache.prototype.add = function(key){ + // initialize store + var len = this.keys.push(key); + + // limit reached, invalidate LRU + if (len > this.limit) this.remove(this.keys.shift()); + + var arr = this.store[key] = []; + arr.createdAt = new Date; + return arr; +}; diff --git a/node_modules/express/node_modules/connect/lib/connect.js b/node_modules/express/node_modules/connect/lib/connect.js new file mode 100644 index 0000000..72961dc --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/connect.js @@ -0,0 +1,92 @@ +/*! + * Connect + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , proto = require('./proto') + , utils = require('./utils') + , path = require('path') + , basename = path.basename + , fs = require('fs'); + +// node patches + +require('./patch'); + +// expose createServer() as the module + +exports = module.exports = createServer; + +/** + * Framework version. + */ + +exports.version = '2.7.11'; + +/** + * Expose mime module. + */ + +exports.mime = require('./middleware/static').mime; + +/** + * Expose the prototype. + */ + +exports.proto = proto; + +/** + * Auto-load middleware getters. + */ + +exports.middleware = {}; + +/** + * Expose utilities. + */ + +exports.utils = utils; + +/** + * Create a new connect server. + * + * @return {Function} + * @api public + */ + +function createServer() { + function app(req, res, next){ app.handle(req, res, next); } + utils.merge(app, proto); + utils.merge(app, EventEmitter.prototype); + app.route = '/'; + app.stack = []; + for (var i = 0; i < arguments.length; ++i) { + app.use(arguments[i]); + } + return app; +}; + +/** + * Support old `.createServer()` method. + */ + +createServer.createServer = createServer; + +/** + * Auto-load bundled middleware with getters. + */ + +fs.readdirSync(__dirname + '/middleware').forEach(function(filename){ + if (!/\.js$/.test(filename)) return; + var name = basename(filename, '.js'); + function load(){ return require('./middleware/' + name); } + exports.middleware.__defineGetter__(name, load); + exports.__defineGetter__(name, load); +}); diff --git a/node_modules/express/node_modules/connect/lib/index.js b/node_modules/express/node_modules/connect/lib/index.js new file mode 100644 index 0000000..2618ddc --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/index.js @@ -0,0 +1,50 @@ + +/** + * Connect is a middleware framework for node, + * shipping with over 18 bundled middleware and a rich selection of + * 3rd-party middleware. + * + * var app = connect() + * .use(connect.logger('dev')) + * .use(connect.static('public')) + * .use(function(req, res){ + * res.end('hello world\n'); + * }) + * .listen(3000); + * + * Installation: + * + * $ npm install connect + * + * Middleware: + * + * - [logger](logger.html) request logger with custom format support + * - [csrf](csrf.html) Cross-site request forgery protection + * - [compress](compress.html) Gzip compression middleware + * - [basicAuth](basicAuth.html) basic http authentication + * - [bodyParser](bodyParser.html) extensible request body parser + * - [json](json.html) application/json parser + * - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser + * - [multipart](multipart.html) multipart/form-data parser + * - [timeout](timeout.html) request timeouts + * - [cookieParser](cookieParser.html) cookie parser + * - [session](session.html) session management support with bundled MemoryStore + * - [cookieSession](cookieSession.html) cookie-based session support + * - [methodOverride](methodOverride.html) faux HTTP method support + * - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time + * - [staticCache](staticCache.html) memory cache layer for the static() middleware + * - [static](static.html) streaming static file server supporting `Range` and more + * - [directory](directory.html) directory listing middleware + * - [vhost](vhost.html) virtual host sub-domain mapping middleware + * - [favicon](favicon.html) efficient favicon server (with default icon) + * - [limit](limit.html) limit the bytesize of request bodies + * - [query](query.html) automatic querystring parser, populating `req.query` + * - [errorHandler](errorHandler.html) flexible error handler + * + * Links: + * + * - list of [3rd-party](https://github.com/senchalabs/connect/wiki) middleware + * - GitHub [repository](http://github.com/senchalabs/connect) + * - [test documentation](https://github.com/senchalabs/connect/blob/gh-pages/tests.md) + * + */ \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js b/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js new file mode 100644 index 0000000..bc7ec97 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js @@ -0,0 +1,103 @@ + +/*! + * Connect - basicAuth + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , unauthorized = utils.unauthorized; + +/** + * Basic Auth: + * + * Enfore basic authentication by providing a `callback(user, pass)`, + * which must return `true` in order to gain access. Alternatively an async + * method is provided as well, invoking `callback(user, pass, callback)`. Populates + * `req.user`. The final alternative is simply passing username / password + * strings. + * + * Simple username and password + * + * connect(connect.basicAuth('username', 'password')); + * + * Callback verification + * + * connect() + * .use(connect.basicAuth(function(user, pass){ + * return 'tj' == user & 'wahoo' == pass; + * })) + * + * Async callback verification, accepting `fn(err, user)`. + * + * connect() + * .use(connect.basicAuth(function(user, pass, fn){ + * User.authenticate({ user: user, pass: pass }, fn); + * })) + * + * @param {Function|String} callback or username + * @param {String} realm + * @api public + */ + +module.exports = function basicAuth(callback, realm) { + var username, password; + + // user / pass strings + if ('string' == typeof callback) { + username = callback; + password = realm; + if ('string' != typeof password) throw new Error('password argument required'); + realm = arguments[2]; + callback = function(user, pass){ + return user == username && pass == password; + } + } + + realm = realm || 'Authorization Required'; + + return function(req, res, next) { + var authorization = req.headers.authorization; + + if (req.user) return next(); + if (!authorization) return unauthorized(res, realm); + + var parts = authorization.split(' '); + + if (parts.length !== 2) return next(utils.error(400)); + + var scheme = parts[0] + , credentials = new Buffer(parts[1], 'base64').toString() + , index = credentials.indexOf(':'); + + if ('Basic' != scheme || index < 0) return next(utils.error(400)); + + var user = credentials.slice(0, index) + , pass = credentials.slice(index + 1); + + // async + if (callback.length >= 3) { + var pause = utils.pause(req); + callback(user, pass, function(err, user){ + if (err || !user) return unauthorized(res, realm); + req.user = req.remoteUser = user; + next(); + pause.resume(); + }); + // sync + } else { + if (callback(user, pass)) { + req.user = req.remoteUser = user; + next(); + } else { + unauthorized(res, realm); + } + } + } +}; + diff --git a/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js b/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js new file mode 100644 index 0000000..9f692cd --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js @@ -0,0 +1,61 @@ + +/*! + * Connect - bodyParser + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var multipart = require('./multipart') + , urlencoded = require('./urlencoded') + , json = require('./json'); + +/** + * Body parser: + * + * Parse request bodies, supports _application/json_, + * _application/x-www-form-urlencoded_, and _multipart/form-data_. + * + * This is equivalent to: + * + * app.use(connect.json()); + * app.use(connect.urlencoded()); + * app.use(connect.multipart()); + * + * Examples: + * + * connect() + * .use(connect.bodyParser()) + * .use(function(req, res) { + * res.end('viewing user ' + req.body.user.name); + * }); + * + * $ curl -d 'user[name]=tj' http://local/ + * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/ + * + * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function bodyParser(options){ + var _urlencoded = urlencoded(options) + , _multipart = multipart(options) + , _json = json(options); + + return function bodyParser(req, res, next) { + _json(req, res, function(err){ + if (err) return next(err); + _urlencoded(req, res, function(err){ + if (err) return next(err); + _multipart(req, res, next); + }); + }); + } +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/middleware/compress.js b/node_modules/express/node_modules/connect/lib/middleware/compress.js new file mode 100644 index 0000000..db60af5 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/compress.js @@ -0,0 +1,189 @@ +/*! + * Connect - compress + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var zlib = require('zlib'); +var utils = require('../utils'); + +/** + * Supported content-encoding methods. + */ + +exports.methods = { + gzip: zlib.createGzip + , deflate: zlib.createDeflate +}; + +/** + * Default filter function. + */ + +exports.filter = function(req, res){ + return /json|text|javascript/.test(res.getHeader('Content-Type')); +}; + +/** + * Compress: + * + * Compress response data with gzip/deflate. + * + * Filter: + * + * A `filter` callback function may be passed to + * replace the default logic of: + * + * exports.filter = function(req, res){ + * return /json|text|javascript/.test(res.getHeader('Content-Type')); + * }; + * + * Threshold: + * + * Only compress the response if the byte size is at or above a threshold. + * Always compress while streaming. + * + * - `threshold` - string representation of size or bytes as an integer. + * + * Options: + * + * All remaining options are passed to the gzip/deflate + * creation functions. Consult node's docs for additional details. + * + * - `chunkSize` (default: 16*1024) + * - `windowBits` + * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression + * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more + * - `strategy`: compression strategy + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function compress(options) { + options = options || {}; + var names = Object.keys(exports.methods) + , filter = options.filter || exports.filter + , threshold; + + if (false === options.threshold || 0 === options.threshold) { + threshold = 0 + } else if ('string' === typeof options.threshold) { + threshold = utils.parseBytes(options.threshold) + } else { + threshold = options.threshold || 1024 + } + + return function compress(req, res, next){ + var accept = req.headers['accept-encoding'] + , vary = res.getHeader('Vary') + , write = res.write + , end = res.end + , compress = true + , stream + , method; + + // vary + if (!vary) { + res.setHeader('Vary', 'Accept-Encoding'); + } else if (!~vary.indexOf('Accept-Encoding')) { + res.setHeader('Vary', vary + ', Accept-Encoding'); + } + + // see #724 + req.on('close', function(){ + res.write = res.end = function(){}; + }); + + // proxy + + res.write = function(chunk, encoding){ + if (!this.headerSent) this._implicitHeader(); + return stream + ? stream.write(new Buffer(chunk, encoding)) + : write.call(res, chunk, encoding); + }; + + res.end = function(chunk, encoding){ + if (chunk) { + if (!this.headerSent && getSize(chunk) < threshold) compress = false; + this.write(chunk, encoding); + } else if (!this.headerSent) { + // response size === 0 + compress = false; + } + return stream + ? stream.end() + : end.call(res); + }; + + res.on('header', function(){ + if (!compress) return; + + var encoding = res.getHeader('Content-Encoding') || 'identity'; + + // already encoded + if ('identity' != encoding) return; + + // default request filter + if (!filter(req, res)) return; + + // SHOULD use identity + if (!accept) return; + + // head + if ('HEAD' == req.method) return; + + // default to gzip + if ('*' == accept.trim()) method = 'gzip'; + + // compression method + if (!method) { + for (var i = 0, len = names.length; i < len; ++i) { + if (~accept.indexOf(names[i])) { + method = names[i]; + break; + } + } + } + + // compression method + if (!method) return; + + // compression stream + stream = exports.methods[method](options); + + // header fields + res.setHeader('Content-Encoding', method); + res.removeHeader('Content-Length'); + + // compression + + stream.on('data', function(chunk){ + write.call(res, chunk); + }); + + stream.on('end', function(){ + end.call(res); + }); + + stream.on('drain', function() { + res.emit('drain'); + }); + }); + + next(); + }; +}; + +function getSize(chunk) { + return Buffer.isBuffer(chunk) + ? chunk.length + : Buffer.byteLength(chunk); +} \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js b/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js new file mode 100644 index 0000000..5da23f2 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js @@ -0,0 +1,62 @@ + +/*! + * Connect - cookieParser + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('./../utils') + , cookie = require('cookie'); + +/** + * Cookie parser: + * + * Parse _Cookie_ header and populate `req.cookies` + * with an object keyed by the cookie names. Optionally + * you may enabled signed cookie support by passing + * a `secret` string, which assigns `req.secret` so + * it may be used by other middleware. + * + * Examples: + * + * connect() + * .use(connect.cookieParser('optional secret string')) + * .use(function(req, res, next){ + * res.end(JSON.stringify(req.cookies)); + * }) + * + * @param {String} secret + * @return {Function} + * @api public + */ + +module.exports = function cookieParser(secret){ + return function cookieParser(req, res, next) { + if (req.cookies) return next(); + var cookies = req.headers.cookie; + + req.secret = secret; + req.cookies = {}; + req.signedCookies = {}; + + if (cookies) { + try { + req.cookies = cookie.parse(cookies); + if (secret) { + req.signedCookies = utils.parseSignedCookies(req.cookies, secret); + req.signedCookies = utils.parseJSONCookies(req.signedCookies); + } + req.cookies = utils.parseJSONCookies(req.cookies); + } catch (err) { + err.status = 400; + return next(err); + } + } + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/cookieSession.js b/node_modules/express/node_modules/connect/lib/middleware/cookieSession.js new file mode 100644 index 0000000..21011b8 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/cookieSession.js @@ -0,0 +1,115 @@ +/*! + * Connect - cookieSession + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('./../utils') + , Cookie = require('./session/cookie') + , debug = require('debug')('connect:cookieSession') + , signature = require('cookie-signature') + , crc32 = require('buffer-crc32'); + +/** + * Cookie Session: + * + * Cookie session middleware. + * + * var app = connect(); + * app.use(connect.cookieParser()); + * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }})); + * + * Options: + * + * - `key` cookie name defaulting to `connect.sess` + * - `secret` prevents cookie tampering + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") + * + * Clearing sessions: + * + * To clear the session simply set its value to `null`, + * `cookieSession()` will then respond with a 1970 Set-Cookie. + * + * req.session = null; + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function cookieSession(options){ + // TODO: utilize Session/Cookie to unify API + options = options || {}; + var key = options.key || 'connect.sess' + , trustProxy = options.proxy; + + return function cookieSession(req, res, next) { + + // req.secret is for backwards compatibility + var secret = options.secret || req.secret; + if (!secret) throw new Error('`secret` option required for cookie sessions'); + + // default session + req.session = {}; + var cookie = req.session.cookie = new Cookie(options.cookie); + + // pathname mismatch + if (0 != req.originalUrl.indexOf(cookie.path)) return next(); + + // cookieParser secret + if (!options.secret && req.secret) { + req.session = req.signedCookies[key] || {}; + req.session.cookie = cookie; + } else { + // TODO: refactor + var rawCookie = req.cookies[key]; + if (rawCookie) { + var unsigned = utils.parseSignedCookie(rawCookie, secret); + if (unsigned) { + var originalHash = crc32.signed(unsigned); + req.session = utils.parseJSONCookie(unsigned) || {}; + req.session.cookie = cookie; + } + } + } + + res.on('header', function(){ + // removed + if (!req.session) { + debug('clear session'); + cookie.expires = new Date(0); + res.setHeader('Set-Cookie', cookie.serialize(key, '')); + return; + } + + delete req.session.cookie; + + // check security + var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase() + , tls = req.connection.encrypted || (trustProxy && 'https' == proto.split(/\s*,\s*/)[0]); + + // only send secure cookies via https + if (cookie.secure && !tls) return debug('not secured'); + + // serialize + debug('serializing %j', req.session); + var val = 'j:' + JSON.stringify(req.session); + + // compare hashes, no need to set-cookie if unchanged + if (originalHash == crc32.signed(val)) return debug('unmodified session'); + + // set-cookie + val = 's:' + signature.sign(val, secret); + val = cookie.serialize(key, val); + debug('set-cookie %j', cookie); + res.setHeader('Set-Cookie', val); + }); + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/csrf.js b/node_modules/express/node_modules/connect/lib/middleware/csrf.js new file mode 100644 index 0000000..a815444 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/csrf.js @@ -0,0 +1,75 @@ +/*! + * Connect - csrf + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils'); +var uid = require('uid2'); + +/** + * Anti CSRF: + * + * CRSF protection middleware. + * + * By default this middleware generates a token named "_csrf" + * which should be added to requests which mutate + * state, within a hidden form field, query-string etc. This + * token is validated against the visitor's `req.session._csrf` + * property. + * + * The default `value` function checks `req.body` generated + * by the `bodyParser()` middleware, `req.query` generated + * by `query()`, and the "X-CSRF-Token" header field. + * + * This middleware requires session support, thus should be added + * somewhere _below_ `session()` and `cookieParser()`. + * + * Options: + * + * - `value` a function accepting the request, returning the token + * + * @param {Object} options + * @api public + */ + +module.exports = function csrf(options) { + options = options || {}; + var value = options.value || defaultValue; + + return function(req, res, next){ + // generate CSRF token + var token = req.session._csrf || (req.session._csrf = uid(24)); + + // ignore these methods + if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next(); + + // determine value + var val = value(req); + + // check + if (val != token) return next(utils.error(403)); + + next(); + } +}; + +/** + * Default value function, checking the `req.body` + * and `req.query` for the CSRF token. + * + * @param {IncomingMessage} req + * @return {String} + * @api private + */ + +function defaultValue(req) { + return (req.body && req.body._csrf) + || (req.query && req.query._csrf) + || (req.headers['x-csrf-token']) + || (req.headers['x-xsrf-token']); +} diff --git a/node_modules/express/node_modules/connect/lib/middleware/directory.js b/node_modules/express/node_modules/connect/lib/middleware/directory.js new file mode 100644 index 0000000..1c925a7 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/directory.js @@ -0,0 +1,229 @@ + +/*! + * Connect - directory + * Copyright(c) 2011 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +// TODO: icon / style for directories +// TODO: arrow key navigation +// TODO: make icons extensible + +/** + * Module dependencies. + */ + +var fs = require('fs') + , parse = require('url').parse + , utils = require('../utils') + , path = require('path') + , normalize = path.normalize + , extname = path.extname + , join = path.join; + +/*! + * Icon cache. + */ + +var cache = {}; + +/** + * Directory: + * + * Serve directory listings with the given `root` path. + * + * Options: + * + * - `hidden` display hidden (dot) files. Defaults to false. + * - `icons` display icons. Defaults to false. + * - `filter` Apply this filter function to files. Defaults to false. + * + * @param {String} root + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function directory(root, options){ + options = options || {}; + + // root required + if (!root) throw new Error('directory() root path required'); + var hidden = options.hidden + , icons = options.icons + , filter = options.filter + , root = normalize(root); + + return function directory(req, res, next) { + if ('GET' != req.method && 'HEAD' != req.method) return next(); + + var accept = req.headers.accept || 'text/plain' + , url = parse(req.url) + , dir = decodeURIComponent(url.pathname) + , path = normalize(join(root, dir)) + , originalUrl = parse(req.originalUrl) + , originalDir = decodeURIComponent(originalUrl.pathname) + , showUp = path != root && path != root + '/'; + + // null byte(s), bad request + if (~path.indexOf('\0')) return next(utils.error(400)); + + // malicious path, forbidden + if (0 != path.indexOf(root)) return next(utils.error(403)); + + // check if we have a directory + fs.stat(path, function(err, stat){ + if (err) return 'ENOENT' == err.code + ? next() + : next(err); + + if (!stat.isDirectory()) return next(); + + // fetch files + fs.readdir(path, function(err, files){ + if (err) return next(err); + if (!hidden) files = removeHidden(files); + if (filter) files = files.filter(filter); + files.sort(); + + // content-negotiation + for (var key in exports) { + if (~accept.indexOf(key) || ~accept.indexOf('*/*')) { + exports[key](req, res, files, next, originalDir, showUp, icons); + return; + } + } + + // not acceptable + next(utils.error(406)); + }); + }); + }; +}; + +/** + * Respond with text/html. + */ + +exports.html = function(req, res, files, next, dir, showUp, icons){ + fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){ + if (err) return next(err); + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){ + if (err) return next(err); + if (showUp) files.unshift('..'); + str = str + .replace('{style}', style) + .replace('{files}', html(files, dir, icons)) + .replace('{directory}', dir) + .replace('{linked-path}', htmlPath(dir)); + res.setHeader('Content-Type', 'text/html'); + res.setHeader('Content-Length', str.length); + res.end(str); + }); + }); +}; + +/** + * Respond with application/json. + */ + +exports.json = function(req, res, files){ + files = JSON.stringify(files); + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Length', files.length); + res.end(files); +}; + +/** + * Respond with text/plain. + */ + +exports.plain = function(req, res, files){ + files = files.join('\n') + '\n'; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Length', files.length); + res.end(files); +}; + +/** + * Map html `dir`, returning a linked path. + */ + +function htmlPath(dir) { + var curr = []; + return dir.split('/').map(function(part){ + curr.push(part); + return '' + part + ''; + }).join(' / '); +} + +/** + * Map html `files`, returning an html unordered list. + */ + +function html(files, dir, useIcons) { + return '
    ' + files.map(function(file){ + var icon = '' + , classes = []; + + if (useIcons && '..' != file) { + icon = icons[extname(file)] || icons.default; + icon = ''; + classes.push('icon'); + } + + return '
  • ' + + icon + file + '
  • '; + + }).join('\n') + '
'; +} + +/** + * Load and cache the given `icon`. + * + * @param {String} icon + * @return {String} + * @api private + */ + +function load(icon) { + if (cache[icon]) return cache[icon]; + return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64'); +} + +/** + * Filter "hidden" `files`, aka files + * beginning with a `.`. + * + * @param {Array} files + * @return {Array} + * @api private + */ + +function removeHidden(files) { + return files.filter(function(file){ + return '.' != file[0]; + }); +} + +/** + * Icon map. + */ + +var icons = { + '.js': 'page_white_code_red.png' + , '.c': 'page_white_c.png' + , '.h': 'page_white_h.png' + , '.cc': 'page_white_cplusplus.png' + , '.php': 'page_white_php.png' + , '.rb': 'page_white_ruby.png' + , '.cpp': 'page_white_cplusplus.png' + , '.swf': 'page_white_flash.png' + , '.pdf': 'page_white_acrobat.png' + , 'default': 'page_white.png' +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js b/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js new file mode 100644 index 0000000..4a84edc --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js @@ -0,0 +1,86 @@ +/*! + * Connect - errorHandler + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , fs = require('fs'); + +// environment + +var env = process.env.NODE_ENV || 'development'; + +/** + * Error handler: + * + * Development error handler, providing stack traces + * and error message responses for requests accepting text, html, + * or json. + * + * Text: + * + * By default, and when _text/plain_ is accepted a simple stack trace + * or error message will be returned. + * + * JSON: + * + * When _application/json_ is accepted, connect will respond with + * an object in the form of `{ "error": error }`. + * + * HTML: + * + * When accepted connect will output a nice html stack trace. + * + * @return {Function} + * @api public + */ + +exports = module.exports = function errorHandler(){ + return function errorHandler(err, req, res, next){ + if (err.status) res.statusCode = err.status; + if (res.statusCode < 400) res.statusCode = 500; + if ('test' != env) console.error(err.stack); + var accept = req.headers.accept || ''; + // html + if (~accept.indexOf('html')) { + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){ + fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){ + var stack = (err.stack || '') + .split('\n').slice(1) + .map(function(v){ return '
  • ' + v + '
  • '; }).join(''); + html = html + .replace('{style}', style) + .replace('{stack}', stack) + .replace('{title}', exports.title) + .replace('{statusCode}', res.statusCode) + .replace(/\{error\}/g, utils.escape(err.toString())); + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + res.end(html); + }); + }); + // json + } else if (~accept.indexOf('json')) { + var error = { message: err.message, stack: err.stack }; + for (var prop in err) error[prop] = err[prop]; + var json = JSON.stringify({ error: error }); + res.setHeader('Content-Type', 'application/json'); + res.end(json); + // plain text + } else { + res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' }); + res.end(err.stack); + } + }; +}; + +/** + * Template title, framework authors may override this value. + */ + +exports.title = 'Connect'; diff --git a/node_modules/express/node_modules/connect/lib/middleware/favicon.js b/node_modules/express/node_modules/connect/lib/middleware/favicon.js new file mode 100644 index 0000000..ef54354 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/favicon.js @@ -0,0 +1,80 @@ +/*! + * Connect - favicon + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , utils = require('../utils'); + +/** + * Favicon: + * + * By default serves the connect favicon, or the favicon + * located by the given `path`. + * + * Options: + * + * - `maxAge` cache-control max-age directive, defaulting to 1 day + * + * Examples: + * + * Serve default favicon: + * + * connect() + * .use(connect.favicon()) + * + * Serve favicon before logging for brevity: + * + * connect() + * .use(connect.favicon()) + * .use(connect.logger('dev')) + * + * Serve custom favicon: + * + * connect() + * .use(connect.favicon('public/favicon.ico')) + * + * @param {String} path + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function favicon(path, options){ + var options = options || {} + , path = path || __dirname + '/../public/favicon.ico' + , maxAge = options.maxAge || 86400000 + , icon; // favicon cache + + return function favicon(req, res, next){ + if ('/favicon.ico' == req.url) { + if (icon) { + res.writeHead(200, icon.headers); + res.end(icon.body); + } else { + fs.readFile(path, function(err, buf){ + if (err) return next(err); + icon = { + headers: { + 'Content-Type': 'image/x-icon' + , 'Content-Length': buf.length + , 'ETag': '"' + utils.md5(buf) + '"' + , 'Cache-Control': 'public, max-age=' + (maxAge / 1000) + }, + body: buf + }; + res.writeHead(200, icon.headers); + res.end(icon.body); + }); + } + } else { + next(); + } + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/json.js b/node_modules/express/node_modules/connect/lib/middleware/json.js new file mode 100644 index 0000000..29878d2 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/json.js @@ -0,0 +1,89 @@ + +/*! + * Connect - json + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , _limit = require('./limit'); + +/** + * noop middleware. + */ + +function noop(req, res, next) { + next(); +} + +/** + * JSON: + * + * Parse JSON request bodies, providing the + * parsed object as `req.body`. + * + * Options: + * + * - `strict` when `false` anything `JSON.parse()` accepts will be parsed + * - `reviver` used as the second "reviver" argument for JSON.parse + * - `limit` byte limit disabled by default + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(options){ + var options = options || {} + , strict = options.strict !== false; + + var limit = options.limit + ? _limit(options.limit) + : noop; + + return function json(req, res, next) { + if (req._body) return next(); + req.body = req.body || {}; + + if (!utils.hasBody(req)) return next(); + + // check Content-Type + if (!exports.regexp.test(utils.mime(req))) return next(); + + // flag as parsed + req._body = true; + + // parse + limit(req, res, function(err){ + if (err) return next(err); + var buf = ''; + req.setEncoding('utf8'); + req.on('data', function(chunk){ buf += chunk }); + req.on('end', function(){ + var first = buf.trim()[0]; + + if (0 == buf.length) { + return next(utils.error(400, 'invalid json, empty body')); + } + + if (strict && '{' != first && '[' != first) return next(utils.error(400, 'invalid json')); + try { + req.body = JSON.parse(buf, options.reviver); + } catch (err){ + err.body = buf; + err.status = 400; + return next(err); + } + next(); + }); + }); + }; +}; + +exports.regexp = /^application\/([\w!#\$%&\*`\-\.\^~]*\+)?json$/i; + diff --git a/node_modules/express/node_modules/connect/lib/middleware/limit.js b/node_modules/express/node_modules/connect/lib/middleware/limit.js new file mode 100644 index 0000000..09bd1c4 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/limit.js @@ -0,0 +1,78 @@ + +/*! + * Connect - limit + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils'), + brokenPause = utils.brokenPause; + +/** + * Limit: + * + * Limit request bodies to the given size in `bytes`. + * + * A string representation of the bytesize may also be passed, + * for example "5mb", "200kb", "1gb", etc. + * + * connect() + * .use(connect.limit('5.5mb')) + * .use(handleImageUpload) + * + * @param {Number|String} bytes + * @return {Function} + * @api public + */ + +module.exports = function limit(bytes){ + if ('string' == typeof bytes) bytes = utils.parseBytes(bytes); + if ('number' != typeof bytes) throw new Error('limit() bytes required'); + return function limit(req, res, next){ + var received = 0 + , len = req.headers['content-length'] + ? parseInt(req.headers['content-length'], 10) + : null; + + // self-awareness + if (req._limit) return next(); + req._limit = true; + + // limit by content-length + if (len && len > bytes) return next(utils.error(413)); + + // limit + if (brokenPause) { + listen(); + } else { + req.on('newListener', function handler(event) { + if (event !== 'data') return; + + req.removeListener('newListener', handler); + // Start listening at the end of the current loop + // otherwise the request will be consumed too early. + // Sideaffect is `limit` will miss the first chunk, + // but that's not a big deal. + // Unfortunately, the tests don't have large enough + // request bodies to test this. + process.nextTick(listen); + }); + }; + + next(); + + function listen() { + req.on('data', function(chunk) { + received += Buffer.isBuffer(chunk) + ? chunk.length : + Buffer.byteLength(chunk); + + if (received > bytes) req.destroy(); + }); + }; + }; +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/middleware/logger.js b/node_modules/express/node_modules/connect/lib/middleware/logger.js new file mode 100644 index 0000000..7e88248 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/logger.js @@ -0,0 +1,339 @@ +/*! + * Connect - logger + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var bytes = require('bytes'); + +/*! + * Log buffer. + */ + +var buf = []; + +/*! + * Default log buffer duration. + */ + +var defaultBufferDuration = 1000; + +/** + * Logger: + * + * Log requests with the given `options` or a `format` string. + * + * Options: + * + * - `format` Format string, see below for tokens + * - `stream` Output stream, defaults to _stdout_ + * - `buffer` Buffer duration, defaults to 1000ms when _true_ + * - `immediate` Write log line on request instead of response (for response times) + * + * Tokens: + * + * - `:req[header]` ex: `:req[Accept]` + * - `:res[header]` ex: `:res[Content-Length]` + * - `:http-version` + * - `:response-time` + * - `:remote-addr` + * - `:date` + * - `:method` + * - `:url` + * - `:referrer` + * - `:user-agent` + * - `:status` + * + * Formats: + * + * Pre-defined formats that ship with connect: + * + * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"' + * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms' + * - `tiny` ':method :url :status :res[content-length] - :response-time ms' + * - `dev` concise output colored by response status for development use + * + * Examples: + * + * connect.logger() // default + * connect.logger('short') + * connect.logger('tiny') + * connect.logger({ immediate: true, format: 'dev' }) + * connect.logger(':method :url - :referrer') + * connect.logger(':req[content-type] -> :res[content-type]') + * connect.logger(function(tokens, req, res){ return 'some format string' }) + * + * Defining Tokens: + * + * To define a token, simply invoke `connect.logger.token()` with the + * name and a callback function. The value returned is then available + * as ":type" in this case. + * + * connect.logger.token('type', function(req, res){ return req.headers['content-type']; }) + * + * Defining Formats: + * + * All default formats are defined this way, however it's public API as well: + * + * connect.logger.format('name', 'string or function') + * + * @param {String|Function|Object} format or options + * @return {Function} + * @api public + */ + +exports = module.exports = function logger(options) { + if ('object' == typeof options) { + options = options || {}; + } else if (options) { + options = { format: options }; + } else { + options = {}; + } + + // output on request instead of response + var immediate = options.immediate; + + // format name + var fmt = exports[options.format] || options.format || exports.default; + + // compile format + if ('function' != typeof fmt) fmt = compile(fmt); + + // options + var stream = options.stream || process.stdout + , buffer = options.buffer; + + // buffering support + if (buffer) { + var realStream = stream + , interval = 'number' == typeof buffer + ? buffer + : defaultBufferDuration; + + // flush interval + setInterval(function(){ + if (buf.length) { + realStream.write(buf.join('')); + buf.length = 0; + } + }, interval); + + // swap the stream + stream = { + write: function(str){ + buf.push(str); + } + }; + } + + return function logger(req, res, next) { + req._startTime = new Date; + + // immediate + if (immediate) { + var line = fmt(exports, req, res); + if (null == line) return; + stream.write(line + '\n'); + // proxy end to output logging + } else { + var end = res.end; + res.end = function(chunk, encoding){ + res.end = end; + res.end(chunk, encoding); + var line = fmt(exports, req, res); + if (null == line) return; + stream.write(line + '\n'); + }; + } + + + next(); + }; +}; + +/** + * Compile `fmt` into a function. + * + * @param {String} fmt + * @return {Function} + * @api private + */ + +function compile(fmt) { + fmt = fmt.replace(/"/g, '\\"'); + var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){ + return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "'; + }) + '";' + return new Function('tokens, req, res', js); +}; + +/** + * Define a token function with the given `name`, + * and callback `fn(req, res)`. + * + * @param {String} name + * @param {Function} fn + * @return {Object} exports for chaining + * @api public + */ + +exports.token = function(name, fn) { + exports[name] = fn; + return this; +}; + +/** + * Define a `fmt` with the given `name`. + * + * @param {String} name + * @param {String|Function} fmt + * @return {Object} exports for chaining + * @api public + */ + +exports.format = function(name, str){ + exports[name] = str; + return this; +}; + +/** + * Default format. + */ + +exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'); + +/** + * Short format. + */ + +exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'); + +/** + * Tiny format. + */ + +exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms'); + +/** + * dev (colored) + */ + +exports.format('dev', function(tokens, req, res){ + var status = res.statusCode + , len = parseInt(res.getHeader('Content-Length'), 10) + , color = 32; + + if (status >= 500) color = 31 + else if (status >= 400) color = 33 + else if (status >= 300) color = 36; + + len = isNaN(len) + ? '' + : len = ' - ' + bytes(len); + + return '\x1b[90m' + req.method + + ' ' + req.originalUrl + ' ' + + '\x1b[' + color + 'm' + res.statusCode + + ' \x1b[90m' + + (new Date - req._startTime) + + 'ms' + len + + '\x1b[0m'; +}); + +/** + * request url + */ + +exports.token('url', function(req){ + return req.originalUrl || req.url; +}); + +/** + * request method + */ + +exports.token('method', function(req){ + return req.method; +}); + +/** + * response time in milliseconds + */ + +exports.token('response-time', function(req){ + return new Date - req._startTime; +}); + +/** + * UTC date + */ + +exports.token('date', function(){ + return new Date().toUTCString(); +}); + +/** + * response status code + */ + +exports.token('status', function(req, res){ + return res.statusCode; +}); + +/** + * normalized referrer + */ + +exports.token('referrer', function(req){ + return req.headers['referer'] || req.headers['referrer']; +}); + +/** + * remote address + */ + +exports.token('remote-addr', function(req){ + if (req.ip) return req.ip; + var sock = req.socket; + if (sock.socket) return sock.socket.remoteAddress; + return sock.remoteAddress; +}); + +/** + * HTTP version + */ + +exports.token('http-version', function(req){ + return req.httpVersionMajor + '.' + req.httpVersionMinor; +}); + +/** + * UA string + */ + +exports.token('user-agent', function(req){ + return req.headers['user-agent']; +}); + +/** + * request header + */ + +exports.token('req', function(req, res, field){ + return req.headers[field.toLowerCase()]; +}); + +/** + * response header + */ + +exports.token('res', function(req, res, field){ + return (res._headers || {})[field.toLowerCase()]; +}); + diff --git a/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js b/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js new file mode 100644 index 0000000..9ce4939 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js @@ -0,0 +1,59 @@ + +/*! + * Connect - methodOverride + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var methods = require('methods'); + +/** + * Method Override: + * + * Provides faux HTTP method support. + * + * Pass an optional `key` to use when checking for + * a method override, othewise defaults to _\_method_. + * The original method is available via `req.originalMethod`. + * + * @param {String} key + * @return {Function} + * @api public + */ + +module.exports = function methodOverride(key){ + key = key || "_method"; + return function methodOverride(req, res, next) { + var method; + req.originalMethod = req.originalMethod || req.method; + + // req.body + if (req.body && key in req.body) { + method = req.body[key].toLowerCase(); + delete req.body[key]; + } + + // check X-HTTP-Method-Override + if (req.headers['x-http-method-override']) { + method = req.headers['x-http-method-override'].toLowerCase(); + } + + // replace + if (supports(method)) req.method = method.toUpperCase(); + + next(); + }; +}; + +/** + * Check if node supports `method`. + */ + +function supports(method) { + return ~methods.indexOf(method); +} diff --git a/node_modules/express/node_modules/connect/lib/middleware/multipart.js b/node_modules/express/node_modules/connect/lib/middleware/multipart.js new file mode 100644 index 0000000..7b26fae --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/multipart.js @@ -0,0 +1,133 @@ +/*! + * Connect - multipart + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var formidable = require('formidable') + , _limit = require('./limit') + , utils = require('../utils') + , qs = require('qs'); + +/** + * noop middleware. + */ + +function noop(req, res, next) { + next(); +} + +/** + * Multipart: + * + * Parse multipart/form-data request bodies, + * providing the parsed object as `req.body` + * and `req.files`. + * + * Configuration: + * + * The options passed are merged with [formidable](https://github.com/felixge/node-formidable)'s + * `IncomingForm` object, allowing you to configure the upload directory, + * size limits, etc. For example if you wish to change the upload dir do the following. + * + * app.use(connect.multipart({ uploadDir: path })); + * + * Options: + * + * - `limit` byte limit defaulting to none + * - `defer` defers processing and exposes the Formidable form object as `req.form`. + * `next()` is called without waiting for the form's "end" event. + * This option is useful if you need to bind to the "progress" event, for example. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(options){ + options = options || {}; + + var limit = options.limit + ? _limit(options.limit) + : noop; + + return function multipart(req, res, next) { + if (req._body) return next(); + req.body = req.body || {}; + req.files = req.files || {}; + + if (!utils.hasBody(req)) return next(); + + // ignore GET + if ('GET' == req.method || 'HEAD' == req.method) return next(); + + // check Content-Type + if ('multipart/form-data' != utils.mime(req)) return next(); + + // flag as parsed + req._body = true; + + // parse + limit(req, res, function(err){ + if (err) return next(err); + + var form = new formidable.IncomingForm + , data = {} + , files = {} + , done; + + Object.keys(options).forEach(function(key){ + form[key] = options[key]; + }); + + function ondata(name, val, data){ + if (Array.isArray(data[name])) { + data[name].push(val); + } else if (data[name]) { + data[name] = [data[name], val]; + } else { + data[name] = val; + } + } + + form.on('field', function(name, val){ + ondata(name, val, data); + }); + + form.on('file', function(name, val){ + ondata(name, val, files); + }); + + form.on('error', function(err){ + if (!options.defer) { + err.status = 400; + next(err); + } + done = true; + }); + + form.on('end', function(){ + if (done) return; + try { + req.body = qs.parse(data); + req.files = qs.parse(files); + if (!options.defer) next(); + } catch (err) { + form.emit('error', err); + } + }); + + form.parse(req); + + if (options.defer) { + req.form = form; + next(); + } + }); + } +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/query.js b/node_modules/express/node_modules/connect/lib/middleware/query.js new file mode 100644 index 0000000..93fc5d3 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/query.js @@ -0,0 +1,46 @@ +/*! + * Connect - query + * Copyright(c) 2011 TJ Holowaychuk + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var qs = require('qs') + , parse = require('../utils').parseUrl; + +/** + * Query: + * + * Automatically parse the query-string when available, + * populating the `req.query` object. + * + * Examples: + * + * connect() + * .use(connect.query()) + * .use(function(req, res){ + * res.end(JSON.stringify(req.query)); + * }); + * + * The `options` passed are provided to qs.parse function. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function query(options){ + return function query(req, res, next){ + if (!req.query) { + req.query = ~req.url.indexOf('?') + ? qs.parse(parse(req).query, options) + : {}; + } + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/responseTime.js b/node_modules/express/node_modules/connect/lib/middleware/responseTime.js new file mode 100644 index 0000000..62abc04 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/responseTime.js @@ -0,0 +1,32 @@ + +/*! + * Connect - responseTime + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Reponse time: + * + * Adds the `X-Response-Time` header displaying the response + * duration in milliseconds. + * + * @return {Function} + * @api public + */ + +module.exports = function responseTime(){ + return function(req, res, next){ + var start = new Date; + + if (res._responseTime) return next(); + res._responseTime = true; + + res.on('header', function(){ + var duration = new Date - start; + res.setHeader('X-Response-Time', duration + 'ms'); + }); + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/session.js b/node_modules/express/node_modules/connect/lib/middleware/session.js new file mode 100644 index 0000000..a107295 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session.js @@ -0,0 +1,355 @@ +/*! + * Connect - session + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Session = require('./session/session') + , debug = require('debug')('connect:session') + , MemoryStore = require('./session/memory') + , signature = require('cookie-signature') + , Cookie = require('./session/cookie') + , Store = require('./session/store') + , utils = require('./../utils') + , uid = require('uid2') + , parse = utils.parseUrl + , crc32 = require('buffer-crc32'); + +// environment + +var env = process.env.NODE_ENV; + +/** + * Expose the middleware. + */ + +exports = module.exports = session; + +/** + * Expose constructors. + */ + +exports.Store = Store; +exports.Cookie = Cookie; +exports.Session = Session; +exports.MemoryStore = MemoryStore; + +/** + * Warning message for `MemoryStore` usage in production. + */ + +var warning = 'Warning: connection.session() MemoryStore is not\n' + + 'designed for a production environment, as it will leak\n' + + 'memory, and will not scale past a single process.'; + +/** + * Session: + * + * Setup session store with the given `options`. + * + * Session data is _not_ saved in the cookie itself, however + * cookies are used, so we must use the [cookieParser()](cookieParser.html) + * middleware _before_ `session()`. + * + * Examples: + * + * connect() + * .use(connect.cookieParser()) + * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }})) + * + * Options: + * + * - `key` cookie name defaulting to `connect.sid` + * - `store` session store instance + * - `secret` session cookie is signed with this secret to prevent tampering + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") + * + * Cookie option: + * + * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set + * so the cookie becomes a browser-session cookie. When the user closes the + * browser the cookie (and session) will be removed. + * + * ## req.session + * + * To store or access session data, simply use the request property `req.session`, + * which is (generally) serialized as JSON by the store, so nested objects + * are typically fine. For example below is a user-specific view counter: + * + * connect() + * .use(connect.favicon()) + * .use(connect.cookieParser()) + * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})) + * .use(function(req, res, next){ + * var sess = req.session; + * if (sess.views) { + * res.setHeader('Content-Type', 'text/html'); + * res.write('

    views: ' + sess.views + '

    '); + * res.write('

    expires in: ' + (sess.cookie.maxAge / 1000) + 's

    '); + * res.end(); + * sess.views++; + * } else { + * sess.views = 1; + * res.end('welcome to the session demo. refresh!'); + * } + * } + * )).listen(3000); + * + * ## Session#regenerate() + * + * To regenerate the session simply invoke the method, once complete + * a new SID and `Session` instance will be initialized at `req.session`. + * + * req.session.regenerate(function(err){ + * // will have a new session here + * }); + * + * ## Session#destroy() + * + * Destroys the session, removing `req.session`, will be re-generated next request. + * + * req.session.destroy(function(err){ + * // cannot access session here + * }); + * + * ## Session#reload() + * + * Reloads the session data. + * + * req.session.reload(function(err){ + * // session updated + * }); + * + * ## Session#save() + * + * Save the session. + * + * req.session.save(function(err){ + * // session saved + * }); + * + * ## Session#touch() + * + * Updates the `.maxAge` property. Typically this is + * not necessary to call, as the session middleware does this for you. + * + * ## Session#cookie + * + * Each session has a unique cookie object accompany it. This allows + * you to alter the session cookie per visitor. For example we can + * set `req.session.cookie.expires` to `false` to enable the cookie + * to remain for only the duration of the user-agent. + * + * ## Session#maxAge + * + * Alternatively `req.session.cookie.maxAge` will return the time + * remaining in milliseconds, which we may also re-assign a new value + * to adjust the `.expires` property appropriately. The following + * are essentially equivalent + * + * var hour = 3600000; + * req.session.cookie.expires = new Date(Date.now() + hour); + * req.session.cookie.maxAge = hour; + * + * For example when `maxAge` is set to `60000` (one minute), and 30 seconds + * has elapsed it will return `30000` until the current request has completed, + * at which time `req.session.touch()` is called to reset `req.session.maxAge` + * to its original value. + * + * req.session.cookie.maxAge; + * // => 30000 + * + * Session Store Implementation: + * + * Every session store _must_ implement the following methods + * + * - `.get(sid, callback)` + * - `.set(sid, session, callback)` + * - `.destroy(sid, callback)` + * + * Recommended methods include, but are not limited to: + * + * - `.length(callback)` + * - `.clear(callback)` + * + * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +function session(options){ + var options = options || {} + , key = options.key || 'connect.sid' + , store = options.store || new MemoryStore + , cookie = options.cookie || {} + , trustProxy = options.proxy + , storeReady = true; + + // notify user that this store is not + // meant for a production environment + if ('production' == env && store instanceof MemoryStore) { + console.warn(warning); + } + + // generates the new session + store.generate = function(req){ + req.sessionID = uid(24); + req.session = new Session(req); + req.session.cookie = new Cookie(cookie); + }; + + store.on('disconnect', function(){ storeReady = false; }); + store.on('connect', function(){ storeReady = true; }); + + return function session(req, res, next) { + // self-awareness + if (req.session) return next(); + + // Handle connection as if there is no session if + // the store has temporarily disconnected etc + if (!storeReady) return debug('store is disconnected'), next(); + + // pathname mismatch + if (0 != req.originalUrl.indexOf(cookie.path || '/')) return next(); + + // backwards compatibility for signed cookies + // req.secret is passed from the cookie parser middleware + var secret = options.secret || req.secret; + + // ensure secret is available or bail + if (!secret) throw new Error('`secret` option required for sessions'); + + // parse url + var originalHash + , originalId; + + // expose store + req.sessionStore = store; + + // grab the session cookie value and check the signature + var rawCookie = req.cookies[key]; + + // get signedCookies for backwards compat with signed cookies + var unsignedCookie = req.signedCookies[key]; + + if (!unsignedCookie && rawCookie) { + unsignedCookie = utils.parseSignedCookie(rawCookie, secret); + } + + // set-cookie + res.on('header', function(){ + if (!req.session) return; + var cookie = req.session.cookie + , proto = (req.headers['x-forwarded-proto'] || '').split(',')[0].toLowerCase().trim() + , tls = req.connection.encrypted || (trustProxy && 'https' == proto) + , isNew = unsignedCookie != req.sessionID; + + // only send secure cookies via https + if (cookie.secure && !tls) return debug('not secured'); + + // long expires, handle expiry server-side + if (!isNew && cookie.hasLongExpires) return debug('already set cookie'); + + // browser-session length cookie + if (null == cookie.expires) { + if (!isNew) return debug('already set browser-session cookie'); + // compare hashes and ids + } else if (originalHash == hash(req.session) && originalId == req.session.id) { + return debug('unmodified session'); + } + + var val = 's:' + signature.sign(req.sessionID, secret); + val = cookie.serialize(key, val); + debug('set-cookie %s', val); + res.setHeader('Set-Cookie', val); + }); + + // proxy end() to commit the session + var end = res.end; + res.end = function(data, encoding){ + res.end = end; + if (!req.session) return res.end(data, encoding); + debug('saving'); + req.session.resetMaxAge(); + req.session.save(function(err){ + if (err) console.error(err.stack); + debug('saved'); + res.end(data, encoding); + }); + }; + + // generate the session + function generate() { + store.generate(req); + } + + // get the sessionID from the cookie + req.sessionID = unsignedCookie; + + // generate a session if the browser doesn't send a sessionID + if (!req.sessionID) { + debug('no SID sent, generating session'); + generate(); + next(); + return; + } + + // generate the session object + var pause = utils.pause(req); + debug('fetching %s', req.sessionID); + store.get(req.sessionID, function(err, sess){ + // proxy to resume() events + var _next = next; + next = function(err){ + _next(err); + pause.resume(); + }; + + // error handling + if (err) { + debug('error %j', err); + if ('ENOENT' == err.code) { + generate(); + next(); + } else { + next(err); + } + // no session + } else if (!sess) { + debug('no session found'); + generate(); + next(); + // populate req.session + } else { + debug('session found'); + store.createSession(req, sess); + originalId = req.sessionID; + originalHash = hash(sess); + next(); + } + }); + }; +}; + +/** + * Hash the given `sess` object omitting changes + * to `.cookie`. + * + * @param {Object} sess + * @return {String} + * @api private + */ + +function hash(sess) { + return crc32.signed(JSON.stringify(sess, function(key, val){ + if ('cookie' != key) return val; + })); +} diff --git a/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js b/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js new file mode 100644 index 0000000..cdce2a5 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js @@ -0,0 +1,140 @@ + +/*! + * Connect - session - Cookie + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../../utils') + , cookie = require('cookie'); + +/** + * Initialize a new `Cookie` with the given `options`. + * + * @param {IncomingMessage} req + * @param {Object} options + * @api private + */ + +var Cookie = module.exports = function Cookie(options) { + this.path = '/'; + this.maxAge = null; + this.httpOnly = true; + if (options) utils.merge(this, options); + this.originalMaxAge = undefined == this.originalMaxAge + ? this.maxAge + : this.originalMaxAge; +}; + +/*! + * Prototype. + */ + +Cookie.prototype = { + + /** + * Set expires `date`. + * + * @param {Date} date + * @api public + */ + + set expires(date) { + this._expires = date; + this.originalMaxAge = this.maxAge; + }, + + /** + * Get expires `date`. + * + * @return {Date} + * @api public + */ + + get expires() { + return this._expires; + }, + + /** + * Set expires via max-age in `ms`. + * + * @param {Number} ms + * @api public + */ + + set maxAge(ms) { + this.expires = 'number' == typeof ms + ? new Date(Date.now() + ms) + : ms; + }, + + /** + * Get expires max-age in `ms`. + * + * @return {Number} + * @api public + */ + + get maxAge() { + return this.expires instanceof Date + ? this.expires.valueOf() - Date.now() + : this.expires; + }, + + /** + * Return cookie data object. + * + * @return {Object} + * @api private + */ + + get data() { + return { + originalMaxAge: this.originalMaxAge + , expires: this._expires + , secure: this.secure + , httpOnly: this.httpOnly + , domain: this.domain + , path: this.path + } + }, + + /** + * Check if the cookie has a reasonably large max-age. + * + * @return {Boolean} + * @api private + */ + + get hasLongExpires() { + var week = 604800000; + return this.maxAge > (4 * week); + }, + + /** + * Return a serialized cookie string. + * + * @return {String} + * @api public + */ + + serialize: function(name, val){ + return cookie.serialize(name, val, this.data); + }, + + /** + * Return JSON representation of this cookie. + * + * @return {Object} + * @api private + */ + + toJSON: function(){ + return this.data; + } +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/session/memory.js b/node_modules/express/node_modules/connect/lib/middleware/session/memory.js new file mode 100644 index 0000000..fb93939 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/memory.js @@ -0,0 +1,129 @@ + +/*! + * Connect - session - MemoryStore + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Store = require('./store'); + +/** + * Initialize a new `MemoryStore`. + * + * @api public + */ + +var MemoryStore = module.exports = function MemoryStore() { + this.sessions = {}; +}; + +/** + * Inherit from `Store.prototype`. + */ + +MemoryStore.prototype.__proto__ = Store.prototype; + +/** + * Attempt to fetch session by the given `sid`. + * + * @param {String} sid + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.get = function(sid, fn){ + var self = this; + process.nextTick(function(){ + var expires + , sess = self.sessions[sid]; + if (sess) { + sess = JSON.parse(sess); + expires = 'string' == typeof sess.cookie.expires + ? new Date(sess.cookie.expires) + : sess.cookie.expires; + if (!expires || new Date < expires) { + fn(null, sess); + } else { + self.destroy(sid, fn); + } + } else { + fn(); + } + }); +}; + +/** + * Commit the given `sess` object associated with the given `sid`. + * + * @param {String} sid + * @param {Session} sess + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.set = function(sid, sess, fn){ + var self = this; + process.nextTick(function(){ + self.sessions[sid] = JSON.stringify(sess); + fn && fn(); + }); +}; + +/** + * Destroy the session associated with the given `sid`. + * + * @param {String} sid + * @api public + */ + +MemoryStore.prototype.destroy = function(sid, fn){ + var self = this; + process.nextTick(function(){ + delete self.sessions[sid]; + fn && fn(); + }); +}; + +/** + * Invoke the given callback `fn` with all active sessions. + * + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.all = function(fn){ + var arr = [] + , keys = Object.keys(this.sessions); + for (var i = 0, len = keys.length; i < len; ++i) { + arr.push(this.sessions[keys[i]]); + } + fn(null, arr); +}; + +/** + * Clear all sessions. + * + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.clear = function(fn){ + this.sessions = {}; + fn && fn(); +}; + +/** + * Fetch number of sessions. + * + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.length = function(fn){ + fn(null, Object.keys(this.sessions).length); +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/session/session.js b/node_modules/express/node_modules/connect/lib/middleware/session/session.js new file mode 100644 index 0000000..0dd4b40 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/session.js @@ -0,0 +1,116 @@ + +/*! + * Connect - session - Session + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../../utils'); + +/** + * Create a new `Session` with the given request and `data`. + * + * @param {IncomingRequest} req + * @param {Object} data + * @api private + */ + +var Session = module.exports = function Session(req, data) { + Object.defineProperty(this, 'req', { value: req }); + Object.defineProperty(this, 'id', { value: req.sessionID }); + if ('object' == typeof data) utils.merge(this, data); +}; + +/** + * Update reset `.cookie.maxAge` to prevent + * the cookie from expiring when the + * session is still active. + * + * @return {Session} for chaining + * @api public + */ + +Session.prototype.touch = function(){ + return this.resetMaxAge(); +}; + +/** + * Reset `.maxAge` to `.originalMaxAge`. + * + * @return {Session} for chaining + * @api public + */ + +Session.prototype.resetMaxAge = function(){ + this.cookie.maxAge = this.cookie.originalMaxAge; + return this; +}; + +/** + * Save the session data with optional callback `fn(err)`. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.save = function(fn){ + this.req.sessionStore.set(this.id, this, fn || function(){}); + return this; +}; + +/** + * Re-loads the session data _without_ altering + * the maxAge properties. Invokes the callback `fn(err)`, + * after which time if no exception has occurred the + * `req.session` property will be a new `Session` object, + * although representing the same session. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.reload = function(fn){ + var req = this.req + , store = this.req.sessionStore; + store.get(this.id, function(err, sess){ + if (err) return fn(err); + if (!sess) return fn(new Error('failed to load session')); + store.createSession(req, sess); + fn(); + }); + return this; +}; + +/** + * Destroy `this` session. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.destroy = function(fn){ + delete this.req.session; + this.req.sessionStore.destroy(this.id, fn); + return this; +}; + +/** + * Regenerate this request's session. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.regenerate = function(fn){ + this.req.sessionStore.regenerate(this.req, fn); + return this; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/session/store.js b/node_modules/express/node_modules/connect/lib/middleware/session/store.js new file mode 100644 index 0000000..54294cb --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/store.js @@ -0,0 +1,84 @@ + +/*! + * Connect - session - Store + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , Session = require('./session') + , Cookie = require('./cookie'); + +/** + * Initialize abstract `Store`. + * + * @api private + */ + +var Store = module.exports = function Store(options){}; + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Store.prototype.__proto__ = EventEmitter.prototype; + +/** + * Re-generate the given requests's session. + * + * @param {IncomingRequest} req + * @return {Function} fn + * @api public + */ + +Store.prototype.regenerate = function(req, fn){ + var self = this; + this.destroy(req.sessionID, function(err){ + self.generate(req); + fn(err); + }); +}; + +/** + * Load a `Session` instance via the given `sid` + * and invoke the callback `fn(err, sess)`. + * + * @param {String} sid + * @param {Function} fn + * @api public + */ + +Store.prototype.load = function(sid, fn){ + var self = this; + this.get(sid, function(err, sess){ + if (err) return fn(err); + if (!sess) return fn(); + var req = { sessionID: sid, sessionStore: self }; + sess = self.createSession(req, sess); + fn(null, sess); + }); +}; + +/** + * Create session from JSON `sess` data. + * + * @param {IncomingRequest} req + * @param {Object} sess + * @return {Session} + * @api private + */ + +Store.prototype.createSession = function(req, sess){ + var expires = sess.cookie.expires + , orig = sess.cookie.originalMaxAge; + sess.cookie = new Cookie(sess.cookie); + if ('string' == typeof expires) sess.cookie.expires = new Date(expires); + sess.cookie.originalMaxAge = orig; + req.session = new Session(req, sess); + return req.session; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/static.js b/node_modules/express/node_modules/connect/lib/middleware/static.js new file mode 100644 index 0000000..7762ac1 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/static.js @@ -0,0 +1,95 @@ +/*! + * Connect - static + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var send = require('send') + , utils = require('../utils') + , parse = utils.parseUrl + , url = require('url'); + +/** + * Static: + * + * Static file server with the given `root` path. + * + * Examples: + * + * var oneDay = 86400000; + * + * connect() + * .use(connect.static(__dirname + '/public')) + * + * connect() + * .use(connect.static(__dirname + '/public', { maxAge: oneDay })) + * + * Options: + * + * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0 + * - `hidden` Allow transfer of hidden files. defaults to false + * - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true + * - `index` Default file name, defaults to 'index.html' + * + * @param {String} root + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(root, options){ + options = options || {}; + + // root required + if (!root) throw new Error('static() root path required'); + + // default redirect + var redirect = false !== options.redirect; + + return function staticMiddleware(req, res, next) { + if ('GET' != req.method && 'HEAD' != req.method) return next(); + var path = parse(req).pathname; + var pause = utils.pause(req); + + function resume() { + next(); + pause.resume(); + } + + function directory() { + if (!redirect) return resume(); + var pathname = url.parse(req.originalUrl).pathname; + res.statusCode = 303; + res.setHeader('Location', pathname + '/'); + res.end('Redirecting to ' + utils.escape(pathname) + '/'); + } + + function error(err) { + if (404 == err.status) return resume(); + next(err); + } + + send(req, path) + .maxage(options.maxAge || 0) + .root(root) + .index(options.index || 'index.html') + .hidden(options.hidden) + .on('error', error) + .on('directory', directory) + .pipe(res); + }; +}; + +/** + * Expose mime module. + * + * If you wish to extend the mime table use this + * reference to the "mime" module in the npm registry. + */ + +exports.mime = send.mime; diff --git a/node_modules/express/node_modules/connect/lib/middleware/staticCache.js b/node_modules/express/node_modules/connect/lib/middleware/staticCache.js new file mode 100644 index 0000000..7354a8f --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/staticCache.js @@ -0,0 +1,231 @@ + +/*! + * Connect - staticCache + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , Cache = require('../cache') + , fresh = require('fresh'); + +/** + * Static cache: + * + * Enables a memory cache layer on top of + * the `static()` middleware, serving popular + * static files. + * + * By default a maximum of 128 objects are + * held in cache, with a max of 256k each, + * totalling ~32mb. + * + * A Least-Recently-Used (LRU) cache algo + * is implemented through the `Cache` object, + * simply rotating cache objects as they are + * hit. This means that increasingly popular + * objects maintain their positions while + * others get shoved out of the stack and + * garbage collected. + * + * Benchmarks: + * + * static(): 2700 rps + * node-static: 5300 rps + * static() + staticCache(): 7500 rps + * + * Options: + * + * - `maxObjects` max cache objects [128] + * - `maxLength` max cache object length 256kb + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function staticCache(options){ + var options = options || {} + , cache = new Cache(options.maxObjects || 128) + , maxlen = options.maxLength || 1024 * 256; + + console.warn('connect.staticCache() is deprecated and will be removed in 3.0'); + console.warn('use varnish or similar reverse proxy caches.'); + + return function staticCache(req, res, next){ + var key = cacheKey(req) + , ranges = req.headers.range + , hasCookies = req.headers.cookie + , hit = cache.get(key); + + // cache static + // TODO: change from staticCache() -> cache() + // and make this work for any request + req.on('static', function(stream){ + var headers = res._headers + , cc = utils.parseCacheControl(headers['cache-control'] || '') + , contentLength = headers['content-length'] + , hit; + + // dont cache set-cookie responses + if (headers['set-cookie']) return hasCookies = true; + + // dont cache when cookies are present + if (hasCookies) return; + + // ignore larger files + if (!contentLength || contentLength > maxlen) return; + + // don't cache partial files + if (headers['content-range']) return; + + // dont cache items we shouldn't be + // TODO: real support for must-revalidate / no-cache + if ( cc['no-cache'] + || cc['no-store'] + || cc['private'] + || cc['must-revalidate']) return; + + // if already in cache then validate + if (hit = cache.get(key)){ + if (headers.etag == hit[0].etag) { + hit[0].date = new Date; + return; + } else { + cache.remove(key); + } + } + + // validation notifiactions don't contain a steam + if (null == stream) return; + + // add the cache object + var arr = []; + + // store the chunks + stream.on('data', function(chunk){ + arr.push(chunk); + }); + + // flag it as complete + stream.on('end', function(){ + var cacheEntry = cache.add(key); + delete headers['x-cache']; // Clean up (TODO: others) + cacheEntry.push(200); + cacheEntry.push(headers); + cacheEntry.push.apply(cacheEntry, arr); + }); + }); + + if (req.method == 'GET' || req.method == 'HEAD') { + if (ranges) { + next(); + } else if (!hasCookies && hit && !mustRevalidate(req, hit)) { + res.setHeader('X-Cache', 'HIT'); + respondFromCache(req, res, hit); + } else { + res.setHeader('X-Cache', 'MISS'); + next(); + } + } else { + next(); + } + } +}; + +/** + * Respond with the provided cached value. + * TODO: Assume 200 code, that's iffy. + * + * @param {Object} req + * @param {Object} res + * @param {Object} cacheEntry + * @return {String} + * @api private + */ + +function respondFromCache(req, res, cacheEntry) { + var status = cacheEntry[0] + , headers = utils.merge({}, cacheEntry[1]) + , content = cacheEntry.slice(2); + + headers.age = (new Date - new Date(headers.date)) / 1000 || 0; + + switch (req.method) { + case 'HEAD': + res.writeHead(status, headers); + res.end(); + break; + case 'GET': + if (utils.conditionalGET(req) && fresh(req.headers, headers)) { + headers['content-length'] = 0; + res.writeHead(304, headers); + res.end(); + } else { + res.writeHead(status, headers); + + function write() { + while (content.length) { + if (false === res.write(content.shift())) { + res.once('drain', write); + return; + } + } + res.end(); + } + + write(); + } + break; + default: + // This should never happen. + res.writeHead(500, ''); + res.end(); + } +} + +/** + * Determine whether or not a cached value must be revalidated. + * + * @param {Object} req + * @param {Object} cacheEntry + * @return {String} + * @api private + */ + +function mustRevalidate(req, cacheEntry) { + var cacheHeaders = cacheEntry[1] + , reqCC = utils.parseCacheControl(req.headers['cache-control'] || '') + , cacheCC = utils.parseCacheControl(cacheHeaders['cache-control'] || '') + , cacheAge = (new Date - new Date(cacheHeaders.date)) / 1000 || 0; + + if ( cacheCC['no-cache'] + || cacheCC['must-revalidate'] + || cacheCC['proxy-revalidate']) return true; + + if (reqCC['no-cache']) return true; + + if (null != reqCC['max-age']) return reqCC['max-age'] < cacheAge; + + if (null != cacheCC['max-age']) return cacheCC['max-age'] < cacheAge; + + return false; +} + +/** + * The key to use in the cache. For now, this is the URL path and query. + * + * 'http://example.com?key=value' -> '/?key=value' + * + * @param {Object} req + * @return {String} + * @api private + */ + +function cacheKey(req) { + return utils.parseUrl(req).path; +} diff --git a/node_modules/express/node_modules/connect/lib/middleware/timeout.js b/node_modules/express/node_modules/connect/lib/middleware/timeout.js new file mode 100644 index 0000000..5496c02 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/timeout.js @@ -0,0 +1,55 @@ +/*! + * Connect - timeout + * Ported from https://github.com/LearnBoost/connect-timeout + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var debug = require('debug')('connect:timeout'); + +/** + * Timeout: + * + * Times out the request in `ms`, defaulting to `5000`. The + * method `req.clearTimeout()` is added to revert this behaviour + * programmatically within your application's middleware, routes, etc. + * + * The timeout error is passed to `next()` so that you may customize + * the response behaviour. This error has the `.timeout` property as + * well as `.status == 503`. + * + * @param {Number} ms + * @return {Function} + * @api public + */ + +module.exports = function timeout(ms) { + ms = ms || 5000; + + return function(req, res, next) { + var id = setTimeout(function(){ + req.emit('timeout', ms); + }, ms); + + req.on('timeout', function(){ + if (res.headerSent) return debug('response started, cannot timeout'); + var err = new Error('Response timeout'); + err.timeout = ms; + err.status = 503; + next(err); + }); + + req.clearTimeout = function(){ + clearTimeout(id); + }; + + res.on('header', function(){ + clearTimeout(id); + }); + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/urlencoded.js b/node_modules/express/node_modules/connect/lib/middleware/urlencoded.js new file mode 100644 index 0000000..cceafc0 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/urlencoded.js @@ -0,0 +1,78 @@ + +/*! + * Connect - urlencoded + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , _limit = require('./limit') + , qs = require('qs'); + +/** + * noop middleware. + */ + +function noop(req, res, next) { + next(); +} + +/** + * Urlencoded: + * + * Parse x-ww-form-urlencoded request bodies, + * providing the parsed object as `req.body`. + * + * Options: + * + * - `limit` byte limit disabled by default + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(options){ + options = options || {}; + + var limit = options.limit + ? _limit(options.limit) + : noop; + + return function urlencoded(req, res, next) { + if (req._body) return next(); + req.body = req.body || {}; + + if (!utils.hasBody(req)) return next(); + + // check Content-Type + if ('application/x-www-form-urlencoded' != utils.mime(req)) return next(); + + // flag as parsed + req._body = true; + + // parse + limit(req, res, function(err){ + if (err) return next(err); + var buf = ''; + req.setEncoding('utf8'); + req.on('data', function(chunk){ buf += chunk }); + req.on('end', function(){ + try { + req.body = buf.length + ? qs.parse(buf, options) + : {}; + next(); + } catch (err){ + err.body = buf; + next(err); + } + }); + }); + } +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/vhost.js b/node_modules/express/node_modules/connect/lib/middleware/vhost.js new file mode 100644 index 0000000..abbb050 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/vhost.js @@ -0,0 +1,40 @@ + +/*! + * Connect - vhost + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Vhost: + * + * Setup vhost for the given `hostname` and `server`. + * + * connect() + * .use(connect.vhost('foo.com', fooApp)) + * .use(connect.vhost('bar.com', barApp)) + * .use(connect.vhost('*.com', mainApp)) + * + * The `server` may be a Connect server or + * a regular Node `http.Server`. + * + * @param {String} hostname + * @param {Server} server + * @return {Function} + * @api public + */ + +module.exports = function vhost(hostname, server){ + if (!hostname) throw new Error('vhost hostname required'); + if (!server) throw new Error('vhost server required'); + var regexp = new RegExp('^' + hostname.replace(/[^*\w]/g, '\\$&').replace(/[*]/g, '(?:.*?)') + '$', 'i'); + if (server.onvhost) server.onvhost(hostname); + return function vhost(req, res, next){ + if (!req.headers.host) return next(); + var host = req.headers.host.split(':')[0]; + if (!regexp.test(host)) return next(); + if ('function' == typeof server) return server(req, res, next); + server.emit('request', req, res); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/patch.js b/node_modules/express/node_modules/connect/lib/patch.js new file mode 100644 index 0000000..7cf0012 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/patch.js @@ -0,0 +1,79 @@ + +/*! + * Connect + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , res = http.ServerResponse.prototype + , setHeader = res.setHeader + , _renderHeaders = res._renderHeaders + , writeHead = res.writeHead; + +// apply only once + +if (!res._hasConnectPatch) { + + /** + * Provide a public "header sent" flag + * until node does. + * + * @return {Boolean} + * @api public + */ + + res.__defineGetter__('headerSent', function(){ + return this._header; + }); + + /** + * Set header `field` to `val`, special-casing + * the `Set-Cookie` field for multiple support. + * + * @param {String} field + * @param {String} val + * @api public + */ + + res.setHeader = function(field, val){ + var key = field.toLowerCase() + , prev; + + // special-case Set-Cookie + if (this._headers && 'set-cookie' == key) { + if (prev = this.getHeader(field)) { + val = Array.isArray(prev) + ? prev.concat(val) + : [prev, val]; + } + // charset + } else if ('content-type' == key && this.charset) { + val += '; charset=' + this.charset; + } + + return setHeader.call(this, field, val); + }; + + /** + * Proxy to emit "header" event. + */ + + res._renderHeaders = function(){ + if (!this._emittedHeader) this.emit('header'); + this._emittedHeader = true; + return _renderHeaders.call(this); + }; + + res.writeHead = function(){ + if (!this._emittedHeader) this.emit('header'); + this._emittedHeader = true; + return writeHead.apply(this, arguments); + }; + + res._hasConnectPatch = true; +} diff --git a/node_modules/express/node_modules/connect/lib/proto.js b/node_modules/express/node_modules/connect/lib/proto.js new file mode 100644 index 0000000..6fadf8f --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/proto.js @@ -0,0 +1,230 @@ + +/*! + * Connect - HTTPServer + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , utils = require('./utils') + , debug = require('debug')('connect:dispatcher'); + +// prototype + +var app = module.exports = {}; + +// environment + +var env = process.env.NODE_ENV || 'development'; + +/** + * Utilize the given middleware `handle` to the given `route`, + * defaulting to _/_. This "route" is the mount-point for the + * middleware, when given a value other than _/_ the middleware + * is only effective when that segment is present in the request's + * pathname. + * + * For example if we were to mount a function at _/admin_, it would + * be invoked on _/admin_, and _/admin/settings_, however it would + * not be invoked for _/_, or _/posts_. + * + * Examples: + * + * var app = connect(); + * app.use(connect.favicon()); + * app.use(connect.logger()); + * app.use(connect.static(__dirname + '/public')); + * + * If we wanted to prefix static files with _/public_, we could + * "mount" the `static()` middleware: + * + * app.use('/public', connect.static(__dirname + '/public')); + * + * This api is chainable, so the following is valid: + * + * connect() + * .use(connect.favicon()) + * .use(connect.logger()) + * .use(connect.static(__dirname + '/public')) + * .listen(3000); + * + * @param {String|Function|Server} route, callback or server + * @param {Function|Server} callback or server + * @return {Server} for chaining + * @api public + */ + +app.use = function(route, fn){ + // default route to '/' + if ('string' != typeof route) { + fn = route; + route = '/'; + } + + // wrap sub-apps + if ('function' == typeof fn.handle) { + var server = fn; + fn.route = route; + fn = function(req, res, next){ + server.handle(req, res, next); + }; + } + + // wrap vanilla http.Servers + if (fn instanceof http.Server) { + fn = fn.listeners('request')[0]; + } + + // strip trailing slash + if ('/' == route[route.length - 1]) { + route = route.slice(0, -1); + } + + // add the middleware + debug('use %s %s', route || '/', fn.name || 'anonymous'); + this.stack.push({ route: route, handle: fn }); + + return this; +}; + +/** + * Handle server requests, punting them down + * the middleware stack. + * + * @api private + */ + +app.handle = function(req, res, out) { + var stack = this.stack + , fqdn = ~req.url.indexOf('://') + , removed = '' + , slashAdded = false + , index = 0; + + function next(err) { + var layer, path, status, c; + + if (slashAdded) { + req.url = req.url.substr(1); + slashAdded = false; + } + + req.url = removed + req.url; + req.originalUrl = req.originalUrl || req.url; + removed = ''; + + // next callback + layer = stack[index++]; + + // all done + if (!layer || res.headerSent) { + // delegate to parent + if (out) return out(err); + + // unhandled error + if (err) { + // default to 500 + if (res.statusCode < 400) res.statusCode = 500; + debug('default %s', res.statusCode); + + // respect err.status + if (err.status) res.statusCode = err.status; + + // production gets a basic error message + var msg = 'production' == env + ? http.STATUS_CODES[res.statusCode] + : err.stack || err.toString(); + + // log to stderr in a non-test env + if ('test' != env) console.error(err.stack || err.toString()); + if (res.headerSent) return req.socket.destroy(); + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Length', Buffer.byteLength(msg)); + if ('HEAD' == req.method) return res.end(); + res.end(msg); + } else { + debug('default 404'); + res.statusCode = 404; + res.setHeader('Content-Type', 'text/plain'); + if ('HEAD' == req.method) return res.end(); + res.end('Cannot ' + utils.escape(req.method) + ' ' + utils.escape(req.originalUrl)); + } + return; + } + + try { + path = utils.parseUrl(req).pathname; + if (undefined == path) path = '/'; + + // skip this layer if the route doesn't match. + if (0 != path.toLowerCase().indexOf(layer.route.toLowerCase())) return next(err); + + c = path[layer.route.length]; + if (c && '/' != c && '.' != c) return next(err); + + // Call the layer handler + // Trim off the part of the url that matches the route + removed = layer.route; + req.url = req.url.substr(removed.length); + + // Ensure leading slash + if (!fqdn && '/' != req.url[0]) { + req.url = '/' + req.url; + slashAdded = true; + } + + debug('%s %s : %s', layer.handle.name || 'anonymous', layer.route, req.originalUrl); + var arity = layer.handle.length; + if (err) { + if (arity === 4) { + layer.handle(err, req, res, next); + } else { + next(err); + } + } else if (arity < 4) { + layer.handle(req, res, next); + } else { + next(); + } + } catch (e) { + next(e); + } + } + next(); +}; + +/** + * Listen for connections. + * + * This method takes the same arguments + * as node's `http.Server#listen()`. + * + * HTTP and HTTPS: + * + * If you run your application both as HTTP + * and HTTPS you may wrap them individually, + * since your Connect "server" is really just + * a JavaScript `Function`. + * + * var connect = require('connect') + * , http = require('http') + * , https = require('https'); + * + * var app = connect(); + * + * http.createServer(app).listen(80); + * https.createServer(options, app).listen(443); + * + * @return {http.Server} + * @api public + */ + +app.listen = function(){ + var server = http.createServer(this); + return server.listen.apply(server, arguments); +}; diff --git a/node_modules/express/node_modules/connect/lib/public/directory.html b/node_modules/express/node_modules/connect/lib/public/directory.html new file mode 100644 index 0000000..2d63704 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/public/directory.html @@ -0,0 +1,81 @@ + + + + + listing directory {directory} + + + + + +
    +

    {linked-path}

    + {files} +
    + + \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/public/error.html b/node_modules/express/node_modules/connect/lib/public/error.html new file mode 100644 index 0000000..a6d3faf --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/public/error.html @@ -0,0 +1,14 @@ + + + + {error} + + + +
    +

    {title}

    +

    {statusCode} {error}

    +
      {stack}
    +
    + + diff --git a/node_modules/express/node_modules/connect/lib/public/favicon.ico b/node_modules/express/node_modules/connect/lib/public/favicon.ico new file mode 100644 index 0000000..895fc96 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/favicon.ico differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page.png b/node_modules/express/node_modules/connect/lib/public/icons/page.png new file mode 100644 index 0000000..03ddd79 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_add.png b/node_modules/express/node_modules/connect/lib/public/icons/page_add.png new file mode 100644 index 0000000..d5bfa07 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_add.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png b/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png new file mode 100644 index 0000000..89ee2da Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_code.png b/node_modules/express/node_modules/connect/lib/public/icons/page_code.png new file mode 100644 index 0000000..f7ea904 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_code.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png b/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png new file mode 100644 index 0000000..195dc6d Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png b/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png new file mode 100644 index 0000000..3141467 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png b/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png new file mode 100644 index 0000000..046811e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_error.png b/node_modules/express/node_modules/connect/lib/public/icons/page_error.png new file mode 100644 index 0000000..f07f449 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_error.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png b/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png new file mode 100644 index 0000000..eb6158e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_find.png b/node_modules/express/node_modules/connect/lib/public/icons/page_find.png new file mode 100644 index 0000000..2f19388 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_find.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png b/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png new file mode 100644 index 0000000..8e83281 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_go.png b/node_modules/express/node_modules/connect/lib/public/icons/page_go.png new file mode 100644 index 0000000..80fe1ed Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_go.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_green.png b/node_modules/express/node_modules/connect/lib/public/icons/page_green.png new file mode 100644 index 0000000..de8e003 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_green.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_key.png b/node_modules/express/node_modules/connect/lib/public/icons/page_key.png new file mode 100644 index 0000000..d6626cb Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_key.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png b/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png new file mode 100644 index 0000000..7e56870 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_link.png b/node_modules/express/node_modules/connect/lib/public/icons/page_link.png new file mode 100644 index 0000000..312eab0 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_link.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png b/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png new file mode 100644 index 0000000..246a2f0 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png b/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png new file mode 100644 index 0000000..968f073 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_red.png b/node_modules/express/node_modules/connect/lib/public/icons/page_red.png new file mode 100644 index 0000000..0b18247 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_red.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png b/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png new file mode 100644 index 0000000..cf347c7 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_save.png b/node_modules/express/node_modules/connect/lib/public/icons/page_save.png new file mode 100644 index 0000000..caea546 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_save.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white.png new file mode 100644 index 0000000..8b8b1ca Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png new file mode 100644 index 0000000..8f8095e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png new file mode 100644 index 0000000..159b240 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png new file mode 100644 index 0000000..aa23dde Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png new file mode 100644 index 0000000..34a05cc Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png new file mode 100644 index 0000000..f501a59 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png new file mode 100644 index 0000000..848bdaf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png new file mode 100644 index 0000000..0c76bd1 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png new file mode 100644 index 0000000..87a6914 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png new file mode 100644 index 0000000..c66011f Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png new file mode 100644 index 0000000..2b6b100 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png new file mode 100644 index 0000000..a9f31a2 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png new file mode 100644 index 0000000..a87cf84 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png new file mode 100644 index 0000000..ffb8fc9 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png new file mode 100644 index 0000000..0a7d6f4 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png new file mode 100644 index 0000000..bddba1f Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png new file mode 100644 index 0000000..af1ecaf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png new file mode 100644 index 0000000..4cc537a Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png new file mode 100644 index 0000000..b93e776 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png new file mode 100644 index 0000000..9fc5a0a Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png new file mode 100644 index 0000000..b977d7e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png new file mode 100644 index 0000000..5818436 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png new file mode 100644 index 0000000..5769120 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png new file mode 100644 index 0000000..8d719df Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png new file mode 100644 index 0000000..106f5aa Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png new file mode 100644 index 0000000..e4a1ecb Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png new file mode 100644 index 0000000..7e62a92 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png new file mode 100644 index 0000000..e902abb Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png new file mode 100644 index 0000000..1d2d0a4 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png new file mode 100644 index 0000000..d616484 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png new file mode 100644 index 0000000..7215d1e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png new file mode 100644 index 0000000..bf7bd1c Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png new file mode 100644 index 0000000..f6b74cc Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png new file mode 100644 index 0000000..d3fffb6 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png new file mode 100644 index 0000000..a65bcb3 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png new file mode 100644 index 0000000..23a37b8 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png new file mode 100644 index 0000000..f907e44 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png new file mode 100644 index 0000000..5b2cbb3 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png new file mode 100644 index 0000000..7868a25 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png new file mode 100644 index 0000000..134b669 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png new file mode 100644 index 0000000..c4eff03 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png new file mode 100644 index 0000000..884ffd6 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png new file mode 100644 index 0000000..f59b7c4 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png new file mode 100644 index 0000000..44084ad Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png new file mode 100644 index 0000000..3a1441c Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png new file mode 100644 index 0000000..e770829 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png new file mode 100644 index 0000000..813f712 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png new file mode 100644 index 0000000..d9cf132 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png new file mode 100644 index 0000000..52699bf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png new file mode 100644 index 0000000..4a05955 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png new file mode 100644 index 0000000..a0a433d Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png new file mode 100644 index 0000000..1eb8809 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png new file mode 100644 index 0000000..ae8ecbf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png new file mode 100644 index 0000000..6ed2490 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png new file mode 100644 index 0000000..fecadd0 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png new file mode 100644 index 0000000..fd4bbcc Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_word.png b/node_modules/express/node_modules/connect/lib/public/icons/page_word.png new file mode 100644 index 0000000..834cdfa Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_word.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_world.png b/node_modules/express/node_modules/connect/lib/public/icons/page_world.png new file mode 100644 index 0000000..b8895dd Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_world.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/style.css b/node_modules/express/node_modules/connect/lib/public/style.css new file mode 100644 index 0000000..32b6507 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/public/style.css @@ -0,0 +1,141 @@ +body { + margin: 0; + padding: 80px 100px; + font: 13px "Helvetica Neue", "Lucida Grande", "Arial"; + background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9)); + background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9); + background-repeat: no-repeat; + color: #555; + -webkit-font-smoothing: antialiased; +} +h1, h2, h3 { + margin: 0; + font-size: 22px; + color: #343434; +} +h1 em, h2 em { + padding: 0 5px; + font-weight: normal; +} +h1 { + font-size: 60px; +} +h2 { + margin-top: 10px; +} +h3 { + margin: 5px 0 10px 0; + padding-bottom: 5px; + border-bottom: 1px solid #eee; + font-size: 18px; +} +ul { + margin: 0; + padding: 0; +} +ul li { + margin: 5px 0; + padding: 3px 8px; + list-style: none; +} +ul li:hover { + cursor: pointer; + color: #2e2e2e; +} +ul li .path { + padding-left: 5px; + font-weight: bold; +} +ul li .line { + padding-right: 5px; + font-style: italic; +} +ul li:first-child .path { + padding-left: 0; +} +p { + line-height: 1.5; +} +a { + color: #555; + text-decoration: none; +} +a:hover { + color: #303030; +} +#stacktrace { + margin-top: 15px; +} +.directory h1 { + margin-bottom: 15px; + font-size: 18px; +} +ul#files { + width: 100%; + height: 500px; +} +ul#files li { + padding: 0; +} +ul#files li img { + position: absolute; + top: 5px; + left: 5px; +} +ul#files li a { + position: relative; + display: block; + margin: 1px; + width: 30%; + height: 25px; + line-height: 25px; + text-indent: 8px; + float: left; + border: 1px solid transparent; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + overflow: hidden; + text-overflow: ellipsis; +} +ul#files li a.icon { + text-indent: 25px; +} +ul#files li a:focus, +ul#files li a:hover { + outline: none; + background: rgba(255,255,255,0.65); + border: 1px solid #ececec; +} +ul#files li a.highlight { + -webkit-transition: background .4s ease-in-out; + background: #ffff4f; + border-color: #E9DC51; +} +#search { + display: block; + position: fixed; + top: 20px; + right: 20px; + width: 90px; + -webkit-transition: width ease 0.2s, opacity ease 0.4s; + -moz-transition: width ease 0.2s, opacity ease 0.4s; + -webkit-border-radius: 32px; + -moz-border-radius: 32px; + -webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03); + -moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03); + -webkit-font-smoothing: antialiased; + text-align: left; + font: 13px "Helvetica Neue", Arial, sans-serif; + padding: 4px 10px; + border: none; + background: transparent; + margin-bottom: 0; + outline: none; + opacity: 0.7; + color: #888; +} +#search:focus { + width: 120px; + opacity: 1.0; +} diff --git a/node_modules/express/node_modules/connect/lib/utils.js b/node_modules/express/node_modules/connect/lib/utils.js new file mode 100644 index 0000000..d52009a --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/utils.js @@ -0,0 +1,386 @@ + +/*! + * Connect - utils + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , crypto = require('crypto') + , parse = require('url').parse + , signature = require('cookie-signature') + , nodeVersion = process.versions.node.split('.'); + +// pause is broken in node < 0.10 +exports.brokenPause = parseInt(nodeVersion[0], 10) === 0 + && parseInt(nodeVersion[1], 10) < 10; + +/** + * Return `true` if the request has a body, otherwise return `false`. + * + * @param {IncomingMessage} req + * @return {Boolean} + * @api private + */ + +exports.hasBody = function(req) { + var encoding = 'transfer-encoding' in req.headers; + var length = 'content-length' in req.headers && req.headers['content-length'] !== '0'; + return encoding || length; +}; + +/** + * Extract the mime type from the given request's + * _Content-Type_ header. + * + * @param {IncomingMessage} req + * @return {String} + * @api private + */ + +exports.mime = function(req) { + var str = req.headers['content-type'] || ''; + return str.split(';')[0]; +}; + +/** + * Generate an `Error` from the given status `code` + * and optional `msg`. + * + * @param {Number} code + * @param {String} msg + * @return {Error} + * @api private + */ + +exports.error = function(code, msg){ + var err = new Error(msg || http.STATUS_CODES[code]); + err.status = code; + return err; +}; + +/** + * Return md5 hash of the given string and optional encoding, + * defaulting to hex. + * + * utils.md5('wahoo'); + * // => "e493298061761236c96b02ea6aa8a2ad" + * + * @param {String} str + * @param {String} encoding + * @return {String} + * @api private + */ + +exports.md5 = function(str, encoding){ + return crypto + .createHash('md5') + .update(str) + .digest(encoding || 'hex'); +}; + +/** + * Merge object b with object a. + * + * var a = { foo: 'bar' } + * , b = { bar: 'baz' }; + * + * utils.merge(a, b); + * // => { foo: 'bar', bar: 'baz' } + * + * @param {Object} a + * @param {Object} b + * @return {Object} + * @api private + */ + +exports.merge = function(a, b){ + if (a && b) { + for (var key in b) { + a[key] = b[key]; + } + } + return a; +}; + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; + +/** + * Sign the given `val` with `secret`. + * + * @param {String} val + * @param {String} secret + * @return {String} + * @api private + */ + +exports.sign = function(val, secret){ + console.warn('do not use utils.sign(), use https://github.com/visionmedia/node-cookie-signature') + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/=+$/, ''); +}; + +/** + * Unsign and decode the given `val` with `secret`, + * returning `false` if the signature is invalid. + * + * @param {String} val + * @param {String} secret + * @return {String|Boolean} + * @api private + */ + +exports.unsign = function(val, secret){ + console.warn('do not use utils.unsign(), use https://github.com/visionmedia/node-cookie-signature') + var str = val.slice(0, val.lastIndexOf('.')); + return exports.sign(str, secret) == val + ? str + : false; +}; + +/** + * Parse signed cookies, returning an object + * containing the decoded key/value pairs, + * while removing the signed key from `obj`. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +exports.parseSignedCookies = function(obj, secret){ + var ret = {}; + Object.keys(obj).forEach(function(key){ + var val = obj[key]; + if (0 == val.indexOf('s:')) { + val = signature.unsign(val.slice(2), secret); + if (val) { + ret[key] = val; + delete obj[key]; + } + } + }); + return ret; +}; + +/** + * Parse a signed cookie string, return the decoded value + * + * @param {String} str signed cookie string + * @param {String} secret + * @return {String} decoded value + * @api private + */ + +exports.parseSignedCookie = function(str, secret){ + return 0 == str.indexOf('s:') + ? signature.unsign(str.slice(2), secret) + : str; +}; + +/** + * Parse JSON cookies. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +exports.parseJSONCookies = function(obj){ + Object.keys(obj).forEach(function(key){ + var val = obj[key]; + var res = exports.parseJSONCookie(val); + if (res) obj[key] = res; + }); + return obj; +}; + +/** + * Parse JSON cookie string + * + * @param {String} str + * @return {Object} Parsed object or null if not json cookie + * @api private + */ + +exports.parseJSONCookie = function(str) { + if (0 == str.indexOf('j:')) { + try { + return JSON.parse(str.slice(2)); + } catch (err) { + // no op + } + } +}; + +/** + * Pause `data` and `end` events on the given `obj`. + * Middleware performing async tasks _should_ utilize + * this utility (or similar), to re-emit data once + * the async operation has completed, otherwise these + * events may be lost. Pause is only required for + * node versions less than 10, and is replaced with + * noop's otherwise. + * + * var pause = utils.pause(req); + * fs.readFile(path, function(){ + * next(); + * pause.resume(); + * }); + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +exports.pause = exports.brokenPause + ? require('pause') + : function () { + return { + end: noop, + resume: noop + } + } + +/** + * Strip `Content-*` headers from `res`. + * + * @param {ServerResponse} res + * @api private + */ + +exports.removeContentHeaders = function(res){ + Object.keys(res._headers).forEach(function(field){ + if (0 == field.indexOf('content')) { + res.removeHeader(field); + } + }); +}; + +/** + * Check if `req` is a conditional GET request. + * + * @param {IncomingMessage} req + * @return {Boolean} + * @api private + */ + +exports.conditionalGET = function(req) { + return req.headers['if-modified-since'] + || req.headers['if-none-match']; +}; + +/** + * Respond with 401 "Unauthorized". + * + * @param {ServerResponse} res + * @param {String} realm + * @api private + */ + +exports.unauthorized = function(res, realm) { + res.statusCode = 401; + res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"'); + res.end('Unauthorized'); +}; + +/** + * Respond with 304 "Not Modified". + * + * @param {ServerResponse} res + * @param {Object} headers + * @api private + */ + +exports.notModified = function(res) { + exports.removeContentHeaders(res); + res.statusCode = 304; + res.end(); +}; + +/** + * Return an ETag in the form of `"-"` + * from the given `stat`. + * + * @param {Object} stat + * @return {String} + * @api private + */ + +exports.etag = function(stat) { + return '"' + stat.size + '-' + Number(stat.mtime) + '"'; +}; + +/** + * Parse the given Cache-Control `str`. + * + * @param {String} str + * @return {Object} + * @api private + */ + +exports.parseCacheControl = function(str){ + var directives = str.split(',') + , obj = {}; + + for(var i = 0, len = directives.length; i < len; i++) { + var parts = directives[i].split('=') + , key = parts.shift().trim() + , val = parseInt(parts.shift(), 10); + + obj[key] = isNaN(val) ? true : val; + } + + return obj; +}; + +/** + * Parse the `req` url with memoization. + * + * @param {ServerRequest} req + * @return {Object} + * @api private + */ + +exports.parseUrl = function(req){ + var parsed = req._parsedUrl; + if (parsed && parsed.href == req.url) { + return parsed; + } else { + return req._parsedUrl = parse(req.url); + } +}; + +/** + * Parse byte `size` string. + * + * @param {String} size + * @return {Number} + * @api private + */ + +exports.parseBytes = require('bytes'); + +function noop() {} diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/.npmignore b/node_modules/express/node_modules/connect/node_modules/bytes/.npmignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/.npmignore @@ -0,0 +1 @@ +test diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/History.md b/node_modules/express/node_modules/connect/node_modules/bytes/History.md new file mode 100644 index 0000000..1332808 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/History.md @@ -0,0 +1,10 @@ + +0.2.0 / 2012-10-28 +================== + + * bytes(200).should.eql('200b') + +0.1.0 / 2012-07-04 +================== + + * add bytes to string conversion [yields] diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/Makefile b/node_modules/express/node_modules/connect/node_modules/bytes/Makefile new file mode 100644 index 0000000..8e8640f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --reporter spec \ + --require should + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/Readme.md b/node_modules/express/node_modules/connect/node_modules/bytes/Readme.md new file mode 100644 index 0000000..9325d5b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/Readme.md @@ -0,0 +1,51 @@ +# node-bytes + + Byte string parser / formatter. + +## Example: + +```js +bytes('1kb') +// => 1024 + +bytes('2mb') +// => 2097152 + +bytes('1gb') +// => 1073741824 + +bytes(1073741824) +// => 1gb +``` + +## Installation + +``` +$ npm install bytes +$ component install visionmedia/bytes.js +``` + +## License + +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/component.json b/node_modules/express/node_modules/connect/node_modules/bytes/component.json new file mode 100644 index 0000000..76a6057 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/component.json @@ -0,0 +1,7 @@ +{ + "name": "bytes", + "description": "byte size string parser / serializer", + "keywords": ["bytes", "utility"], + "version": "0.1.0", + "scripts": ["index.js"] +} diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/index.js b/node_modules/express/node_modules/connect/node_modules/bytes/index.js new file mode 100644 index 0000000..70b2e01 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/index.js @@ -0,0 +1,39 @@ + +/** + * Parse byte `size` string. + * + * @param {String} size + * @return {Number} + * @api public + */ + +module.exports = function(size) { + if ('number' == typeof size) return convert(size); + var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/) + , n = parseFloat(parts[1]) + , type = parts[2]; + + var map = { + kb: 1 << 10 + , mb: 1 << 20 + , gb: 1 << 30 + }; + + return map[type] * n; +}; + +/** + * convert bytes into string. + * + * @param {Number} b - bytes to convert + * @return {String} + * @api public + */ + +function convert (b) { + var gb = 1 << 30, mb = 1 << 20, kb = 1 << 10; + if (b >= gb) return (Math.round(b / gb * 100) / 100) + 'gb'; + if (b >= mb) return (Math.round(b / mb * 100) / 100) + 'mb'; + if (b >= kb) return (Math.round(b / kb * 100) / 100) + 'kb'; + return b + 'b'; +} diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/package.json b/node_modules/express/node_modules/connect/node_modules/bytes/package.json new file mode 100644 index 0000000..e8c4b79 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/package.json @@ -0,0 +1,24 @@ +{ + "name": "bytes", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "description": "byte size string parser / serializer", + "version": "0.2.0", + "main": "index.js", + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "readme": "# node-bytes\n\n Byte string parser / formatter.\n\n## Example:\n\n```js\nbytes('1kb')\n// => 1024\n\nbytes('2mb')\n// => 2097152\n\nbytes('1gb')\n// => 1073741824\n\nbytes(1073741824)\n// => 1gb\n```\n\n## Installation\n\n```\n$ npm install bytes\n$ component install visionmedia/bytes.js\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "_id": "bytes@0.2.0", + "dist": { + "shasum": "db5d9936e2520114a4f9bd3c03a630a68613eeb3" + }, + "_from": "bytes@0.2.0", + "_resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/.npmignore b/node_modules/express/node_modules/connect/node_modules/formidable/.npmignore new file mode 100644 index 0000000..4fbabb3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/.npmignore @@ -0,0 +1,4 @@ +/test/tmp/ +*.upload +*.un~ +*.http diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/.travis.yml b/node_modules/express/node_modules/connect/node_modules/formidable/.travis.yml new file mode 100644 index 0000000..cb931cb --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.8 + - 0.9 + - "0.10" diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/LICENSE b/node_modules/express/node_modules/connect/node_modules/formidable/LICENSE new file mode 100644 index 0000000..38d3c9c --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/LICENSE @@ -0,0 +1,7 @@ +Copyright (C) 2011 Felix Geisendörfer + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/Readme.md b/node_modules/express/node_modules/connect/node_modules/formidable/Readme.md new file mode 100644 index 0000000..08e9eca --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/Readme.md @@ -0,0 +1,419 @@ +# Formidable + +[![Build Status](https://secure.travis-ci.org/felixge/node-formidable.png?branch=master)](http://travis-ci.org/felixge/node-formidable) + +## Purpose + +A node.js module for parsing form data, especially file uploads. + +## Current status + +This module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading +and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from +a large variety of clients and is considered production-ready. + +## Features + +* Fast (~500mb/sec), non-buffering multipart parser +* Automatically writing file uploads to disk +* Low memory footprint +* Graceful error handling +* Very high test coverage + +## Installation + +Via [npm](http://github.com/isaacs/npm): +``` +npm install formidable@latest +``` +Manually: +``` +git clone git://github.com/felixge/node-formidable.git formidable +vim my.js +# var formidable = require('./formidable'); +``` + +Note: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library. + +## Example + +Parse an incoming file upload. +```javascript +var formidable = require('formidable'), + http = require('http'), + util = require('util'); + +http.createServer(function(req, res) { + if (req.url == '/upload' && req.method.toLowerCase() == 'post') { + // parse a file upload + var form = new formidable.IncomingForm(); + + form.parse(req, function(err, fields, files) { + res.writeHead(200, {'content-type': 'text/plain'}); + res.write('received upload:\n\n'); + res.end(util.inspect({fields: fields, files: files})); + }); + + return; + } + + // show a file upload form + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); +}).listen(8080); +``` +## API + +### Formidable.IncomingForm +```javascript +var form = new formidable.IncomingForm() +``` +Creates a new incoming form. + +```javascript +form.encoding = 'utf-8'; +``` +Sets encoding for incoming form fields. + +```javascript +form.uploadDir = process.env.TMP || process.env.TMPDIR || process.env.TEMP || '/tmp' || process.cwd(); +``` +The directory for placing file uploads in. You can move them later on using +`fs.rename()`. The default directory is picked at module load time depending on +the first existing directory from those listed above. + +```javascript +form.keepExtensions = false; +``` +If you want the files written to `form.uploadDir` to include the extensions of the original files, set this property to `true`. + +```javascript +form.type +``` +Either 'multipart' or 'urlencoded' depending on the incoming request. + +```javascript +form.maxFieldsSize = 2 * 1024 * 1024; +``` +Limits the amount of memory a field (not file) can allocate in bytes. +If this value is exceeded, an `'error'` event is emitted. The default +size is 2MB. + +```javascript +form.maxFields = 0; +``` +Limits the number of fields that the querystring parser will decode. Defaults +to 0 (unlimited). + +```javascript +form.hash = false; +``` +If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`. + +```javascript +form.bytesReceived +``` +The amount of bytes received for this form so far. + +```javascript +form.bytesExpected +``` +The expected number of bytes in this form. + +```javascript +form.parse(request, [cb]); +``` +Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields an files are collected and passed to the callback: + + +```javascript +form.parse(req, function(err, fields, files) { + // ... +}); + +form.onPart(part); +``` +You may overwrite this method if you are interested in directly accessing the multipart stream. Doing so will disable any `'field'` / `'file'` events processing which would occur otherwise, making you fully responsible for handling the processing. + +```javascript +form.onPart = function(part) { + part.addListener('data', function() { + // ... + }); +} +``` +If you want to use formidable to only handle certain parts for you, you can do so: +```javascript +form.onPart = function(part) { + if (!part.filename) { + // let formidable handle all non-file parts + form.handlePart(part); + } +} +``` +Check the code in this method for further inspiration. + + +### Formidable.File +```javascript +file.size = 0 +``` +The size of the uploaded file in bytes. If the file is still being uploaded (see `'fileBegin'` event), this property says how many bytes of the file have been written to disk yet. +```javascript +file.path = null +``` +The path this file is being written to. You can modify this in the `'fileBegin'` event in +case you are unhappy with the way formidable generates a temporary path for your files. +```javascript +file.name = null +``` +The name this file had according to the uploading client. +```javascript +file.type = null +``` +The mime type of this file, according to the uploading client. +```javascript +file.lastModifiedDate = null +``` +A date object (or `null`) containing the time this file was last written to. Mostly +here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/). +```javascript +file.hash = null +``` +If hash calculation was set, you can read the hex digest out of this var. + +#### Formidable.File#toJSON() + + This method returns a JSON-representation of the file, allowing you to + `JSON.stringify()` the file which is useful for logging and responding + to requests. + +### Events + + +#### 'progress' +```javascript +form.on('progress', function(bytesReceived, bytesExpected) { +}); +``` +Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar. + + + +#### 'field' +```javascript +form.on('field', function(name, value) { +}); +``` + +#### 'fileBegin' + +Emitted whenever a field / value pair has been received. +```javascript +form.on('fileBegin', function(name, file) { +}); +``` + +#### 'file' + +Emitted whenever a new file is detected in the upload stream. Use this even if +you want to stream the file to somewhere else while buffering the upload on +the file system. + +Emitted whenever a field / file pair has been received. `file` is an instance of `File`. +```javascript +form.on('file', function(name, file) { +}); +``` + +#### 'error' + +Emitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events. +```javascript +form.on('error', function(err) { +}); +``` + +#### 'aborted' + + +Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. In the future there will be a separate 'timeout' event (needs a change in the node core). +```javascript +form.on('aborted', function() { +}); +``` + +##### 'end' +```javascript +form.on('end', function() { +}); +``` +Emitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response. + + + +## Changelog + +### v1.0.14 + +* Add failing hash tests. (Ben Trask) +* Enable hash calculation again (Eugene Girshov) +* Test for immediate data events (Tim Smart) +* Re-arrange IncomingForm#parse (Tim Smart) + +### v1.0.13 + +* Only update hash if update method exists (Sven Lito) +* According to travis v0.10 needs to go quoted (Sven Lito) +* Bumping build node versions (Sven Lito) +* Additional fix for empty requests (Eugene Girshov) +* Change the default to 1000, to match the new Node behaviour. (OrangeDog) +* Add ability to control maxKeys in the querystring parser. (OrangeDog) +* Adjust test case to work with node 0.9.x (Eugene Girshov) +* Update package.json (Sven Lito) +* Path adjustment according to eb4468b (Markus Ast) + +### v1.0.12 + +* Emit error on aborted connections (Eugene Girshov) +* Add support for empty requests (Eugene Girshov) +* Fix name/filename handling in Content-Disposition (jesperp) +* Tolerate malformed closing boundary in multipart (Eugene Girshov) +* Ignore preamble in multipart messages (Eugene Girshov) +* Add support for application/json (Mike Frey, Carlos Rodriguez) +* Add support for Base64 encoding (Elmer Bulthuis) +* Add File#toJSON (TJ Holowaychuk) +* Remove support for Node.js 0.4 & 0.6 (Andrew Kelley) +* Documentation improvements (Sven Lito, Andre Azevedo) +* Add support for application/octet-stream (Ion Lupascu, Chris Scribner) +* Use os.tmpDir() to get tmp directory (Andrew Kelley) +* Improve package.json (Andrew Kelley, Sven Lito) +* Fix benchmark script (Andrew Kelley) +* Fix scope issue in incoming_forms (Sven Lito) +* Fix file handle leak on error (OrangeDog) + +### v1.0.11 + +* Calculate checksums for incoming files (sreuter) +* Add definition parameters to "IncomingForm" as an argument (Math-) + +### v1.0.10 + +* Make parts to be proper Streams (Matt Robenolt) + +### v1.0.9 + +* Emit progress when content length header parsed (Tim Koschützki) +* Fix Readme syntax due to GitHub changes (goob) +* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara) + +### v1.0.8 + +* Strip potentially unsafe characters when using `keepExtensions: true`. +* Switch to utest / urun for testing +* Add travis build + +### v1.0.7 + +* Remove file from package that was causing problems when installing on windows. (#102) +* Fix typos in Readme (Jason Davies). + +### v1.0.6 + +* Do not default to the default to the field name for file uploads where + filename="". + +### v1.0.5 + +* Support filename="" in multipart parts +* Explain unexpected end() errors in parser better + +**Note:** Starting with this version, formidable emits 'file' events for empty +file input fields. Previously those were incorrectly emitted as regular file +input fields with value = "". + +### v1.0.4 + +* Detect a good default tmp directory regardless of platform. (#88) + +### v1.0.3 + +* Fix problems with utf8 characters (#84) / semicolons in filenames (#58) +* Small performance improvements +* New test suite and fixture system + +### v1.0.2 + +* Exclude node\_modules folder from git +* Implement new `'aborted'` event +* Fix files in example folder to work with recent node versions +* Make gently a devDependency + +[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2) + +### v1.0.1 + +* Fix package.json to refer to proper main directory. (#68, Dean Landolt) + +[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1) + +### v1.0.0 + +* Add support for multipart boundaries that are quoted strings. (Jeff Craig) + +This marks the beginning of development on version 2.0 which will include +several architectural improvements. + +[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0) + +### v0.9.11 + +* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki) +* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class + +**Important:** The old property names of the File class will be removed in a +future release. + +[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11) + +### Older releases + +These releases were done before starting to maintain the above Changelog: + +* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10) +* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9) +* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8) +* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7) +* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6) +* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5) +* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4) +* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3) +* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2) +* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0) + +## License + +Formidable is licensed under the MIT license. + +## Ports + +* [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ parser based on formidable + +## Credits + +* [Ryan Dahl](http://twitter.com/ryah) for his work on [http-parser](http://github.com/ry/http-parser) which heavily inspired multipart_parser.js diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/benchmark/bench-multipart-parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/benchmark/bench-multipart-parser.js new file mode 100644 index 0000000..49abc43 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/benchmark/bench-multipart-parser.js @@ -0,0 +1,71 @@ +var assert = require('assert'); +require('../test/common'); +var multipartParser = require('../lib/multipart_parser'), + MultipartParser = multipartParser.MultipartParser, + parser = new MultipartParser(), + Buffer = require('buffer').Buffer, + boundary = '-----------------------------168072824752491622650073', + mb = 100, + buffer = createMultipartBuffer(boundary, mb * 1024 * 1024), + callbacks = + { partBegin: -1, + partEnd: -1, + headerField: -1, + headerValue: -1, + partData: -1, + end: -1, + }; + + +parser.initWithBoundary(boundary); +parser.onHeaderField = function() { + callbacks.headerField++; +}; + +parser.onHeaderValue = function() { + callbacks.headerValue++; +}; + +parser.onPartBegin = function() { + callbacks.partBegin++; +}; + +parser.onPartData = function() { + callbacks.partData++; +}; + +parser.onPartEnd = function() { + callbacks.partEnd++; +}; + +parser.onEnd = function() { + callbacks.end++; +}; + +var start = +new Date(), + nparsed = parser.write(buffer), + duration = +new Date - start, + mbPerSec = (mb / (duration / 1000)).toFixed(2); + +console.log(mbPerSec+' mb/sec'); + +assert.equal(nparsed, buffer.length); + +function createMultipartBuffer(boundary, size) { + var head = + '--'+boundary+'\r\n' + + 'content-disposition: form-data; name="field1"\r\n' + + '\r\n' + , tail = '\r\n--'+boundary+'--\r\n' + , buffer = new Buffer(size); + + buffer.write(head, 'ascii', 0); + buffer.write(tail, 'ascii', buffer.length - tail.length); + return buffer; +} + +process.on('exit', function() { + for (var k in callbacks) { + assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]); + } +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/example/json.js b/node_modules/express/node_modules/connect/node_modules/formidable/example/json.js new file mode 100644 index 0000000..eb8a724 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/example/json.js @@ -0,0 +1,67 @@ +var common = require('../test/common'), + http = require('http'), + util = require('util'), + formidable = common.formidable, + Buffer = require('buffer').Buffer, + port = common.port, + server; + +server = http.createServer(function(req, res) { + if (req.method !== 'POST') { + res.writeHead(200, {'content-type': 'text/plain'}) + res.end('Please POST a JSON payload to http://localhost:'+port+'/') + return; + } + + var form = new formidable.IncomingForm(), + fields = {}; + + form + .on('error', function(err) { + res.writeHead(500, {'content-type': 'text/plain'}); + res.end('error:\n\n'+util.inspect(err)); + console.error(err); + }) + .on('field', function(field, value) { + console.log(field, value); + fields[field] = value; + }) + .on('end', function() { + console.log('-> post done'); + res.writeHead(200, {'content-type': 'text/plain'}); + res.end('received fields:\n\n '+util.inspect(fields)); + }); + form.parse(req); +}); +server.listen(port); + +console.log('listening on http://localhost:'+port+'/'); + + +var request = http.request({ + host: 'localhost', + path: '/', + port: port, + method: 'POST', + headers: { 'content-type':'application/json', 'content-length':48 } +}, function(response) { + var data = ''; + console.log('\nServer responded with:'); + console.log('Status:', response.statusCode); + response.pipe(process.stdout); + response.on('end', function() { + console.log('\n') + process.exit(); + }); + // response.on('data', function(chunk) { + // data += chunk.toString('utf8'); + // }); + // response.on('end', function() { + // console.log('Response Data:') + // console.log(data); + // process.exit(); + // }); +}) + +request.write('{"numbers":[1,2,3,4,5],"nested":{"key":"value"}}'); +request.end(); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/example/post.js b/node_modules/express/node_modules/connect/node_modules/formidable/example/post.js new file mode 100644 index 0000000..f6c15a6 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/example/post.js @@ -0,0 +1,43 @@ +require('../test/common'); +var http = require('http'), + util = require('util'), + formidable = require('formidable'), + server; + +server = http.createServer(function(req, res) { + if (req.url == '/') { + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); + } else if (req.url == '/post') { + var form = new formidable.IncomingForm(), + fields = []; + + form + .on('error', function(err) { + res.writeHead(200, {'content-type': 'text/plain'}); + res.end('error:\n\n'+util.inspect(err)); + }) + .on('field', function(field, value) { + console.log(field, value); + fields.push([field, value]); + }) + .on('end', function() { + console.log('-> post done'); + res.writeHead(200, {'content-type': 'text/plain'}); + res.end('received fields:\n\n '+util.inspect(fields)); + }); + form.parse(req); + } else { + res.writeHead(404, {'content-type': 'text/plain'}); + res.end('404'); + } +}); +server.listen(TEST_PORT); + +console.log('listening on http://localhost:'+TEST_PORT+'/'); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/example/upload.js b/node_modules/express/node_modules/connect/node_modules/formidable/example/upload.js new file mode 100644 index 0000000..050cdd9 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/example/upload.js @@ -0,0 +1,48 @@ +require('../test/common'); +var http = require('http'), + util = require('util'), + formidable = require('formidable'), + server; + +server = http.createServer(function(req, res) { + if (req.url == '/') { + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); + } else if (req.url == '/upload') { + var form = new formidable.IncomingForm(), + files = [], + fields = []; + + form.uploadDir = TEST_TMP; + + form + .on('field', function(field, value) { + console.log(field, value); + fields.push([field, value]); + }) + .on('file', function(field, file) { + console.log(field, file); + files.push([field, file]); + }) + .on('end', function() { + console.log('-> upload done'); + res.writeHead(200, {'content-type': 'text/plain'}); + res.write('received fields:\n\n '+util.inspect(fields)); + res.write('\n\n'); + res.end('received files:\n\n '+util.inspect(files)); + }); + form.parse(req); + } else { + res.writeHead(404, {'content-type': 'text/plain'}); + res.end('404'); + } +}); +server.listen(TEST_PORT); + +console.log('listening on http://localhost:'+TEST_PORT+'/'); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/index.js b/node_modules/express/node_modules/connect/node_modules/formidable/index.js new file mode 100644 index 0000000..4cc88b3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/index.js @@ -0,0 +1 @@ +module.exports = require('./lib'); \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/lib/file.js b/node_modules/express/node_modules/connect/node_modules/formidable/lib/file.js new file mode 100644 index 0000000..e34c10e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/lib/file.js @@ -0,0 +1,72 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +var util = require('util'), + WriteStream = require('fs').WriteStream, + EventEmitter = require('events').EventEmitter, + crypto = require('crypto'); + +function File(properties) { + EventEmitter.call(this); + + this.size = 0; + this.path = null; + this.name = null; + this.type = null; + this.hash = null; + this.lastModifiedDate = null; + + this._writeStream = null; + + for (var key in properties) { + this[key] = properties[key]; + } + + if(typeof this.hash === 'string') { + this.hash = crypto.createHash(properties.hash); + } else { + this.hash = null; + } +} +module.exports = File; +util.inherits(File, EventEmitter); + +File.prototype.open = function() { + this._writeStream = new WriteStream(this.path); +}; + +File.prototype.toJSON = function() { + return { + size: this.size, + path: this.path, + name: this.name, + type: this.type, + mtime: this.lastModifiedDate, + length: this.length, + filename: this.filename, + mime: this.mime + }; +}; + +File.prototype.write = function(buffer, cb) { + var self = this; + if (self.hash) { + self.hash.update(buffer); + } + this._writeStream.write(buffer, function() { + self.lastModifiedDate = new Date(); + self.size += buffer.length; + self.emit('progress', self.size); + cb(); + }); +}; + +File.prototype.end = function(cb) { + var self = this; + if (self.hash) { + self.hash = self.hash.digest('hex'); + } + this._writeStream.end(function() { + self.emit('end'); + cb(); + }); +}; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/lib/incoming_form.js b/node_modules/express/node_modules/connect/node_modules/formidable/lib/incoming_form.js new file mode 100644 index 0000000..c2eeaf8 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/lib/incoming_form.js @@ -0,0 +1,535 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +var fs = require('fs'); +var util = require('util'), + path = require('path'), + File = require('./file'), + MultipartParser = require('./multipart_parser').MultipartParser, + QuerystringParser = require('./querystring_parser').QuerystringParser, + OctetParser = require('./octet_parser').OctetParser, + JSONParser = require('./json_parser').JSONParser, + StringDecoder = require('string_decoder').StringDecoder, + EventEmitter = require('events').EventEmitter, + Stream = require('stream').Stream, + os = require('os'); + +function IncomingForm(opts) { + if (!(this instanceof IncomingForm)) return new IncomingForm(opts); + EventEmitter.call(this); + + opts=opts||{}; + + this.error = null; + this.ended = false; + + this.maxFields = opts.maxFields || 1000; + this.maxFieldsSize = opts.maxFieldsSize || 2 * 1024 * 1024; + this.keepExtensions = opts.keepExtensions || false; + this.uploadDir = opts.uploadDir || os.tmpDir(); + this.encoding = opts.encoding || 'utf-8'; + this.headers = null; + this.type = null; + this.hash = false; + + this.bytesReceived = null; + this.bytesExpected = null; + + this._parser = null; + this._flushing = 0; + this._fieldsSize = 0; + this.openedFiles = []; + + return this; +}; +util.inherits(IncomingForm, EventEmitter); +exports.IncomingForm = IncomingForm; + +IncomingForm.prototype.parse = function(req, cb) { + this.pause = function() { + try { + req.pause(); + } catch (err) { + // the stream was destroyed + if (!this.ended) { + // before it was completed, crash & burn + this._error(err); + } + return false; + } + return true; + }; + + this.resume = function() { + try { + req.resume(); + } catch (err) { + // the stream was destroyed + if (!this.ended) { + // before it was completed, crash & burn + this._error(err); + } + return false; + } + + return true; + }; + + // Setup callback first, so we don't miss anything from data events emitted + // immediately. + if (cb) { + var fields = {}, files = {}; + this + .on('field', function(name, value) { + fields[name] = value; + }) + .on('file', function(name, file) { + files[name] = file; + }) + .on('error', function(err) { + cb(err, fields, files); + }) + .on('end', function() { + cb(null, fields, files); + }); + } + + // Parse headers and setup the parser, ready to start listening for data. + this.writeHeaders(req.headers); + + // Start listening for data. + var self = this; + req + .on('error', function(err) { + self._error(err); + }) + .on('aborted', function() { + self.emit('aborted'); + self._error(new Error('Request aborted')); + }) + .on('data', function(buffer) { + self.write(buffer); + }) + .on('end', function() { + if (self.error) { + return; + } + + var err = self._parser.end(); + if (err) { + self._error(err); + } + }); + + return this; +}; + +IncomingForm.prototype.writeHeaders = function(headers) { + this.headers = headers; + this._parseContentLength(); + this._parseContentType(); +}; + +IncomingForm.prototype.write = function(buffer) { + if (!this._parser) { + this._error(new Error('unintialized parser')); + return; + } + + this.bytesReceived += buffer.length; + this.emit('progress', this.bytesReceived, this.bytesExpected); + + var bytesParsed = this._parser.write(buffer); + if (bytesParsed !== buffer.length) { + this._error(new Error('parser error, '+bytesParsed+' of '+buffer.length+' bytes parsed')); + } + + return bytesParsed; +}; + +IncomingForm.prototype.pause = function() { + // this does nothing, unless overwritten in IncomingForm.parse + return false; +}; + +IncomingForm.prototype.resume = function() { + // this does nothing, unless overwritten in IncomingForm.parse + return false; +}; + +IncomingForm.prototype.onPart = function(part) { + // this method can be overwritten by the user + this.handlePart(part); +}; + +IncomingForm.prototype.handlePart = function(part) { + var self = this; + + if (part.filename === undefined) { + var value = '' + , decoder = new StringDecoder(this.encoding); + + part.on('data', function(buffer) { + self._fieldsSize += buffer.length; + if (self._fieldsSize > self.maxFieldsSize) { + self._error(new Error('maxFieldsSize exceeded, received '+self._fieldsSize+' bytes of field data')); + return; + } + value += decoder.write(buffer); + }); + + part.on('end', function() { + self.emit('field', part.name, value); + }); + return; + } + + this._flushing++; + + var file = new File({ + path: this._uploadPath(part.filename), + name: part.filename, + type: part.mime, + hash: self.hash + }); + + this.emit('fileBegin', part.name, file); + + file.open(); + this.openedFiles.push(file); + + part.on('data', function(buffer) { + self.pause(); + file.write(buffer, function() { + self.resume(); + }); + }); + + part.on('end', function() { + file.end(function() { + self._flushing--; + self.emit('file', part.name, file); + self._maybeEnd(); + }); + }); +}; + +function dummyParser(self) { + return { + end: function () { + self.ended = true; + self._maybeEnd(); + return null; + } + }; +} + +IncomingForm.prototype._parseContentType = function() { + if (this.bytesExpected === 0) { + this._parser = dummyParser(this); + return; + } + + if (!this.headers['content-type']) { + this._error(new Error('bad content-type header, no content-type')); + return; + } + + if (this.headers['content-type'].match(/octet-stream/i)) { + this._initOctetStream(); + return; + } + + if (this.headers['content-type'].match(/urlencoded/i)) { + this._initUrlencoded(); + return; + } + + if (this.headers['content-type'].match(/multipart/i)) { + var m; + if (m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i)) { + this._initMultipart(m[1] || m[2]); + } else { + this._error(new Error('bad content-type header, no multipart boundary')); + } + return; + } + + if (this.headers['content-type'].match(/json/i)) { + this._initJSONencoded(); + return; + } + + this._error(new Error('bad content-type header, unknown content-type: '+this.headers['content-type'])); +}; + +IncomingForm.prototype._error = function(err) { + if (this.error || this.ended) { + return; + } + + this.error = err; + this.pause(); + this.emit('error', err); + + if (Array.isArray(this.openedFiles)) { + this.openedFiles.forEach(function(file) { + file._writeStream.destroy(); + setTimeout(fs.unlink, 0, file.path); + }); + } +}; + +IncomingForm.prototype._parseContentLength = function() { + this.bytesReceived = 0; + if (this.headers['content-length']) { + this.bytesExpected = parseInt(this.headers['content-length'], 10); + } else if (this.headers['transfer-encoding'] === undefined) { + this.bytesExpected = 0; + } + + if (this.bytesExpected !== null) { + this.emit('progress', this.bytesReceived, this.bytesExpected); + } +}; + +IncomingForm.prototype._newParser = function() { + return new MultipartParser(); +}; + +IncomingForm.prototype._initMultipart = function(boundary) { + this.type = 'multipart'; + + var parser = new MultipartParser(), + self = this, + headerField, + headerValue, + part; + + parser.initWithBoundary(boundary); + + parser.onPartBegin = function() { + part = new Stream(); + part.readable = true; + part.headers = {}; + part.name = null; + part.filename = null; + part.mime = null; + + part.transferEncoding = 'binary'; + part.transferBuffer = ''; + + headerField = ''; + headerValue = ''; + }; + + parser.onHeaderField = function(b, start, end) { + headerField += b.toString(self.encoding, start, end); + }; + + parser.onHeaderValue = function(b, start, end) { + headerValue += b.toString(self.encoding, start, end); + }; + + parser.onHeaderEnd = function() { + headerField = headerField.toLowerCase(); + part.headers[headerField] = headerValue; + + var m; + if (headerField == 'content-disposition') { + if (m = headerValue.match(/\bname="([^"]+)"/i)) { + part.name = m[1]; + } + + part.filename = self._fileName(headerValue); + } else if (headerField == 'content-type') { + part.mime = headerValue; + } else if (headerField == 'content-transfer-encoding') { + part.transferEncoding = headerValue.toLowerCase(); + } + + headerField = ''; + headerValue = ''; + }; + + parser.onHeadersEnd = function() { + switch(part.transferEncoding){ + case 'binary': + case '7bit': + case '8bit': + parser.onPartData = function(b, start, end) { + part.emit('data', b.slice(start, end)); + }; + + parser.onPartEnd = function() { + part.emit('end'); + }; + break; + + case 'base64': + parser.onPartData = function(b, start, end) { + part.transferBuffer += b.slice(start, end).toString('ascii'); + + /* + four bytes (chars) in base64 converts to three bytes in binary + encoding. So we should always work with a number of bytes that + can be divided by 4, it will result in a number of buytes that + can be divided vy 3. + */ + var offset = parseInt(part.transferBuffer.length / 4) * 4; + part.emit('data', new Buffer(part.transferBuffer.substring(0, offset), 'base64')) + part.transferBuffer = part.transferBuffer.substring(offset); + }; + + parser.onPartEnd = function() { + part.emit('data', new Buffer(part.transferBuffer, 'base64')) + part.emit('end'); + }; + break; + + default: + return self._error(new Error('unknown transfer-encoding')); + } + + self.onPart(part); + }; + + + parser.onEnd = function() { + self.ended = true; + self._maybeEnd(); + }; + + this._parser = parser; +}; + +IncomingForm.prototype._fileName = function(headerValue) { + var m = headerValue.match(/\bfilename="(.*?)"($|; )/i); + if (!m) return; + + var filename = m[1].substr(m[1].lastIndexOf('\\') + 1); + filename = filename.replace(/%22/g, '"'); + filename = filename.replace(/&#([\d]{4});/g, function(m, code) { + return String.fromCharCode(code); + }); + return filename; +}; + +IncomingForm.prototype._initUrlencoded = function() { + this.type = 'urlencoded'; + + var parser = new QuerystringParser(this.maxFields) + , self = this; + + parser.onField = function(key, val) { + self.emit('field', key, val); + }; + + parser.onEnd = function() { + self.ended = true; + self._maybeEnd(); + }; + + this._parser = parser; +}; + +IncomingForm.prototype._initOctetStream = function() { + this.type = 'octet-stream'; + var filename = this.headers['x-file-name']; + var mime = this.headers['content-type']; + + var file = new File({ + path: this._uploadPath(filename), + name: filename, + type: mime + }); + + file.open(); + + this.emit('fileBegin', filename, file); + + this._flushing++; + + var self = this; + + self._parser = new OctetParser(); + + //Keep track of writes that haven't finished so we don't emit the file before it's done being written + var outstandingWrites = 0; + + self._parser.on('data', function(buffer){ + self.pause(); + outstandingWrites++; + + file.write(buffer, function() { + outstandingWrites--; + self.resume(); + + if(self.ended){ + self._parser.emit('doneWritingFile'); + } + }); + }); + + self._parser.on('end', function(){ + self._flushing--; + self.ended = true; + + var done = function(){ + self.emit('file', 'file', file); + self._maybeEnd(); + }; + + if(outstandingWrites === 0){ + done(); + } else { + self._parser.once('doneWritingFile', done); + } + }); +}; + +IncomingForm.prototype._initJSONencoded = function() { + this.type = 'json'; + + var parser = new JSONParser() + , self = this; + + if (this.bytesExpected) { + parser.initWithLength(this.bytesExpected); + } + + parser.onField = function(key, val) { + self.emit('field', key, val); + } + + parser.onEnd = function() { + self.ended = true; + self._maybeEnd(); + }; + + this._parser = parser; +}; + +IncomingForm.prototype._uploadPath = function(filename) { + var name = ''; + for (var i = 0; i < 32; i++) { + name += Math.floor(Math.random() * 16).toString(16); + } + + if (this.keepExtensions) { + var ext = path.extname(filename); + ext = ext.replace(/(\.[a-z0-9]+).*/, '$1'); + + name += ext; + } + + return path.join(this.uploadDir, name); +}; + +IncomingForm.prototype._maybeEnd = function() { + if (!this.ended || this._flushing || this.error) { + return; + } + + this.emit('end'); +}; + diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/lib/index.js b/node_modules/express/node_modules/connect/node_modules/formidable/lib/index.js new file mode 100644 index 0000000..7a6e3e1 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/lib/index.js @@ -0,0 +1,3 @@ +var IncomingForm = require('./incoming_form').IncomingForm; +IncomingForm.IncomingForm = IncomingForm; +module.exports = IncomingForm; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/lib/json_parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/lib/json_parser.js new file mode 100644 index 0000000..6ce966b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/lib/json_parser.js @@ -0,0 +1,35 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +var Buffer = require('buffer').Buffer + +function JSONParser() { + this.data = new Buffer(''); + this.bytesWritten = 0; +}; +exports.JSONParser = JSONParser; + +JSONParser.prototype.initWithLength = function(length) { + this.data = new Buffer(length); +} + +JSONParser.prototype.write = function(buffer) { + if (this.data.length >= this.bytesWritten + buffer.length) { + buffer.copy(this.data, this.bytesWritten); + } else { + this.data = Buffer.concat([this.data, buffer]); + } + this.bytesWritten += buffer.length; + return buffer.length; +} + +JSONParser.prototype.end = function() { + try { + var fields = JSON.parse(this.data.toString('utf8')) + for (var field in fields) { + this.onField(field, fields[field]); + } + } catch (e) {} + this.data = null; + + this.onEnd(); +} \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/lib/multipart_parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/lib/multipart_parser.js new file mode 100644 index 0000000..98a6856 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/lib/multipart_parser.js @@ -0,0 +1,324 @@ +var Buffer = require('buffer').Buffer, + s = 0, + S = + { PARSER_UNINITIALIZED: s++, + START: s++, + START_BOUNDARY: s++, + HEADER_FIELD_START: s++, + HEADER_FIELD: s++, + HEADER_VALUE_START: s++, + HEADER_VALUE: s++, + HEADER_VALUE_ALMOST_DONE: s++, + HEADERS_ALMOST_DONE: s++, + PART_DATA_START: s++, + PART_DATA: s++, + PART_END: s++, + END: s++ + }, + + f = 1, + F = + { PART_BOUNDARY: f, + LAST_BOUNDARY: f *= 2 + }, + + LF = 10, + CR = 13, + SPACE = 32, + HYPHEN = 45, + COLON = 58, + A = 97, + Z = 122, + + lower = function(c) { + return c | 0x20; + }; + +for (s in S) { + exports[s] = S[s]; +} + +function MultipartParser() { + this.boundary = null; + this.boundaryChars = null; + this.lookbehind = null; + this.state = S.PARSER_UNINITIALIZED; + + this.index = null; + this.flags = 0; +}; +exports.MultipartParser = MultipartParser; + +MultipartParser.stateToString = function(stateNumber) { + for (var state in S) { + var number = S[state]; + if (number === stateNumber) return state; + } +}; + +MultipartParser.prototype.initWithBoundary = function(str) { + this.boundary = new Buffer(str.length+4); + this.boundary.write('\r\n--', 'ascii', 0); + this.boundary.write(str, 'ascii', 4); + this.lookbehind = new Buffer(this.boundary.length+8); + this.state = S.START; + + this.boundaryChars = {}; + for (var i = 0; i < this.boundary.length; i++) { + this.boundaryChars[this.boundary[i]] = true; + } +}; + +MultipartParser.prototype.write = function(buffer) { + var self = this, + i = 0, + len = buffer.length, + prevIndex = this.index, + index = this.index, + state = this.state, + flags = this.flags, + lookbehind = this.lookbehind, + boundary = this.boundary, + boundaryChars = this.boundaryChars, + boundaryLength = this.boundary.length, + boundaryEnd = boundaryLength - 1, + bufferLength = buffer.length, + c, + cl, + + mark = function(name) { + self[name+'Mark'] = i; + }, + clear = function(name) { + delete self[name+'Mark']; + }, + callback = function(name, buffer, start, end) { + if (start !== undefined && start === end) { + return; + } + + var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1); + if (callbackSymbol in self) { + self[callbackSymbol](buffer, start, end); + } + }, + dataCallback = function(name, clear) { + var markSymbol = name+'Mark'; + if (!(markSymbol in self)) { + return; + } + + if (!clear) { + callback(name, buffer, self[markSymbol], buffer.length); + self[markSymbol] = 0; + } else { + callback(name, buffer, self[markSymbol], i); + delete self[markSymbol]; + } + }; + + for (i = 0; i < len; i++) { + c = buffer[i]; + switch (state) { + case S.PARSER_UNINITIALIZED: + return i; + case S.START: + index = 0; + state = S.START_BOUNDARY; + case S.START_BOUNDARY: + if (index == boundary.length - 2) { + if (c != CR) { + return i; + } + index++; + break; + } else if (index - 1 == boundary.length - 2) { + if (c != LF) { + return i; + } + index = 0; + callback('partBegin'); + state = S.HEADER_FIELD_START; + break; + } + + if (c != boundary[index+2]) { + index = -2; + } + if (c == boundary[index+2]) { + index++; + } + break; + case S.HEADER_FIELD_START: + state = S.HEADER_FIELD; + mark('headerField'); + index = 0; + case S.HEADER_FIELD: + if (c == CR) { + clear('headerField'); + state = S.HEADERS_ALMOST_DONE; + break; + } + + index++; + if (c == HYPHEN) { + break; + } + + if (c == COLON) { + if (index == 1) { + // empty header field + return i; + } + dataCallback('headerField', true); + state = S.HEADER_VALUE_START; + break; + } + + cl = lower(c); + if (cl < A || cl > Z) { + return i; + } + break; + case S.HEADER_VALUE_START: + if (c == SPACE) { + break; + } + + mark('headerValue'); + state = S.HEADER_VALUE; + case S.HEADER_VALUE: + if (c == CR) { + dataCallback('headerValue', true); + callback('headerEnd'); + state = S.HEADER_VALUE_ALMOST_DONE; + } + break; + case S.HEADER_VALUE_ALMOST_DONE: + if (c != LF) { + return i; + } + state = S.HEADER_FIELD_START; + break; + case S.HEADERS_ALMOST_DONE: + if (c != LF) { + return i; + } + + callback('headersEnd'); + state = S.PART_DATA_START; + break; + case S.PART_DATA_START: + state = S.PART_DATA; + mark('partData'); + case S.PART_DATA: + prevIndex = index; + + if (index == 0) { + // boyer-moore derrived algorithm to safely skip non-boundary data + i += boundaryEnd; + while (i < bufferLength && !(buffer[i] in boundaryChars)) { + i += boundaryLength; + } + i -= boundaryEnd; + c = buffer[i]; + } + + if (index < boundary.length) { + if (boundary[index] == c) { + if (index == 0) { + dataCallback('partData', true); + } + index++; + } else { + index = 0; + } + } else if (index == boundary.length) { + index++; + if (c == CR) { + // CR = part boundary + flags |= F.PART_BOUNDARY; + } else if (c == HYPHEN) { + // HYPHEN = end boundary + flags |= F.LAST_BOUNDARY; + } else { + index = 0; + } + } else if (index - 1 == boundary.length) { + if (flags & F.PART_BOUNDARY) { + index = 0; + if (c == LF) { + // unset the PART_BOUNDARY flag + flags &= ~F.PART_BOUNDARY; + callback('partEnd'); + callback('partBegin'); + state = S.HEADER_FIELD_START; + break; + } + } else if (flags & F.LAST_BOUNDARY) { + if (c == HYPHEN) { + callback('partEnd'); + callback('end'); + state = S.END; + } else { + index = 0; + } + } else { + index = 0; + } + } + + if (index > 0) { + // when matching a possible boundary, keep a lookbehind reference + // in case it turns out to be a false lead + lookbehind[index-1] = c; + } else if (prevIndex > 0) { + // if our boundary turned out to be rubbish, the captured lookbehind + // belongs to partData + callback('partData', lookbehind, 0, prevIndex); + prevIndex = 0; + mark('partData'); + + // reconsider the current character even so it interrupted the sequence + // it could be the beginning of a new sequence + i--; + } + + break; + case S.END: + break; + default: + return i; + } + } + + dataCallback('headerField'); + dataCallback('headerValue'); + dataCallback('partData'); + + this.index = index; + this.state = state; + this.flags = flags; + + return len; +}; + +MultipartParser.prototype.end = function() { + var callback = function(self, name) { + var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1); + if (callbackSymbol in self) { + self[callbackSymbol](); + } + }; + if ((this.state == S.HEADER_FIELD_START && this.index == 0) || + (this.state == S.PART_DATA && this.index == this.boundary.length)) { + callback(this, 'partEnd'); + callback(this, 'end'); + } else if (this.state != S.END) { + return new Error('MultipartParser.end(): stream ended unexpectedly: ' + this.explain()); + } +}; + +MultipartParser.prototype.explain = function() { + return 'state = ' + MultipartParser.stateToString(this.state); +}; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/lib/octet_parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/lib/octet_parser.js new file mode 100644 index 0000000..6e8b551 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/lib/octet_parser.js @@ -0,0 +1,20 @@ +var EventEmitter = require('events').EventEmitter + , util = require('util'); + +function OctetParser(options){ + if(!(this instanceof OctetParser)) return new OctetParser(options); + EventEmitter.call(this); +} + +util.inherits(OctetParser, EventEmitter); + +exports.OctetParser = OctetParser; + +OctetParser.prototype.write = function(buffer) { + this.emit('data', buffer); + return buffer.length; +}; + +OctetParser.prototype.end = function() { + this.emit('end'); +}; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/lib/querystring_parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/lib/querystring_parser.js new file mode 100644 index 0000000..320ce5a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/lib/querystring_parser.js @@ -0,0 +1,27 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +// This is a buffering parser, not quite as nice as the multipart one. +// If I find time I'll rewrite this to be fully streaming as well +var querystring = require('querystring'); + +function QuerystringParser(maxKeys) { + this.maxKeys = maxKeys; + this.buffer = ''; +}; +exports.QuerystringParser = QuerystringParser; + +QuerystringParser.prototype.write = function(buffer) { + this.buffer += buffer.toString('ascii'); + return buffer.length; +}; + +QuerystringParser.prototype.end = function() { + var fields = querystring.parse(this.buffer, '&', '=', { maxKeys: this.maxKeys }); + for (var field in fields) { + this.onField(field, fields[field]); + } + this.buffer = ''; + + this.onEnd(); +}; + diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/package.json b/node_modules/express/node_modules/connect/node_modules/formidable/package.json new file mode 100644 index 0000000..e42cc58 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/package.json @@ -0,0 +1,42 @@ +{ + "name": "formidable", + "description": "A node.js module for parsing form data, especially file uploads.", + "homepage": "https://github.com/felixge/node-formidable", + "version": "1.0.14", + "devDependencies": { + "gently": "0.8.0", + "findit": "0.1.1", + "hashish": "0.0.4", + "urun": "~0.0.6", + "utest": "0.0.3", + "request": "~2.11.4" + }, + "directories": { + "lib": "./lib" + }, + "main": "./lib/index", + "scripts": { + "test": "node test/run.js", + "clean": "rm test/tmp/*" + }, + "engines": { + "node": ">=0.8.0" + }, + "repository": { + "type": "git", + "url": "git://github.com/felixge/node-formidable.git" + }, + "bugs": { + "url": "http://github.com/felixge/node-formidable/issues" + }, + "optionalDependencies": {}, + "readme": "# Formidable\n\n[![Build Status](https://secure.travis-ci.org/felixge/node-formidable.png?branch=master)](http://travis-ci.org/felixge/node-formidable)\n\n## Purpose\n\nA node.js module for parsing form data, especially file uploads.\n\n## Current status\n\nThis module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading\nand encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from\na large variety of clients and is considered production-ready.\n\n## Features\n\n* Fast (~500mb/sec), non-buffering multipart parser\n* Automatically writing file uploads to disk\n* Low memory footprint\n* Graceful error handling\n* Very high test coverage\n\n## Installation\n\nVia [npm](http://github.com/isaacs/npm):\n```\nnpm install formidable@latest\n```\nManually:\n```\ngit clone git://github.com/felixge/node-formidable.git formidable\nvim my.js\n# var formidable = require('./formidable');\n```\n\nNote: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.\n\n## Example\n\nParse an incoming file upload.\n```javascript\nvar formidable = require('formidable'),\n http = require('http'),\n util = require('util');\n\nhttp.createServer(function(req, res) {\n if (req.url == '/upload' && req.method.toLowerCase() == 'post') {\n // parse a file upload\n var form = new formidable.IncomingForm();\n\n form.parse(req, function(err, fields, files) {\n res.writeHead(200, {'content-type': 'text/plain'});\n res.write('received upload:\\n\\n');\n res.end(util.inspect({fields: fields, files: files}));\n });\n\n return;\n }\n\n // show a file upload form\n res.writeHead(200, {'content-type': 'text/html'});\n res.end(\n '
    '+\n '
    '+\n '
    '+\n ''+\n '
    '\n );\n}).listen(8080);\n```\n## API\n\n### Formidable.IncomingForm\n```javascript\nvar form = new formidable.IncomingForm()\n```\nCreates a new incoming form.\n\n```javascript\nform.encoding = 'utf-8';\n```\nSets encoding for incoming form fields.\n\n```javascript\nform.uploadDir = process.env.TMP || process.env.TMPDIR || process.env.TEMP || '/tmp' || process.cwd();\n```\nThe directory for placing file uploads in. You can move them later on using\n`fs.rename()`. The default directory is picked at module load time depending on\nthe first existing directory from those listed above.\n\n```javascript\nform.keepExtensions = false;\n```\nIf you want the files written to `form.uploadDir` to include the extensions of the original files, set this property to `true`.\n\n```javascript\nform.type\n```\nEither 'multipart' or 'urlencoded' depending on the incoming request.\n\n```javascript\nform.maxFieldsSize = 2 * 1024 * 1024;\n```\nLimits the amount of memory a field (not file) can allocate in bytes.\nIf this value is exceeded, an `'error'` event is emitted. The default\nsize is 2MB.\n\n```javascript\nform.maxFields = 0;\n```\nLimits the number of fields that the querystring parser will decode. Defaults\nto 0 (unlimited).\n\n```javascript\nform.hash = false;\n```\nIf you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.\n\n```javascript\nform.bytesReceived\n```\nThe amount of bytes received for this form so far.\n\n```javascript\nform.bytesExpected\n```\nThe expected number of bytes in this form.\n\n```javascript\nform.parse(request, [cb]);\n```\nParses an incoming node.js `request` containing form data. If `cb` is provided, all fields an files are collected and passed to the callback:\n\n\n```javascript\nform.parse(req, function(err, fields, files) {\n // ...\n});\n\nform.onPart(part);\n```\nYou may overwrite this method if you are interested in directly accessing the multipart stream. Doing so will disable any `'field'` / `'file'` events processing which would occur otherwise, making you fully responsible for handling the processing.\n\n```javascript\nform.onPart = function(part) {\n part.addListener('data', function() {\n // ...\n });\n}\n```\nIf you want to use formidable to only handle certain parts for you, you can do so:\n```javascript\nform.onPart = function(part) {\n if (!part.filename) {\n // let formidable handle all non-file parts\n form.handlePart(part);\n }\n}\n```\nCheck the code in this method for further inspiration.\n\n\n### Formidable.File\n```javascript\nfile.size = 0\n```\nThe size of the uploaded file in bytes. If the file is still being uploaded (see `'fileBegin'` event), this property says how many bytes of the file have been written to disk yet.\n```javascript\nfile.path = null\n```\nThe path this file is being written to. You can modify this in the `'fileBegin'` event in\ncase you are unhappy with the way formidable generates a temporary path for your files.\n```javascript\nfile.name = null\n```\nThe name this file had according to the uploading client.\n```javascript\nfile.type = null\n```\nThe mime type of this file, according to the uploading client.\n```javascript\nfile.lastModifiedDate = null\n```\nA date object (or `null`) containing the time this file was last written to. Mostly\nhere for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).\n```javascript\nfile.hash = null\n```\nIf hash calculation was set, you can read the hex digest out of this var.\n\n#### Formidable.File#toJSON()\n\n This method returns a JSON-representation of the file, allowing you to\n `JSON.stringify()` the file which is useful for logging and responding\n to requests.\n\n### Events\n\n\n#### 'progress'\n```javascript\nform.on('progress', function(bytesReceived, bytesExpected) {\n});\n```\nEmitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.\n\n\n\n#### 'field'\n```javascript\nform.on('field', function(name, value) {\n});\n```\n\n#### 'fileBegin'\n\nEmitted whenever a field / value pair has been received.\n```javascript\nform.on('fileBegin', function(name, file) {\n});\n```\n\n#### 'file'\n\nEmitted whenever a new file is detected in the upload stream. Use this even if\nyou want to stream the file to somewhere else while buffering the upload on\nthe file system.\n\nEmitted whenever a field / file pair has been received. `file` is an instance of `File`.\n```javascript\nform.on('file', function(name, file) {\n});\n```\n\n#### 'error'\n\nEmitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events.\n```javascript\nform.on('error', function(err) {\n});\n```\n\n#### 'aborted'\n\n\nEmitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. In the future there will be a separate 'timeout' event (needs a change in the node core).\n```javascript\nform.on('aborted', function() {\n});\n```\n\n##### 'end'\n```javascript\nform.on('end', function() {\n});\n```\nEmitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response.\n\n\n\n## Changelog\n\n### v1.0.14\n\n* Add failing hash tests. (Ben Trask)\n* Enable hash calculation again (Eugene Girshov)\n* Test for immediate data events (Tim Smart)\n* Re-arrange IncomingForm#parse (Tim Smart)\n\n### v1.0.13\n\n* Only update hash if update method exists (Sven Lito)\n* According to travis v0.10 needs to go quoted (Sven Lito)\n* Bumping build node versions (Sven Lito)\n* Additional fix for empty requests (Eugene Girshov)\n* Change the default to 1000, to match the new Node behaviour. (OrangeDog)\n* Add ability to control maxKeys in the querystring parser. (OrangeDog)\n* Adjust test case to work with node 0.9.x (Eugene Girshov)\n* Update package.json (Sven Lito)\n* Path adjustment according to eb4468b (Markus Ast)\n\n### v1.0.12\n\n* Emit error on aborted connections (Eugene Girshov)\n* Add support for empty requests (Eugene Girshov)\n* Fix name/filename handling in Content-Disposition (jesperp)\n* Tolerate malformed closing boundary in multipart (Eugene Girshov)\n* Ignore preamble in multipart messages (Eugene Girshov)\n* Add support for application/json (Mike Frey, Carlos Rodriguez)\n* Add support for Base64 encoding (Elmer Bulthuis)\n* Add File#toJSON (TJ Holowaychuk)\n* Remove support for Node.js 0.4 & 0.6 (Andrew Kelley)\n* Documentation improvements (Sven Lito, Andre Azevedo)\n* Add support for application/octet-stream (Ion Lupascu, Chris Scribner)\n* Use os.tmpDir() to get tmp directory (Andrew Kelley)\n* Improve package.json (Andrew Kelley, Sven Lito)\n* Fix benchmark script (Andrew Kelley)\n* Fix scope issue in incoming_forms (Sven Lito)\n* Fix file handle leak on error (OrangeDog)\n\n### v1.0.11\n\n* Calculate checksums for incoming files (sreuter)\n* Add definition parameters to \"IncomingForm\" as an argument (Math-)\n\n### v1.0.10\n\n* Make parts to be proper Streams (Matt Robenolt)\n\n### v1.0.9\n\n* Emit progress when content length header parsed (Tim Koschützki)\n* Fix Readme syntax due to GitHub changes (goob)\n* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara)\n\n### v1.0.8\n\n* Strip potentially unsafe characters when using `keepExtensions: true`.\n* Switch to utest / urun for testing\n* Add travis build\n\n### v1.0.7\n\n* Remove file from package that was causing problems when installing on windows. (#102)\n* Fix typos in Readme (Jason Davies).\n\n### v1.0.6\n\n* Do not default to the default to the field name for file uploads where\n filename=\"\".\n\n### v1.0.5\n\n* Support filename=\"\" in multipart parts\n* Explain unexpected end() errors in parser better\n\n**Note:** Starting with this version, formidable emits 'file' events for empty\nfile input fields. Previously those were incorrectly emitted as regular file\ninput fields with value = \"\".\n\n### v1.0.4\n\n* Detect a good default tmp directory regardless of platform. (#88)\n\n### v1.0.3\n\n* Fix problems with utf8 characters (#84) / semicolons in filenames (#58)\n* Small performance improvements\n* New test suite and fixture system\n\n### v1.0.2\n\n* Exclude node\\_modules folder from git\n* Implement new `'aborted'` event\n* Fix files in example folder to work with recent node versions\n* Make gently a devDependency\n\n[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2)\n\n### v1.0.1\n\n* Fix package.json to refer to proper main directory. (#68, Dean Landolt)\n\n[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1)\n\n### v1.0.0\n\n* Add support for multipart boundaries that are quoted strings. (Jeff Craig)\n\nThis marks the beginning of development on version 2.0 which will include\nseveral architectural improvements.\n\n[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0)\n\n### v0.9.11\n\n* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki)\n* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class\n\n**Important:** The old property names of the File class will be removed in a\nfuture release.\n\n[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11)\n\n### Older releases\n\nThese releases were done before starting to maintain the above Changelog:\n\n* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10)\n* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9)\n* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8)\n* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7)\n* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6)\n* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5)\n* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4)\n* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3)\n* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2)\n* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)\n* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0)\n\n## License\n\nFormidable is licensed under the MIT license.\n\n## Ports\n\n* [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ parser based on formidable\n\n## Credits\n\n* [Ryan Dahl](http://twitter.com/ryah) for his work on [http-parser](http://github.com/ry/http-parser) which heavily inspired multipart_parser.js\n", + "readmeFilename": "Readme.md", + "dependencies": {}, + "_id": "formidable@1.0.14", + "dist": { + "shasum": "77531a1be1baefef3ad84373ac1ab3bc75d239a3" + }, + "_from": "formidable@1.0.14", + "_resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/common.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/common.js new file mode 100644 index 0000000..6a94295 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/common.js @@ -0,0 +1,18 @@ +var path = require('path'); + +var root = path.join(__dirname, '../'); +exports.dir = { + root : root, + lib : root + '/lib', + fixture : root + '/test/fixture', + tmp : root + '/test/tmp', +}; + +exports.port = 13532; + +exports.formidable = require('..'); +exports.assert = require('assert'); + +exports.require = function(lib) { + return require(exports.dir.lib + '/' + lib); +}; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/beta-sticker-1.png b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/beta-sticker-1.png new file mode 100644 index 0000000..20b1a7f Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/beta-sticker-1.png differ diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/binaryfile.tar.gz b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/binaryfile.tar.gz new file mode 100644 index 0000000..4a85af7 Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/binaryfile.tar.gz differ diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/blank.gif b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/blank.gif new file mode 100755 index 0000000..75b945d Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/blank.gif differ diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/funkyfilename.txt b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/funkyfilename.txt new file mode 100644 index 0000000..e7a4785 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/funkyfilename.txt @@ -0,0 +1 @@ +I am a text file with a funky name! diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/menu_separator.png b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/menu_separator.png new file mode 100644 index 0000000..1c16a71 Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/menu_separator.png differ diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/plain.txt b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/plain.txt new file mode 100644 index 0000000..9b6903e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/file/plain.txt @@ -0,0 +1 @@ +I am a plain text file diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/info.md b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/info.md new file mode 100644 index 0000000..3c9dbe3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/info.md @@ -0,0 +1,3 @@ +* Opera does not allow submitting this file, it shows a warning to the + user that the file could not be found instead. Tested in 9.8, 11.51 on OSX. + Reported to Opera on 08.09.2011 (tracking email DSK-346009@bugs.opera.com). diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/encoding.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/encoding.js new file mode 100644 index 0000000..fc22026 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/encoding.js @@ -0,0 +1,24 @@ +module.exports['menu_seperator.png.http'] = [ + {type: 'file', name: 'image', filename: 'menu_separator.png', fixture: 'menu_separator.png', + sha1: 'c845ca3ea794be298f2a1b79769b71939eaf4e54'} +]; + +module.exports['beta-sticker-1.png.http'] = [ + {type: 'file', name: 'sticker', filename: 'beta-sticker-1.png', fixture: 'beta-sticker-1.png', + sha1: '6abbcffd12b4ada5a6a084fe9e4584f846331bc4'} +]; + +module.exports['blank.gif.http'] = [ + {type: 'file', name: 'file', filename: 'blank.gif', fixture: 'blank.gif', + sha1: 'a1fdee122b95748d81cee426d717c05b5174fe96'} +]; + +module.exports['binaryfile.tar.gz.http'] = [ + {type: 'file', name: 'file', filename: 'binaryfile.tar.gz', fixture: 'binaryfile.tar.gz', + sha1: 'cfabe13b348e5e69287d677860880c52a69d2155'} +]; + +module.exports['plain.txt.http'] = [ + {type: 'file', name: 'file', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'} +]; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/misc.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/misc.js new file mode 100644 index 0000000..4489176 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/misc.js @@ -0,0 +1,6 @@ +module.exports = { + 'empty.http': [], + 'empty-urlencoded.http': [], + 'empty-multipart.http': [], + 'minimal.http': [], +}; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/no-filename.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/no-filename.js new file mode 100644 index 0000000..f03b4f0 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/no-filename.js @@ -0,0 +1,9 @@ +module.exports['generic.http'] = [ + {type: 'file', name: 'upload', filename: '', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; + +module.exports['filename-name.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/preamble.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/preamble.js new file mode 100644 index 0000000..d2e4cfd --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/preamble.js @@ -0,0 +1,9 @@ +module.exports['crlf.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; + +module.exports['preamble.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/special-chars-in-filename.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/special-chars-in-filename.js new file mode 100644 index 0000000..eb76fdc --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/special-chars-in-filename.js @@ -0,0 +1,21 @@ +var properFilename = 'funkyfilename.txt'; + +function expect(filename) { + return [ + {type: 'field', name: 'title', value: 'Weird filename'}, + {type: 'file', name: 'upload', filename: filename, fixture: properFilename}, + ]; +}; + +var webkit = " ? % * | \" < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"; +var ffOrIe = " ? % * | \" < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"; + +module.exports = { + 'osx-chrome-13.http' : expect(webkit), + 'osx-firefox-3.6.http' : expect(ffOrIe), + 'osx-safari-5.http' : expect(webkit), + 'xp-chrome-12.http' : expect(webkit), + 'xp-ie-7.http' : expect(ffOrIe), + 'xp-ie-8.http' : expect(ffOrIe), + 'xp-safari-5.http' : expect(webkit), +}; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/workarounds.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/workarounds.js new file mode 100644 index 0000000..e59c5b2 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/js/workarounds.js @@ -0,0 +1,8 @@ +module.exports['missing-hyphens1.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; +module.exports['missing-hyphens2.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/multipart.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/multipart.js new file mode 100644 index 0000000..a476169 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/multipart.js @@ -0,0 +1,72 @@ +exports['rfc1867'] = + { boundary: 'AaB03x', + raw: + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="field1"\r\n'+ + '\r\n'+ + 'Joe Blow\r\nalmost tricked you!\r\n'+ + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+ + 'Content-Type: text/plain\r\n'+ + '\r\n'+ + '... contents of file1.txt ...\r\r\n'+ + '--AaB03x--\r\n', + parts: + [ { headers: { + 'content-disposition': 'form-data; name="field1"', + }, + data: 'Joe Blow\r\nalmost tricked you!', + }, + { headers: { + 'content-disposition': 'form-data; name="pics"; filename="file1.txt"', + 'Content-Type': 'text/plain', + }, + data: '... contents of file1.txt ...\r', + } + ] + }; + +exports['noTrailing\r\n'] = + { boundary: 'AaB03x', + raw: + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="field1"\r\n'+ + '\r\n'+ + 'Joe Blow\r\nalmost tricked you!\r\n'+ + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+ + 'Content-Type: text/plain\r\n'+ + '\r\n'+ + '... contents of file1.txt ...\r\r\n'+ + '--AaB03x--', + parts: + [ { headers: { + 'content-disposition': 'form-data; name="field1"', + }, + data: 'Joe Blow\r\nalmost tricked you!', + }, + { headers: { + 'content-disposition': 'form-data; name="pics"; filename="file1.txt"', + 'Content-Type': 'text/plain', + }, + data: '... contents of file1.txt ...\r', + } + ] + }; + +exports['emptyHeader'] = + { boundary: 'AaB03x', + raw: + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="field1"\r\n'+ + ': foo\r\n'+ + '\r\n'+ + 'Joe Blow\r\nalmost tricked you!\r\n'+ + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+ + 'Content-Type: text/plain\r\n'+ + '\r\n'+ + '... contents of file1.txt ...\r\r\n'+ + '--AaB03x--\r\n', + expectError: true, + }; diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-fixtures.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-fixtures.js new file mode 100644 index 0000000..8e10ac9 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-fixtures.js @@ -0,0 +1,96 @@ +var hashish = require('hashish'); +var fs = require('fs'); +var findit = require('findit'); +var path = require('path'); +var http = require('http'); +var net = require('net'); +var assert = require('assert'); + +var common = require('../common'); +var formidable = common.formidable; + +var server = http.createServer(); +server.listen(common.port, findFixtures); + +function findFixtures() { + var fixtures = []; + findit + .sync(common.dir.fixture + '/js') + .forEach(function(jsPath) { + if (!/\.js$/.test(jsPath)) return; + + var group = path.basename(jsPath, '.js'); + hashish.forEach(require(jsPath), function(fixture, name) { + fixtures.push({ + name : group + '/' + name, + fixture : fixture, + }); + }); + }); + + testNext(fixtures); +} + +function testNext(fixtures) { + var fixture = fixtures.shift(); + if (!fixture) return server.close(); + + var name = fixture.name; + var fixture = fixture.fixture; + + uploadFixture(name, function(err, parts) { + if (err) throw err; + + fixture.forEach(function(expectedPart, i) { + var parsedPart = parts[i]; + assert.equal(parsedPart.type, expectedPart.type); + assert.equal(parsedPart.name, expectedPart.name); + + if (parsedPart.type === 'file') { + var file = parsedPart.value; + assert.equal(file.name, expectedPart.filename); + if(expectedPart.sha1) assert.equal(file.hash, expectedPart.sha1); + } + }); + + testNext(fixtures); + }); +}; + +function uploadFixture(name, cb) { + server.once('request', function(req, res) { + var form = new formidable.IncomingForm(); + form.uploadDir = common.dir.tmp; + form.hash = "sha1"; + form.parse(req); + + function callback() { + var realCallback = cb; + cb = function() {}; + realCallback.apply(null, arguments); + } + + var parts = []; + form + .on('error', callback) + .on('fileBegin', function(name, value) { + parts.push({type: 'file', name: name, value: value}); + }) + .on('field', function(name, value) { + parts.push({type: 'field', name: name, value: value}); + }) + .on('end', function() { + res.end('OK'); + callback(null, parts); + }); + }); + + var socket = net.createConnection(common.port); + var file = fs.createReadStream(common.dir.fixture + '/http/' + name); + + file.pipe(socket, {end: false}); + socket.on('data', function () { + socket.end(); + }); + +} diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-json.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-json.js new file mode 100644 index 0000000..28e758e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-json.js @@ -0,0 +1,38 @@ +var common = require('../common'); +var formidable = common.formidable; +var http = require('http'); +var assert = require('assert'); + +var testData = { + numbers: [1, 2, 3, 4, 5], + nested: { key: 'value' } +}; + +var server = http.createServer(function(req, res) { + var form = new formidable.IncomingForm(); + + form.parse(req, function(err, fields, files) { + assert.deepEqual(fields, testData); + + res.end(); + server.close(); + }); +}); + +var port = common.port; + +server.listen(port, function(err){ + assert.equal(err, null); + + var request = http.request({ + port: port, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + }); + + request.write(JSON.stringify(testData)); + request.end(); +}); + diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-octet-stream.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-octet-stream.js new file mode 100644 index 0000000..643d2c6 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/integration/test-octet-stream.js @@ -0,0 +1,45 @@ +var common = require('../common'); +var formidable = common.formidable; +var http = require('http'); +var fs = require('fs'); +var path = require('path'); +var hashish = require('hashish'); +var assert = require('assert'); + +var testFilePath = path.join(__dirname, '../fixture/file/binaryfile.tar.gz'); + +var server = http.createServer(function(req, res) { + var form = new formidable.IncomingForm(); + + form.parse(req, function(err, fields, files) { + assert.equal(hashish(files).length, 1); + var file = files.file; + + assert.equal(file.size, 301); + + var uploaded = fs.readFileSync(file.path); + var original = fs.readFileSync(testFilePath); + + assert.deepEqual(uploaded, original); + + res.end(); + server.close(); + }); +}); + +var port = common.port; + +server.listen(port, function(err){ + assert.equal(err, null); + + var request = http.request({ + port: port, + method: 'POST', + headers: { + 'Content-Type': 'application/octet-stream' + } + }); + + fs.createReadStream(testFilePath).pipe(request); +}); + diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/common.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/common.js new file mode 100644 index 0000000..2b98598 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/common.js @@ -0,0 +1,24 @@ +var path = require('path'), + fs = require('fs'); + +try { + global.Gently = require('gently'); +} catch (e) { + throw new Error('this test suite requires node-gently'); +} + +exports.lib = path.join(__dirname, '../../lib'); + +global.GENTLY = new Gently(); + +global.assert = require('assert'); +global.TEST_PORT = 13532; +global.TEST_FIXTURES = path.join(__dirname, '../fixture'); +global.TEST_TMP = path.join(__dirname, '../tmp'); + +// Stupid new feature in node that complains about gently attaching too many +// listeners to process 'exit'. This is a workaround until I can think of a +// better way to deal with this. +if (process.setMaxListeners) { + process.setMaxListeners(10000); +} diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/integration/test-multipart-parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/integration/test-multipart-parser.js new file mode 100644 index 0000000..75232aa --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/integration/test-multipart-parser.js @@ -0,0 +1,80 @@ +var common = require('../common'); +var CHUNK_LENGTH = 10, + multipartParser = require(common.lib + '/multipart_parser'), + MultipartParser = multipartParser.MultipartParser, + parser = new MultipartParser(), + fixtures = require(TEST_FIXTURES + '/multipart'), + Buffer = require('buffer').Buffer; + +Object.keys(fixtures).forEach(function(name) { + var fixture = fixtures[name], + buffer = new Buffer(Buffer.byteLength(fixture.raw, 'binary')), + offset = 0, + chunk, + nparsed, + + parts = [], + part = null, + headerField, + headerValue, + endCalled = ''; + + parser.initWithBoundary(fixture.boundary); + parser.onPartBegin = function() { + part = {headers: {}, data: ''}; + parts.push(part); + headerField = ''; + headerValue = ''; + }; + + parser.onHeaderField = function(b, start, end) { + headerField += b.toString('ascii', start, end); + }; + + parser.onHeaderValue = function(b, start, end) { + headerValue += b.toString('ascii', start, end); + } + + parser.onHeaderEnd = function() { + part.headers[headerField] = headerValue; + headerField = ''; + headerValue = ''; + }; + + parser.onPartData = function(b, start, end) { + var str = b.toString('ascii', start, end); + part.data += b.slice(start, end); + } + + parser.onEnd = function() { + endCalled = true; + } + + buffer.write(fixture.raw, 'binary', 0); + + while (offset < buffer.length) { + if (offset + CHUNK_LENGTH < buffer.length) { + chunk = buffer.slice(offset, offset+CHUNK_LENGTH); + } else { + chunk = buffer.slice(offset, buffer.length); + } + offset = offset + CHUNK_LENGTH; + + nparsed = parser.write(chunk); + if (nparsed != chunk.length) { + if (fixture.expectError) { + return; + } + puts('-- ERROR --'); + p(chunk.toString('ascii')); + throw new Error(chunk.length+' bytes written, but only '+nparsed+' bytes parsed!'); + } + } + + if (fixture.expectError) { + throw new Error('expected parse error did not happen'); + } + + assert.ok(endCalled); + assert.deepEqual(parts, fixture.parts); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-file.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-file.js new file mode 100644 index 0000000..52ceedb --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-file.js @@ -0,0 +1,104 @@ +var common = require('../common'); +var WriteStreamStub = GENTLY.stub('fs', 'WriteStream'); + +var File = require(common.lib + '/file'), + EventEmitter = require('events').EventEmitter, + file, + gently; + +function test(test) { + gently = new Gently(); + file = new File(); + test(); + gently.verify(test.name); +} + +test(function constructor() { + assert.ok(file instanceof EventEmitter); + assert.strictEqual(file.size, 0); + assert.strictEqual(file.path, null); + assert.strictEqual(file.name, null); + assert.strictEqual(file.type, null); + assert.strictEqual(file.lastModifiedDate, null); + + assert.strictEqual(file._writeStream, null); + + (function testSetProperties() { + var file2 = new File({foo: 'bar'}); + assert.equal(file2.foo, 'bar'); + })(); +}); + +test(function open() { + var WRITE_STREAM; + file.path = '/foo'; + + gently.expect(WriteStreamStub, 'new', function (path) { + WRITE_STREAM = this; + assert.strictEqual(path, file.path); + }); + + file.open(); + assert.strictEqual(file._writeStream, WRITE_STREAM); +}); + +test(function write() { + var BUFFER = {length: 10}, + CB_STUB, + CB = function() { + CB_STUB.apply(this, arguments); + }; + + file._writeStream = {}; + + gently.expect(file._writeStream, 'write', function (buffer, cb) { + assert.strictEqual(buffer, BUFFER); + + gently.expect(file, 'emit', function (event, bytesWritten) { + assert.ok(file.lastModifiedDate instanceof Date); + assert.equal(event, 'progress'); + assert.equal(bytesWritten, file.size); + }); + + CB_STUB = gently.expect(function writeCb() { + assert.equal(file.size, 10); + }); + + cb(); + + gently.expect(file, 'emit', function (event, bytesWritten) { + assert.equal(event, 'progress'); + assert.equal(bytesWritten, file.size); + }); + + CB_STUB = gently.expect(function writeCb() { + assert.equal(file.size, 20); + }); + + cb(); + }); + + file.write(BUFFER, CB); +}); + +test(function end() { + var CB_STUB, + CB = function() { + CB_STUB.apply(this, arguments); + }; + + file._writeStream = {}; + + gently.expect(file._writeStream, 'end', function (cb) { + gently.expect(file, 'emit', function (event) { + assert.equal(event, 'end'); + }); + + CB_STUB = gently.expect(function endCb() { + }); + + cb(); + }); + + file.end(CB); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-incoming-form.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-incoming-form.js new file mode 100644 index 0000000..25bd887 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-incoming-form.js @@ -0,0 +1,756 @@ +var common = require('../common'); +var MultipartParserStub = GENTLY.stub('./multipart_parser', 'MultipartParser'), + QuerystringParserStub = GENTLY.stub('./querystring_parser', 'QuerystringParser'), + EventEmitterStub = GENTLY.stub('events', 'EventEmitter'), + StreamStub = GENTLY.stub('stream', 'Stream'), + FileStub = GENTLY.stub('./file'); + +var formidable = require(common.lib + '/index'), + IncomingForm = formidable.IncomingForm, + events = require('events'), + fs = require('fs'), + path = require('path'), + Buffer = require('buffer').Buffer, + fixtures = require(TEST_FIXTURES + '/multipart'), + form, + gently; + +function test(test) { + gently = new Gently(); + gently.expect(EventEmitterStub, 'call'); + form = new IncomingForm(); + test(); + gently.verify(test.name); +} + +test(function constructor() { + assert.strictEqual(form.error, null); + assert.strictEqual(form.ended, false); + assert.strictEqual(form.type, null); + assert.strictEqual(form.headers, null); + assert.strictEqual(form.keepExtensions, false); + // Can't assume dir === '/tmp' for portability + // assert.strictEqual(form.uploadDir, '/tmp'); + // Make sure it is a directory instead + assert.doesNotThrow(function () { + assert(fs.statSync(form.uploadDir).isDirectory()); + }); + assert.strictEqual(form.encoding, 'utf-8'); + assert.strictEqual(form.bytesReceived, null); + assert.strictEqual(form.bytesExpected, null); + assert.strictEqual(form.maxFieldsSize, 2 * 1024 * 1024); + assert.strictEqual(form._parser, null); + assert.strictEqual(form._flushing, 0); + assert.strictEqual(form._fieldsSize, 0); + assert.ok(form instanceof EventEmitterStub); + assert.equal(form.constructor.name, 'IncomingForm'); + + (function testSimpleConstructor() { + gently.expect(EventEmitterStub, 'call'); + var form = IncomingForm(); + assert.ok(form instanceof IncomingForm); + })(); + + (function testSimpleConstructorShortcut() { + gently.expect(EventEmitterStub, 'call'); + var form = formidable(); + assert.ok(form instanceof IncomingForm); + })(); +}); + +test(function parse() { + var REQ = {headers: {}} + , emit = {}; + + gently.expect(form, 'writeHeaders', function(headers) { + assert.strictEqual(headers, REQ.headers); + }); + + var EVENTS = ['error', 'aborted', 'data', 'end']; + gently.expect(REQ, 'on', EVENTS.length, function(event, fn) { + assert.equal(event, EVENTS.shift()); + emit[event] = fn; + return this; + }); + + form.parse(REQ); + + (function testPause() { + gently.expect(REQ, 'pause'); + assert.strictEqual(form.pause(), true); + })(); + + (function testPauseCriticalException() { + form.ended = false; + + var ERR = new Error('dasdsa'); + gently.expect(REQ, 'pause', function() { + throw ERR; + }); + + gently.expect(form, '_error', function(err) { + assert.strictEqual(err, ERR); + }); + + assert.strictEqual(form.pause(), false); + })(); + + (function testPauseHarmlessException() { + form.ended = true; + + var ERR = new Error('dasdsa'); + gently.expect(REQ, 'pause', function() { + throw ERR; + }); + + assert.strictEqual(form.pause(), false); + })(); + + (function testResume() { + gently.expect(REQ, 'resume'); + assert.strictEqual(form.resume(), true); + })(); + + (function testResumeCriticalException() { + form.ended = false; + + var ERR = new Error('dasdsa'); + gently.expect(REQ, 'resume', function() { + throw ERR; + }); + + gently.expect(form, '_error', function(err) { + assert.strictEqual(err, ERR); + }); + + assert.strictEqual(form.resume(), false); + })(); + + (function testResumeHarmlessException() { + form.ended = true; + + var ERR = new Error('dasdsa'); + gently.expect(REQ, 'resume', function() { + throw ERR; + }); + + assert.strictEqual(form.resume(), false); + })(); + + (function testEmitError() { + var ERR = new Error('something bad happened'); + gently.expect(form, '_error',function(err) { + assert.strictEqual(err, ERR); + }); + emit.error(ERR); + })(); + + (function testEmitAborted() { + gently.expect(form, 'emit',function(event) { + assert.equal(event, 'aborted'); + }); + gently.expect(form, '_error'); + + emit.aborted(); + })(); + + + (function testEmitData() { + var BUFFER = [1, 2, 3]; + gently.expect(form, 'write', function(buffer) { + assert.strictEqual(buffer, BUFFER); + }); + emit.data(BUFFER); + })(); + + (function testEmitEnd() { + form._parser = {}; + + (function testWithError() { + var ERR = new Error('haha'); + gently.expect(form._parser, 'end', function() { + return ERR; + }); + + gently.expect(form, '_error', function(err) { + assert.strictEqual(err, ERR); + }); + + emit.end(); + })(); + + (function testWithoutError() { + gently.expect(form._parser, 'end'); + emit.end(); + })(); + + (function testAfterError() { + form.error = true; + emit.end(); + })(); + })(); + + (function testWithCallback() { + gently.expect(EventEmitterStub, 'call'); + var form = new IncomingForm(), + REQ = {headers: {}}, + parseCalled = 0; + + gently.expect(form, 'on', 4, function(event, fn) { + if (event == 'field') { + fn('field1', 'foo'); + fn('field1', 'bar'); + fn('field2', 'nice'); + } + + if (event == 'file') { + fn('file1', '1'); + fn('file1', '2'); + fn('file2', '3'); + } + + if (event == 'end') { + fn(); + } + return this; + }); + + gently.expect(form, 'writeHeaders'); + + gently.expect(REQ, 'on', 4, function() { + return this; + }); + + var parseCbOk = function (err, fields, files) { + assert.deepEqual(fields, {field1: 'bar', field2: 'nice'}); + assert.deepEqual(files, {file1: '2', file2: '3'}); + }; + form.parse(REQ, parseCbOk); + + var ERR = new Error('test'); + gently.expect(form, 'on', 3, function(event, fn) { + if (event == 'field') { + fn('foo', 'bar'); + } + + if (event == 'error') { + fn(ERR); + gently.expect(form, 'on'); + gently.expect(form, 'writeHeaders'); + gently.expect(REQ, 'on', 4, function() { + return this; + }); + } + return this; + }); + + form.parse(REQ, function parseCbErr(err, fields, files) { + assert.strictEqual(err, ERR); + assert.deepEqual(fields, {foo: 'bar'}); + }); + })(); + + (function testWriteOrder() { + gently.expect(EventEmitterStub, 'call'); + var form = new IncomingForm(); + var REQ = new events.EventEmitter(); + var BUF = {}; + var DATACB = null; + + REQ.on('newListener', function(event, fn) { + if ('data' === event) fn(BUF); + }); + + gently.expect(form, 'writeHeaders'); + gently.expect(form, 'write', function(buf) { + assert.strictEqual(buf, BUF); + }); + + form.parse(REQ); + })(); +}); + +test(function pause() { + assert.strictEqual(form.pause(), false); +}); + +test(function resume() { + assert.strictEqual(form.resume(), false); +}); + + +test(function writeHeaders() { + var HEADERS = {}; + gently.expect(form, '_parseContentLength'); + gently.expect(form, '_parseContentType'); + + form.writeHeaders(HEADERS); + assert.strictEqual(form.headers, HEADERS); +}); + +test(function write() { + var parser = {}, + BUFFER = [1, 2, 3]; + + form._parser = parser; + form.bytesExpected = 523423; + + (function testBasic() { + gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) { + assert.equal(event, 'progress'); + assert.equal(bytesReceived, BUFFER.length); + assert.equal(bytesExpected, form.bytesExpected); + }); + + gently.expect(parser, 'write', function(buffer) { + assert.strictEqual(buffer, BUFFER); + return buffer.length; + }); + + assert.equal(form.write(BUFFER), BUFFER.length); + assert.equal(form.bytesReceived, BUFFER.length); + })(); + + (function testParserError() { + gently.expect(form, 'emit'); + + gently.expect(parser, 'write', function(buffer) { + assert.strictEqual(buffer, BUFFER); + return buffer.length - 1; + }); + + gently.expect(form, '_error', function(err) { + assert.ok(err.message.match(/parser error/i)); + }); + + assert.equal(form.write(BUFFER), BUFFER.length - 1); + assert.equal(form.bytesReceived, BUFFER.length + BUFFER.length); + })(); + + (function testUninitialized() { + delete form._parser; + + gently.expect(form, '_error', function(err) { + assert.ok(err.message.match(/unintialized parser/i)); + }); + form.write(BUFFER); + })(); +}); + +test(function parseContentType() { + var HEADERS = {}; + + form.headers = {'content-type': 'application/x-www-form-urlencoded'}; + gently.expect(form, '_initUrlencoded'); + form._parseContentType(); + + // accept anything that has 'urlencoded' in it + form.headers = {'content-type': 'broken-client/urlencoded-stupid'}; + gently.expect(form, '_initUrlencoded'); + form._parseContentType(); + + var BOUNDARY = '---------------------------57814261102167618332366269'; + form.headers = {'content-type': 'multipart/form-data; boundary='+BOUNDARY}; + + gently.expect(form, '_initMultipart', function(boundary) { + assert.equal(boundary, BOUNDARY); + }); + form._parseContentType(); + + (function testQuotedBoundary() { + form.headers = {'content-type': 'multipart/form-data; boundary="' + BOUNDARY + '"'}; + + gently.expect(form, '_initMultipart', function(boundary) { + assert.equal(boundary, BOUNDARY); + }); + form._parseContentType(); + })(); + + (function testNoBoundary() { + form.headers = {'content-type': 'multipart/form-data'}; + + gently.expect(form, '_error', function(err) { + assert.ok(err.message.match(/no multipart boundary/i)); + }); + form._parseContentType(); + })(); + + (function testNoContentType() { + form.headers = {}; + + gently.expect(form, '_error', function(err) { + assert.ok(err.message.match(/no content-type/i)); + }); + form._parseContentType(); + })(); + + (function testUnknownContentType() { + form.headers = {'content-type': 'invalid'}; + + gently.expect(form, '_error', function(err) { + assert.ok(err.message.match(/unknown content-type/i)); + }); + form._parseContentType(); + })(); +}); + +test(function parseContentLength() { + var HEADERS = {}; + + form.headers = {}; + gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) { + assert.equal(event, 'progress'); + assert.equal(bytesReceived, 0); + assert.equal(bytesExpected, 0); + }); + form._parseContentLength(); + + form.headers['content-length'] = '8'; + gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) { + assert.equal(event, 'progress'); + assert.equal(bytesReceived, 0); + assert.equal(bytesExpected, 8); + }); + form._parseContentLength(); + assert.strictEqual(form.bytesReceived, 0); + assert.strictEqual(form.bytesExpected, 8); + + // JS can be evil, lets make sure we are not + form.headers['content-length'] = '08'; + gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) { + assert.equal(event, 'progress'); + assert.equal(bytesReceived, 0); + assert.equal(bytesExpected, 8); + }); + form._parseContentLength(); + assert.strictEqual(form.bytesExpected, 8); +}); + +test(function _initMultipart() { + var BOUNDARY = '123', + PARSER; + + gently.expect(MultipartParserStub, 'new', function() { + PARSER = this; + }); + + gently.expect(MultipartParserStub.prototype, 'initWithBoundary', function(boundary) { + assert.equal(boundary, BOUNDARY); + }); + + form._initMultipart(BOUNDARY); + assert.equal(form.type, 'multipart'); + assert.strictEqual(form._parser, PARSER); + + (function testRegularField() { + var PART; + gently.expect(StreamStub, 'new', function() { + PART = this; + }); + + gently.expect(form, 'onPart', function(part) { + assert.strictEqual(part, PART); + assert.deepEqual + ( part.headers + , { 'content-disposition': 'form-data; name="field1"' + , 'foo': 'bar' + } + ); + assert.equal(part.name, 'field1'); + + var strings = ['hello', ' world']; + gently.expect(part, 'emit', 2, function(event, b) { + assert.equal(event, 'data'); + assert.equal(b.toString(), strings.shift()); + }); + + gently.expect(part, 'emit', function(event, b) { + assert.equal(event, 'end'); + }); + }); + + PARSER.onPartBegin(); + PARSER.onHeaderField(new Buffer('content-disposition'), 0, 10); + PARSER.onHeaderField(new Buffer('content-disposition'), 10, 19); + PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 0, 14); + PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 14, 24); + PARSER.onHeaderEnd(); + PARSER.onHeaderField(new Buffer('foo'), 0, 3); + PARSER.onHeaderValue(new Buffer('bar'), 0, 3); + PARSER.onHeaderEnd(); + PARSER.onHeadersEnd(); + PARSER.onPartData(new Buffer('hello world'), 0, 5); + PARSER.onPartData(new Buffer('hello world'), 5, 11); + PARSER.onPartEnd(); + })(); + + (function testFileField() { + var PART; + gently.expect(StreamStub, 'new', function() { + PART = this; + }); + + gently.expect(form, 'onPart', function(part) { + assert.deepEqual + ( part.headers + , { 'content-disposition': 'form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"' + , 'content-type': 'text/plain' + } + ); + assert.equal(part.name, 'field2'); + assert.equal(part.filename, 'Sun"et.jpg'); + assert.equal(part.mime, 'text/plain'); + + gently.expect(part, 'emit', function(event, b) { + assert.equal(event, 'data'); + assert.equal(b.toString(), '... contents of file1.txt ...'); + }); + + gently.expect(part, 'emit', function(event, b) { + assert.equal(event, 'end'); + }); + }); + + PARSER.onPartBegin(); + PARSER.onHeaderField(new Buffer('content-disposition'), 0, 19); + PARSER.onHeaderValue(new Buffer('form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"'), 0, 85); + PARSER.onHeaderEnd(); + PARSER.onHeaderField(new Buffer('Content-Type'), 0, 12); + PARSER.onHeaderValue(new Buffer('text/plain'), 0, 10); + PARSER.onHeaderEnd(); + PARSER.onHeadersEnd(); + PARSER.onPartData(new Buffer('... contents of file1.txt ...'), 0, 29); + PARSER.onPartEnd(); + })(); + + (function testEnd() { + gently.expect(form, '_maybeEnd'); + PARSER.onEnd(); + assert.ok(form.ended); + })(); +}); + +test(function _fileName() { + // TODO + return; +}); + +test(function _initUrlencoded() { + var PARSER; + + gently.expect(QuerystringParserStub, 'new', function() { + PARSER = this; + }); + + form._initUrlencoded(); + assert.equal(form.type, 'urlencoded'); + assert.strictEqual(form._parser, PARSER); + + (function testOnField() { + var KEY = 'KEY', VAL = 'VAL'; + gently.expect(form, 'emit', function(field, key, val) { + assert.equal(field, 'field'); + assert.equal(key, KEY); + assert.equal(val, VAL); + }); + + PARSER.onField(KEY, VAL); + })(); + + (function testOnEnd() { + gently.expect(form, '_maybeEnd'); + + PARSER.onEnd(); + assert.equal(form.ended, true); + })(); +}); + +test(function _error() { + var ERR = new Error('bla'); + + gently.expect(form, 'pause'); + gently.expect(form, 'emit', function(event, err) { + assert.equal(event, 'error'); + assert.strictEqual(err, ERR); + }); + + form._error(ERR); + assert.strictEqual(form.error, ERR); + + // make sure _error only does its thing once + form._error(ERR); +}); + +test(function onPart() { + var PART = {}; + gently.expect(form, 'handlePart', function(part) { + assert.strictEqual(part, PART); + }); + + form.onPart(PART); +}); + +test(function handlePart() { + (function testUtf8Field() { + var PART = new events.EventEmitter(); + PART.name = 'my_field'; + + gently.expect(form, 'emit', function(event, field, value) { + assert.equal(event, 'field'); + assert.equal(field, 'my_field'); + assert.equal(value, 'hello world: €'); + }); + + form.handlePart(PART); + PART.emit('data', new Buffer('hello')); + PART.emit('data', new Buffer(' world: ')); + PART.emit('data', new Buffer([0xE2])); + PART.emit('data', new Buffer([0x82, 0xAC])); + PART.emit('end'); + })(); + + (function testBinaryField() { + var PART = new events.EventEmitter(); + PART.name = 'my_field2'; + + gently.expect(form, 'emit', function(event, field, value) { + assert.equal(event, 'field'); + assert.equal(field, 'my_field2'); + assert.equal(value, 'hello world: '+new Buffer([0xE2, 0x82, 0xAC]).toString('binary')); + }); + + form.encoding = 'binary'; + form.handlePart(PART); + PART.emit('data', new Buffer('hello')); + PART.emit('data', new Buffer(' world: ')); + PART.emit('data', new Buffer([0xE2])); + PART.emit('data', new Buffer([0x82, 0xAC])); + PART.emit('end'); + })(); + + (function testFieldSize() { + form.maxFieldsSize = 8; + var PART = new events.EventEmitter(); + PART.name = 'my_field'; + + gently.expect(form, '_error', function(err) { + assert.equal(err.message, 'maxFieldsSize exceeded, received 9 bytes of field data'); + }); + + form.handlePart(PART); + form._fieldsSize = 1; + PART.emit('data', new Buffer(7)); + PART.emit('data', new Buffer(1)); + })(); + + (function testFilePart() { + var PART = new events.EventEmitter(), + FILE = new events.EventEmitter(), + PATH = '/foo/bar'; + + PART.name = 'my_file'; + PART.filename = 'sweet.txt'; + PART.mime = 'sweet.txt'; + + gently.expect(form, '_uploadPath', function(filename) { + assert.equal(filename, PART.filename); + return PATH; + }); + + gently.expect(FileStub, 'new', function(properties) { + assert.equal(properties.path, PATH); + assert.equal(properties.name, PART.filename); + assert.equal(properties.type, PART.mime); + FILE = this; + + gently.expect(form, 'emit', function (event, field, file) { + assert.equal(event, 'fileBegin'); + assert.strictEqual(field, PART.name); + assert.strictEqual(file, FILE); + }); + + gently.expect(FILE, 'open'); + }); + + form.handlePart(PART); + assert.equal(form._flushing, 1); + + var BUFFER; + gently.expect(form, 'pause'); + gently.expect(FILE, 'write', function(buffer, cb) { + assert.strictEqual(buffer, BUFFER); + gently.expect(form, 'resume'); + // @todo handle cb(new Err) + cb(); + }); + + PART.emit('data', BUFFER = new Buffer('test')); + + gently.expect(FILE, 'end', function(cb) { + gently.expect(form, 'emit', function(event, field, file) { + assert.equal(event, 'file'); + assert.strictEqual(file, FILE); + }); + + gently.expect(form, '_maybeEnd'); + + cb(); + assert.equal(form._flushing, 0); + }); + + PART.emit('end'); + })(); +}); + +test(function _uploadPath() { + (function testUniqueId() { + var UUID_A, UUID_B; + gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) { + assert.equal(uploadDir, form.uploadDir); + UUID_A = uuid; + }); + form._uploadPath(); + + gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) { + UUID_B = uuid; + }); + form._uploadPath(); + + assert.notEqual(UUID_A, UUID_B); + })(); + + (function testFileExtension() { + form.keepExtensions = true; + var FILENAME = 'foo.jpg', + EXT = '.bar'; + + gently.expect(GENTLY.hijacked.path, 'extname', function(filename) { + assert.equal(filename, FILENAME); + gently.restore(path, 'extname'); + + return EXT; + }); + + gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, name) { + assert.equal(path.extname(name), EXT); + }); + form._uploadPath(FILENAME); + })(); +}); + +test(function _maybeEnd() { + gently.expect(form, 'emit', 0); + form._maybeEnd(); + + form.ended = true; + form._flushing = 1; + form._maybeEnd(); + + gently.expect(form, 'emit', function(event) { + assert.equal(event, 'end'); + }); + + form.ended = true; + form._flushing = 0; + form._maybeEnd(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-multipart-parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-multipart-parser.js new file mode 100644 index 0000000..bf2cd5e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-multipart-parser.js @@ -0,0 +1,50 @@ +var common = require('../common'); +var multipartParser = require(common.lib + '/multipart_parser'), + MultipartParser = multipartParser.MultipartParser, + events = require('events'), + Buffer = require('buffer').Buffer, + parser; + +function test(test) { + parser = new MultipartParser(); + test(); +} + +test(function constructor() { + assert.equal(parser.boundary, null); + assert.equal(parser.state, 0); + assert.equal(parser.flags, 0); + assert.equal(parser.boundaryChars, null); + assert.equal(parser.index, null); + assert.equal(parser.lookbehind, null); + assert.equal(parser.constructor.name, 'MultipartParser'); +}); + +test(function initWithBoundary() { + var boundary = 'abc'; + parser.initWithBoundary(boundary); + assert.deepEqual(Array.prototype.slice.call(parser.boundary), [13, 10, 45, 45, 97, 98, 99]); + assert.equal(parser.state, multipartParser.START); + + assert.deepEqual(parser.boundaryChars, {10: true, 13: true, 45: true, 97: true, 98: true, 99: true}); +}); + +test(function parserError() { + var boundary = 'abc', + buffer = new Buffer(5); + + parser.initWithBoundary(boundary); + buffer.write('--ad', 'ascii', 0); + assert.equal(parser.write(buffer), 5); +}); + +test(function end() { + (function testError() { + assert.equal(parser.end().message, 'MultipartParser.end(): stream ended unexpectedly: ' + parser.explain()); + })(); + + (function testRegular() { + parser.state = multipartParser.END; + assert.strictEqual(parser.end(), undefined); + })(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-querystring-parser.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-querystring-parser.js new file mode 100644 index 0000000..54d3e2d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-querystring-parser.js @@ -0,0 +1,45 @@ +var common = require('../common'); +var QuerystringParser = require(common.lib + '/querystring_parser').QuerystringParser, + Buffer = require('buffer').Buffer, + gently, + parser; + +function test(test) { + gently = new Gently(); + parser = new QuerystringParser(); + test(); + gently.verify(test.name); +} + +test(function constructor() { + assert.equal(parser.buffer, ''); + assert.equal(parser.constructor.name, 'QuerystringParser'); +}); + +test(function write() { + var a = new Buffer('a=1'); + assert.equal(parser.write(a), a.length); + + var b = new Buffer('&b=2'); + parser.write(b); + assert.equal(parser.buffer, a + b); +}); + +test(function end() { + var FIELDS = {a: ['b', {c: 'd'}], e: 'f'}; + + gently.expect(GENTLY.hijacked.querystring, 'parse', function(str) { + assert.equal(str, parser.buffer); + return FIELDS; + }); + + gently.expect(parser, 'onField', Object.keys(FIELDS).length, function(key, val) { + assert.deepEqual(FIELDS[key], val); + }); + + gently.expect(parser, 'onEnd'); + + parser.buffer = 'my buffer'; + parser.end(); + assert.equal(parser.buffer, ''); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/system/test-multi-video-upload.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/system/test-multi-video-upload.js new file mode 100644 index 0000000..b35ffd6 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/system/test-multi-video-upload.js @@ -0,0 +1,71 @@ +var common = require('../common'); +var BOUNDARY = '---------------------------10102754414578508781458777923', + FIXTURE = TEST_FIXTURES+'/multi_video.upload', + fs = require('fs'), + http = require('http'), + formidable = require(common.lib + '/index'), + server = http.createServer(); + +server.on('request', function(req, res) { + var form = new formidable.IncomingForm(), + uploads = {}; + + form.uploadDir = TEST_TMP; + form.hash = 'sha1'; + form.parse(req); + + form + .on('fileBegin', function(field, file) { + assert.equal(field, 'upload'); + + var tracker = {file: file, progress: [], ended: false}; + uploads[file.name] = tracker; + file + .on('progress', function(bytesReceived) { + tracker.progress.push(bytesReceived); + assert.equal(bytesReceived, file.size); + }) + .on('end', function() { + tracker.ended = true; + }); + }) + .on('field', function(field, value) { + assert.equal(field, 'title'); + assert.equal(value, ''); + }) + .on('file', function(field, file) { + assert.equal(field, 'upload'); + assert.strictEqual(uploads[file.name].file, file); + }) + .on('end', function() { + assert.ok(uploads['shortest_video.flv']); + assert.ok(uploads['shortest_video.flv'].ended); + assert.ok(uploads['shortest_video.flv'].progress.length > 3); + assert.equal(uploads['shortest_video.flv'].file.hash, 'd6a17616c7143d1b1438ceeef6836d1a09186b3a'); + assert.equal(uploads['shortest_video.flv'].progress.slice(-1), uploads['shortest_video.flv'].file.size); + assert.ok(uploads['shortest_video.mp4']); + assert.ok(uploads['shortest_video.mp4'].ended); + assert.ok(uploads['shortest_video.mp4'].progress.length > 3); + assert.equal(uploads['shortest_video.mp4'].file.hash, '937dfd4db263f4887ceae19341dcc8d63bcd557f'); + + server.close(); + res.writeHead(200); + res.end('good'); + }); +}); + +server.listen(TEST_PORT, function() { + var stat, headers, request, fixture; + + stat = fs.statSync(FIXTURE); + request = http.request({ + port: TEST_PORT, + path: '/', + method: 'POST', + headers: { + 'content-type': 'multipart/form-data; boundary='+BOUNDARY, + 'content-length': stat.size, + }, + }); + fs.createReadStream(FIXTURE).pipe(request); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/run.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/run.js new file mode 100755 index 0000000..02d6d5c --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/run.js @@ -0,0 +1 @@ +require('urun')(__dirname) diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-connection-aborted.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-connection-aborted.js new file mode 100644 index 0000000..4ea4431 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-connection-aborted.js @@ -0,0 +1,27 @@ +var assert = require('assert'); +var http = require('http'); +var net = require('net'); +var formidable = require('../../lib/index'); + +var server = http.createServer(function (req, res) { + var form = new formidable.IncomingForm(); + var aborted_received = false; + form.on('aborted', function () { + aborted_received = true; + }); + form.on('error', function () { + assert(aborted_received, 'Error event should follow aborted'); + server.close(); + }); + form.on('end', function () { + throw new Error('Unexpected "end" event'); + }); + form.parse(req); +}).listen(0, 'localhost', function () { + var client = net.connect(server.address().port); + client.write( + "POST / HTTP/1.1\r\n" + + "Content-Length: 70\r\n" + + "Content-Type: multipart/form-data; boundary=foo\r\n\r\n"); + client.end(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-content-transfer-encoding.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-content-transfer-encoding.js new file mode 100644 index 0000000..165628a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-content-transfer-encoding.js @@ -0,0 +1,48 @@ +var assert = require('assert'); +var common = require('../common'); +var formidable = require('../../lib/index'); +var http = require('http'); + +var server = http.createServer(function(req, res) { + var form = new formidable.IncomingForm(); + form.uploadDir = common.dir.tmp; + form.on('end', function () { + throw new Error('Unexpected "end" event'); + }); + form.on('error', function (e) { + res.writeHead(500); + res.end(e.message); + }); + form.parse(req); +}); + +server.listen(0, function() { + var body = + '--foo\r\n' + + 'Content-Disposition: form-data; name="file1"; filename="file1"\r\n' + + 'Content-Type: application/octet-stream\r\n' + + '\r\nThis is the first file\r\n' + + '--foo\r\n' + + 'Content-Type: application/octet-stream\r\n' + + 'Content-Disposition: form-data; name="file2"; filename="file2"\r\n' + + 'Content-Transfer-Encoding: unknown\r\n' + + '\r\nThis is the second file\r\n' + + '--foo--\r\n'; + + var req = http.request({ + method: 'POST', + port: server.address().port, + headers: { + 'Content-Length': body.length, + 'Content-Type': 'multipart/form-data; boundary=foo' + } + }); + req.on('response', function (res) { + assert.equal(res.statusCode, 500); + res.on('data', function () {}); + res.on('end', function () { + server.close(); + }); + }); + req.end(body); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-issue-46.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-issue-46.js new file mode 100644 index 0000000..1939328 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/standalone/test-issue-46.js @@ -0,0 +1,49 @@ +var http = require('http'), + formidable = require('../../lib/index'), + request = require('request'), + assert = require('assert'); + +var host = 'localhost'; + +var index = [ + '
    ', + ' ', + ' ', + '
    ' +].join("\n"); + +var server = http.createServer(function(req, res) { + + // Show a form for testing purposes. + if (req.method == 'GET') { + res.writeHead(200, {'content-type': 'text/html'}); + res.end(index); + return; + } + + // Parse form and write results to response. + var form = new formidable.IncomingForm(); + form.parse(req, function(err, fields, files) { + res.writeHead(200, {'content-type': 'text/plain'}); + res.write(JSON.stringify({err: err, fields: fields, files: files})); + res.end(); + }); + +}).listen(0, host, function() { + + console.log("Server up and running..."); + + var server = this, + url = 'http://' + host + ':' + server.address().port; + + var parts = [ + {'Content-Disposition': 'form-data; name="foo"', 'body': 'bar'} + ] + + var req = request({method: 'POST', url: url, multipart: parts}, function(e, res, body) { + var obj = JSON.parse(body); + assert.equal("bar", obj.fields.foo); + server.close(); + }); + +}); diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/tools/base64.html b/node_modules/express/node_modules/connect/node_modules/formidable/test/tools/base64.html new file mode 100644 index 0000000..48ad92e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/tools/base64.html @@ -0,0 +1,67 @@ + + + Convert a file to a base64 request + + + + + + + +
    +
    +
    +
    +
    +
    +

    +Don't forget to save the output with windows (CRLF) line endings! +

    + + + diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/unit/test-file.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/unit/test-file.js new file mode 100644 index 0000000..fc8f36e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/unit/test-file.js @@ -0,0 +1,33 @@ +var common = require('../common'); +var test = require('utest'); +var assert = common.assert; +var File = common.require('file'); + +var file; +var now = new Date; +test('IncomingForm', { + before: function() { + file = new File({ + size: 1024, + path: '/tmp/cat.png', + name: 'cat.png', + type: 'image/png', + lastModifiedDate: now, + filename: 'cat.png', + mime: 'image/png' + }) + }, + + '#toJSON()': function() { + var obj = file.toJSON(); + var len = Object.keys(obj).length; + assert.equal(1024, obj.size); + assert.equal('/tmp/cat.png', obj.path); + assert.equal('cat.png', obj.name); + assert.equal('image/png', obj.type); + assert.equal('image/png', obj.mime); + assert.equal('cat.png', obj.filename); + assert.equal(now, obj.mtime); + assert.equal(len, 8); + } +}); \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/test/unit/test-incoming-form.js b/node_modules/express/node_modules/connect/node_modules/formidable/test/unit/test-incoming-form.js new file mode 100644 index 0000000..fe2ac1c --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/test/unit/test-incoming-form.js @@ -0,0 +1,63 @@ +var common = require('../common'); +var test = require('utest'); +var assert = common.assert; +var IncomingForm = common.require('incoming_form').IncomingForm; +var path = require('path'); + +var form; +test('IncomingForm', { + before: function() { + form = new IncomingForm(); + }, + + '#_fileName with regular characters': function() { + var filename = 'foo.txt'; + assert.equal(form._fileName(makeHeader(filename)), 'foo.txt'); + }, + + '#_fileName with unescaped quote': function() { + var filename = 'my".txt'; + assert.equal(form._fileName(makeHeader(filename)), 'my".txt'); + }, + + '#_fileName with escaped quote': function() { + var filename = 'my%22.txt'; + assert.equal(form._fileName(makeHeader(filename)), 'my".txt'); + }, + + '#_fileName with bad quote and additional sub-header': function() { + var filename = 'my".txt'; + var header = makeHeader(filename) + '; foo="bar"'; + assert.equal(form._fileName(header), filename); + }, + + '#_fileName with semicolon': function() { + var filename = 'my;.txt'; + assert.equal(form._fileName(makeHeader(filename)), 'my;.txt'); + }, + + '#_fileName with utf8 character': function() { + var filename = 'my☃.txt'; + assert.equal(form._fileName(makeHeader(filename)), 'my☃.txt'); + }, + + '#_uploadPath strips harmful characters from extension when keepExtensions': function() { + form.keepExtensions = true; + + var ext = path.extname(form._uploadPath('fine.jpg?foo=bar')); + assert.equal(ext, '.jpg'); + + var ext = path.extname(form._uploadPath('fine?foo=bar')); + assert.equal(ext, ''); + + var ext = path.extname(form._uploadPath('super.cr2+dsad')); + assert.equal(ext, '.cr2'); + + var ext = path.extname(form._uploadPath('super.bar')); + assert.equal(ext, '.bar'); + }, +}); + +function makeHeader(filename) { + return 'Content-Disposition: form-data; name="upload"; filename="' + filename + '"'; +} diff --git a/node_modules/express/node_modules/connect/node_modules/formidable/tool/record.js b/node_modules/express/node_modules/connect/node_modules/formidable/tool/record.js new file mode 100644 index 0000000..9f1cef8 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/formidable/tool/record.js @@ -0,0 +1,47 @@ +var http = require('http'); +var fs = require('fs'); +var connections = 0; + +var server = http.createServer(function(req, res) { + var socket = req.socket; + console.log('Request: %s %s -> %s', req.method, req.url, socket.filename); + + req.on('end', function() { + if (req.url !== '/') { + res.end(JSON.stringify({ + method: req.method, + url: req.url, + filename: socket.filename, + })); + return; + } + + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); + }); +}); + +server.on('connection', function(socket) { + connections++; + + socket.id = connections; + socket.filename = 'connection-' + socket.id + '.http'; + socket.file = fs.createWriteStream(socket.filename); + socket.pipe(socket.file); + + console.log('--> %s', socket.filename); + socket.on('close', function() { + console.log('<-- %s', socket.filename); + }); +}); + +var port = process.env.PORT || 8080; +server.listen(port, function() { + console.log('Recording connections on port %s', port); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/pause/.npmignore b/node_modules/express/node_modules/connect/node_modules/pause/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/express/node_modules/connect/node_modules/pause/History.md b/node_modules/express/node_modules/connect/node_modules/pause/History.md new file mode 100644 index 0000000..c8aa68f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/History.md @@ -0,0 +1,5 @@ + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/connect/node_modules/pause/Makefile b/node_modules/express/node_modules/connect/node_modules/pause/Makefile new file mode 100644 index 0000000..4e9c8d3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --require should \ + --reporter spec + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/pause/Readme.md b/node_modules/express/node_modules/connect/node_modules/pause/Readme.md new file mode 100644 index 0000000..1cdd68a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/Readme.md @@ -0,0 +1,29 @@ + +# pause + + Pause streams... + +## License + +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/pause/index.js b/node_modules/express/node_modules/connect/node_modules/pause/index.js new file mode 100644 index 0000000..1b7b379 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/index.js @@ -0,0 +1,29 @@ + +module.exports = function(obj){ + var onData + , onEnd + , events = []; + + // buffer data + obj.on('data', onData = function(data, encoding){ + events.push(['data', data, encoding]); + }); + + // buffer end + obj.on('end', onEnd = function(data, encoding){ + events.push(['end', data, encoding]); + }); + + return { + end: function(){ + obj.removeListener('data', onData); + obj.removeListener('end', onEnd); + }, + resume: function(){ + this.end(); + for (var i = 0, len = events.length; i < len; ++i) { + obj.emit.apply(obj, events[i]); + } + } + }; +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/pause/package.json b/node_modules/express/node_modules/connect/node_modules/pause/package.json new file mode 100644 index 0000000..9296b24 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/package.json @@ -0,0 +1,24 @@ +{ + "name": "pause", + "version": "0.0.1", + "description": "Pause streams...", + "keywords": [], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "main": "index", + "readme": "\n# pause\n\n Pause streams...\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "_id": "pause@0.0.1", + "dist": { + "shasum": "1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + }, + "_from": "pause@0.0.1", + "_resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/qs/.gitmodules b/node_modules/express/node_modules/connect/node_modules/qs/.gitmodules new file mode 100644 index 0000000..49e31da --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/.gitmodules @@ -0,0 +1,6 @@ +[submodule "support/expresso"] + path = support/expresso + url = git://github.com/visionmedia/expresso.git +[submodule "support/should"] + path = support/should + url = git://github.com/visionmedia/should.js.git diff --git a/node_modules/express/node_modules/connect/node_modules/qs/.npmignore b/node_modules/express/node_modules/connect/node_modules/qs/.npmignore new file mode 100644 index 0000000..e85ce2a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/.npmignore @@ -0,0 +1,7 @@ +test +.travis.yml +benchmark.js +component.json +examples.js +History.md +Makefile diff --git a/node_modules/express/node_modules/connect/node_modules/qs/Readme.md b/node_modules/express/node_modules/connect/node_modules/qs/Readme.md new file mode 100644 index 0000000..27e54a4 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/Readme.md @@ -0,0 +1,58 @@ +# node-querystring + + query string parser for node and the browser supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others. + +## Installation + + $ npm install qs + +## Examples + +```js +var qs = require('qs'); + +qs.parse('user[name][first]=Tobi&user[email]=tobi@learnboost.com'); +// => { user: { name: { first: 'Tobi' }, email: 'tobi@learnboost.com' } } + +qs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }}) +// => user[name]=Tobi&user[email]=tobi%40learnboost.com +``` + +## Testing + +Install dev dependencies: + + $ npm install -d + +and execute: + + $ make test + +browser: + + $ open test/browser/index.html + +## License + +(The MIT License) + +Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/qs/index.js b/node_modules/express/node_modules/connect/node_modules/qs/index.js new file mode 100644 index 0000000..590491e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/index.js @@ -0,0 +1,387 @@ +/** + * Object#toString() ref for stringify(). + */ + +var toString = Object.prototype.toString; + +/** + * Object#hasOwnProperty ref + */ + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Array#indexOf shim. + */ + +var indexOf = typeof Array.prototype.indexOf === 'function' + ? function(arr, el) { return arr.indexOf(el); } + : function(arr, el) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] === el) return i; + } + return -1; + }; + +/** + * Array.isArray shim. + */ + +var isArray = Array.isArray || function(arr) { + return toString.call(arr) == '[object Array]'; +}; + +/** + * Object.keys shim. + */ + +var objectKeys = Object.keys || function(obj) { + var ret = []; + for (var key in obj) ret.push(key); + return ret; +}; + +/** + * Array#forEach shim. + */ + +var forEach = typeof Array.prototype.forEach === 'function' + ? function(arr, fn) { return arr.forEach(fn); } + : function(arr, fn) { + for (var i = 0; i < arr.length; i++) fn(arr[i]); + }; + +/** + * Array#reduce shim. + */ + +var reduce = function(arr, fn, initial) { + if (typeof arr.reduce === 'function') return arr.reduce(fn, initial); + var res = initial; + for (var i = 0; i < arr.length; i++) res = fn(res, arr[i]); + return res; +}; + +/** + * Create a nullary object if possible + */ + +function createObject() { + return Object.create + ? Object.create(null) + : {}; +} + +/** + * Cache non-integer test regexp. + */ + +var isint = /^[0-9]+$/; + +function promote(parent, key) { + if (parent[key].length == 0) return parent[key] = createObject(); + var t = createObject(); + for (var i in parent[key]) { + if (hasOwnProperty.call(parent[key], i)) { + t[i] = parent[key][i]; + } + } + parent[key] = t; + return t; +} + +function parse(parts, parent, key, val) { + var part = parts.shift(); + // end + if (!part) { + if (isArray(parent[key])) { + parent[key].push(val); + } else if ('object' == typeof parent[key]) { + parent[key] = val; + } else if ('undefined' == typeof parent[key]) { + parent[key] = val; + } else { + parent[key] = [parent[key], val]; + } + // array + } else { + var obj = parent[key] = parent[key] || []; + if (']' == part) { + if (isArray(obj)) { + if ('' != val) obj.push(val); + } else if ('object' == typeof obj) { + obj[objectKeys(obj).length] = val; + } else { + obj = parent[key] = [parent[key], val]; + } + // prop + } else if (~indexOf(part, ']')) { + part = part.substr(0, part.length - 1); + if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + // key + } else { + if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + } + } +} + +/** + * Merge parent key/val pair. + */ + +function merge(parent, key, val){ + if (~indexOf(key, ']')) { + var parts = key.split('[') + , len = parts.length + , last = len - 1; + parse(parts, parent, 'base', val); + // optimize + } else { + if (!isint.test(key) && isArray(parent.base)) { + var t = createObject(); + for (var k in parent.base) t[k] = parent.base[k]; + parent.base = t; + } + set(parent.base, key, val); + } + + return parent; +} + +/** + * Compact sparse arrays. + */ + +function compact(obj) { + if ('object' != typeof obj) return obj; + + if (isArray(obj)) { + var ret = []; + + for (var i in obj) { + if (hasOwnProperty.call(obj, i)) { + ret.push(obj[i]); + } + } + + return ret; + } + + for (var key in obj) { + obj[key] = compact(obj[key]); + } + + return obj; +} + +/** + * Restore Object.prototype. + * see pull-request #58 + */ + +function restoreProto(obj) { + if (!Object.create) return obj; + if (isArray(obj)) return obj; + if (obj && 'object' != typeof obj) return obj; + + for (var key in obj) { + if (hasOwnProperty.call(obj, key)) { + obj[key] = restoreProto(obj[key]); + } + } + + obj.__proto__ = Object.prototype; + return obj; +} + +/** + * Parse the given obj. + */ + +function parseObject(obj){ + var ret = { base: {} }; + + forEach(objectKeys(obj), function(name){ + merge(ret, name, obj[name]); + }); + + return compact(ret.base); +} + +/** + * Parse the given str. + */ + +function parseString(str){ + var ret = reduce(String(str).split('&'), function(ret, pair){ + var eql = indexOf(pair, '=') + , brace = lastBraceInKey(pair) + , key = pair.substr(0, brace || eql) + , val = pair.substr(brace || eql, pair.length) + , val = val.substr(indexOf(val, '=') + 1, val.length); + + // ?foo + if ('' == key) key = pair, val = ''; + if ('' == key) return ret; + + return merge(ret, decode(key), decode(val)); + }, { base: createObject() }).base; + + return restoreProto(compact(ret)); +} + +/** + * Parse the given query `str` or `obj`, returning an object. + * + * @param {String} str | {Object} obj + * @return {Object} + * @api public + */ + +exports.parse = function(str){ + if (null == str || '' == str) return {}; + return 'object' == typeof str + ? parseObject(str) + : parseString(str); +}; + +/** + * Turn the given `obj` into a query string + * + * @param {Object} obj + * @return {String} + * @api public + */ + +var stringify = exports.stringify = function(obj, prefix) { + if (isArray(obj)) { + return stringifyArray(obj, prefix); + } else if ('[object Object]' == toString.call(obj)) { + return stringifyObject(obj, prefix); + } else if ('string' == typeof obj) { + return stringifyString(obj, prefix); + } else { + return prefix + '=' + encodeURIComponent(String(obj)); + } +}; + +/** + * Stringify the given `str`. + * + * @param {String} str + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyString(str, prefix) { + if (!prefix) throw new TypeError('stringify expects an object'); + return prefix + '=' + encodeURIComponent(str); +} + +/** + * Stringify the given `arr`. + * + * @param {Array} arr + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyArray(arr, prefix) { + var ret = []; + if (!prefix) throw new TypeError('stringify expects an object'); + for (var i = 0; i < arr.length; i++) { + ret.push(stringify(arr[i], prefix + '[' + i + ']')); + } + return ret.join('&'); +} + +/** + * Stringify the given `obj`. + * + * @param {Object} obj + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyObject(obj, prefix) { + var ret = [] + , keys = objectKeys(obj) + , key; + + for (var i = 0, len = keys.length; i < len; ++i) { + key = keys[i]; + if ('' == key) continue; + if (null == obj[key]) { + ret.push(encodeURIComponent(key) + '='); + } else { + ret.push(stringify(obj[key], prefix + ? prefix + '[' + encodeURIComponent(key) + ']' + : encodeURIComponent(key))); + } + } + + return ret.join('&'); +} + +/** + * Set `obj`'s `key` to `val` respecting + * the weird and wonderful syntax of a qs, + * where "foo=bar&foo=baz" becomes an array. + * + * @param {Object} obj + * @param {String} key + * @param {String} val + * @api private + */ + +function set(obj, key, val) { + var v = obj[key]; + if (undefined === v) { + obj[key] = val; + } else if (isArray(v)) { + v.push(val); + } else { + obj[key] = [v, val]; + } +} + +/** + * Locate last brace in `str` within the key. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function lastBraceInKey(str) { + var len = str.length + , brace + , c; + for (var i = 0; i < len; ++i) { + c = str[i]; + if (']' == c) brace = false; + if ('[' == c) brace = true; + if ('=' == c && !brace) return i; + } +} + +/** + * Decode `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +function decode(str) { + try { + return decodeURIComponent(str.replace(/\+/g, ' ')); + } catch (err) { + return str; + } +} diff --git a/node_modules/express/node_modules/connect/node_modules/qs/package.json b/node_modules/express/node_modules/connect/node_modules/qs/package.json new file mode 100644 index 0000000..73c360f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/package.json @@ -0,0 +1,41 @@ +{ + "name": "qs", + "description": "querystring parser", + "version": "0.6.5", + "keywords": [ + "query string", + "parser", + "component" + ], + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/node-querystring.git" + }, + "devDependencies": { + "mocha": "*", + "expect.js": "*" + }, + "scripts": { + "test": "make test" + }, + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "main": "index", + "engines": { + "node": "*" + }, + "readme": "# node-querystring\n\n query string parser for node and the browser supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others.\n\n## Installation\n\n $ npm install qs\n\n## Examples\n\n```js\nvar qs = require('qs');\n\nqs.parse('user[name][first]=Tobi&user[email]=tobi@learnboost.com');\n// => { user: { name: { first: 'Tobi' }, email: 'tobi@learnboost.com' } }\n\nqs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }})\n// => user[name]=Tobi&user[email]=tobi%40learnboost.com\n```\n\n## Testing\n\nInstall dev dependencies:\n\n $ npm install -d\n\nand execute:\n\n $ make test\n\nbrowser:\n\n $ open test/browser/index.html\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/node-querystring/issues" + }, + "_id": "qs@0.6.5", + "dist": { + "shasum": "294b268e4b0d4250f6dde19b3b8b34935dff14ef" + }, + "_from": "qs@0.6.5", + "_resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/uid2/index.js b/node_modules/express/node_modules/connect/node_modules/uid2/index.js new file mode 100644 index 0000000..d665f51 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/uid2/index.js @@ -0,0 +1,49 @@ +/** + * Module dependencies + */ + +var crypto = require('crypto'); + +/** + * The size ratio between a base64 string and the equivalent byte buffer + */ + +var ratio = Math.log(64) / Math.log(256); + +/** + * Make a Base64 string ready for use in URLs + * + * @param {String} + * @returns {String} + * @api private + */ + +function urlReady(str) { + return str.replace(/\+/g, '_').replace(/\//g, '-'); +} + +/** + * Generate an Unique Id + * + * @param {Number} length The number of chars of the uid + * @param {Number} cb (optional) Callback for async uid generation + * @api public + */ + +function uid(length, cb) { + var numbytes = Math.ceil(length * ratio); + if (typeof cb === 'undefined') { + return urlReady(crypto.randomBytes(numbytes).toString('base64').slice(0, length)); + } else { + crypto.randomBytes(numbytes, function(err, bytes) { + if (err) return cb(err); + cb(null, urlReady(bytes.toString('base64').slice(0, length))); + }) + } +} + +/** + * Exports + */ + +module.exports = uid; diff --git a/node_modules/express/node_modules/connect/node_modules/uid2/package.json b/node_modules/express/node_modules/connect/node_modules/uid2/package.json new file mode 100644 index 0000000..6b606d2 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/uid2/package.json @@ -0,0 +1,16 @@ +{ + "name": "uid2", + "description": "strong uid", + "tags": [ + "uid" + ], + "version": "0.0.2", + "dependencies": {}, + "readme": "ERROR: No README data found!", + "_id": "uid2@0.0.2", + "dist": { + "shasum": "ec7db9024a0043009b46e99de842e6e9376f7a7f" + }, + "_from": "uid2@0.0.2", + "_resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz" +} diff --git a/node_modules/express/node_modules/connect/package.json b/node_modules/express/node_modules/connect/package.json new file mode 100644 index 0000000..14a3985 --- /dev/null +++ b/node_modules/express/node_modules/connect/package.json @@ -0,0 +1,59 @@ +{ + "name": "connect", + "version": "2.8.4", + "description": "High performance middleware framework", + "keywords": [ + "framework", + "web", + "middleware", + "connect", + "rack" + ], + "repository": { + "type": "git", + "url": "git://github.com/senchalabs/connect.git" + }, + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "dependencies": { + "qs": "0.6.5", + "formidable": "1.0.14", + "cookie-signature": "1.0.1", + "buffer-crc32": "0.2.1", + "cookie": "0.1.0", + "send": "0.1.3", + "bytes": "0.2.0", + "fresh": "0.1.0", + "pause": "0.0.1", + "uid2": "0.0.2", + "debug": "*", + "methods": "0.0.1" + }, + "devDependencies": { + "should": "*", + "mocha": "*", + "jade": "*", + "dox": "*" + }, + "main": "index", + "engines": { + "node": ">= 0.8.0" + }, + "scripts": { + "test": "make" + }, + "readme": "[![build status](https://secure.travis-ci.org/senchalabs/connect.png)](http://travis-ci.org/senchalabs/connect)\n# Connect\n\n Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance \"plugins\" known as _middleware_.\n\n Connect is bundled with over _20_ commonly used middleware, including\n a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://senchalabs.github.com/connect/).\n\n```js\nvar connect = require('connect')\n , http = require('http');\n\nvar app = connect()\n .use(connect.favicon())\n .use(connect.logger('dev'))\n .use(connect.static('public'))\n .use(connect.directory('public'))\n .use(connect.cookieParser())\n .use(connect.session({ secret: 'my secret here' }))\n .use(function(req, res){\n res.end('Hello from Connect!\\n');\n });\n\nhttp.createServer(app).listen(3000);\n```\n\n## Middleware\n\n - [csrf](http://www.senchalabs.org/connect/csrf.html)\n - [basicAuth](http://www.senchalabs.org/connect/basicAuth.html)\n - [bodyParser](http://www.senchalabs.org/connect/bodyParser.html)\n - [json](http://www.senchalabs.org/connect/json.html)\n - [multipart](http://www.senchalabs.org/connect/multipart.html)\n - [urlencoded](http://www.senchalabs.org/connect/urlencoded.html)\n - [cookieParser](http://www.senchalabs.org/connect/cookieParser.html)\n - [directory](http://www.senchalabs.org/connect/directory.html)\n - [compress](http://www.senchalabs.org/connect/compress.html)\n - [errorHandler](http://www.senchalabs.org/connect/errorHandler.html)\n - [favicon](http://www.senchalabs.org/connect/favicon.html)\n - [limit](http://www.senchalabs.org/connect/limit.html)\n - [logger](http://www.senchalabs.org/connect/logger.html)\n - [methodOverride](http://www.senchalabs.org/connect/methodOverride.html)\n - [query](http://www.senchalabs.org/connect/query.html)\n - [responseTime](http://www.senchalabs.org/connect/responseTime.html)\n - [session](http://www.senchalabs.org/connect/session.html)\n - [static](http://www.senchalabs.org/connect/static.html)\n - [staticCache](http://www.senchalabs.org/connect/staticCache.html)\n - [vhost](http://www.senchalabs.org/connect/vhost.html)\n - [subdomains](http://www.senchalabs.org/connect/subdomains.html)\n - [cookieSession](http://www.senchalabs.org/connect/cookieSession.html)\n\n## Running Tests\n\nfirst:\n\n $ npm install -d\n\nthen:\n\n $ make test\n\n## Authors\n\n Below is the output from [git-summary](http://github.com/visionmedia/git-extras).\n\n\n project: connect\n commits: 2033\n active : 301 days\n files : 171\n authors: \n 1414\tTj Holowaychuk 69.6%\n 298\tvisionmedia 14.7%\n 191\tTim Caswell 9.4%\n 51\tTJ Holowaychuk 2.5%\n 10\tRyan Olds 0.5%\n 8\tAstro 0.4%\n 5\tNathan Rajlich 0.2%\n 5\tJakub Nešetřil 0.2%\n 3\tDaniel Dickison 0.1%\n 3\tDavid Rio Deiros 0.1%\n 3\tAlexander Simmerl 0.1%\n 3\tAndreas Lind Petersen 0.1%\n 2\tAaron Heckmann 0.1%\n 2\tJacques Crocker 0.1%\n 2\tFabian Jakobs 0.1%\n 2\tBrian J Brennan 0.1%\n 2\tAdam Malcontenti-Wilson 0.1%\n 2\tGlen Mailer 0.1%\n 2\tJames Campos 0.1%\n 1\tTrent Mick 0.0%\n 1\tTroy Kruthoff 0.0%\n 1\tWei Zhu 0.0%\n 1\tcomerc 0.0%\n 1\tdarobin 0.0%\n 1\tnateps 0.0%\n 1\tMarco Sanson 0.0%\n 1\tArthur Taylor 0.0%\n 1\tAseem Kishore 0.0%\n 1\tBart Teeuwisse 0.0%\n 1\tCameron Howey 0.0%\n 1\tChad Weider 0.0%\n 1\tCraig Barnes 0.0%\n 1\tEran Hammer-Lahav 0.0%\n 1\tGregory McWhirter 0.0%\n 1\tGuillermo Rauch 0.0%\n 1\tJae Kwon 0.0%\n 1\tJakub Nesetril 0.0%\n 1\tJoshua Peek 0.0%\n 1\tJxck 0.0%\n 1\tAJ ONeal 0.0%\n 1\tMichael Hemesath 0.0%\n 1\tMorten Siebuhr 0.0%\n 1\tSamori Gorse 0.0%\n 1\tTom Jensen 0.0%\n\n## Node Compatibility\n\n Connect `< 1.x` is compatible with node 0.2.x\n\n\n Connect `1.x` is compatible with node 0.4.x\n\n\n Connect (_master_) `2.x` is compatible with node 0.6.x\n\n## CLA\n\n [http://sencha.com/cla](http://sencha.com/cla)\n\n## License\n\nView the [LICENSE](https://github.com/senchalabs/connect/blob/master/LICENSE) file. The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons used by the `directory` middleware created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/).\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/senchalabs/connect/issues" + }, + "_id": "connect@2.8.4", + "dist": { + "shasum": "e32809a1abd9c792654658917265d0113c6aa815" + }, + "_from": "connect@2.8.4", + "_resolved": "https://registry.npmjs.org/connect/-/connect-2.8.4.tgz" +} diff --git a/node_modules/express/node_modules/connect/test.js b/node_modules/express/node_modules/connect/test.js new file mode 100644 index 0000000..ef743f2 --- /dev/null +++ b/node_modules/express/node_modules/connect/test.js @@ -0,0 +1,8 @@ +var crypto = require('crypto') + +exports.uid = function(len) { + return crypto.randomBytes(Math.ceil(len * 3 / 4)) + .toString('hex') +}; + +console.log(exports.uid(10)); diff --git a/node_modules/express/node_modules/cookie-signature/.npmignore b/node_modules/express/node_modules/cookie-signature/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/express/node_modules/cookie-signature/History.md b/node_modules/express/node_modules/cookie-signature/History.md new file mode 100644 index 0000000..9e30179 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/History.md @@ -0,0 +1,11 @@ + +1.0.1 / 2013-04-15 +================== + + * Revert "Changed underlying HMAC algo. to sha512." + * Revert "Fix for timing attacks on MAC verification." + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/cookie-signature/Makefile b/node_modules/express/node_modules/cookie-signature/Makefile new file mode 100644 index 0000000..4e9c8d3 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --require should \ + --reporter spec + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/cookie-signature/Readme.md b/node_modules/express/node_modules/cookie-signature/Readme.md new file mode 100644 index 0000000..2559e84 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/Readme.md @@ -0,0 +1,42 @@ + +# cookie-signature + + Sign and unsign cookies. + +## Example + +```js +var cookie = require('cookie-signature'); + +var val = cookie.sign('hello', 'tobiiscool'); +val.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI'); + +var val = cookie.sign('hello', 'tobiiscool'); +cookie.unsign(val, 'tobiiscool').should.equal('hello'); +cookie.unsign(val, 'luna').should.be.false; +``` + +## License + +(The MIT License) + +Copyright (c) 2012 LearnBoost <tj@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/cookie-signature/index.js b/node_modules/express/node_modules/cookie-signature/index.js new file mode 100644 index 0000000..ed62814 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/index.js @@ -0,0 +1,42 @@ + +/** + * Module dependencies. + */ + +var crypto = require('crypto'); + +/** + * Sign the given `val` with `secret`. + * + * @param {String} val + * @param {String} secret + * @return {String} + * @api private + */ + +exports.sign = function(val, secret){ + if ('string' != typeof val) throw new TypeError('cookie required'); + if ('string' != typeof secret) throw new TypeError('secret required'); + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/\=+$/, ''); +}; + +/** + * Unsign and decode the given `val` with `secret`, + * returning `false` if the signature is invalid. + * + * @param {String} val + * @param {String} secret + * @return {String|Boolean} + * @api private + */ + +exports.unsign = function(val, secret){ + if ('string' != typeof val) throw new TypeError('cookie required'); + if ('string' != typeof secret) throw new TypeError('secret required'); + var str = val.slice(0, val.lastIndexOf('.')); + return exports.sign(str, secret) == val ? str : false; +}; diff --git a/node_modules/express/node_modules/cookie-signature/package.json b/node_modules/express/node_modules/cookie-signature/package.json new file mode 100644 index 0000000..5203d81 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/package.json @@ -0,0 +1,28 @@ +{ + "name": "cookie-signature", + "version": "1.0.1", + "description": "Sign and unsign cookies", + "keywords": [ + "cookie", + "sign", + "unsign" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@learnboost.com" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "main": "index", + "readme": "\n# cookie-signature\n\n Sign and unsign cookies.\n\n## Example\n\n```js\nvar cookie = require('cookie-signature');\n\nvar val = cookie.sign('hello', 'tobiiscool');\nval.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI');\n\nvar val = cookie.sign('hello', 'tobiiscool');\ncookie.unsign(val, 'tobiiscool').should.equal('hello');\ncookie.unsign(val, 'luna').should.be.false;\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 LearnBoost <tj@learnboost.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "_id": "cookie-signature@1.0.1", + "dist": { + "shasum": "44e072148af01e6e8e24afbf12690d68ae698ecb" + }, + "_from": "cookie-signature@1.0.1", + "_resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz" +} diff --git a/node_modules/express/node_modules/cookie/.npmignore b/node_modules/express/node_modules/cookie/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/express/node_modules/cookie/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/express/node_modules/cookie/.travis.yml b/node_modules/express/node_modules/cookie/.travis.yml new file mode 100644 index 0000000..9400c11 --- /dev/null +++ b/node_modules/express/node_modules/cookie/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "0.6" + - "0.8" + - "0.10" diff --git a/node_modules/express/node_modules/cookie/LICENSE b/node_modules/express/node_modules/cookie/LICENSE new file mode 100644 index 0000000..249d9de --- /dev/null +++ b/node_modules/express/node_modules/cookie/LICENSE @@ -0,0 +1,9 @@ +// MIT License + +Copyright (C) Roman Shtylman + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/cookie/README.md b/node_modules/express/node_modules/cookie/README.md new file mode 100644 index 0000000..5187ed1 --- /dev/null +++ b/node_modules/express/node_modules/cookie/README.md @@ -0,0 +1,44 @@ +# cookie [![Build Status](https://secure.travis-ci.org/shtylman/node-cookie.png?branch=master)](http://travis-ci.org/shtylman/node-cookie) # + +cookie is a basic cookie parser and serializer. It doesn't make assumptions about how you are going to deal with your cookies. It basically just provides a way to read and write the HTTP cookie headers. + +See [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies. + +## how? + +``` +npm install cookie +``` + +```javascript +var cookie = require('cookie'); + +var hdr = cookie.serialize('foo', 'bar'); +// hdr = 'foo=bar'; + +var cookies = cookie.parse('foo=bar; cat=meow; dog=ruff'); +// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' }; +``` + +## more + +The serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values. + +### path +> cookie path + +### expires +> absolute expiration date for the cookie (Date object) + +### maxAge +> relative max age of the cookie from when the client receives it (seconds) + +### domain +> domain for the cookie + +### secure +> true or false + +### httpOnly +> true or false + diff --git a/node_modules/express/node_modules/cookie/index.js b/node_modules/express/node_modules/cookie/index.js new file mode 100644 index 0000000..16bdb65 --- /dev/null +++ b/node_modules/express/node_modules/cookie/index.js @@ -0,0 +1,70 @@ + +/// Serialize the a name value pair into a cookie string suitable for +/// http headers. An optional options object specified cookie parameters +/// +/// serialize('foo', 'bar', { httpOnly: true }) +/// => "foo=bar; httpOnly" +/// +/// @param {String} name +/// @param {String} val +/// @param {Object} options +/// @return {String} +var serialize = function(name, val, opt){ + opt = opt || {}; + var enc = opt.encode || encode; + var pairs = [name + '=' + enc(val)]; + + if (opt.maxAge) pairs.push('Max-Age=' + opt.maxAge); + if (opt.domain) pairs.push('Domain=' + opt.domain); + if (opt.path) pairs.push('Path=' + opt.path); + if (opt.expires) pairs.push('Expires=' + opt.expires.toUTCString()); + if (opt.httpOnly) pairs.push('HttpOnly'); + if (opt.secure) pairs.push('Secure'); + + return pairs.join('; '); +}; + +/// Parse the given cookie header string into an object +/// The object has the various cookies as keys(names) => values +/// @param {String} str +/// @return {Object} +var parse = function(str, opt) { + opt = opt || {}; + var obj = {} + var pairs = str.split(/[;,] */); + var dec = opt.decode || decode; + + pairs.forEach(function(pair) { + var eq_idx = pair.indexOf('=') + + // skip things that don't look like key=value + if (eq_idx < 0) { + return; + } + + var key = pair.substr(0, eq_idx).trim() + var val = pair.substr(++eq_idx, pair.length).trim(); + + // quoted values + if ('"' == val[0]) { + val = val.slice(1, -1); + } + + // only assign once + if (undefined == obj[key]) { + try { + obj[key] = dec(val); + } catch (e) { + obj[key] = val; + } + } + }); + + return obj; +}; + +var encode = encodeURIComponent; +var decode = decodeURIComponent; + +module.exports.serialize = serialize; +module.exports.parse = parse; diff --git a/node_modules/express/node_modules/cookie/package.json b/node_modules/express/node_modules/cookie/package.json new file mode 100644 index 0000000..7f6da52 --- /dev/null +++ b/node_modules/express/node_modules/cookie/package.json @@ -0,0 +1,40 @@ +{ + "author": { + "name": "Roman Shtylman", + "email": "shtylman@gmail.com" + }, + "name": "cookie", + "description": "cookie parsing and serialization", + "version": "0.1.0", + "repository": { + "type": "git", + "url": "git://github.com/shtylman/node-cookie.git" + }, + "keywords": [ + "cookie", + "cookies" + ], + "main": "index.js", + "scripts": { + "test": "mocha" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "1.x.x" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "readme": "# cookie [![Build Status](https://secure.travis-ci.org/shtylman/node-cookie.png?branch=master)](http://travis-ci.org/shtylman/node-cookie) #\n\ncookie is a basic cookie parser and serializer. It doesn't make assumptions about how you are going to deal with your cookies. It basically just provides a way to read and write the HTTP cookie headers.\n\nSee [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies.\n\n## how?\n\n```\nnpm install cookie\n```\n\n```javascript\nvar cookie = require('cookie');\n\nvar hdr = cookie.serialize('foo', 'bar');\n// hdr = 'foo=bar';\n\nvar cookies = cookie.parse('foo=bar; cat=meow; dog=ruff');\n// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' };\n```\n\n## more\n\nThe serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values.\n\n### path\n> cookie path\n\n### expires\n> absolute expiration date for the cookie (Date object)\n\n### maxAge\n> relative max age of the cookie from when the client receives it (seconds)\n\n### domain\n> domain for the cookie\n\n### secure\n> true or false\n\n### httpOnly\n> true or false\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/shtylman/node-cookie/issues" + }, + "_id": "cookie@0.1.0", + "dist": { + "shasum": "90eb469ddce905c866de687efc43131d8801f9d0" + }, + "_from": "cookie@0.1.0", + "_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz" +} diff --git a/node_modules/express/node_modules/cookie/test/mocha.opts b/node_modules/express/node_modules/cookie/test/mocha.opts new file mode 100644 index 0000000..e2bfcc5 --- /dev/null +++ b/node_modules/express/node_modules/cookie/test/mocha.opts @@ -0,0 +1 @@ +--ui qunit diff --git a/node_modules/express/node_modules/cookie/test/parse.js b/node_modules/express/node_modules/cookie/test/parse.js new file mode 100644 index 0000000..c6c27a2 --- /dev/null +++ b/node_modules/express/node_modules/cookie/test/parse.js @@ -0,0 +1,44 @@ + +var assert = require('assert'); + +var cookie = require('..'); + +suite('parse'); + +test('basic', function() { + assert.deepEqual({ foo: 'bar' }, cookie.parse('foo=bar')); + assert.deepEqual({ foo: '123' }, cookie.parse('foo=123')); +}); + +test('ignore spaces', function() { + assert.deepEqual({ FOO: 'bar', baz: 'raz' }, + cookie.parse('FOO = bar; baz = raz')); +}); + +test('escaping', function() { + assert.deepEqual({ foo: 'bar=123456789&name=Magic+Mouse' }, + cookie.parse('foo="bar=123456789&name=Magic+Mouse"')); + + assert.deepEqual({ email: ' ",;/' }, + cookie.parse('email=%20%22%2c%3b%2f')); +}); + +test('ignore escaping error and return original value', function() { + assert.deepEqual({ foo: '%1', bar: 'bar' }, cookie.parse('foo=%1;bar=bar')); +}); + +test('ignore non values', function() { + assert.deepEqual({ foo: '%1', bar: 'bar' }, cookie.parse('foo=%1;bar=bar;HttpOnly;Secure')); +}); + +test('unencoded', function() { + assert.deepEqual({ foo: 'bar=123456789&name=Magic+Mouse' }, + cookie.parse('foo="bar=123456789&name=Magic+Mouse"',{ + decode: function(value) { return value; } + })); + + assert.deepEqual({ email: '%20%22%2c%3b%2f' }, + cookie.parse('email=%20%22%2c%3b%2f',{ + decode: function(value) { return value; } + })); +}) diff --git a/node_modules/express/node_modules/cookie/test/serialize.js b/node_modules/express/node_modules/cookie/test/serialize.js new file mode 100644 index 0000000..86bb8c9 --- /dev/null +++ b/node_modules/express/node_modules/cookie/test/serialize.js @@ -0,0 +1,64 @@ +// builtin +var assert = require('assert'); + +var cookie = require('..'); + +suite('serialize'); + +test('basic', function() { + assert.equal('foo=bar', cookie.serialize('foo', 'bar')); + assert.equal('foo=bar%20baz', cookie.serialize('foo', 'bar baz')); +}); + +test('path', function() { + assert.equal('foo=bar; Path=/', cookie.serialize('foo', 'bar', { + path: '/' + })); +}); + +test('secure', function() { + assert.equal('foo=bar; Secure', cookie.serialize('foo', 'bar', { + secure: true + })); + + assert.equal('foo=bar', cookie.serialize('foo', 'bar', { + secure: false + })); +}); + +test('domain', function() { + assert.equal('foo=bar; Domain=example.com', cookie.serialize('foo', 'bar', { + domain: 'example.com' + })); +}); + +test('httpOnly', function() { + assert.equal('foo=bar; HttpOnly', cookie.serialize('foo', 'bar', { + httpOnly: true + })); +}); + +test('maxAge', function() { + assert.equal('foo=bar; Max-Age=1000', cookie.serialize('foo', 'bar', { + maxAge: 1000 + })); +}); + +test('escaping', function() { + assert.deepEqual('cat=%2B%20', cookie.serialize('cat', '+ ')); +}); + +test('parse->serialize', function() { + + assert.deepEqual({ cat: 'foo=123&name=baz five' }, cookie.parse( + cookie.serialize('cat', 'foo=123&name=baz five'))); + + assert.deepEqual({ cat: ' ";/' }, cookie.parse( + cookie.serialize('cat', ' ";/'))); +}); + +test('unencoded', function() { + assert.deepEqual('cat=+ ', cookie.serialize('cat', '+ ', { + encode: function(value) { return value; } + })); +}) diff --git a/node_modules/express/node_modules/debug/.npmignore b/node_modules/express/node_modules/debug/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/express/node_modules/debug/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/express/node_modules/debug/History.md b/node_modules/express/node_modules/debug/History.md new file mode 100644 index 0000000..f023269 --- /dev/null +++ b/node_modules/express/node_modules/debug/History.md @@ -0,0 +1,62 @@ + +0.7.2 / 2013-02-06 +================== + + * fix package.json + * fix: Mobile Safari (private mode) is broken with debug + * fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript + +0.7.1 / 2013-02-05 +================== + + * add repository URL to package.json + * add DEBUG_COLORED to force colored output + * add browserify support + * fix component. Closes #24 + +0.7.0 / 2012-05-04 +================== + + * Added .component to package.json + * Added debug.component.js build + +0.6.0 / 2012-03-16 +================== + + * Added support for "-" prefix in DEBUG [Vinay Pulim] + * Added `.enabled` flag to the node version [TooTallNate] + +0.5.0 / 2012-02-02 +================== + + * Added: humanize diffs. Closes #8 + * Added `debug.disable()` to the CS variant + * Removed padding. Closes #10 + * Fixed: persist client-side variant again. Closes #9 + +0.4.0 / 2012-02-01 +================== + + * Added browser variant support for older browsers [TooTallNate] + * Added `debug.enable('project:*')` to browser variant [TooTallNate] + * Added padding to diff (moved it to the right) + +0.3.0 / 2012-01-26 +================== + + * Added millisecond diff when isatty, otherwise UTC string + +0.2.0 / 2012-01-22 +================== + + * Added wildcard support + +0.1.0 / 2011-12-02 +================== + + * Added: remove colors unless stderr isatty [TooTallNate] + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/debug/Readme.md b/node_modules/express/node_modules/debug/Readme.md new file mode 100644 index 0000000..15ee501 --- /dev/null +++ b/node_modules/express/node_modules/debug/Readme.md @@ -0,0 +1,115 @@ + +# debug + + tiny node.js debugging utility modelled after node core's debugging technique. + +## Installation + +``` +$ npm install debug +``` + +## Usage + + With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility. + +Example _app.js_: + +```js +var debug = require('debug')('http') + , http = require('http') + , name = 'My App'; + +// fake app + +debug('booting %s', name); + +http.createServer(function(req, res){ + debug(req.method + ' ' + req.url); + res.end('hello\n'); +}).listen(3000, function(){ + debug('listening'); +}); + +// fake worker of some kind + +require('./worker'); +``` + +Example _worker.js_: + +```js +var debug = require('debug')('worker'); + +setInterval(function(){ + debug('doing some work'); +}, 1000); +``` + + The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples: + + ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png) + + ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png) + +## Millisecond diff + + When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls. + + ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png) + + When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below: + + ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png) + +## Conventions + + If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". + +## Wildcards + + The "*" character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`. + + You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with "connect:". + +## Browser support + + Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. + +```js +a = debug('worker:a'); +b = debug('worker:b'); + +setInterval(function(){ + a('doing some work'); +}, 1000); + +setInterval(function(){ + a('doing some work'); +}, 1200); +``` + +## License + +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/debug/component.json b/node_modules/express/node_modules/debug/component.json new file mode 100644 index 0000000..4ad0971 --- /dev/null +++ b/node_modules/express/node_modules/debug/component.json @@ -0,0 +1,9 @@ +{ + "name": "debug", + "repo": "visionmedia/debug", + "description": "small debugging utility", + "version": "0.7.2", + "keywords": ["debug", "log", "debugger"], + "scripts": ["index.js", "debug.js"], + "dependencies": {} +} diff --git a/node_modules/express/node_modules/debug/debug.js b/node_modules/express/node_modules/debug/debug.js new file mode 100644 index 0000000..e47ba5b --- /dev/null +++ b/node_modules/express/node_modules/debug/debug.js @@ -0,0 +1,124 @@ + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + if (!debug.enabled(name)) return function(){}; + + return function(fmt){ + var curr = new Date; + var ms = curr - (debug[name] || curr); + debug[name] = curr; + + fmt = name + + ' ' + + fmt + + ' +' + debug.humanize(ms); + + // This hackery is required for IE8 + // where `console.log` doesn't have 'apply' + window.console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); + } +} + +/** + * The currently active debug mode names. + */ + +debug.names = []; +debug.skips = []; + +/** + * Enables a debug mode by name. This can include modes + * separated by a colon and wildcards. + * + * @param {String} name + * @api public + */ + +debug.enable = function(name) { + try { + localStorage.debug = name; + } catch(e){} + + var split = (name || '').split(/[\s,]+/) + , len = split.length; + + for (var i = 0; i < len; i++) { + name = split[i].replace('*', '.*?'); + if (name[0] === '-') { + debug.skips.push(new RegExp('^' + name.substr(1) + '$')); + } + else { + debug.names.push(new RegExp('^' + name + '$')); + } + } +}; + +/** + * Disable debug output. + * + * @api public + */ + +debug.disable = function(){ + debug.enable(''); +}; + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +debug.humanize = function(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +}; + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +debug.enabled = function(name) { + for (var i = 0, len = debug.skips.length; i < len; i++) { + if (debug.skips[i].test(name)) { + return false; + } + } + for (var i = 0, len = debug.names.length; i < len; i++) { + if (debug.names[i].test(name)) { + return true; + } + } + return false; +}; + +// persist + +if (window.localStorage) debug.enable(localStorage.debug); diff --git a/node_modules/express/node_modules/debug/example/app.js b/node_modules/express/node_modules/debug/example/app.js new file mode 100644 index 0000000..05374d9 --- /dev/null +++ b/node_modules/express/node_modules/debug/example/app.js @@ -0,0 +1,19 @@ + +var debug = require('../')('http') + , http = require('http') + , name = 'My App'; + +// fake app + +debug('booting %s', name); + +http.createServer(function(req, res){ + debug(req.method + ' ' + req.url); + res.end('hello\n'); +}).listen(3000, function(){ + debug('listening'); +}); + +// fake worker of some kind + +require('./worker'); \ No newline at end of file diff --git a/node_modules/express/node_modules/debug/example/browser.html b/node_modules/express/node_modules/debug/example/browser.html new file mode 100644 index 0000000..7510eee --- /dev/null +++ b/node_modules/express/node_modules/debug/example/browser.html @@ -0,0 +1,24 @@ + + + debug() + + + + + + + diff --git a/node_modules/express/node_modules/debug/example/wildcards.js b/node_modules/express/node_modules/debug/example/wildcards.js new file mode 100644 index 0000000..1fdac20 --- /dev/null +++ b/node_modules/express/node_modules/debug/example/wildcards.js @@ -0,0 +1,10 @@ + +var debug = { + foo: require('../')('test:foo'), + bar: require('../')('test:bar'), + baz: require('../')('test:baz') +}; + +debug.foo('foo') +debug.bar('bar') +debug.baz('baz') \ No newline at end of file diff --git a/node_modules/express/node_modules/debug/example/worker.js b/node_modules/express/node_modules/debug/example/worker.js new file mode 100644 index 0000000..7f6d288 --- /dev/null +++ b/node_modules/express/node_modules/debug/example/worker.js @@ -0,0 +1,22 @@ + +// DEBUG=* node example/worker +// DEBUG=worker:* node example/worker +// DEBUG=worker:a node example/worker +// DEBUG=worker:b node example/worker + +var a = require('../')('worker:a') + , b = require('../')('worker:b'); + +function work() { + a('doing lots of uninteresting work'); + setTimeout(work, Math.random() * 1000); +} + +work(); + +function workb() { + b('doing some work'); + setTimeout(workb, Math.random() * 2000); +} + +workb(); \ No newline at end of file diff --git a/node_modules/express/node_modules/debug/index.js b/node_modules/express/node_modules/debug/index.js new file mode 100644 index 0000000..e02c13b --- /dev/null +++ b/node_modules/express/node_modules/debug/index.js @@ -0,0 +1,5 @@ +if ('undefined' == typeof window) { + module.exports = require('./lib/debug'); +} else { + module.exports = require('./debug'); +} diff --git a/node_modules/express/node_modules/debug/lib/debug.js b/node_modules/express/node_modules/debug/lib/debug.js new file mode 100644 index 0000000..0b07aa1 --- /dev/null +++ b/node_modules/express/node_modules/debug/lib/debug.js @@ -0,0 +1,134 @@ +/** + * Module dependencies. + */ + +var tty = require('tty'); + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Enabled debuggers. + */ + +var names = [] + , skips = []; + +(process.env.DEBUG || '') + .split(/[\s,]+/) + .forEach(function(name){ + name = name.replace('*', '.*?'); + if (name[0] === '-') { + skips.push(new RegExp('^' + name.substr(1) + '$')); + } else { + names.push(new RegExp('^' + name + '$')); + } + }); + +/** + * Colors. + */ + +var colors = [6, 2, 3, 4, 5, 1]; + +/** + * Previous debug() call. + */ + +var prev = {}; + +/** + * Previously assigned color. + */ + +var prevColor = 0; + +/** + * Is stdout a TTY? Colored output is disabled when `true`. + */ + +var isatty = tty.isatty(2); + +/** + * Select a color. + * + * @return {Number} + * @api private + */ + +function color() { + return colors[prevColor++ % colors.length]; +} + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +function humanize(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +} + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + function disabled(){} + disabled.enabled = false; + + var match = skips.some(function(re){ + return re.test(name); + }); + + if (match) return disabled; + + match = names.some(function(re){ + return re.test(name); + }); + + if (!match) return disabled; + var c = color(); + + function colored(fmt) { + var curr = new Date; + var ms = curr - (prev[name] || curr); + prev[name] = curr; + + fmt = ' \u001b[9' + c + 'm' + name + ' ' + + '\u001b[3' + c + 'm\u001b[90m' + + fmt + '\u001b[3' + c + 'm' + + ' +' + humanize(ms) + '\u001b[0m'; + + console.error.apply(this, arguments); + } + + function plain(fmt) { + fmt = new Date().toUTCString() + + ' ' + name + ' ' + fmt; + console.error.apply(this, arguments); + } + + colored.enabled = plain.enabled = true; + + return isatty || process.env.DEBUG_COLORS + ? colored + : plain; +} diff --git a/node_modules/express/node_modules/debug/package.json b/node_modules/express/node_modules/debug/package.json new file mode 100644 index 0000000..5a4ef66 --- /dev/null +++ b/node_modules/express/node_modules/debug/package.json @@ -0,0 +1,44 @@ +{ + "name": "debug", + "version": "0.7.2", + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/debug.git" + }, + "description": "small debugging utility", + "keywords": [ + "debug", + "log", + "debugger" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*" + }, + "main": "lib/debug.js", + "browserify": "debug.js", + "engines": { + "node": "*" + }, + "component": { + "scripts": { + "debug/index.js": "index.js", + "debug/debug.js": "debug.js" + } + }, + "readme": "\n# debug\n\n tiny node.js debugging utility modelled after node core's debugging technique.\n\n## Installation\n\n```\n$ npm install debug\n```\n\n## Usage\n\n With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.\n \nExample _app.js_:\n\n```js\nvar debug = require('debug')('http')\n , http = require('http')\n , name = 'My App';\n\n// fake app\n\ndebug('booting %s', name);\n\nhttp.createServer(function(req, res){\n debug(req.method + ' ' + req.url);\n res.end('hello\\n');\n}).listen(3000, function(){\n debug('listening');\n});\n\n// fake worker of some kind\n\nrequire('./worker');\n```\n\nExample _worker.js_:\n\n```js\nvar debug = require('debug')('worker');\n\nsetInterval(function(){\n debug('doing some work');\n}, 1000);\n```\n\n The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:\n\n ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)\n\n ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)\n\n## Millisecond diff\n\n When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the \"+NNNms\" will show you how much time was spent between calls.\n\n ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)\n\n When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:\n \n ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)\n\n## Conventions\n\n If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use \":\" to separate features. For example \"bodyParser\" from Connect would then be \"connect:bodyParser\". \n\n## Wildcards\n\n The \"*\" character may be used as a wildcard. Suppose for example your library has debuggers named \"connect:bodyParser\", \"connect:compress\", \"connect:session\", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.\n\n You can also exclude specific debuggers by prefixing them with a \"-\" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with \"connect:\".\n\n## Browser support\n\n Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. \n\n```js\na = debug('worker:a');\nb = debug('worker:b');\n\nsetInterval(function(){\n a('doing some work');\n}, 1000);\n\nsetInterval(function(){\n a('doing some work');\n}, 1200);\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/debug/issues" + }, + "_id": "debug@0.7.2", + "dist": { + "shasum": "bd250e1f909852d023c830057b56eee09073479d" + }, + "_from": "debug@*", + "_resolved": "https://registry.npmjs.org/debug/-/debug-0.7.2.tgz" +} diff --git a/node_modules/express/node_modules/fresh/.npmignore b/node_modules/express/node_modules/fresh/.npmignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/node_modules/express/node_modules/fresh/.npmignore @@ -0,0 +1 @@ +test diff --git a/node_modules/express/node_modules/fresh/Makefile b/node_modules/express/node_modules/fresh/Makefile new file mode 100644 index 0000000..8e8640f --- /dev/null +++ b/node_modules/express/node_modules/fresh/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --reporter spec \ + --require should + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/fresh/Readme.md b/node_modules/express/node_modules/fresh/Readme.md new file mode 100644 index 0000000..273130d --- /dev/null +++ b/node_modules/express/node_modules/fresh/Readme.md @@ -0,0 +1,32 @@ + +# node-fresh + + HTTP response freshness testing + +## fresh(req, res) + + Check freshness of `req` and `res` headers. + + When the cache is "fresh" __true__ is returned, + otherwise __false__ is returned to indicate that + the cache is now stale. + +## Example: + +```js +var req = { 'if-none-match': 'tobi' }; +var res = { 'etag': 'luna' }; +fresh(req, res); +// => false + +var req = { 'if-none-match': 'tobi' }; +var res = { 'etag': 'tobi' }; +fresh(req, res); +// => true +``` + +## Installation + +``` +$ npm install fresh +``` \ No newline at end of file diff --git a/node_modules/express/node_modules/fresh/index.js b/node_modules/express/node_modules/fresh/index.js new file mode 100644 index 0000000..b2f4d41 --- /dev/null +++ b/node_modules/express/node_modules/fresh/index.js @@ -0,0 +1,49 @@ + +/** + * Expose `fresh()`. + */ + +module.exports = fresh; + +/** + * Check freshness of `req` and `res` headers. + * + * When the cache is "fresh" __true__ is returned, + * otherwise __false__ is returned to indicate that + * the cache is now stale. + * + * @param {Object} req + * @param {Object} res + * @return {Boolean} + * @api public + */ + +function fresh(req, res) { + // defaults + var etagMatches = true; + var notModified = true; + + // fields + var modifiedSince = req['if-modified-since']; + var noneMatch = req['if-none-match']; + var lastModified = res['last-modified']; + var etag = res['etag']; + + // unconditional request + if (!modifiedSince && !noneMatch) return false; + + // parse if-none-match + if (noneMatch) noneMatch = noneMatch.split(/ *, */); + + // if-none-match + if (noneMatch) etagMatches = ~noneMatch.indexOf(etag) || '*' == noneMatch[0]; + + // if-modified-since + if (modifiedSince) { + modifiedSince = new Date(modifiedSince); + lastModified = new Date(lastModified); + notModified = lastModified <= modifiedSince; + } + + return !! (etagMatches && notModified); +} \ No newline at end of file diff --git a/node_modules/express/node_modules/fresh/package.json b/node_modules/express/node_modules/fresh/package.json new file mode 100644 index 0000000..470e0eb --- /dev/null +++ b/node_modules/express/node_modules/fresh/package.json @@ -0,0 +1,24 @@ +{ + "name": "fresh", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "description": "HTTP response freshness testing", + "version": "0.1.0", + "main": "index.js", + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "readme": "\n# node-fresh\n\n HTTP response freshness testing\n\n## fresh(req, res)\n\n Check freshness of `req` and `res` headers.\n\n When the cache is \"fresh\" __true__ is returned,\n otherwise __false__ is returned to indicate that\n the cache is now stale.\n\n## Example:\n\n```js\nvar req = { 'if-none-match': 'tobi' };\nvar res = { 'etag': 'luna' };\nfresh(req, res);\n// => false\n\nvar req = { 'if-none-match': 'tobi' };\nvar res = { 'etag': 'tobi' };\nfresh(req, res);\n// => true\n```\n\n## Installation\n\n```\n$ npm install fresh\n```", + "readmeFilename": "Readme.md", + "_id": "fresh@0.1.0", + "dist": { + "shasum": "03e4b0178424e4c2d5d19a54d8814cdc97934850" + }, + "_from": "fresh@0.1.0", + "_resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz" +} diff --git a/node_modules/express/node_modules/methods/index.js b/node_modules/express/node_modules/methods/index.js new file mode 100644 index 0000000..297d022 --- /dev/null +++ b/node_modules/express/node_modules/methods/index.js @@ -0,0 +1,26 @@ + +module.exports = [ + 'get' + , 'post' + , 'put' + , 'head' + , 'delete' + , 'options' + , 'trace' + , 'copy' + , 'lock' + , 'mkcol' + , 'move' + , 'propfind' + , 'proppatch' + , 'unlock' + , 'report' + , 'mkactivity' + , 'checkout' + , 'merge' + , 'm-search' + , 'notify' + , 'subscribe' + , 'unsubscribe' + , 'patch' +]; \ No newline at end of file diff --git a/node_modules/express/node_modules/methods/package.json b/node_modules/express/node_modules/methods/package.json new file mode 100644 index 0000000..1c15a33 --- /dev/null +++ b/node_modules/express/node_modules/methods/package.json @@ -0,0 +1,24 @@ +{ + "name": "methods", + "version": "0.0.1", + "description": "HTTP methods that node supports", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "http", + "methods" + ], + "author": { + "name": "TJ Holowaychuk" + }, + "license": "MIT", + "readme": "ERROR: No README data found!", + "_id": "methods@0.0.1", + "dist": { + "shasum": "277c90f8bef39709645a8371c51c3b6c648e068c" + }, + "_from": "methods@0.0.1", + "_resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz" +} diff --git a/node_modules/express/node_modules/mkdirp/.npmignore b/node_modules/express/node_modules/mkdirp/.npmignore new file mode 100644 index 0000000..9303c34 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/.npmignore @@ -0,0 +1,2 @@ +node_modules/ +npm-debug.log \ No newline at end of file diff --git a/node_modules/express/node_modules/mkdirp/.travis.yml b/node_modules/express/node_modules/mkdirp/.travis.yml new file mode 100644 index 0000000..84fd7ca --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 diff --git a/node_modules/express/node_modules/mkdirp/LICENSE b/node_modules/express/node_modules/mkdirp/LICENSE new file mode 100644 index 0000000..432d1ae --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/express/node_modules/mkdirp/examples/pow.js b/node_modules/express/node_modules/mkdirp/examples/pow.js new file mode 100644 index 0000000..e692421 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/examples/pow.js @@ -0,0 +1,6 @@ +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); diff --git a/node_modules/express/node_modules/mkdirp/index.js b/node_modules/express/node_modules/mkdirp/index.js new file mode 100644 index 0000000..fda6de8 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/index.js @@ -0,0 +1,82 @@ +var path = require('path'); +var fs = require('fs'); + +module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; + +function mkdirP (p, mode, f, made) { + if (typeof mode === 'function' || mode === undefined) { + f = mode; + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + var cb = f || function () {}; + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + fs.mkdir(p, mode, function (er) { + if (!er) { + made = made || p; + return cb(null, made); + } + switch (er.code) { + case 'ENOENT': + mkdirP(path.dirname(p), mode, function (er, made) { + if (er) cb(er, made); + else mkdirP(p, mode, cb, made); + }); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + fs.stat(p, function (er2, stat) { + // if the stat fails, then that's super weird. + // let the original error be the failure reason. + if (er2 || !stat.isDirectory()) cb(er, made) + else cb(null, made); + }); + break; + } + }); +} + +mkdirP.sync = function sync (p, mode, made) { + if (mode === undefined) { + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + try { + fs.mkdirSync(p, mode); + made = made || p; + } + catch (err0) { + switch (err0.code) { + case 'ENOENT' : + made = sync(path.dirname(p), mode, made); + sync(p, mode, made); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + var stat; + try { + stat = fs.statSync(p); + } + catch (err1) { + throw err0; + } + if (!stat.isDirectory()) throw err0; + break; + } + } + + return made; +}; diff --git a/node_modules/express/node_modules/mkdirp/package.json b/node_modules/express/node_modules/mkdirp/package.json new file mode 100644 index 0000000..58f6439 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/package.json @@ -0,0 +1,37 @@ +{ + "name": "mkdirp", + "description": "Recursively mkdir, like `mkdir -p`", + "version": "0.3.5", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "main": "./index", + "keywords": [ + "mkdir", + "directory" + ], + "repository": { + "type": "git", + "url": "http://github.com/substack/node-mkdirp.git" + }, + "scripts": { + "test": "tap test/*.js" + }, + "devDependencies": { + "tap": "~0.4.0" + }, + "license": "MIT", + "readme": "# mkdirp\n\nLike `mkdir -p`, but in node.js!\n\n[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)\n\n# example\n\n## pow.js\n\n```js\nvar mkdirp = require('mkdirp');\n \nmkdirp('/tmp/foo/bar/baz', function (err) {\n if (err) console.error(err)\n else console.log('pow!')\n});\n```\n\nOutput\n\n```\npow!\n```\n\nAnd now /tmp/foo/bar/baz exists, huzzah!\n\n# methods\n\n```js\nvar mkdirp = require('mkdirp');\n```\n\n## mkdirp(dir, mode, cb)\n\nCreate a new directory and any necessary subdirectories at `dir` with octal\npermission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\n`cb(err, made)` fires with the error or the first directory `made`\nthat had to be created, if any.\n\n## mkdirp.sync(dir, mode)\n\nSynchronously create a new directory and any necessary subdirectories at `dir`\nwith octal permission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\nReturns the first directory that had to be created, if any.\n\n# install\n\nWith [npm](http://npmjs.org) do:\n\n```\nnpm install mkdirp\n```\n\n# license\n\nMIT\n", + "readmeFilename": "readme.markdown", + "bugs": { + "url": "https://github.com/substack/node-mkdirp/issues" + }, + "_id": "mkdirp@0.3.5", + "dist": { + "shasum": "3ca8fc91ed924e281236eec99e74505873ac5a45" + }, + "_from": "mkdirp@0.3.5", + "_resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz" +} diff --git a/node_modules/express/node_modules/mkdirp/readme.markdown b/node_modules/express/node_modules/mkdirp/readme.markdown new file mode 100644 index 0000000..83b0216 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/readme.markdown @@ -0,0 +1,63 @@ +# mkdirp + +Like `mkdir -p`, but in node.js! + +[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp) + +# example + +## pow.js + +```js +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); +``` + +Output + +``` +pow! +``` + +And now /tmp/foo/bar/baz exists, huzzah! + +# methods + +```js +var mkdirp = require('mkdirp'); +``` + +## mkdirp(dir, mode, cb) + +Create a new directory and any necessary subdirectories at `dir` with octal +permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +`cb(err, made)` fires with the error or the first directory `made` +that had to be created, if any. + +## mkdirp.sync(dir, mode) + +Synchronously create a new directory and any necessary subdirectories at `dir` +with octal permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +Returns the first directory that had to be created, if any. + +# install + +With [npm](http://npmjs.org) do: + +``` +npm install mkdirp +``` + +# license + +MIT diff --git a/node_modules/express/node_modules/mkdirp/test/chmod.js b/node_modules/express/node_modules/mkdirp/test/chmod.js new file mode 100644 index 0000000..520dcb8 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/chmod.js @@ -0,0 +1,38 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +test('chmod-pre', function (t) { + var mode = 0744 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.equal(stat && stat.mode & 0777, mode, 'should be 0744'); + t.end(); + }); + }); +}); + +test('chmod', function (t) { + var mode = 0755 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.end(); + }); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/clobber.js b/node_modules/express/node_modules/mkdirp/test/clobber.js new file mode 100644 index 0000000..0eb7099 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/clobber.js @@ -0,0 +1,37 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +// a file in the way +var itw = ps.slice(0, 3).join('/'); + + +test('clobber-pre', function (t) { + console.error("about to write to "+itw) + fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.'); + + fs.stat(itw, function (er, stat) { + t.ifError(er) + t.ok(stat && stat.isFile(), 'should be file') + t.end() + }) +}) + +test('clobber', function (t) { + t.plan(2); + mkdirp(file, 0755, function (err) { + t.ok(err); + t.equal(err.code, 'ENOTDIR'); + t.end(); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/mkdirp.js b/node_modules/express/node_modules/mkdirp/test/mkdirp.js new file mode 100644 index 0000000..b07cd70 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/mkdirp.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('woo', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/perm.js b/node_modules/express/node_modules/mkdirp/test/perm.js new file mode 100644 index 0000000..23a7abb --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/perm.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('async perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); + +test('async root perm', function (t) { + mkdirp('/tmp', 0755, function (err) { + if (err) t.fail(err); + t.end(); + }); + t.end(); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/perm_sync.js b/node_modules/express/node_modules/mkdirp/test/perm_sync.js new file mode 100644 index 0000000..f685f60 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/perm_sync.js @@ -0,0 +1,39 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16) + '.json'; + + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); + +test('sync root perm', function (t) { + t.plan(1); + + var file = '/tmp'; + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/race.js b/node_modules/express/node_modules/mkdirp/test/race.js new file mode 100644 index 0000000..96a0447 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/race.js @@ -0,0 +1,41 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('race', function (t) { + t.plan(4); + var ps = [ '', 'tmp' ]; + + for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); + } + var file = ps.join('/'); + + var res = 2; + mk(file, function () { + if (--res === 0) t.end(); + }); + + mk(file, function () { + if (--res === 0) t.end(); + }); + + function mk (file, cb) { + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + if (cb) cb(); + } + }) + }) + }); + } +}); diff --git a/node_modules/express/node_modules/mkdirp/test/rel.js b/node_modules/express/node_modules/mkdirp/test/rel.js new file mode 100644 index 0000000..7985824 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/rel.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('rel', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var cwd = process.cwd(); + process.chdir('/tmp'); + + var file = [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + process.chdir(cwd); + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/return.js b/node_modules/express/node_modules/mkdirp/test/return.js new file mode 100644 index 0000000..bce68e5 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/return.js @@ -0,0 +1,25 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(4); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, '/tmp/' + x); + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, null); + }); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/return_sync.js b/node_modules/express/node_modules/mkdirp/test/return_sync.js new file mode 100644 index 0000000..7c222d3 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/return_sync.js @@ -0,0 +1,24 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + // Note that this will throw on failure, which will fail the test. + var made = mkdirp.sync(file); + t.equal(made, '/tmp/' + x); + + // making the same file again should have no effect. + made = mkdirp.sync(file); + t.equal(made, null); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/root.js b/node_modules/express/node_modules/mkdirp/test/root.js new file mode 100644 index 0000000..97ad7a2 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/root.js @@ -0,0 +1,18 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('root', function (t) { + // '/' on unix, 'c:/' on windows. + var file = path.resolve('/'); + + mkdirp(file, 0755, function (err) { + if (err) throw err + fs.stat(file, function (er, stat) { + if (er) throw er + t.ok(stat.isDirectory(), 'target is a directory'); + t.end(); + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/sync.js b/node_modules/express/node_modules/mkdirp/test/sync.js new file mode 100644 index 0000000..7530cad --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file, 0755); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/umask.js b/node_modules/express/node_modules/mkdirp/test/umask.js new file mode 100644 index 0000000..64ccafe --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/umask.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('implicit mode from umask', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0777 & (~process.umask())); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/umask_sync.js b/node_modules/express/node_modules/mkdirp/test/umask_sync.js new file mode 100644 index 0000000..35bd5cb --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/umask_sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('umask sync modes', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, (0777 & (~process.umask()))); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/express/node_modules/range-parser/.npmignore b/node_modules/express/node_modules/range-parser/.npmignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/node_modules/express/node_modules/range-parser/.npmignore @@ -0,0 +1 @@ +test diff --git a/node_modules/express/node_modules/range-parser/History.md b/node_modules/express/node_modules/range-parser/History.md new file mode 100644 index 0000000..82df7b1 --- /dev/null +++ b/node_modules/express/node_modules/range-parser/History.md @@ -0,0 +1,15 @@ + +0.0.4 / 2012-06-17 +================== + + * changed: ret -1 for unsatisfiable and -2 when invalid + +0.0.3 / 2012-06-17 +================== + + * fix last-byte-pos default to len - 1 + +0.0.2 / 2012-06-14 +================== + + * add `.type` diff --git a/node_modules/express/node_modules/range-parser/Makefile b/node_modules/express/node_modules/range-parser/Makefile new file mode 100644 index 0000000..8e8640f --- /dev/null +++ b/node_modules/express/node_modules/range-parser/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --reporter spec \ + --require should + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/range-parser/Readme.md b/node_modules/express/node_modules/range-parser/Readme.md new file mode 100644 index 0000000..b2a67fe --- /dev/null +++ b/node_modules/express/node_modules/range-parser/Readme.md @@ -0,0 +1,28 @@ + +# node-range-parser + + Range header field parser. + +## Example: + +```js +assert(-1 == parse(200, 'bytes=500-20')); +assert(-2 == parse(200, 'bytes=malformed')); +parse(200, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 199 }])); +parse(1000, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 499 }])); +parse(1000, 'bytes=40-80').should.eql(arr('bytes', [{ start: 40, end: 80 }])); +parse(1000, 'bytes=-500').should.eql(arr('bytes', [{ start: 500, end: 999 }])); +parse(1000, 'bytes=-400').should.eql(arr('bytes', [{ start: 600, end: 999 }])); +parse(1000, 'bytes=500-').should.eql(arr('bytes', [{ start: 500, end: 999 }])); +parse(1000, 'bytes=400-').should.eql(arr('bytes', [{ start: 400, end: 999 }])); +parse(1000, 'bytes=0-0').should.eql(arr('bytes', [{ start: 0, end: 0 }])); +parse(1000, 'bytes=-1').should.eql(arr('bytes', [{ start: 999, end: 999 }])); +parse(1000, 'items=0-5').should.eql(arr('items', [{ start: 0, end: 5 }])); +parse(1000, 'bytes=40-80,-1').should.eql(arr('bytes', [{ start: 40, end: 80 }, { start: 999, end: 999 }])); +``` + +## Installation + +``` +$ npm install range-parser +``` \ No newline at end of file diff --git a/node_modules/express/node_modules/range-parser/index.js b/node_modules/express/node_modules/range-parser/index.js new file mode 100644 index 0000000..9b0f7a8 --- /dev/null +++ b/node_modules/express/node_modules/range-parser/index.js @@ -0,0 +1,49 @@ + +/** + * Parse "Range" header `str` relative to the given file `size`. + * + * @param {Number} size + * @param {String} str + * @return {Array} + * @api public + */ + +module.exports = function(size, str){ + var valid = true; + var i = str.indexOf('='); + + if (-1 == i) return -2; + + var arr = str.slice(i + 1).split(',').map(function(range){ + var range = range.split('-') + , start = parseInt(range[0], 10) + , end = parseInt(range[1], 10); + + // -nnn + if (isNaN(start)) { + start = size - end; + end = size - 1; + // nnn- + } else if (isNaN(end)) { + end = size - 1; + } + + // limit last-byte-pos to current length + if (end > size - 1) end = size - 1; + + // invalid + if (isNaN(start) + || isNaN(end) + || start > end + || start < 0) valid = false; + + return { + start: start, + end: end + }; + }); + + arr.type = str.slice(0, i); + + return valid ? arr : -1; +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/range-parser/package.json b/node_modules/express/node_modules/range-parser/package.json new file mode 100644 index 0000000..0e048f7 --- /dev/null +++ b/node_modules/express/node_modules/range-parser/package.json @@ -0,0 +1,24 @@ +{ + "name": "range-parser", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "description": "Range header field string parser", + "version": "0.0.4", + "main": "index.js", + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "readme": "\n# node-range-parser\n\n Range header field parser.\n\n## Example:\n\n```js\nassert(-1 == parse(200, 'bytes=500-20'));\nassert(-2 == parse(200, 'bytes=malformed'));\nparse(200, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 199 }]));\nparse(1000, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 499 }]));\nparse(1000, 'bytes=40-80').should.eql(arr('bytes', [{ start: 40, end: 80 }]));\nparse(1000, 'bytes=-500').should.eql(arr('bytes', [{ start: 500, end: 999 }]));\nparse(1000, 'bytes=-400').should.eql(arr('bytes', [{ start: 600, end: 999 }]));\nparse(1000, 'bytes=500-').should.eql(arr('bytes', [{ start: 500, end: 999 }]));\nparse(1000, 'bytes=400-').should.eql(arr('bytes', [{ start: 400, end: 999 }]));\nparse(1000, 'bytes=0-0').should.eql(arr('bytes', [{ start: 0, end: 0 }]));\nparse(1000, 'bytes=-1').should.eql(arr('bytes', [{ start: 999, end: 999 }]));\nparse(1000, 'items=0-5').should.eql(arr('items', [{ start: 0, end: 5 }]));\nparse(1000, 'bytes=40-80,-1').should.eql(arr('bytes', [{ start: 40, end: 80 }, { start: 999, end: 999 }]));\n```\n\n## Installation\n\n```\n$ npm install range-parser\n```", + "readmeFilename": "Readme.md", + "_id": "range-parser@0.0.4", + "dist": { + "shasum": "c0427ffef51c10acba0782a46c9602e744ff620b" + }, + "_from": "range-parser@0.0.4", + "_resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz" +} diff --git a/node_modules/express/node_modules/send/.npmignore b/node_modules/express/node_modules/send/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/express/node_modules/send/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/express/node_modules/send/History.md b/node_modules/express/node_modules/send/History.md new file mode 100644 index 0000000..e348db5 --- /dev/null +++ b/node_modules/express/node_modules/send/History.md @@ -0,0 +1,35 @@ + +0.1.3 / 2013-07-08 +================== + + * Revert "Fix fd leak" + +0.1.2 / 2013-07-03 +================== + + * Fix fd leak + +0.1.0 / 2012-08-25 +================== + + * add options parameter to send() that is passed to fs.createReadStream() [kanongil] + +0.0.4 / 2012-08-16 +================== + + * allow custom "Accept-Ranges" definition + +0.0.3 / 2012-07-16 +================== + + * fix normalization of the root directory. Closes #3 + +0.0.2 / 2012-07-09 +================== + + * add passing of req explicitly for now (YUCK) + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/send/Makefile b/node_modules/express/node_modules/send/Makefile new file mode 100644 index 0000000..a9dcfd5 --- /dev/null +++ b/node_modules/express/node_modules/send/Makefile @@ -0,0 +1,8 @@ + +test: + @./node_modules/.bin/mocha \ + --require should \ + --reporter spec \ + --bail + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/send/Readme.md b/node_modules/express/node_modules/send/Readme.md new file mode 100644 index 0000000..ea7b234 --- /dev/null +++ b/node_modules/express/node_modules/send/Readme.md @@ -0,0 +1,128 @@ +# send + + Send is Connect's `static()` extracted for generalized use, a streaming static file + server supporting partial responses (Ranges), conditional-GET negotiation, high test coverage, and granular events which may be leveraged to take appropriate actions in your application or framework. + +## Installation + + $ npm install send + +## Examples + + Small: + +```js +var http = require('http'); +var send = require('send'); + +var app = http.createServer(function(req, res){ + send(req, req.url).pipe(res); +}).listen(3000); +``` + + Serving from a root directory with custom error-handling: + +```js +var http = require('http'); +var send = require('send'); +var url = require('url'); + +var app = http.createServer(function(req, res){ + // your custom error-handling logic: + function error(err) { + res.statusCode = err.status || 500; + res.end(err.message); + } + + // your custom directory handling logic: + function redirect() { + res.statusCode = 301; + res.setHeader('Location', req.url + '/'); + res.end('Redirecting to ' + req.url + '/'); + } + + // transfer arbitrary files from within + // /www/example.com/public/* + send(req, url.parse(req.url).pathname) + .root('/www/example.com/public') + .on('error', error) + .on('directory', redirect) + .pipe(res); +}).listen(3000); +``` + +## API + +### Events + + - `error` an error occurred `(err)` + - `directory` a directory was requested + - `file` a file was requested `(path, stat)` + - `stream` file streaming has started `(stream)` + - `end` streaming has completed + +### .root(dir) + + Serve files relative to `path`. Aliased as `.from(dir)`. + +### .index(path) + + By default send supports "index.html" files, to disable this + invoke `.index(false)` or to supply a new index pass a string. + +### .maxage(ms) + + Provide a max-age in milliseconds for http caching, defaults to 0. + +### .hidden(bool) + + Enable or disable transfer of hidden files, defaults to false. + +## Error-handling + + By default when no `error` listeners are present an automatic response will be made, otherwise you have full control over the response, aka you may show a 5xx page etc. + +## Caching + + It does _not_ perform internal caching, you should use a reverse proxy cache such + as Varnish for this, or those fancy things called CDNs. If your application is small enough that it would benefit from single-node memory caching, it's small enough that it does not need caching at all ;). + +## Debugging + + To enable `debug()` instrumentation output export __DEBUG__: + +``` +$ DEBUG=send node app +``` + +## Running tests + +``` +$ npm install +$ make test +``` + +## License + +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/send/index.js b/node_modules/express/node_modules/send/index.js new file mode 100644 index 0000000..f17158d --- /dev/null +++ b/node_modules/express/node_modules/send/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/send'); \ No newline at end of file diff --git a/node_modules/express/node_modules/send/lib/send.js b/node_modules/express/node_modules/send/lib/send.js new file mode 100644 index 0000000..a3d94a6 --- /dev/null +++ b/node_modules/express/node_modules/send/lib/send.js @@ -0,0 +1,474 @@ + +/** + * Module dependencies. + */ + +var debug = require('debug')('send') + , parseRange = require('range-parser') + , Stream = require('stream') + , mime = require('mime') + , fresh = require('fresh') + , path = require('path') + , http = require('http') + , fs = require('fs') + , basename = path.basename + , normalize = path.normalize + , join = path.join + , utils = require('./utils'); + +/** + * Expose `send`. + */ + +exports = module.exports = send; + +/** + * Expose mime module. + */ + +exports.mime = mime; + +/** + * Return a `SendStream` for `req` and `path`. + * + * @param {Request} req + * @param {String} path + * @param {Object} options + * @return {SendStream} + * @api public + */ + +function send(req, path, options) { + return new SendStream(req, path, options); +} + +/** + * Initialize a `SendStream` with the given `path`. + * + * Events: + * + * - `error` an error occurred + * - `stream` file streaming has started + * - `end` streaming has completed + * - `directory` a directory was requested + * + * @param {Request} req + * @param {String} path + * @param {Object} options + * @api private + */ + +function SendStream(req, path, options) { + var self = this; + this.req = req; + this.path = path; + this.options = options || {}; + this.maxage(0); + this.hidden(false); + this.index('index.html'); +} + +/** + * Inherits from `Stream.prototype`. + */ + +SendStream.prototype.__proto__ = Stream.prototype; + +/** + * Enable or disable "hidden" (dot) files. + * + * @param {Boolean} path + * @return {SendStream} + * @api public + */ + +SendStream.prototype.hidden = function(val){ + debug('hidden %s', val); + this._hidden = val; + return this; +}; + +/** + * Set index `path`, set to a falsy + * value to disable index support. + * + * @param {String|Boolean} path + * @return {SendStream} + * @api public + */ + +SendStream.prototype.index = function(path){ + debug('index %s', path); + this._index = path; + return this; +}; + +/** + * Set root `path`. + * + * @param {String} path + * @return {SendStream} + * @api public + */ + +SendStream.prototype.root = +SendStream.prototype.from = function(path){ + this._root = normalize(path); + return this; +}; + +/** + * Set max-age to `ms`. + * + * @param {Number} ms + * @return {SendStream} + * @api public + */ + +SendStream.prototype.maxage = function(ms){ + if (Infinity == ms) ms = 60 * 60 * 24 * 365 * 1000; + debug('max-age %d', ms); + this._maxage = ms; + return this; +}; + +/** + * Emit error with `status`. + * + * @param {Number} status + * @api private + */ + +SendStream.prototype.error = function(status, err){ + var res = this.res; + var msg = http.STATUS_CODES[status]; + err = err || new Error(msg); + err.status = status; + if (this.listeners('error').length) return this.emit('error', err); + res.statusCode = err.status; + res.end(msg); +}; + +/** + * Check if the pathname is potentially malicious. + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isMalicious = function(){ + return !this._root && ~this.path.indexOf('..'); +}; + +/** + * Check if the pathname ends with "/". + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.hasTrailingSlash = function(){ + return '/' == this.path[this.path.length - 1]; +}; + +/** + * Check if the basename leads with ".". + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.hasLeadingDot = function(){ + return '.' == basename(this.path)[0]; +}; + +/** + * Check if this is a conditional GET request. + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isConditionalGET = function(){ + return this.req.headers['if-none-match'] + || this.req.headers['if-modified-since']; +}; + +/** + * Strip content-* header fields. + * + * @api private + */ + +SendStream.prototype.removeContentHeaderFields = function(){ + var res = this.res; + Object.keys(res._headers).forEach(function(field){ + if (0 == field.indexOf('content')) { + res.removeHeader(field); + } + }); +}; + +/** + * Respond with 304 not modified. + * + * @api private + */ + +SendStream.prototype.notModified = function(){ + var res = this.res; + debug('not modified'); + this.removeContentHeaderFields(); + res.statusCode = 304; + res.end(); +}; + +/** + * Check if the request is cacheable, aka + * responded with 2xx or 304 (see RFC 2616 section 14.2{5,6}). + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isCachable = function(){ + var res = this.res; + return (res.statusCode >= 200 && res.statusCode < 300) || 304 == res.statusCode; +}; + +/** + * Handle stat() error. + * + * @param {Error} err + * @api private + */ + +SendStream.prototype.onStatError = function(err){ + var notfound = ['ENOENT', 'ENAMETOOLONG', 'ENOTDIR']; + if (~notfound.indexOf(err.code)) return this.error(404, err); + this.error(500, err); +}; + +/** + * Check if the cache is fresh. + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isFresh = function(){ + return fresh(this.req.headers, this.res._headers); +}; + +/** + * Redirect to `path`. + * + * @param {String} path + * @api private + */ + +SendStream.prototype.redirect = function(path){ + if (this.listeners('directory').length) return this.emit('directory'); + var res = this.res; + path += '/'; + res.statusCode = 301; + res.setHeader('Location', path); + res.end('Redirecting to ' + utils.escape(path)); +}; + +/** + * Pipe to `res. + * + * @param {Stream} res + * @return {Stream} res + * @api public + */ + +SendStream.prototype.pipe = function(res){ + var self = this + , args = arguments + , path = this.path + , root = this._root; + + // references + this.res = res; + + // invalid request uri + path = utils.decode(path); + if (-1 == path) return this.error(400); + + // null byte(s) + if (~path.indexOf('\0')) return this.error(400); + + // join / normalize from optional root dir + if (root) path = normalize(join(this._root, path)); + + // ".." is malicious without "root" + if (this.isMalicious()) return this.error(403); + + // malicious path + if (root && 0 != path.indexOf(root)) return this.error(403); + + // hidden file support + if (!this._hidden && this.hasLeadingDot()) return this.error(404); + + // index file support + if (this._index && this.hasTrailingSlash()) path += this._index; + + debug('stat "%s"', path); + fs.stat(path, function(err, stat){ + if (err) return self.onStatError(err); + if (stat.isDirectory()) return self.redirect(self.path); + self.emit('file', path, stat); + self.send(path, stat); + }); + + return res; +}; + +/** + * Transfer `path`. + * + * @param {String} path + * @api public + */ + +SendStream.prototype.send = function(path, stat){ + var options = this.options; + var len = stat.size; + var res = this.res; + var req = this.req; + var ranges = req.headers.range; + var offset = options.start || 0; + + // set header fields + this.setHeader(stat); + + // set content-type + this.type(path); + + // conditional GET support + if (this.isConditionalGET() + && this.isCachable() + && this.isFresh()) { + return this.notModified(); + } + + // adjust len to start/end options + len = Math.max(0, len - offset); + if (options.end !== undefined) { + var bytes = options.end - offset + 1; + if (len > bytes) len = bytes; + } + + // Range support + if (ranges) { + ranges = parseRange(len, ranges); + + // unsatisfiable + if (-1 == ranges) { + res.setHeader('Content-Range', 'bytes */' + stat.size); + return this.error(416); + } + + // valid (syntactically invalid ranges are treated as a regular response) + if (-2 != ranges) { + options.start = offset + ranges[0].start; + options.end = offset + ranges[0].end; + + // Content-Range + res.statusCode = 206; + res.setHeader('Content-Range', 'bytes ' + + ranges[0].start + + '-' + + ranges[0].end + + '/' + + len); + len = options.end - options.start + 1; + } + } + + // content-length + res.setHeader('Content-Length', len); + + // HEAD support + if ('HEAD' == req.method) return res.end(); + + this.stream(path, options); +}; + +/** + * Stream `path` to the response. + * + * @param {String} path + * @param {Object} options + * @api private + */ + +SendStream.prototype.stream = function(path, options){ + // TODO: this is all lame, refactor meeee + var self = this; + var res = this.res; + var req = this.req; + + // pipe + var stream = fs.createReadStream(path, options); + this.emit('stream', stream); + stream.pipe(res); + + // socket closed, done with the fd + req.on('close', stream.destroy.bind(stream)); + + // error handling code-smell + stream.on('error', function(err){ + // no hope in responding + if (res._header) { + console.error(err.stack); + req.destroy(); + return; + } + + // 500 + err.status = 500; + self.emit('error', err); + }); + + // end + stream.on('end', function(){ + self.emit('end'); + }); +}; + +/** + * Set content-type based on `path` + * if it hasn't been explicitly set. + * + * @param {String} path + * @api private + */ + +SendStream.prototype.type = function(path){ + var res = this.res; + if (res.getHeader('Content-Type')) return; + var type = mime.lookup(path); + var charset = mime.charsets.lookup(type); + debug('content-type %s', type); + res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : '')); +}; + +/** + * Set reaponse header fields, most + * fields may be pre-defined. + * + * @param {Object} stat + * @api private + */ + +SendStream.prototype.setHeader = function(stat){ + var res = this.res; + if (!res.getHeader('Accept-Ranges')) res.setHeader('Accept-Ranges', 'bytes'); + if (!res.getHeader('ETag')) res.setHeader('ETag', utils.etag(stat)); + if (!res.getHeader('Date')) res.setHeader('Date', new Date().toUTCString()); + if (!res.getHeader('Cache-Control')) res.setHeader('Cache-Control', 'public, max-age=' + (this._maxage / 1000)); + if (!res.getHeader('Last-Modified')) res.setHeader('Last-Modified', stat.mtime.toUTCString()); +}; diff --git a/node_modules/express/node_modules/send/lib/utils.js b/node_modules/express/node_modules/send/lib/utils.js new file mode 100644 index 0000000..950e5a2 --- /dev/null +++ b/node_modules/express/node_modules/send/lib/utils.js @@ -0,0 +1,47 @@ + +/** + * Return an ETag in the form of `"-"` + * from the given `stat`. + * + * @param {Object} stat + * @return {String} + * @api private + */ + +exports.etag = function(stat) { + return '"' + stat.size + '-' + Number(stat.mtime) + '"'; +}; + +/** + * decodeURIComponent. + * + * Allows V8 to only deoptimize this fn instead of all + * of send(). + * + * @param {String} path + * @api private + */ + +exports.decode = function(path){ + try { + return decodeURIComponent(path); + } catch (err) { + return -1; + } +}; + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/send/node_modules/mime/LICENSE b/node_modules/express/node_modules/send/node_modules/mime/LICENSE new file mode 100644 index 0000000..451fc45 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Benjamin Thomas, Robert Kieffer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/express/node_modules/send/node_modules/mime/README.md b/node_modules/express/node_modules/send/node_modules/mime/README.md new file mode 100644 index 0000000..6ca19bd --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/README.md @@ -0,0 +1,66 @@ +# mime + +Comprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community. + +## Install + +Install with [npm](http://github.com/isaacs/npm): + + npm install mime + +## API - Queries + +### mime.lookup(path) +Get the mime type associated with a file, if no mime type is found `application/octet-stream` is returned. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g. + + var mime = require('mime'); + + mime.lookup('/path/to/file.txt'); // => 'text/plain' + mime.lookup('file.txt'); // => 'text/plain' + mime.lookup('.TXT'); // => 'text/plain' + mime.lookup('htm'); // => 'text/html' + +### mime.default_type +Sets the mime type returned when `mime.lookup` fails to find the extension searched for. (Default is `application/octet-stream`.) + +### mime.extension(type) +Get the default extension for `type` + + mime.extension('text/html'); // => 'html' + mime.extension('application/octet-stream'); // => 'bin' + +### mime.charsets.lookup() + +Map mime-type to charset + + mime.charsets.lookup('text/plain'); // => 'UTF-8' + +(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.) + +## API - Defining Custom Types + +The following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types). + +### mime.define() + +Add custom mime/extension mappings + + mime.define({ + 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'], + 'application/x-my-type': ['x-mt', 'x-mtt'], + // etc ... + }); + + mime.lookup('x-sft'); // => 'text/x-some-format' + +The first entry in the extensions array is returned by `mime.extension()`. E.g. + + mime.extension('text/x-some-format'); // => 'x-sf' + +### mime.load(filepath) + +Load mappings from an Apache ".types" format file + + mime.load('./my_project.types'); + +The .types file format is simple - See the `types` dir for examples. diff --git a/node_modules/express/node_modules/send/node_modules/mime/mime.js b/node_modules/express/node_modules/send/node_modules/mime/mime.js new file mode 100644 index 0000000..8a7eb09 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/mime.js @@ -0,0 +1,114 @@ +var path = require('path'); +var fs = require('fs'); + +function Mime() { + // Map of extension -> mime type + this.types = Object.create(null); + + // Map of mime type -> extension + this.extensions = Object.create(null); +} + +/** + * Define mimetype -> extension mappings. Each key is a mime-type that maps + * to an array of extensions associated with the type. The first extension is + * used as the default extension for the type. + * + * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); + * + * @param map (Object) type definitions + */ +Mime.prototype.define = function (map) { + for (var type in map) { + var exts = map[type]; + + for (var i = 0; i < exts.length; i++) { + if (process.env.DEBUG_MIME && this.types[exts]) { + console.warn(this._loading.replace(/.*\//, ''), 'changes "' + exts[i] + '" extension type from ' + + this.types[exts] + ' to ' + type); + } + + this.types[exts[i]] = type; + } + + // Default extension is the first one we encounter + if (!this.extensions[type]) { + this.extensions[type] = exts[0]; + } + } +}; + +/** + * Load an Apache2-style ".types" file + * + * This may be called multiple times (it's expected). Where files declare + * overlapping types/extensions, the last file wins. + * + * @param file (String) path of file to load. + */ +Mime.prototype.load = function(file) { + + this._loading = file; + // Read file and split into lines + var map = {}, + content = fs.readFileSync(file, 'ascii'), + lines = content.split(/[\r\n]+/); + + lines.forEach(function(line) { + // Clean up whitespace/comments, and split into fields + var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/); + map[fields.shift()] = fields; + }); + + this.define(map); + + this._loading = null; +}; + +/** + * Lookup a mime type based on extension + */ +Mime.prototype.lookup = function(path, fallback) { + var ext = path.replace(/.*[\.\/]/, '').toLowerCase(); + + return this.types[ext] || fallback || this.default_type; +}; + +/** + * Return file extension associated with a mime type + */ +Mime.prototype.extension = function(mimeType) { + var type = mimeType.match(/^\s*([^;\s]*)(?:;|\s|$)/)[1].toLowerCase(); + return this.extensions[type]; +}; + +// Default instance +var mime = new Mime(); + +// Load local copy of +// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types +mime.load(path.join(__dirname, 'types/mime.types')); + +// Load additional types from node.js community +mime.load(path.join(__dirname, 'types/node.types')); + +// Default type +mime.default_type = mime.lookup('bin'); + +// +// Additional API specific to the default instance +// + +mime.Mime = Mime; + +/** + * Lookup a charset based on mime type. + */ +mime.charsets = { + lookup: function(mimeType, fallback) { + // Assume text types are utf8 + return (/^text\//).test(mimeType) ? 'UTF-8' : fallback; + } +}; + +module.exports = mime; diff --git a/node_modules/express/node_modules/send/node_modules/mime/package.json b/node_modules/express/node_modules/send/node_modules/mime/package.json new file mode 100644 index 0000000..5b836b6 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/package.json @@ -0,0 +1,39 @@ +{ + "author": { + "name": "Robert Kieffer", + "email": "robert@broofa.com", + "url": "http://github.com/broofa" + }, + "contributors": [ + { + "name": "Benjamin Thomas", + "email": "benjamin@benjaminthomas.org", + "url": "http://github.com/bentomas" + } + ], + "dependencies": {}, + "description": "A comprehensive library for mime-type mapping", + "devDependencies": {}, + "keywords": [ + "util", + "mime" + ], + "main": "mime.js", + "name": "mime", + "repository": { + "url": "https://github.com/broofa/node-mime", + "type": "git" + }, + "version": "1.2.10", + "readme": "# mime\n\nComprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community.\n\n## Install\n\nInstall with [npm](http://github.com/isaacs/npm):\n\n npm install mime\n\n## API - Queries\n\n### mime.lookup(path)\nGet the mime type associated with a file, if no mime type is found `application/octet-stream` is returned. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g.\n\n var mime = require('mime');\n\n mime.lookup('/path/to/file.txt'); // => 'text/plain'\n mime.lookup('file.txt'); // => 'text/plain'\n mime.lookup('.TXT'); // => 'text/plain'\n mime.lookup('htm'); // => 'text/html'\n\n### mime.default_type\nSets the mime type returned when `mime.lookup` fails to find the extension searched for. (Default is `application/octet-stream`.)\n\n### mime.extension(type)\nGet the default extension for `type`\n\n mime.extension('text/html'); // => 'html'\n mime.extension('application/octet-stream'); // => 'bin'\n\n### mime.charsets.lookup()\n\nMap mime-type to charset\n\n mime.charsets.lookup('text/plain'); // => 'UTF-8'\n\n(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.)\n\n## API - Defining Custom Types\n\nThe following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types).\n\n### mime.define()\n\nAdd custom mime/extension mappings\n\n mime.define({\n 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'],\n 'application/x-my-type': ['x-mt', 'x-mtt'],\n // etc ...\n });\n\n mime.lookup('x-sft'); // => 'text/x-some-format'\n\nThe first entry in the extensions array is returned by `mime.extension()`. E.g.\n\n mime.extension('text/x-some-format'); // => 'x-sf'\n\n### mime.load(filepath)\n\nLoad mappings from an Apache \".types\" format file\n\n mime.load('./my_project.types');\n\nThe .types file format is simple - See the `types` dir for examples.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/broofa/node-mime/issues" + }, + "_id": "mime@1.2.10", + "dist": { + "shasum": "a5e2a8b618f5ded19cd4be31c9993f817015898c" + }, + "_from": "mime@~1.2.9", + "_resolved": "https://registry.npmjs.org/mime/-/mime-1.2.10.tgz" +} diff --git a/node_modules/express/node_modules/send/node_modules/mime/test.js b/node_modules/express/node_modules/send/node_modules/mime/test.js new file mode 100644 index 0000000..27df440 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/test.js @@ -0,0 +1,84 @@ +/** + * Usage: node test.js + */ + +var mime = require('./mime'); +var assert = require('assert'); +var path = require('path'); + +function eq(a, b) { + console.log('Test: ' + a + ' === ' + b); + assert.strictEqual.apply(null, arguments); +} + +console.log(Object.keys(mime.extensions).length + ' types'); +console.log(Object.keys(mime.types).length + ' extensions\n'); + +// +// Test mime lookups +// + +eq('text/plain', mime.lookup('text.txt')); +eq('text/plain', mime.lookup('.text.txt')); +eq('text/plain', mime.lookup('.txt')); +eq('text/plain', mime.lookup('txt')); +eq('application/octet-stream', mime.lookup('text.nope')); +eq('fallback', mime.lookup('text.fallback', 'fallback')); +eq('application/octet-stream', mime.lookup('constructor')); +eq('text/plain', mime.lookup('TEXT.TXT')); +eq('text/event-stream', mime.lookup('text/event-stream')); +eq('application/x-web-app-manifest+json', mime.lookup('text.webapp')); + +// +// Test extensions +// + +eq('txt', mime.extension(mime.types.text)); +eq('html', mime.extension(mime.types.htm)); +eq('bin', mime.extension('application/octet-stream')); +eq('bin', mime.extension('application/octet-stream ')); +eq('html', mime.extension(' text/html; charset=UTF-8')); +eq('html', mime.extension('text/html; charset=UTF-8 ')); +eq('html', mime.extension('text/html; charset=UTF-8')); +eq('html', mime.extension('text/html ; charset=UTF-8')); +eq('html', mime.extension('text/html;charset=UTF-8')); +eq('html', mime.extension('text/Html;charset=UTF-8')); +eq(undefined, mime.extension('constructor')); + +// +// Test node types +// + +eq('application/font-woff', mime.lookup('file.woff')); +eq('application/octet-stream', mime.lookup('file.buffer')); +eq('audio/mp4', mime.lookup('file.m4a')); +eq('font/opentype', mime.lookup('file.otf')); + +// +// Test charsets +// + +eq('UTF-8', mime.charsets.lookup('text/plain')); +eq(undefined, mime.charsets.lookup(mime.types.js)); +eq('fallback', mime.charsets.lookup('application/octet-stream', 'fallback')); + +// +// Test for overlaps between mime.types and node.types +// + +var apacheTypes = new mime.Mime(), nodeTypes = new mime.Mime(); +apacheTypes.load(path.join(__dirname, 'types/mime.types')); +nodeTypes.load(path.join(__dirname, 'types/node.types')); + +var keys = [].concat(Object.keys(apacheTypes.types)) + .concat(Object.keys(nodeTypes.types)); +keys.sort(); +for (var i = 1; i < keys.length; i++) { + if (keys[i] == keys[i-1]) { + console.warn('Warning: ' + + 'node.types defines ' + keys[i] + '->' + nodeTypes.types[keys[i]] + + ', mime.types defines ' + keys[i] + '->' + apacheTypes.types[keys[i]]); + } +} + +console.log('\nOK'); diff --git a/node_modules/express/node_modules/send/node_modules/mime/types/mime.types b/node_modules/express/node_modules/send/node_modules/mime/types/mime.types new file mode 100644 index 0000000..da8cd69 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/types/mime.types @@ -0,0 +1,1588 @@ +# This file maps Internet media types to unique file extension(s). +# Although created for httpd, this file is used by many software systems +# and has been placed in the public domain for unlimited redisribution. +# +# The table below contains both registered and (common) unregistered types. +# A type that has no unique extension can be ignored -- they are listed +# here to guide configurations toward known types and to make it easier to +# identify "new" types. File extensions are also commonly used to indicate +# content languages and encodings, so choose them carefully. +# +# Internet media types should be registered as described in RFC 4288. +# The registry is at . +# +# MIME type (lowercased) Extensions +# ============================================ ========== +# application/1d-interleaved-parityfec +# application/3gpp-ims+xml +# application/activemessage +application/andrew-inset ez +# application/applefile +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +# application/atomicmail +application/atomsvc+xml atomsvc +# application/auth-policy+xml +# application/batch-smtp +# application/beep+xml +# application/calendar+xml +# application/cals-1840 +# application/ccmp+xml +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +# application/cea-2018+xml +# application/cellml+xml +# application/cfw +# application/cnrp+xml +# application/commonground +# application/conference-info+xml +# application/cpl+xml +# application/csta+xml +# application/cstadata+xml +application/cu-seeme cu +# application/cybercash +application/davmount+xml davmount +# application/dca-rft +# application/dec-dx +# application/dialog-info+xml +# application/dicom +# application/dns +application/docbook+xml dbk +# application/dskpp+xml +application/dssc+der dssc +application/dssc+xml xdssc +# application/dvcs +application/ecmascript ecma +# application/edi-consent +# application/edi-x12 +# application/edifact +application/emma+xml emma +# application/epp+xml +application/epub+zip epub +# application/eshop +# application/example +application/exi exi +# application/fastinfoset +# application/fastsoap +# application/fits +application/font-tdpfr pfr +# application/framework-attributes+xml +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +# application/h224 +# application/held+xml +# application/http +application/hyperstudio stk +# application/ibe-key-request+xml +# application/ibe-pkg-reply+xml +# application/ibe-pp-data +# application/iges +# application/im-iscomposing+xml +# application/index +# application/index.cmd +# application/index.obj +# application/index.response +# application/index.vnd +application/inkml+xml ink inkml +# application/iotp +application/ipfix ipfix +# application/ipp +# application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/jsonml+json jsonml +# application/kpml-request+xml +# application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +# application/macwriteii +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma nb mb +# application/mathml-content+xml +# application/mathml-presentation+xml +application/mathml+xml mathml +# application/mbms-associated-procedure-description+xml +# application/mbms-deregister+xml +# application/mbms-envelope+xml +# application/mbms-msk+xml +# application/mbms-msk-response+xml +# application/mbms-protection-description+xml +# application/mbms-reception-report+xml +# application/mbms-register+xml +# application/mbms-register-response+xml +# application/mbms-user-service-description+xml +application/mbox mbox +# application/media_control+xml +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +# application/mikey +application/mods+xml mods +# application/moss-keys +# application/moss-signature +# application/mosskey-data +# application/mosskey-request +application/mp21 m21 mp21 +application/mp4 mp4s +# application/mpeg4-generic +# application/mpeg4-iod +# application/mpeg4-iod-xmt +# application/msc-ivr+xml +# application/msc-mixer+xml +application/msword doc dot +application/mxf mxf +# application/nasdata +# application/news-checkgroups +# application/news-groupinfo +# application/news-transmission +# application/nss +# application/ocsp-request +# application/ocsp-response +application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onetoc onetoc2 onetmp onepkg +application/oxps oxps +# application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +# application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +# application/pidf+xml +# application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +# application/poc-settings+xml +application/postscript ai eps ps +# application/prs.alvestrand.titrax-sheet +application/prs.cww cww +# application/prs.nprend +# application/prs.plucker +# application/prs.rdf-xml-crypt +# application/prs.xsf+xml +application/pskc+xml pskcxml +# application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +# application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +# application/riscos +# application/rlmi+xml +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +# application/rpki-updown +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +# application/rtx +# application/samlassertion+xml +# application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +# application/set-payment +application/set-payment-initiation setpay +# application/set-registration +application/set-registration-initiation setreg +# application/sgml +# application/sgml-open-catalog +application/shf+xml shf +# application/sieve +# application/simple-filter+xml +# application/simple-message-summary +# application/simplesymbolcontainer +# application/slate +# application/smil +application/smil+xml smi smil +# application/soap+fastinfoset +# application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +# application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +# application/tamp-apex-update +# application/tamp-apex-update-confirm +# application/tamp-community-update +# application/tamp-community-update-confirm +# application/tamp-error +# application/tamp-sequence-adjust +# application/tamp-sequence-adjust-confirm +# application/tamp-status-query +# application/tamp-status-response +# application/tamp-update +# application/tamp-update-confirm +application/tei+xml tei teicorpus +application/thraud+xml tfi +# application/timestamp-query +# application/timestamp-reply +application/timestamped-data tsd +# application/tve-trigger +# application/ulpfec +# application/vcard+xml +# application/vemmi +# application/vividence.scriptfile +# application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +# application/vnd.3gpp.sms +# application/vnd.3gpp2.bcmcsinfo+xml +# application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +# application/vnd.adobe.partial-upload +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +# application/vnd.aether.imp +# application/vnd.ah-barcode +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +# application/vnd.amundsen.maze+xml +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +# application/vnd.arastra.swi +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +# application/vnd.autopackage +# application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +# application/vnd.bluetooth.ep.oob +application/vnd.bmi bmi +application/vnd.businessobjects rep +# application/vnd.cab-jscript +# application/vnd.canon-cpdl +# application/vnd.canon-lips +# application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +# application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +# application/vnd.collection+json +# application/vnd.commerce-battelle +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +# application/vnd.ctct.ws+xml +# application/vnd.cups-pdf +# application/vnd.cups-postscript +application/vnd.cups-ppd ppd +# application/vnd.cups-raster +# application/vnd.cups-raw +# application/vnd.curl +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +# application/vnd.cybank +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.dece.zip uvz uvvz +application/vnd.denovo.fcselayout-link fe_launch +# application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dna dna +application/vnd.dolby.mlp mlp +# application/vnd.dolby.mobile.1 +# application/vnd.dolby.mobile.2 +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +# application/vnd.dvb.dvbj +# application/vnd.dvb.esgcontainer +# application/vnd.dvb.ipdcdftnotifaccess +# application/vnd.dvb.ipdcesgaccess +# application/vnd.dvb.ipdcesgaccess2 +# application/vnd.dvb.ipdcesgpdd +# application/vnd.dvb.ipdcroaming +# application/vnd.dvb.iptv.alfec-base +# application/vnd.dvb.iptv.alfec-enhancement +# application/vnd.dvb.notif-aggregate-root+xml +# application/vnd.dvb.notif-container+xml +# application/vnd.dvb.notif-generic+xml +# application/vnd.dvb.notif-ia-msglist+xml +# application/vnd.dvb.notif-ia-registration-request+xml +# application/vnd.dvb.notif-ia-registration-response+xml +# application/vnd.dvb.notif-init+xml +# application/vnd.dvb.pfr +application/vnd.dvb.service svc +# application/vnd.dxr +application/vnd.dynageo geo +# application/vnd.easykaraoke.cdgdownload +# application/vnd.ecdis-update +application/vnd.ecowin.chart mag +# application/vnd.ecowin.filerequest +# application/vnd.ecowin.fileupdate +# application/vnd.ecowin.series +# application/vnd.ecowin.seriesrequest +# application/vnd.ecowin.seriesupdate +# application/vnd.emclient.accessrequest+xml +application/vnd.enliven nml +# application/vnd.eprints.data+xml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +# application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +# application/vnd.etsi.aoc+xml +# application/vnd.etsi.cug+xml +# application/vnd.etsi.iptvcommand+xml +# application/vnd.etsi.iptvdiscovery+xml +# application/vnd.etsi.iptvprofile+xml +# application/vnd.etsi.iptvsad-bc+xml +# application/vnd.etsi.iptvsad-cod+xml +# application/vnd.etsi.iptvsad-npvr+xml +# application/vnd.etsi.iptvservice+xml +# application/vnd.etsi.iptvsync+xml +# application/vnd.etsi.iptvueprofile+xml +# application/vnd.etsi.mcid+xml +# application/vnd.etsi.overload-control-policy-dataset+xml +# application/vnd.etsi.sci+xml +# application/vnd.etsi.simservs+xml +# application/vnd.etsi.tsl+xml +# application/vnd.etsi.tsl.der +# application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +# application/vnd.f-secure.mobile +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed dataless +# application/vnd.ffsns +# application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +# application/vnd.font-fontforge-sfd +application/vnd.framemaker fm frame maker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +# application/vnd.fujixerox.art-ex +# application/vnd.fujixerox.art4 +# application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +# application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +# application/vnd.geocube+xml +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +# application/vnd.globalplatform.card-content-mgt +# application/vnd.globalplatform.card-content-mgt-response +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +# application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +# application/vnd.hal+json +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +# application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +# application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +# application/vnd.hzn-3d-crossword +# application/vnd.ibm.afplinedata +# application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +# application/vnd.informedcontrol.rms+xml +# application/vnd.informix-visionary +# application/vnd.infotech.project +# application/vnd.infotech.project+xml +# application/vnd.innopath.wamp.notification +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +# application/vnd.intertrust.digibox +# application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +# application/vnd.iptc.g2.conceptitem+xml +# application/vnd.iptc.g2.knowledgeitem+xml +# application/vnd.iptc.g2.newsitem+xml +# application/vnd.iptc.g2.newsmessage+xml +# application/vnd.iptc.g2.packageitem+xml +# application/vnd.iptc.g2.planningitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +# application/vnd.japannet-directory-service +# application/vnd.japannet-jpnstore-wakeup +# application/vnd.japannet-payment-wakeup +# application/vnd.japannet-registration +# application/vnd.japannet-registration-wakeup +# application/vnd.japannet-setstore-wakeup +# application/vnd.japannet-verification +# application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +# application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +# application/vnd.marlin.drm.actiontoken+xml +# application/vnd.marlin.drm.conftoken+xml +# application/vnd.marlin.drm.license+xml +# application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +# application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +# application/vnd.minisoft-hp3000-save +# application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +# application/vnd.motorola.flexsuite +# application/vnd.motorola.flexsuite.adsi +# application/vnd.motorola.flexsuite.fis +# application/vnd.motorola.flexsuite.gotap +# application/vnd.motorola.flexsuite.kmr +# application/vnd.motorola.flexsuite.ttc +# application/vnd.motorola.flexsuite.wem +# application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +# application/vnd.ms-asf +application/vnd.ms-cab-compressed cab +# application/vnd.ms-color.iccprofile +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +# application/vnd.ms-office.activex+xml +application/vnd.ms-officetheme thmx +# application/vnd.ms-opentype +# application/vnd.ms-package.obfuscated-opentype +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +# application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +# application/vnd.ms-printing.printticket+xml +application/vnd.ms-project mpp mpt +# application/vnd.ms-tnef +# application/vnd.ms-wmdrm.lic-chlg-req +# application/vnd.ms-wmdrm.lic-resp +# application/vnd.ms-wmdrm.meter-chlg-req +# application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +# application/vnd.msign +# application/vnd.multiad.creator +# application/vnd.multiad.creator.cif +# application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +# application/vnd.ncd.control +# application/vnd.ncd.reference +# application/vnd.nervana +# application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf ntf nitf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +# application/vnd.nokia.catalogs +# application/vnd.nokia.conml+wbxml +# application/vnd.nokia.conml+xml +# application/vnd.nokia.isds-radio-presets +# application/vnd.nokia.iptv.config+xml +# application/vnd.nokia.landmark+wbxml +# application/vnd.nokia.landmark+xml +# application/vnd.nokia.landmarkcollection+xml +# application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +# application/vnd.nokia.ncd +# application/vnd.nokia.pcd+wbxml +# application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +# application/vnd.ntt-local.file-transfer +# application/vnd.ntt-local.sip-ta_remote +# application/vnd.ntt-local.sip-ta_tcp_stream +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +# application/vnd.obn +# application/vnd.oftn.l10n+json +# application/vnd.oipf.contentaccessdownload+xml +# application/vnd.oipf.contentaccessstreaming+xml +# application/vnd.oipf.cspg-hexbinary +# application/vnd.oipf.dae.svg+xml +# application/vnd.oipf.dae.xhtml+xml +# application/vnd.oipf.mippvcontrolmessage+xml +# application/vnd.oipf.pae.gem +# application/vnd.oipf.spdiscovery+xml +# application/vnd.oipf.spdlist+xml +# application/vnd.oipf.ueprofile+xml +# application/vnd.oipf.userprofile+xml +application/vnd.olpc-sugar xo +# application/vnd.oma-scws-config +# application/vnd.oma-scws-http-request +# application/vnd.oma-scws-http-response +# application/vnd.oma.bcast.associated-procedure-parameter+xml +# application/vnd.oma.bcast.drm-trigger+xml +# application/vnd.oma.bcast.imd+xml +# application/vnd.oma.bcast.ltkm +# application/vnd.oma.bcast.notification+xml +# application/vnd.oma.bcast.provisioningtrigger +# application/vnd.oma.bcast.sgboot +# application/vnd.oma.bcast.sgdd+xml +# application/vnd.oma.bcast.sgdu +# application/vnd.oma.bcast.simple-symbol-container +# application/vnd.oma.bcast.smartcard-trigger+xml +# application/vnd.oma.bcast.sprov+xml +# application/vnd.oma.bcast.stkm +# application/vnd.oma.cab-address-book+xml +# application/vnd.oma.cab-feature-handler+xml +# application/vnd.oma.cab-pcc+xml +# application/vnd.oma.cab-user-prefs+xml +# application/vnd.oma.dcd +# application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +# application/vnd.oma.drm.risd+xml +# application/vnd.oma.group-usage-list+xml +# application/vnd.oma.pal+xml +# application/vnd.oma.poc.detailed-progress-report+xml +# application/vnd.oma.poc.final-report+xml +# application/vnd.oma.poc.groups+xml +# application/vnd.oma.poc.invocation-descriptor+xml +# application/vnd.oma.poc.optimized-progress-report+xml +# application/vnd.oma.push +# application/vnd.oma.scidm.messages+xml +# application/vnd.oma.xcap-directory+xml +# application/vnd.omads-email+xml +# application/vnd.omads-file+xml +# application/vnd.omads-folder+xml +# application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +# application/vnd.openxmlformats-officedocument.custom-properties+xml +# application/vnd.openxmlformats-officedocument.customxmlproperties+xml +# application/vnd.openxmlformats-officedocument.drawing+xml +# application/vnd.openxmlformats-officedocument.drawingml.chart+xml +# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml +# application/vnd.openxmlformats-officedocument.extended-properties+xml +# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml +# application/vnd.openxmlformats-officedocument.presentationml.comments+xml +# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +# application/vnd.openxmlformats-officedocument.presentationml.slide+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml +# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml +# application/vnd.openxmlformats-officedocument.presentationml.tags+xml +application/vnd.openxmlformats-officedocument.presentationml.template potx +# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml +# application/vnd.openxmlformats-officedocument.theme+xml +# application/vnd.openxmlformats-officedocument.themeoverride+xml +# application/vnd.openxmlformats-officedocument.vmldrawing +# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml +# application/vnd.openxmlformats-package.core-properties+xml +# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml +# application/vnd.openxmlformats-package.relationships+xml +# application/vnd.quobject-quoxdocument +# application/vnd.osa.netdeploy +application/vnd.osgeo.mapguide.package mgp +# application/vnd.osgi.bundle +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +# application/vnd.otps.ct-kip+xml +application/vnd.palm pdb pqa oprc +# application/vnd.paos.xml +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +# application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.pmi.widget wg +# application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +# application/vnd.powerbuilder6-s +# application/vnd.powerbuilder7 +# application/vnd.powerbuilder7-s +# application/vnd.powerbuilder75 +# application/vnd.powerbuilder75-s +# application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +# application/vnd.pwg-multiplexed +# application/vnd.pwg-xhtml-print+xml +# application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +# application/vnd.radisys.moml+xml +# application/vnd.radisys.msml+xml +# application/vnd.radisys.msml-audit+xml +# application/vnd.radisys.msml-audit-conf+xml +# application/vnd.radisys.msml-audit-conn+xml +# application/vnd.radisys.msml-audit-dialog+xml +# application/vnd.radisys.msml-audit-stream+xml +# application/vnd.radisys.msml-conf+xml +# application/vnd.radisys.msml-dialog+xml +# application/vnd.radisys.msml-dialog-base+xml +# application/vnd.radisys.msml-dialog-fax-detect+xml +# application/vnd.radisys.msml-dialog-fax-sendrecv+xml +# application/vnd.radisys.msml-dialog-group+xml +# application/vnd.radisys.msml-dialog-speech+xml +# application/vnd.radisys.msml-dialog-transform+xml +# application/vnd.rainstor.data +# application/vnd.rapid +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +# application/vnd.renlearn.rlprint +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +# application/vnd.rs-274x +# application/vnd.ruckus.download +# application/vnd.s3sms +application/vnd.sailingtracker.track st +# application/vnd.sbm.cid +# application/vnd.sbm.mid2 +# application/vnd.scribus +# application/vnd.sealed.3df +# application/vnd.sealed.csf +# application/vnd.sealed.doc +# application/vnd.sealed.eml +# application/vnd.sealed.mht +# application/vnd.sealed.net +# application/vnd.sealed.ppt +# application/vnd.sealed.tiff +# application/vnd.sealed.xls +# application/vnd.sealedmedia.softseal.html +# application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +# application/vnd.smart.notebook +application/vnd.smart.teacher teacher +# application/vnd.software602.filler.form+xml +# application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +# application/vnd.sss-cod +# application/vnd.sss-dtf +# application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +# application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +# application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +# application/vnd.swiftview-ics +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +# application/vnd.syncml.dm.notification +# application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +# application/vnd.truedoc +# application/vnd.ubisoft.webplayer +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +# application/vnd.uplanet.alert +# application/vnd.uplanet.alert-wbxml +# application/vnd.uplanet.bearer-choice +# application/vnd.uplanet.bearer-choice-wbxml +# application/vnd.uplanet.cacheop +# application/vnd.uplanet.cacheop-wbxml +# application/vnd.uplanet.channel +# application/vnd.uplanet.channel-wbxml +# application/vnd.uplanet.list +# application/vnd.uplanet.list-wbxml +# application/vnd.uplanet.listcmd +# application/vnd.uplanet.listcmd-wbxml +# application/vnd.uplanet.signal +application/vnd.vcx vcx +# application/vnd.vd-study +# application/vnd.vectorworks +# application/vnd.verimatrix.vcas +# application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +# application/vnd.vividence.scriptfile +application/vnd.vsf vsf +# application/vnd.wap.sic +# application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +# application/vnd.wfa.wsc +# application/vnd.wmc +# application/vnd.wmf.bootstrap +# application/vnd.wolfram.mathematica +# application/vnd.wolfram.mathematica.package +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +# application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +# application/vnd.wv.csp+wbxml +# application/vnd.wv.csp+xml +# application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +# application/vnd.xfdl.webform +# application/vnd.xmi+xml +# application/vnd.xmpie.cpkg +# application/vnd.xmpie.dpkg +# application/vnd.xmpie.plan +# application/vnd.xmpie.ppkg +# application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +# application/vnd.yamaha.remote-setup +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +# application/vnd.yamaha.through-ngn +# application/vnd.yamaha.tunnel-udpencap +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +# application/vq-rtcpxr +# application/watcherinfo+xml +# application/whoispp-query +# application/whoispp-response +application/widget wgt +application/winhlp hlp +# application/wita +# application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +# application/x-amf +application/x-apple-diskimage dmg +application/x-authorware-bin aab x32 u32 vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cbr cbr cba cbt cbz cb7 +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-conference nsc +# application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-dgc-compressed dgc +application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +# application/x-font-dos +# application/x-font-framemaker +application/x-font-ghostscript gsf +# application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf otf +application/x-font-pcf pcf +application/x-font-snf snf +# application/x-font-speedo +# application/x-font-sunos-news +application/x-font-ttf ttf ttc +application/x-font-type1 pfa pfb pfm afm +application/font-woff woff +# application/x-font-vfont +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +# application/x-gzip +application/x-hdf hdf +application/x-install-instructions install +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-lzh-compressed lzh lha +application/x-mie mie +application/x-mobipocket-ebook prc mobi +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf wmz emf emz +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-nzb nzb +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-research-info-systems ris +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-tgif obj +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +# application/x400-bp +application/xaml+xml xaml +# application/xcap-att+xml +# application/xcap-caps+xml +application/xcap-diff+xml xdf +# application/xcap-el+xml +# application/xcap-error+xml +# application/xcap-ns+xml +# application/xcon-conference-info-diff+xml +# application/xcon-conference-info+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +# application/xhtml-voice+xml +application/xml xml xsl +application/xml-dtd dtd +# application/xml-external-parsed-entity +# application/xmpp+xml +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yin+xml yin +application/zip zip +# audio/1d-interleaved-parityfec +# audio/32kadpcm +# audio/3gpp +# audio/3gpp2 +# audio/ac3 +audio/adpcm adp +# audio/amr +# audio/amr-wb +# audio/amr-wb+ +# audio/asc +# audio/atrac-advanced-lossless +# audio/atrac-x +# audio/atrac3 +audio/basic au snd +# audio/bv16 +# audio/bv32 +# audio/clearmode +# audio/cn +# audio/dat12 +# audio/dls +# audio/dsr-es201108 +# audio/dsr-es202050 +# audio/dsr-es202211 +# audio/dsr-es202212 +# audio/dv +# audio/dvi4 +# audio/eac3 +# audio/evrc +# audio/evrc-qcp +# audio/evrc0 +# audio/evrc1 +# audio/evrcb +# audio/evrcb0 +# audio/evrcb1 +# audio/evrcwb +# audio/evrcwb0 +# audio/evrcwb1 +# audio/example +# audio/fwdred +# audio/g719 +# audio/g722 +# audio/g7221 +# audio/g723 +# audio/g726-16 +# audio/g726-24 +# audio/g726-32 +# audio/g726-40 +# audio/g728 +# audio/g729 +# audio/g7291 +# audio/g729d +# audio/g729e +# audio/gsm +# audio/gsm-efr +# audio/gsm-hr-08 +# audio/ilbc +# audio/ip-mr_v2.5 +# audio/isac +# audio/l16 +# audio/l20 +# audio/l24 +# audio/l8 +# audio/lpc +audio/midi mid midi kar rmi +# audio/mobile-xmf +audio/mp4 mp4a +# audio/mp4a-latm +# audio/mpa +# audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +# audio/mpeg4-generic +# audio/musepack +audio/ogg oga ogg spx +# audio/opus +# audio/parityfec +# audio/pcma +# audio/pcma-wb +# audio/pcmu-wb +# audio/pcmu +# audio/prs.sid +# audio/qcelp +# audio/red +# audio/rtp-enc-aescm128 +# audio/rtp-midi +# audio/rtx +audio/s3m s3m +audio/silk sil +# audio/smv +# audio/smv0 +# audio/smv-qcp +# audio/sp-midi +# audio/speex +# audio/t140c +# audio/t38 +# audio/telephone-event +# audio/tone +# audio/uemclip +# audio/ulpfec +# audio/vdvi +# audio/vmr-wb +# audio/vnd.3gpp.iufp +# audio/vnd.4sb +# audio/vnd.audiokoz +# audio/vnd.celp +# audio/vnd.cisco.nse +# audio/vnd.cmles.radio-events +# audio/vnd.cns.anp1 +# audio/vnd.cns.inf1 +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +# audio/vnd.dlna.adts +# audio/vnd.dolby.heaac.1 +# audio/vnd.dolby.heaac.2 +# audio/vnd.dolby.mlp +# audio/vnd.dolby.mps +# audio/vnd.dolby.pl2 +# audio/vnd.dolby.pl2x +# audio/vnd.dolby.pl2z +# audio/vnd.dolby.pulse.1 +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +# audio/vnd.dvb.file +# audio/vnd.everad.plj +# audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +# audio/vnd.nokia.mobile-xmf +# audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +# audio/vnd.octel.sbc +# audio/vnd.qcelp +# audio/vnd.rhetorex.32kadpcm +audio/vnd.rip rip +# audio/vnd.sealedmedia.softseal.mpeg +# audio/vnd.vmx.cvsd +# audio/vorbis +# audio/vorbis-config +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aiff aifc +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +# audio/x-tta +audio/x-wav wav +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +# chemical/x-pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +# image/example +# image/fits +image/g3fax g3 +image/gif gif +image/ief ief +# image/jp2 +image/jpeg jpeg jpg jpe +# image/jpm +# image/jpx +image/ktx ktx +# image/naplps +image/png png +image/prs.btif btif +# image/prs.pti +image/sgi sgi +image/svg+xml svg svgz +# image/t38 +image/tiff tiff tif +# image/tiff-fx +image/vnd.adobe.photoshop psd +# image/vnd.cns.inf2 +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.dvb.subtitle sub +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +# image/vnd.globalgraphics.pgb +# image/vnd.microsoft.icon +# image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +# image/vnd.radiance +# image/vnd.sealed.png +# image/vnd.sealedmedia.softseal.gif +# image/vnd.sealedmedia.softseal.jpg +# image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +image/x-mrsid-image sid +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +# message/cpim +# message/delivery-status +# message/disposition-notification +# message/example +# message/external-body +# message/feedback-report +# message/global +# message/global-delivery-status +# message/global-disposition-notification +# message/global-headers +# message/http +# message/imdn+xml +# message/news +# message/partial +message/rfc822 eml mime +# message/s-http +# message/sip +# message/sipfrag +# message/tracking-status +# message/vnd.si.simp +# model/example +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +# model/vnd.flatland.3dml +model/vnd.gdl gdl +# model/vnd.gs-gdl +# model/vnd.gs.gdl +model/vnd.gtw gtw +# model/vnd.moml+xml +model/vnd.mts mts +# model/vnd.parasolid.transmit.binary +# model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +# multipart/alternative +# multipart/appledouble +# multipart/byteranges +# multipart/digest +# multipart/encrypted +# multipart/example +# multipart/form-data +# multipart/header-set +# multipart/mixed +# multipart/parallel +# multipart/related +# multipart/report +# multipart/signed +# multipart/voice-message +# text/1d-interleaved-parityfec +text/cache-manifest appcache +text/calendar ics ifb +text/css css +text/csv csv +# text/directory +# text/dns +# text/ecmascript +# text/enriched +# text/example +# text/fwdred +text/html html htm +# text/javascript +text/n3 n3 +# text/parityfec +text/plain txt text conf def list log in +# text/prs.fallenstein.rst +text/prs.lines.tag dsc +# text/vnd.radisys.msml-basic-layout +# text/red +# text/rfc822-headers +text/richtext rtx +# text/rtf +# text/rtp-enc-aescm128 +# text/rtx +text/sgml sgml sgm +# text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/turtle ttl +# text/ulpfec +text/uri-list uri uris urls +text/vcard vcard +# text/vnd.abc +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.scurl scurl +text/vnd.curl.mcurl mcurl +# text/vnd.dmclientscript +text/vnd.dvb.subtitle sub +# text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +# text/vnd.iptc.newsml +# text/vnd.iptc.nitf +# text/vnd.latex-z +# text/vnd.motorola.reflex +# text/vnd.ms-mediapackage +# text/vnd.net2phone.commcenter.command +# text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +# text/vnd.trolltech.linguist +# text/vnd.wap.si +# text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-java-source java +text/x-opml opml +text/x-pascal p pas +text/x-nfo nfo +text/x-setext etx +text/x-sfv sfv +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +# text/xml +# text/xml-external-parsed-entity +# video/1d-interleaved-parityfec +video/3gpp 3gp +# video/3gpp-tt +video/3gpp2 3g2 +# video/bmpeg +# video/bt656 +# video/celb +# video/dv +# video/example +video/h261 h261 +video/h263 h263 +# video/h263-1998 +# video/h263-2000 +video/h264 h264 +# video/h264-rcdo +# video/h264-svc +video/jpeg jpgv +# video/jpeg2000 +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +# video/mp1s +# video/mp2p +# video/mp2t +video/mp4 mp4 mp4v mpg4 +# video/mp4v-es +video/mpeg mpeg mpg mpe m1v m2v +# video/mpeg4-generic +# video/mpv +# video/nv +video/ogg ogv +# video/parityfec +# video/pointer +video/quicktime qt mov +# video/raw +# video/rtp-enc-aescm128 +# video/rtx +# video/smpte292m +# video/ulpfec +# video/vc1 +# video/vnd.cctv +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +# video/vnd.dece.mp4 +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +# video/vnd.directv.mpeg +# video/vnd.directv.mpeg-tts +# video/vnd.dlna.mpeg-tts +video/vnd.dvb.file dvb +video/vnd.fvt fvt +# video/vnd.hns.video +# video/vnd.iptvforum.1dparityfec-1010 +# video/vnd.iptvforum.1dparityfec-2005 +# video/vnd.iptvforum.2dparityfec-1010 +# video/vnd.iptvforum.2dparityfec-2005 +# video/vnd.iptvforum.ttsavc +# video/vnd.iptvforum.ttsmpeg2 +# video/vnd.motorola.video +# video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +# video/vnd.nokia.interleaved-multimedia +# video/vnd.nokia.videovoip +# video/vnd.objectvideo +# video/vnd.sealed.mpeg1 +# video/vnd.sealed.mpeg4 +# video/vnd.sealed.swf +# video/vnd.sealedmedia.softseal.mov +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mkv mk3d mks +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice diff --git a/node_modules/express/node_modules/send/node_modules/mime/types/node.types b/node_modules/express/node_modules/send/node_modules/mime/types/node.types new file mode 100644 index 0000000..55b2cf7 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/types/node.types @@ -0,0 +1,77 @@ +# What: WebVTT +# Why: To allow formats intended for marking up external text track resources. +# http://dev.w3.org/html5/webvtt/ +# Added by: niftylettuce +text/vtt vtt + +# What: Google Chrome Extension +# Why: To allow apps to (work) be served with the right content type header. +# http://codereview.chromium.org/2830017 +# Added by: niftylettuce +application/x-chrome-extension crx + +# What: HTC support +# Why: To properly render .htc files such as CSS3PIE +# Added by: niftylettuce +text/x-component htc + +# What: HTML5 application cache manifes ('.manifest' extension) +# Why: De-facto standard. Required by Mozilla browser when serving HTML5 apps +# per https://developer.mozilla.org/en/offline_resources_in_firefox +# Added by: louisremi +text/cache-manifest manifest + +# What: node binary buffer format +# Why: semi-standard extension w/in the node community +# Added by: tootallnate +application/octet-stream buffer + +# What: The "protected" MP-4 formats used by iTunes. +# Why: Required for streaming music to browsers (?) +# Added by: broofa +application/mp4 m4p +audio/mp4 m4a + +# What: Video format, Part of RFC1890 +# Why: See https://github.com/bentomas/node-mime/pull/6 +# Added by: mjrusso +video/MP2T ts + +# What: EventSource mime type +# Why: mime type of Server-Sent Events stream +# http://www.w3.org/TR/eventsource/#text-event-stream +# Added by: francois2metz +text/event-stream event-stream + +# What: Mozilla App manifest mime type +# Why: https://developer.mozilla.org/en/Apps/Manifest#Serving_manifests +# Added by: ednapiranha +application/x-web-app-manifest+json webapp + +# What: Lua file types +# Why: Googling around shows de-facto consensus on these +# Added by: creationix (Issue #45) +text/x-lua lua +application/x-lua-bytecode luac + +# What: Markdown files, as per http://daringfireball.net/projects/markdown/syntax +# Why: http://stackoverflow.com/questions/10701983/what-is-the-mime-type-for-markdown +# Added by: avoidwork +text/x-markdown markdown md mkd + +# What: ini files +# Why: because they're just text files +# Added by: Matthew Kastor +text/plain ini + +# What: DASH Adaptive Streaming manifest +# Why: https://developer.mozilla.org/en-US/docs/DASH_Adaptive_Streaming_for_HTML_5_Video +# Added by: eelcocramer +application/dash+xml mdp + +# What: OpenType font files - http://www.microsoft.com/typography/otspec/ +# Why: Browsers usually ignore the font MIME types and sniff the content, +# but Chrome, shows a warning if OpenType fonts aren't served with +# the `font/opentype` MIME type: http://i.imgur.com/8c5RN8M.png. +# Added by: alrra +font/opentype otf diff --git a/node_modules/express/node_modules/send/package.json b/node_modules/express/node_modules/send/package.json new file mode 100644 index 0000000..89277b0 --- /dev/null +++ b/node_modules/express/node_modules/send/package.json @@ -0,0 +1,45 @@ +{ + "name": "send", + "version": "0.1.3", + "description": "Better streaming static file server with Range and conditional-GET support", + "keywords": [ + "static", + "file", + "server" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": { + "debug": "*", + "mime": "~1.2.9", + "fresh": "0.1.0", + "range-parser": "0.0.4" + }, + "devDependencies": { + "mocha": "*", + "should": "*", + "supertest": "0.0.1", + "connect": "2.x" + }, + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/send.git" + }, + "main": "index", + "readme": "# send\n\n Send is Connect's `static()` extracted for generalized use, a streaming static file\n server supporting partial responses (Ranges), conditional-GET negotiation, high test coverage, and granular events which may be leveraged to take appropriate actions in your application or framework.\n\n## Installation\n\n $ npm install send\n\n## Examples\n\n Small:\n\n```js\nvar http = require('http');\nvar send = require('send');\n\nvar app = http.createServer(function(req, res){\n send(req, req.url).pipe(res);\n}).listen(3000);\n```\n\n Serving from a root directory with custom error-handling:\n\n```js\nvar http = require('http');\nvar send = require('send');\nvar url = require('url');\n\nvar app = http.createServer(function(req, res){\n // your custom error-handling logic:\n function error(err) {\n res.statusCode = err.status || 500;\n res.end(err.message);\n }\n\n // your custom directory handling logic:\n function redirect() {\n res.statusCode = 301;\n res.setHeader('Location', req.url + '/');\n res.end('Redirecting to ' + req.url + '/');\n }\n\n // transfer arbitrary files from within\n // /www/example.com/public/*\n send(req, url.parse(req.url).pathname)\n .root('/www/example.com/public')\n .on('error', error)\n .on('directory', redirect)\n .pipe(res);\n}).listen(3000);\n```\n\n## API\n\n### Events\n\n - `error` an error occurred `(err)`\n - `directory` a directory was requested\n - `file` a file was requested `(path, stat)`\n - `stream` file streaming has started `(stream)`\n - `end` streaming has completed\n\n### .root(dir)\n\n Serve files relative to `path`. Aliased as `.from(dir)`.\n\n### .index(path)\n\n By default send supports \"index.html\" files, to disable this\n invoke `.index(false)` or to supply a new index pass a string.\n\n### .maxage(ms)\n\n Provide a max-age in milliseconds for http caching, defaults to 0.\n\n### .hidden(bool)\n\n Enable or disable transfer of hidden files, defaults to false.\n\n## Error-handling\n\n By default when no `error` listeners are present an automatic response will be made, otherwise you have full control over the response, aka you may show a 5xx page etc.\n\n## Caching\n\n It does _not_ perform internal caching, you should use a reverse proxy cache such\n as Varnish for this, or those fancy things called CDNs. If your application is small enough that it would benefit from single-node memory caching, it's small enough that it does not need caching at all ;).\n\n## Debugging\n\n To enable `debug()` instrumentation output export __DEBUG__:\n\n```\n$ DEBUG=send node app\n```\n\n## Running tests\n\n```\n$ npm install\n$ make test\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/send/issues" + }, + "_id": "send@0.1.3", + "dist": { + "shasum": "9ee28109dafceb5445ebec6af5766dcd9fdfe661" + }, + "_from": "send@0.1.3", + "_resolved": "https://registry.npmjs.org/send/-/send-0.1.3.tgz" +} diff --git a/node_modules/express/package.json b/node_modules/express/package.json new file mode 100644 index 0000000..72ee4d2 --- /dev/null +++ b/node_modules/express/package.json @@ -0,0 +1,88 @@ +{ + "name": "express", + "description": "Sinatra inspired web development framework", + "version": "3.3.4", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "contributors": [ + { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + { + "name": "Aaron Heckmann", + "email": "aaron.heckmann+github@gmail.com" + }, + { + "name": "Ciaran Jessup", + "email": "ciaranj@gmail.com" + }, + { + "name": "Guillermo Rauch", + "email": "rauchg@gmail.com" + } + ], + "dependencies": { + "connect": "2.8.4", + "commander": "1.2.0", + "range-parser": "0.0.4", + "mkdirp": "0.3.5", + "cookie": "0.1.0", + "buffer-crc32": "0.2.1", + "fresh": "0.1.0", + "methods": "0.0.1", + "send": "0.1.3", + "cookie-signature": "1.0.1", + "debug": "*" + }, + "devDependencies": { + "ejs": "*", + "mocha": "*", + "jade": "0.30.0", + "hjs": "*", + "stylus": "*", + "should": "*", + "connect-redis": "*", + "marked": "*", + "supertest": "0.6.0" + }, + "keywords": [ + "express", + "framework", + "sinatra", + "web", + "rest", + "restful", + "router", + "app", + "api" + ], + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/express" + }, + "main": "index", + "bin": { + "express": "./bin/express" + }, + "scripts": { + "prepublish": "npm prune", + "test": "make test" + }, + "engines": { + "node": "*" + }, + "readme": "![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)\n\n Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Dependency Status](https://gemnasium.com/visionmedia/express.png)](https://gemnasium.com/visionmedia/express)\n\n```js\nvar express = require('express');\nvar app = express();\n\napp.get('/', function(req, res){\n res.send('Hello World');\n});\n\napp.listen(3000);\n```\n\n## Installation\n\n $ npm install -g express\n\n## Quick Start\n\n The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:\n\n Create the app:\n\n $ npm install -g express\n $ express /tmp/foo && cd /tmp/foo\n\n Install dependencies:\n\n $ npm install\n\n Start the server:\n\n $ node app\n\n## Features\n\n * Built on [Connect](http://github.com/senchalabs/connect)\n * Robust routing\n * HTTP helpers (redirection, caching, etc)\n * View system supporting 14+ template engines\n * Content negotiation\n * Focus on high performance\n * Environment based configuration\n * Executable for generating applications quickly\n * High test coverage\n\n## Philosophy\n\n The Express philosophy is to provide small, robust tooling for HTTP servers. Making\n it a great solution for single page applications, web sites, hybrids, or public\n HTTP APIs.\n\n Built on Connect you can use _only_ what you need, and nothing more, applications\n can be as big or as small as you like, even a single file. Express does\n not force you to use any specific ORM or template engine. With support for over\n 14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js)\n you can quickly craft your perfect framework.\n\n## More Information\n\n * Join #express on freenode\n * [Google Group](http://groups.google.com/group/express-js) for discussion\n * Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates\n * Visit the [Wiki](http://github.com/visionmedia/express/wiki)\n * [Русскоязычная документация](http://jsman.ru/express/)\n * Run express examples [online](https://runnable.com/express)\n\n## Viewing Examples\n\nClone the Express repo, then install the dev dependencies to install all the example / test suite deps:\n\n $ git clone git://github.com/visionmedia/express.git --depth 1\n $ cd express\n $ npm install\n\nthen run whichever tests you want:\n\n $ node examples/content-negotiation\n\n## Running Tests\n\nTo run the test suite first invoke the following command within the repo, installing the development dependencies:\n\n $ npm install\n\nthen run the tests:\n\n $ make test\n\n## Contributors\n\n```\nproject: express\ncommits: 3559\nactive : 468 days\nfiles : 237\nauthors:\n 1891\tTj Holowaychuk 53.1%\n 1285\tvisionmedia 36.1%\n 182\tTJ Holowaychuk 5.1%\n 54\tAaron Heckmann 1.5%\n 34\tcsausdev 1.0%\n 26\tciaranj 0.7%\n 21\tRobert Sköld 0.6%\n 6\tGuillermo Rauch 0.2%\n 3\tDav Glass 0.1%\n 3\tNick Poulden 0.1%\n 2\tRandy Merrill 0.1%\n 2\tBenny Wong 0.1%\n 2\tHunter Loftis 0.1%\n 2\tJake Gordon 0.1%\n 2\tBrian McKinney 0.1%\n 2\tRoman Shtylman 0.1%\n 2\tBen Weaver 0.1%\n 2\tDave Hoover 0.1%\n 2\tEivind Fjeldstad 0.1%\n 2\tDaniel Shaw 0.1%\n 1\tMatt Colyer 0.0%\n 1\tPau Ramon 0.0%\n 1\tPero Pejovic 0.0%\n 1\tPeter Rekdal Sunde 0.0%\n 1\tRaynos 0.0%\n 1\tTeng Siong Ong 0.0%\n 1\tViktor Kelemen 0.0%\n 1\tctide 0.0%\n 1\t8bitDesigner 0.0%\n 1\tisaacs 0.0%\n 1\tmgutz 0.0%\n 1\tpikeas 0.0%\n 1\tshuwatto 0.0%\n 1\ttstrimple 0.0%\n 1\tewoudj 0.0%\n 1\tAdam Sanderson 0.0%\n 1\tAndrii Kostenko 0.0%\n 1\tAndy Hiew 0.0%\n 1\tArpad Borsos 0.0%\n 1\tAshwin Purohit 0.0%\n 1\tBenjen 0.0%\n 1\tDarren Torpey 0.0%\n 1\tGreg Ritter 0.0%\n 1\tGregory Ritter 0.0%\n 1\tJames Herdman 0.0%\n 1\tJim Snodgrass 0.0%\n 1\tJoe McCann 0.0%\n 1\tJonathan Dumaine 0.0%\n 1\tJonathan Palardy 0.0%\n 1\tJonathan Zacsh 0.0%\n 1\tJustin Lilly 0.0%\n 1\tKen Sato 0.0%\n 1\tMaciej Małecki 0.0%\n 1\tMasahiro Hayashi 0.0%\n```\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2009-2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/express/issues" + }, + "_id": "express@3.3.4", + "dist": { + "shasum": "8f14664108bbd60602adb12d28bc1c69e519c0af" + }, + "_from": "express@", + "_resolved": "https://registry.npmjs.org/express/-/express-3.3.4.tgz" +} diff --git a/node_modules/express/test.js b/node_modules/express/test.js new file mode 100644 index 0000000..e7dca26 --- /dev/null +++ b/node_modules/express/test.js @@ -0,0 +1,17 @@ +var http = require('http'); +var express = require('express'); + +var app = express(); +var sub = express(); + +app.use('/', function (req, res, next) { + next(new Error('something broke')); +}); + +sub.use(function (err, req, res, next) { + res.send('error handled'); +}); + +app.use(sub); + +http.createServer(app).listen(4000); diff --git a/node_modules/hogan.js/.git_ignore b/node_modules/hogan.js/.git_ignore new file mode 100755 index 0000000..3c3629e --- /dev/null +++ b/node_modules/hogan.js/.git_ignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/hogan.js/.gitmodules b/node_modules/hogan.js/.gitmodules new file mode 100755 index 0000000..6bfdc18 --- /dev/null +++ b/node_modules/hogan.js/.gitmodules @@ -0,0 +1,3 @@ +[submodule "test/spec"] + path = test/spec + url = https://github.com/mustache/spec.git diff --git a/node_modules/hogan.js/LICENSE b/node_modules/hogan.js/LICENSE new file mode 100755 index 0000000..4947287 --- /dev/null +++ b/node_modules/hogan.js/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/node_modules/hogan.js/Makefile b/node_modules/hogan.js/Makefile new file mode 100755 index 0000000..43ed5e8 --- /dev/null +++ b/node_modules/hogan.js/Makefile @@ -0,0 +1,60 @@ +REPO = git@github.com:twitter/hogan.js.git +BUILD := build +VERSION = ${shell node -e 'console.log(JSON.parse(require("fs").readFileSync("package.json").toString()).version);'} + +# +# Run command line tests +# +test: + @ node test/run.js test/index.html + +# +# Run Mustache spec tests +# +spec: + @ node test/spec.js + +# +# Run benchmark +# +benchmark: + @ node benchmark/console/index.js + +clean: + @ rm -rf dist/* +# +# Make a new version of Hogan from the current dev version. +# +release: clean + @ echo "Creating a new version of Hogan." + @ node tools/release.js + @ mkdir -p web/builds/$(VERSION) + @ cp dist/*.* web/builds/$(VERSION)/. +# +# Make the gh-pages website +# +# This target builds the hogan.js github website using hogan.js. +# +# cd into build/gh-pages to check in the new site. +# +GH_PAGES = $(BUILD)/gh-pages +web: | pages + @cp -R web/* $(GH_PAGES) + @@ node tools/web_templates.js + @echo + @echo "Website built in $(GH_PAGES)." + +# +# Checkout the gh-pages branch. +# +pages: | $(BUILD) + @if [ ! -d "$(GH_PAGES)" ]; then \ + git clone -b gh-pages $(REPO) $(GH_PAGES); \ + rm -rf $(GH_PAGES)/*; \ + fi; + @mkdir -p $(GH_PAGES)/images + +$(BUILD): + mkdir -p $(BUILD) + +.PHONY: test spec benchmark web release diff --git a/node_modules/hogan.js/README.md b/node_modules/hogan.js/README.md new file mode 100755 index 0000000..1fa3e43 --- /dev/null +++ b/node_modules/hogan.js/README.md @@ -0,0 +1,93 @@ +## Hogan.js - A mustache compiler. + +[Hogan.js](http://twitter.github.com/hogan.js/) is a compiler for the +[Mustache](http://mustache.github.com/) templating language. For information +on Mustache, see the [manpage](http://mustache.github.com/mustache.5.html) and +the [spec](https://github.com/mustache/spec). + +## Basics + +Hogan compiles templates to HoganTemplate objects, which have a render method. + +```js +var data = { + screenName: "dhg", +}; + +var template = Hogan.compile("Follow @{{screenName}}."); +var output = template.render(data); + +// prints "Follow @dhg." +console.log(output); +``` + +## Features + +Hogan is fast--try it on your workload. + +Hogan has separate scanning, parsing and code generation phases. This way it's +possible to add new features without touching the scanner at all, and many +different code generation techniques can be tried without changing the parser. + +Hogan exposes scan and parse methods. These can be useful for +pre-processing templates on the server. + +```js +var text = "{{^check}}{{#i18n}}No{{/i18n}}{{/check}}"; +text += "{{#check}}{{#i18n}}Yes{{/i18n}}{{/check}}"; +var tree = Hogan.parse(Hogan.scan(text)); + +// outputs "# check" +console.log(tree[0].tag + " " + tree[0].name); + +// outputs "Yes" +console.log(tree[1].nodes[0].nodes[0]); +``` + +It's also possible to use HoganTemplate objects without the Hogan compiler +present. That means you can pre-compile your templates on the server, and +avoid shipping the compiler. However, the optional lambda features from the +Mustache spec do require the compiler to be present. + +## Why Hogan.js? + +Why another templating library? + +Hogan.js was written to meet three templating library requirements: good +performance, standalone template objects, and a parser API. + +## Issues + +Have a bug? Please create an issue here on GitHub! + +https://github.com/twitter/hogan.js/issues + +## Versioning + +For transparency and insight into our release cycle, releases will be numbered with the follow format: + +`..` + +And constructed with the following guidelines: + +* Breaking backwards compatibility bumps the major +* New additions without breaking backwards compatibility bumps the minor +* Bug fixes and misc changes bump the patch + +For more information on semantic versioning, please visit http://semver.org/. + +## Authors + +**Robert Sayre** + ++ http://github.com/sayrer + +**Jacob Thornton** + ++ http://github.com/fat + +## License + +Copyright 2011 Twitter, Inc. + +Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 \ No newline at end of file diff --git a/node_modules/hogan.js/bin/hulk b/node_modules/hogan.js/bin/hulk new file mode 100755 index 0000000..2b50655 --- /dev/null +++ b/node_modules/hogan.js/bin/hulk @@ -0,0 +1,93 @@ +#!/usr/bin/env node + +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var hogan = require('../lib/hogan.js'), + path = require('path'), + fs = require('fs'); + +var specials = ['/', '.', '*', '+', '?', '|','(', ')', '[', ']', '{', '}', '\\'], + specialsRegExp = new RegExp('(\\' + specials.join('|\\') + ')', 'g'), + templates; + + +// Escape special regexp characters +function esc(text) { + return text.replace(specialsRegExp, '\\$1'); +} + + +// Check for dirs and correct ext (<3 for windows) +function extractFiles(args) { + var usage = 'USAGE: hulk ./templates/*.mustaches\n' + + 'NOTE: hulk supports the "*" wildcard and allows you to target specific extensions too', + files = []; + + if (!args.length) { + console.log(usage); + process.exit(-1); + } + + args.forEach(function (arg) { + + if (/\*/.test(arg)) { + arg = arg.split('*'); + return files = files.concat( + fs.readdirSync(arg[0] || '.') + .map(function (f) { + return new RegExp(esc(arg[1]) + '$').test(f) && path.join(arg[0], f); + }) + .filter(function (f) { + return f; + }) + ); + } + + files.push(arg); + + }) + + return files; +} + + +// Remove utf-8 byte order mark, http://en.wikipedia.org/wiki/Byte_order_mark +function removeByteOrderMark(text) { + if (text.charCodeAt(0) === 0xfeff) { + return text.substring(1); + } + return text; +} + + +// Write a template foreach file that matches template extension +templates = extractFiles(process.argv.slice(2)) + .map(function (file) { + var openedFile = fs.readFileSync(file, 'utf-8'), name; + if (!openedFile) return; + name = path.basename(file).replace(/\..*$/, ''); + openedFile = removeByteOrderMark(openedFile.trim()); + return 'templates.' + name + ' = new Hogan.Template(' + hogan.compile(openedFile, { asString: 1 }) + ');'; + }) + .filter(function (t) { + return t; + }); + + +// Output templates +if (!templates.length) return; +console.log('var templates = {};'); +console.log(templates.join('\n')); diff --git a/node_modules/hogan.js/lib/compiler.js b/node_modules/hogan.js/lib/compiler.js new file mode 100755 index 0000000..f72a0b2 --- /dev/null +++ b/node_modules/hogan.js/lib/compiler.js @@ -0,0 +1,344 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function (Hogan) { + // Setup regex assignments + // remove whitespace according to Mustache spec + var rIsWhitespace = /\S/, + rQuot = /\"/g, + rNewline = /\n/g, + rCr = /\r/g, + rSlash = /\\/g, + tagTypes = { + '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, + '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 + }; + + Hogan.scan = function scan(text, delimiters) { + var len = text.length, + IN_TEXT = 0, + IN_TAG_TYPE = 1, + IN_TAG = 2, + state = IN_TEXT, + tagType = null, + tag = null, + buf = '', + tokens = [], + seenTag = false, + i = 0, + lineStart = 0, + otag = '{{', + ctag = '}}'; + + function addBuf() { + if (buf.length > 0) { + tokens.push(new String(buf)); + buf = ''; + } + } + + function lineIsWhitespace() { + var isAllWhitespace = true; + for (var j = lineStart; j < tokens.length; j++) { + isAllWhitespace = + (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || + (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null); + if (!isAllWhitespace) { + return false; + } + } + + return isAllWhitespace; + } + + function filterLine(haveSeenTag, noNewLine) { + addBuf(); + + if (haveSeenTag && lineIsWhitespace()) { + for (var j = lineStart, next; j < tokens.length; j++) { + if (!tokens[j].tag) { + if ((next = tokens[j+1]) && next.tag == '>') { + // set indent to token value + next.indent = tokens[j].toString() + } + tokens.splice(j, 1); + } + } + } else if (!noNewLine) { + tokens.push({tag:'\n'}); + } + + seenTag = false; + lineStart = tokens.length; + } + + function changeDelimiters(text, index) { + var close = '=' + ctag, + closeIndex = text.indexOf(close, index), + delimiters = trim( + text.substring(text.indexOf('=', index) + 1, closeIndex) + ).split(' '); + + otag = delimiters[0]; + ctag = delimiters[1]; + + return closeIndex + close.length - 1; + } + + if (delimiters) { + delimiters = delimiters.split(' '); + otag = delimiters[0]; + ctag = delimiters[1]; + } + + for (i = 0; i < len; i++) { + if (state == IN_TEXT) { + if (tagChange(otag, text, i)) { + --i; + addBuf(); + state = IN_TAG_TYPE; + } else { + if (text.charAt(i) == '\n') { + filterLine(seenTag); + } else { + buf += text.charAt(i); + } + } + } else if (state == IN_TAG_TYPE) { + i += otag.length - 1; + tag = tagTypes[text.charAt(i + 1)]; + tagType = tag ? text.charAt(i + 1) : '_v'; + if (tagType == '=') { + i = changeDelimiters(text, i); + state = IN_TEXT; + } else { + if (tag) { + i++; + } + state = IN_TAG; + } + seenTag = i; + } else { + if (tagChange(ctag, text, i)) { + tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, + i: (tagType == '/') ? seenTag - ctag.length : i + otag.length}); + buf = ''; + i += ctag.length - 1; + state = IN_TEXT; + if (tagType == '{') { + if (ctag == '}}') { + i++; + } else { + cleanTripleStache(tokens[tokens.length - 1]); + } + } + } else { + buf += text.charAt(i); + } + } + } + + filterLine(seenTag, true); + + return tokens; + } + + function cleanTripleStache(token) { + if (token.n.substr(token.n.length - 1) === '}') { + token.n = token.n.substring(0, token.n.length - 1); + } + } + + function trim(s) { + if (s.trim) { + return s.trim(); + } + + return s.replace(/^\s*|\s*$/g, ''); + } + + function tagChange(tag, text, index) { + if (text.charAt(index) != tag.charAt(0)) { + return false; + } + + for (var i = 1, l = tag.length; i < l; i++) { + if (text.charAt(index + i) != tag.charAt(i)) { + return false; + } + } + + return true; + } + + function buildTree(tokens, kind, stack, customTags) { + var instructions = [], + opener = null, + token = null; + + while (tokens.length > 0) { + token = tokens.shift(); + if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) { + stack.push(token); + token.nodes = buildTree(tokens, token.tag, stack, customTags); + instructions.push(token); + } else if (token.tag == '/') { + if (stack.length === 0) { + throw new Error('Closing tag without opener: /' + token.n); + } + opener = stack.pop(); + if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { + throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); + } + opener.end = token.i; + return instructions; + } else { + instructions.push(token); + } + } + + if (stack.length > 0) { + throw new Error('missing closing tag: ' + stack.pop().n); + } + + return instructions; + } + + function isOpener(token, tags) { + for (var i = 0, l = tags.length; i < l; i++) { + if (tags[i].o == token.n) { + token.tag = '#'; + return true; + } + } + } + + function isCloser(close, open, tags) { + for (var i = 0, l = tags.length; i < l; i++) { + if (tags[i].c == close && tags[i].o == open) { + return true; + } + } + } + + Hogan.generate = function (tree, text, options) { + var code = 'var _=this;_.b(i=i||"");' + walk(tree) + 'return _.fl();'; + if (options.asString) { + return 'function(c,p,i){' + code + ';}'; + } + + return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan, options); + } + + function esc(s) { + return s.replace(rSlash, '\\\\') + .replace(rQuot, '\\\"') + .replace(rNewline, '\\n') + .replace(rCr, '\\r'); + } + + function chooseMethod(s) { + return (~s.indexOf('.')) ? 'd' : 'f'; + } + + function walk(tree) { + var code = ''; + for (var i = 0, l = tree.length; i < l; i++) { + var tag = tree[i].tag; + if (tag == '#') { + code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), + tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag); + } else if (tag == '^') { + code += invertedSection(tree[i].nodes, tree[i].n, + chooseMethod(tree[i].n)); + } else if (tag == '<' || tag == '>') { + code += partial(tree[i]); + } else if (tag == '{' || tag == '&') { + code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); + } else if (tag == '\n') { + code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i')); + } else if (tag == '_v') { + code += variable(tree[i].n, chooseMethod(tree[i].n)); + } else if (tag === undefined) { + code += text('"' + esc(tree[i]) + '"'); + } + } + return code; + } + + function section(nodes, id, method, start, end, tags) { + return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' + + 'c,p,0,' + start + ',' + end + ',"' + tags + '")){' + + '_.rs(c,p,' + + 'function(c,p,_){' + + walk(nodes) + + '});c.pop();}'; + } + + function invertedSection(nodes, id, method) { + return 'if(!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' + + walk(nodes) + + '};'; + } + + function partial(tok) { + return '_.b(_.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '"));'; + } + + function tripleStache(id, method) { + return '_.b(_.t(_.' + method + '("' + esc(id) + '",c,p,0)));'; + } + + function variable(id, method) { + return '_.b(_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; + } + + function text(id) { + return '_.b(' + id + ');'; + } + + Hogan.parse = function(tokens, text, options) { + options = options || {}; + return buildTree(tokens, '', [], options.sectionTags || []); + }, + + Hogan.cache = {}; + + Hogan.compile = function(text, options) { + // options + // + // asString: false (default) + // + // sectionTags: [{o: '_foo', c: 'foo'}] + // An array of object with o and c fields that indicate names for custom + // section tags. The example above allows parsing of {{_foo}}{{/foo}}. + // + // delimiters: A string that overrides the default delimiters. + // Example: "<% %>" + // + options = options || {}; + + var key = text + '||' + !!options.asString; + + var t = this.cache[key]; + + if (t) { + return t; + } + + t = this.generate(this.parse(this.scan(text, options.delimiters), text, options), text, options); + return this.cache[key] = t; + }; +})(typeof exports !== 'undefined' ? exports : Hogan); diff --git a/node_modules/hogan.js/lib/hogan.js b/node_modules/hogan.js/lib/hogan.js new file mode 100755 index 0000000..f0119b5 --- /dev/null +++ b/node_modules/hogan.js/lib/hogan.js @@ -0,0 +1,20 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is for use with Node.js. See dist/ for browser files. + +var Hogan = require('./compiler'); +Hogan.Template = require('./template').Template; +module.exports = Hogan; \ No newline at end of file diff --git a/node_modules/hogan.js/lib/template.js b/node_modules/hogan.js/lib/template.js new file mode 100755 index 0000000..c28ce44 --- /dev/null +++ b/node_modules/hogan.js/lib/template.js @@ -0,0 +1,241 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var Hogan = {}; + +(function (Hogan, useArrayBuffer) { + Hogan.Template = function (renderFunc, text, compiler, options) { + this.r = renderFunc || this.r; + this.c = compiler; + this.options = options; + this.text = text || ''; + this.buf = (useArrayBuffer) ? [] : ''; + } + + Hogan.Template.prototype = { + // render: replaced by generated code. + r: function (context, partials, indent) { return ''; }, + + // variable escaping + v: hoganEscape, + + // triple stache + t: coerceToString, + + render: function render(context, partials, indent) { + return this.ri([context], partials || {}, indent); + }, + + // render internal -- a hook for overrides that catches partials too + ri: function (context, partials, indent) { + return this.r(context, partials, indent); + }, + + // tries to find a partial in the curent scope and render it + rp: function(name, context, partials, indent) { + var partial = partials[name]; + + if (!partial) { + return ''; + } + + if (this.c && typeof partial == 'string') { + partial = this.c.compile(partial, this.options); + } + + return partial.ri(context, partials, indent); + }, + + // render a section + rs: function(context, partials, section) { + var tail = context[context.length - 1]; + + if (!isArray(tail)) { + section(context, partials, this); + return; + } + + for (var i = 0; i < tail.length; i++) { + context.push(tail[i]); + section(context, partials, this); + context.pop(); + } + }, + + // maybe start a section + s: function(val, ctx, partials, inverted, start, end, tags) { + var pass; + + if (isArray(val) && val.length === 0) { + return false; + } + + if (typeof val == 'function') { + val = this.ls(val, ctx, partials, inverted, start, end, tags); + } + + pass = (val === '') || !!val; + + if (!inverted && pass && ctx) { + ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); + } + + return pass; + }, + + // find values with dotted names + d: function(key, ctx, partials, returnFound) { + var names = key.split('.'), + val = this.f(names[0], ctx, partials, returnFound), + cx = null; + + if (key === '.' && isArray(ctx[ctx.length - 2])) { + return ctx[ctx.length - 1]; + } + + for (var i = 1; i < names.length; i++) { + if (val && typeof val == 'object' && names[i] in val) { + cx = val; + val = val[names[i]]; + } else { + val = ''; + } + } + + if (returnFound && !val) { + return false; + } + + if (!returnFound && typeof val == 'function') { + ctx.push(cx); + val = this.lv(val, ctx, partials); + ctx.pop(); + } + + return val; + }, + + // find values with normal names + f: function(key, ctx, partials, returnFound) { + var val = false, + v = null, + found = false; + + for (var i = ctx.length - 1; i >= 0; i--) { + v = ctx[i]; + if (v && typeof v == 'object' && key in v) { + val = v[key]; + found = true; + break; + } + } + + if (!found) { + return (returnFound) ? false : ""; + } + + if (!returnFound && typeof val == 'function') { + val = this.lv(val, ctx, partials); + } + + return val; + }, + + // higher order templates + ho: function(val, cx, partials, text, tags) { + var compiler = this.c; + var options = this.options; + options.delimiters = tags; + var text = val.call(cx, text); + text = (text == null) ? String(text) : text.toString(); + this.b(compiler.compile(text, options).render(cx, partials)); + return false; + }, + + // template result buffering + b: (useArrayBuffer) ? function(s) { this.buf.push(s); } : + function(s) { this.buf += s; }, + fl: (useArrayBuffer) ? function() { var r = this.buf.join(''); this.buf = []; return r; } : + function() { var r = this.buf; this.buf = ''; return r; }, + + // lambda replace section + ls: function(val, ctx, partials, inverted, start, end, tags) { + var cx = ctx[ctx.length - 1], + t = null; + + if (!inverted && this.c && val.length > 0) { + return this.ho(val, cx, partials, this.text.substring(start, end), tags); + } + + t = val.call(cx); + + if (typeof t == 'function') { + if (inverted) { + return true; + } else if (this.c) { + return this.ho(t, cx, partials, this.text.substring(start, end), tags); + } + } + + return t; + }, + + // lambda replace variable + lv: function(val, ctx, partials) { + var cx = ctx[ctx.length - 1]; + var result = val.call(cx); + + if (typeof result == 'function') { + result = coerceToString(result.call(cx)); + if (this.c && ~result.indexOf("{\u007B")) { + return this.c.compile(result, this.options).render(cx, partials); + } + } + + return coerceToString(result); + } + + }; + + var rAmp = /&/g, + rLt = //g, + rApos =/\'/g, + rQuot = /\"/g, + hChars =/[&<>\"\']/; + + + function coerceToString(val) { + return String((val === null || val === undefined) ? '' : val); + } + + function hoganEscape(str) { + str = coerceToString(str); + return hChars.test(str) ? + str + .replace(rAmp,'&') + .replace(rLt,'<') + .replace(rGt,'>') + .replace(rApos,''') + .replace(rQuot, '"') : + str; + } + + var isArray = Array.isArray || function(a) { + return Object.prototype.toString.call(a) === '[object Array]'; + }; + +})(typeof exports !== 'undefined' ? exports : Hogan); + diff --git a/node_modules/hogan.js/package.json b/node_modules/hogan.js/package.json new file mode 100755 index 0000000..021b961 --- /dev/null +++ b/node_modules/hogan.js/package.json @@ -0,0 +1,43 @@ +{ + "name": "hogan.js", + "description": "A mustache compiler.", + "version": "2.0.0", + "keywords": [ + "mustache", + "template" + ], + "main": "./lib/hogan.js", + "homepage": "http://twitter.github.com/hogan.js/", + "author": { + "name": "Twitter Inc." + }, + "repository": { + "type": "git", + "url": "https://github.com/twitter/hogan.js.git" + }, + "licenses": [ + { + "type": "Apache-2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + ], + "devDependencies": { + "uglify-js": "*", + "jsdom": "0.2.10", + "step": "0.0.5" + }, + "bin": { + "hulk": "./bin/hulk" + }, + "readme": "## Hogan.js - A mustache compiler.\n\n[Hogan.js](http://twitter.github.com/hogan.js/) is a compiler for the\n[Mustache](http://mustache.github.com/) templating language. For information\non Mustache, see the [manpage](http://mustache.github.com/mustache.5.html) and\nthe [spec](https://github.com/mustache/spec).\n\n## Basics\n\nHogan compiles templates to HoganTemplate objects, which have a render method.\n\n```js\nvar data = {\n screenName: \"dhg\",\n};\n\nvar template = Hogan.compile(\"Follow @{{screenName}}.\");\nvar output = template.render(data);\n\n// prints \"Follow @dhg.\"\nconsole.log(output);\n```\n\n## Features\n\nHogan is fast--try it on your workload.\n\nHogan has separate scanning, parsing and code generation phases. This way it's\npossible to add new features without touching the scanner at all, and many\ndifferent code generation techniques can be tried without changing the parser.\n\nHogan exposes scan and parse methods. These can be useful for\npre-processing templates on the server.\n\n```js\nvar text = \"{{^check}}{{#i18n}}No{{/i18n}}{{/check}}\";\ntext += \"{{#check}}{{#i18n}}Yes{{/i18n}}{{/check}}\";\nvar tree = Hogan.parse(Hogan.scan(text));\n\n// outputs \"# check\"\nconsole.log(tree[0].tag + \" \" + tree[0].name);\n\n// outputs \"Yes\"\nconsole.log(tree[1].nodes[0].nodes[0]);\n```\n\nIt's also possible to use HoganTemplate objects without the Hogan compiler\npresent. That means you can pre-compile your templates on the server, and\navoid shipping the compiler. However, the optional lambda features from the\nMustache spec do require the compiler to be present.\n\n## Why Hogan.js?\n\nWhy another templating library?\n\nHogan.js was written to meet three templating library requirements: good\nperformance, standalone template objects, and a parser API.\n\n## Issues\n\nHave a bug? Please create an issue here on GitHub!\n\nhttps://github.com/twitter/hogan.js/issues\n\n## Versioning\n\nFor transparency and insight into our release cycle, releases will be numbered with the follow format:\n\n`..`\n\nAnd constructed with the following guidelines:\n\n* Breaking backwards compatibility bumps the major\n* New additions without breaking backwards compatibility bumps the minor\n* Bug fixes and misc changes bump the patch\n\nFor more information on semantic versioning, please visit http://semver.org/.\n\n## Authors\n\n**Robert Sayre**\n\n+ http://github.com/sayrer\n\n**Jacob Thornton**\n\n+ http://github.com/fat\n\n## License\n\nCopyright 2011 Twitter, Inc.\n\nLicensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/twitter/hogan.js/issues" + }, + "_id": "hogan.js@2.0.0", + "dist": { + "shasum": "7d9498e00637b3684e3dde729b2f32d20c34e18c" + }, + "_from": "hogan.js@", + "_resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-2.0.0.tgz" +} diff --git a/node_modules/hogan.js/test/html/list.html b/node_modules/hogan.js/test/html/list.html new file mode 100755 index 0000000..9bb653a --- /dev/null +++ b/node_modules/hogan.js/test/html/list.html @@ -0,0 +1,8 @@ +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    \ No newline at end of file diff --git a/node_modules/hogan.js/test/index.html b/node_modules/hogan.js/test/index.html new file mode 100755 index 0000000..7f63ab2 --- /dev/null +++ b/node_modules/hogan.js/test/index.html @@ -0,0 +1,21 @@ + + + Hogan.js Test Suite + + + + + + + + + + +

    Hogan.js

    +

    +
    +

    +
      +
      + + diff --git a/node_modules/hogan.js/test/index.js b/node_modules/hogan.js/test/index.js new file mode 100755 index 0000000..1ac7594 --- /dev/null +++ b/node_modules/hogan.js/test/index.js @@ -0,0 +1,814 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var is = strictEqual; + +test("Scan Text No Tags", function() { + var text = "

      hi

      "; + var tokens = Hogan.scan(text); + is(tokens.length, 1, "One token"); + is(tokens[0]+'', text, "text is equal to first token"); +}); + +test("Scan One Tag", function() { + var text = "{{hmm}}"; + var tokens = Hogan.scan(text); + is(tokens.length, 1, "One token"); + is(tokens[0].n, "hmm", "First token content is variable name."); +}); + +test("Scan Multiple Tags", function() { + var text = "asdf{{hmm}}asdf2{{hmm2}}asdf3"; + var tokens = Hogan.scan(text); + is(tokens.length, 5, "3 text tokens, 2 tag tokens."); + is(tokens[0]+'', "asdf", "first token is text"); + is(tokens[1].n, "hmm", "second token is tag"); + is(tokens[1].tag, "_v", "second token is a variable"); + is(tokens[2]+'', "asdf2", "third token is text"); + is(tokens[3].n, "hmm2", "fourth token is tag"); + is(tokens[3].tag, "_v", "fourth token is a variable"); + is(tokens[4]+'', "asdf3", "Fifth token is text"); +}); + +test("Scan Section Open", function() { + var text = "{{#hmm}}"; + var tokens = Hogan.scan(text); + is(tokens.length, 1, "One token"); + is(tokens[0].n, "hmm", "First token content is variable name."); + is(tokens[0].tag, "#", "First token is a section."); +}); + +test("Scan Section Close", function() { + var text = "{{/hmm}}"; + var tokens = Hogan.scan(text); + is(tokens.length, 1, "One token"); + is(tokens[0].n, "hmm", "First token content is variable name."); + is(tokens[0].tag, "/", "First token is a section."); +}); + +test("Scan Section", function() { + var text = "{{#hmm}}{{/hmm}}"; + var tokens = Hogan.scan(text); + is(tokens.length, 2, "One token"); + is(tokens[0].n, "hmm", "First token content is variable name."); + is(tokens[0].tag, "#", "First token is a section."); + is(tokens[1].n, "hmm", "Second token content is variable name."); + is(tokens[1].tag, "/", "Second token is a section."); +}); + +test("Scan Section In Content", function() { + var text = "abc{{#hmm}}def{{/hmm}}ghi"; + var tokens = Hogan.scan(text); + is(tokens.length, 5, "3 text tokens, 2 tag tokens."); + is(tokens[0]+'', "abc", "first token is text"); + is(tokens[1].n, "hmm", "second token is tag"); + is(tokens[1].tag, "#", "second token is a variable"); + is(tokens[2]+'', "def", "third token is text"); + is(tokens[3].n, "hmm", "fourth token is tag"); + is(tokens[3].tag, "/", "fourth token is a variable"); + is(tokens[4]+'', "ghi", "Fifth token is text"); +}); + +test("Scan Negative Section", function() { + var text = "{{^hmm}}{{/hmm}}"; + var tokens = Hogan.scan(text); + is(tokens.length, 2, "One token"); + is(tokens[0].n, "hmm", "First token content is variable name."); + is(tokens[0].tag, "^", "First token is a negative section."); + is(tokens[1].n, "hmm", "First token content is variable name."); + is(tokens[1].tag, "/", "Second token is a section."); +}); + +test("Scan Partial", function() { + var text = "{{>hmm}}"; + var tokens = Hogan.scan(text); + is(tokens.length, 1, "One token"); + is(tokens[0].n, "hmm", "First token content is variable name."); + is(tokens[0].tag, ">", "First token is a partial."); +}); + +test("Scan Backward Partial", function() { + var text = "{{
      \' \" &"}); + is(s, "< > <div> ' " &", "input correctly escaped."); + + var ec ={ "'": "'", '"': """, "<": "<", ">": ">", "&": "&"} + for (var char in ec) { + var s = t.render({foo: char + " just me"}); + is(s, ec[char] + " just me", "input correctly escaped."); + } +}); + +test("Mustache Injection", function() { + var text = "{{foo}}"; + var t = Hogan.compile(text); + s = t.render({foo:"{{{<42}}}"}) + is(s, "{{{<42}}}", "Can't inject mustache"); +}); + +test("Triple Stache", function() { + var text = "{{{foo}}}"; + var t = Hogan.compile(text); + var s = t.render({foo: "< >
      \' \" &"}); + is(s, "< >
      \' \" &", "input correctly not-escaped."); +}); + +test("Amp No Escaping", function() { + var text = "{{&foo}}"; + var t = Hogan.compile(text); + var s = t.render({foo: "< >
      \' \" &"}); + is(s, "< >
      \' \" &", "input correctly not-escaped."); +}); + +test("Partial", function() { + var partialText = "this is text from the partial--the magic number {{foo}} is from a variable"; + var p = Hogan.compile(partialText); + + var text = "This template contains a partial ({{>testPartial}})." + var t = Hogan.compile(text); + + var s = t.render({foo: 42}, {testPartial: p}); + is(s, "This template contains a partial (this is text from the partial--the magic number 42 is from a variable).", "partials work"); +}); + +test("Nested Partials", function() { + var partialText = "this is text from the partial--the magic number {{foo}} is from a variable"; + var p = Hogan.compile(partialText); + + var partialText2 = "This template contains a partial ({{>testPartial}})." + var p2 = Hogan.compile(partialText2); + + var text = "This template contains a partial that contains a partial [{{>testPartial2}}]." + var t = Hogan.compile(text); + + var s = t.render({foo: 42}, {testPartial: p, testPartial2: p2}); + is(s, "This template contains a partial that contains a partial [This template contains a partial (this is text from the partial--the magic number 42 is from a variable).].", "nested partials work"); +}); + +test("Negative Section", function() { + var text = "This template {{^foo}}BOO {{/foo}}contains an inverted section." + var t = Hogan.compile(text); + var s = t.render(); + is(s, "This template BOO contains an inverted section.", "inverted sections with no context work"); + + s = t.render({foo:[]}); + is(s, "This template BOO contains an inverted section.", "inverted sections with empty list context work"); + + s = t.render({ foo:false }); + is(s, "This template BOO contains an inverted section.", "inverted sections with false context work"); + + s = t.render({foo:''}); + is(s, "This template contains an inverted section.", "inverted sections with empty string context work"); + + s = t.render({foo:true}); + is(s, "This template contains an inverted section.", "inverted sections with true context work"); + + s = t.render({foo: function() { return false; }}); + is(s, "This template BOO contains an inverted section.", "inverted sections with false returning method in context work"); +}); + +test("Section Elision", function() { + var text = "This template {{#foo}}BOO {{/foo}}contains a section." + var t = Hogan.compile(text); + var s = t.render(); + is(s, "This template contains a section.", "sections with no context work"); + + s = t.render({foo:[]}); + is(s, "This template contains a section.", "sections with empty list context work"); + + s = t.render({foo:false}); + is(s, "This template contains a section.", "sections with false context work"); +}); + +test("Section Object Context", function() { + var text = "This template {{#foo}}{{bar}} {{/foo}}contains a section." + var t = Hogan.compile(text); + var s = t.render({foo:{bar:42}}); + is(s, "This template 42 contains a section.", "sections with object context work"); +}); + +test("Section Array Context", function() { + var text = "This template {{#foo}}{{bar}} {{/foo}}contains a section." + var t = Hogan.compile(text); + var s = t.render({foo:[{bar:42}, {bar:43}, {bar:44}]}); + is(s, "This template 42 43 44 contains a section.", "sections with object ctx and array values work"); +}); + +test("Falsy Variable No Render", function() { + var text = "I ({{cannot}}) be seen!"; + var t = Hogan.compile(text); + var s = t.render(); + is(s, "I () be seen!", "missing value doesn't render."); +}); + +test("Undefined Return Value From Lambda", function() { + var text = "abc{{foo}}def"; + var t = Hogan.compile(text); + var context = { + foo: function(s) { + return undefined; + } + } + var s = t.render(context); + is(s, "abcdef", "deal with undefined return values from lambdas.") +}); + +test("Section Extensions", function() { + var text = "Test {{_//|__foo}}bar{{/foo}}"; + var options = {sectionTags:[{o:'_//|__foo', c:'foo'}]}; + var tree = Hogan.parse(Hogan.scan(text), text, options); + is(tree[1].tag, "#", "_//|__foo node transformed to section"); + is(tree[1].n, "_//|__foo", "_//|__foo node transformed to section"); + + var t = Hogan.compile(text, options ); + var s = t.render({'_//|__foo':true}); + is(s, "Test bar", "Custom sections work"); +}); + +test("Misnested Section Extensions", function() { + var text = "Test {{__foo}}bar{{/bar}}"; + var options = {sectionTags:[{o:'__foo', c:'foo'}, {o:'__bar', c:'bar'}]}; + raises(function() { + var tree = Hogan.parse(Hogan.scan(text), text, options); + }, "Nesting error: __foo vs. bar", "Error is generated"); +}); + +test("Section Extensions In Higher Order Sections", function() { + var text = "Test{{_foo}}bar{{/foo}}"; + var options = {sectionTags:[{o:'_foo', c:'foo'}, {o:'_baz', c:'baz'}]}; + var t = Hogan.compile(text, options); + var context = { + "_foo": function (s) { + return "{{_baz}}" + s + "{{/baz}}"; + } + } + var s = t.render(context); + is(s, "Test", "unprocessed test"); +}); + +test("Section Extensions In Lambda Replace Variable", function() { + var text = "Test{{foo}}"; + var options = {sectionTags:[{o:'_baz', c:'baz'}]}; + var t = Hogan.compile(text, options); + var context = { + "foo": function () { + return function() { "{{_baz}}" + s + "{{/baz}}"; }; + } + } + var s = t.render(context); + is(s, "Test", "unprocessed test"); +}); + +test("Mustache not reprocessed for method calls in interpolations", function() { + var text = "text with {{foo}} inside"; + var t = Hogan.compile(text); + var context = { + foo: function() { + return "no processing of {{tags}}"; + } + } + var s = t.render(context); + is(s, "text with no processing of {{tags}} inside", "method calls should not be processed as mustache."); + + var text = "text with {{{foo}}} inside"; + var t = Hogan.compile(text); + var s = t.render(context); + is(s, "text with no processing of {{tags}} inside", "method calls should not be processed as mustache in triple staches."); +}); + +test("Mustache is reprocessed for lambdas in interpolations", function() { + var text = "text with {{foo}} inside"; + var t = Hogan.compile(text); + var context = { + bar: "42", + foo: function() { + return function() { + return "processing of {{bar}}"; + }; + } + }; + var s = t.render(context); + is(s, "text with processing of 42 inside", "the return value of lambdas should be processed mustache."); +}); + +test("Nested Section", function() { + var text = "{{#foo}}{{#bar}}{{baz}}{{/bar}}{{/foo}}"; + var t = Hogan.compile(text); + var s = t.render({foo: 42, bar: 42, baz:42}); + is(s, "42", "can reach up context stack"); +}); + +test("Dotted Names", function() { + var text = '"{{person.name}}" == "{{#person}}{{name}}{{/person}}"'; + var t = Hogan.compile(text); + var s = t.render({person:{name:'Joe'}}); + is(s, '"Joe" == "Joe"', "dotted names work"); +}); + +test("Implicit Iterator", function() { + var text = '{{#stuff}} {{.}} {{/stuff}}'; + var t = Hogan.compile(text); + var s = t.render({stuff:[42,43,44]}); + is(s, " 42 43 44 ", "implicit iterators work"); +}); + +test("Partials And Delimiters", function() { + var text = '{{>include}}*\n{{= | | =}}\n*|>include|'; + var partialText = ' .{{value}}. '; + var partial = Hogan.compile(partialText); + var t = Hogan.compile(text); + var s = t.render({value:"yes"}, {'include':partial}); + is(s, " .yes. *\n* .yes. ", "partials work around delimiters"); +}); + +test("String Partials", function() { + var text = "foo{{>mypartial}}baz"; + var partialText = " bar "; + var t = Hogan.compile(text); + var s = t.render({}, {'mypartial': partialText}); + is(s, "foo bar baz", "string partial works."); +}); + +test("Missing Partials", function() { + var text = "foo{{>mypartial}} bar"; + var t = Hogan.compile(text); + var s = t.render({}); + is(s, "foo bar", "missing partial works."); +}); + +test("Indented Standalone Comment", function() { + var text = 'Begin.\n {{! Indented Comment Block! }}\nEnd.'; + var t = Hogan.compile(text); + var s = t.render(); + is(s, 'Begin.\nEnd.', "Standalone comment blocks are removed."); +}); + +test("New Line Between Delimiter Changes", function() { + var data = { section: true, data: 'I got interpolated.' }; + var text = '\n{{#section}}\n {{data}}\n |data|\n{{/section}}x\n\n{{= | | =}}\n|#section|\n {{data}}\n |data|\n|/section|'; + var t = Hogan.compile(text); + var s = t.render(data); + is(s, '\n I got interpolated.\n |data|\nx\n\n {{data}}\n I got interpolated.\n', 'render correct') +}); + +test("Mustache JS Apostrophe", function() { + var text = '{{apos}}{{control}}'; + var t = Hogan.compile(text); + var s = t.render({'apos':"'", 'control':"X"}); + is(s, ''X', 'Apostrophe is escaped.'); +}); + +test("Mustache JS Array Of Implicit Partials", function() { + var text = 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}\n'; + var partialText = '{{.}}\n'; + var t = Hogan.compile(text); + var s = t.render({numbers:[1,2,3,4]}, {partial: partialText}); + is(s, 'Here is some stuff!\n1\n2\n3\n4\n', 'Partials with implicit iterators work.'); +}); + +test("Mustache JS Array Of Partials", function() { + var text = 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}\n'; + var partialText = '{{i}}\n'; + var t = Hogan.compile(text); + var s = t.render({numbers:[{i:1},{i:2},{i:3},{i:4}]}, {partial: partialText}); + is(s, 'Here is some stuff!\n1\n2\n3\n4\n', 'Partials with arrays work.'); +}); + +test("Mustache JS Array Of Strings", function() { + var text = '{{#strings}}{{.}} {{/strings}}'; + var t = Hogan.compile(text); + var s = t.render({strings:['foo', 'bar', 'baz']}); + is(s, 'foo bar baz ', 'array of strings works with implicit iterators.'); +}); + +test("Mustache JS Undefined String", function() { + var text = 'foo{{bar}}baz'; + var t = Hogan.compile(text); + var s = t.render({bar:undefined}); + is(s, 'foobaz', 'undefined value does not render.'); +}); + +test("Mustache JS Undefined Triple Stache", function() { + var text = 'foo{{{bar}}}baz'; + var t = Hogan.compile(text); + var s = t.render({bar:undefined}); + is(s, 'foobaz', 'undefined value does not render in triple stache.'); +}); + +test("Mustache JS Null String", function() { + var text = 'foo{{bar}}baz'; + var t = Hogan.compile(text); + var s = t.render({bar:null}); + is(s, 'foobaz', 'undefined value does not render.'); +}); + +test("Mustache JS Null Triple Stache", function() { + var text = 'foo{{{bar}}}baz'; + var t = Hogan.compile(text); + var s = t.render({bar:null}); + is(s, 'foobaz', 'undefined value does not render in triple stache.'); +}); + +test("Mustache JS Triple Stache Alt Delimiter", function() { + var text = '{{=<% %>=}}<% foo %> {{foo}} <%{bar}%> {{{bar}}}'; + var t = Hogan.compile(text); + var s = t.render({foo:'yeah', bar:'hmm'}); + is(s, 'yeah {{foo}} hmm {{{bar}}}', 'triple stache inside alternate delimiter works.'); +}); + +/* Safety tests */ + +test("Updates object state", function() { + var text = '{{foo}} {{bar}} {{foo}}'; + var t = Hogan.compile(text); + var s = t.render({foo: 1, bar: function() { this.foo++; return 42; } }); + is(s, '1 42 2'); +}); + +/* shootout benchmark tests */ + +test("Shoot Out String", function() { + var text = "Hello World!"; + var expected = "Hello World!" + var t = Hogan.compile(text) + var s = t.render({}) + is(s, expected, "Shootout String compiled correctly"); +}); + +test("Shoot Out Replace", function() { + var text = "Hello {{name}}! You have {{count}} new messages."; + var expected = "Hello Mick! You have 30 new messages."; + var t = Hogan.compile(text) + var s = t.render({ name: "Mick", count: 30 }) + is(s, expected, "Shootout Replace compiled correctly"); +}); + +test("Shoot Out Array", function() { + var text = "{{#names}}{{name}}{{/names}}"; + var expected = "MoeLarryCurlyShemp"; + var t = Hogan.compile(text); + var s = t.render({ names: [{name: "Moe"}, {name: "Larry"}, {name: "Curly"}, {name: "Shemp"}] }) + is(s, expected, "Shootout Array compiled correctly"); +}); + +test("Shoot Out Object", function() { + var text = "{{#person}}{{name}}{{age}}{{/person}}"; + var expected = "Larry45"; + var t = Hogan.compile(text) + var s = t.render({ person: { name: "Larry", age: 45 } }) + is(s, expected, "Shootout Object compiled correctly"); +}); + +test("Shoot Out Partial", function() { + var text = "{{#peeps}}{{>replace}}{{/peeps}}"; + var t = Hogan.compile(text); + var partial = Hogan.compile(" Hello {{name}}! You have {{count}} new messages."); + var s = t.render({ peeps: [{name: "Moe", count: 15}, {name: "Larry", count: 5}, {name: "Curly", count: 2}] }, { replace: partial }); + var expected = " Hello Moe! You have 15 new messages. Hello Larry! You have 5 new messages. Hello Curly! You have 2 new messages."; + is(s, expected, "Shootout Partial compiled correctly"); +}); + +test("Shoot Out Recurse", function() { + var text = "{{name}}{{#kids}}{{>recursion}}{{/kids}}"; + var t = Hogan.compile(text); + var partial = Hogan.compile("{{name}}{{#kids}}{{>recursion}}{{/kids}}"); + var s = t.render({ + name: '1', + kids: [ + { + name: '1.1', + kids: [ + { name: '1.1.1', kids: [] } + ] + } + ] + }, { recursion: partial }); + var expected = "11.11.1.1"; + is(s, expected, "Shootout Recurse compiled correctly"); +}); + +test("Shoot Out Filter", function() { + var text = "{{#filter}}foo {{bar}}{{/filter}}"; + var t = Hogan.compile(text); + var s = t.render({ + filter: function() { + return function(text) { + return text.toUpperCase() + "{{bar}}"; + } + }, + bar: "bar" + }); + var expected = "FOO bar" + is(s, expected, "Shootout Filter compiled correctly"); +}); + +test("Shoot Out Complex", function() { + var text = + "

      {{header}}

      " + + "{{#hasItems}}" + + "
        " + + "{{#items}}" + + "{{#current}}" + + "
      • {{name}}
      • " + + "{{/current}}" + + "{{^current}}" + + "
      • {{name}}
      • " + + "{{/current}}" + + "{{/items}}" + + "
      " + + "{{/hasItems}}" + + "{{^hasItems}}" + + "

      The list is empty.

      " + + "{{/hasItems}}"; + + var expected = "

      Colors

      "; + var t = Hogan.compile(text) + var s = t.render({ + header: function() { + return "Colors"; + }, + items: [ + {name: "red", current: true, url: "#Red"}, + {name: "green", current: false, url: "#Green"}, + {name: "blue", current: false, url: "#Blue"} + ], + hasItems: function() { + return this.items.length !== 0; + }, + empty: function() { + return this.items.length === 0; + } + }) + + is(s, expected, "Shootout Complex compiled correctly"); +}); + +$.each(['list'], function(i, name) { + return; + asyncTest("Render Output: " + name, function() { + $.when( + $.get('./templates/' + name + '.mustache'), + $.get('./html/' + name + '.html') + ).done(function(tmpl, html) { + var r = Hogan.compile(tmpl[0]).render({}); + is(r, html[0], name + ': should correctly render html'); + }) + .fail(function() { ok(false, 'file missing'); }) + .always(function() { start(); }); + }); +}); + +test("Default Render Impl", function() { + var ht = new Hogan.Template(); + is(ht.render() === '', true, 'default renderImpl returns an array.'); +}); diff --git a/node_modules/hogan.js/test/jquery.js b/node_modules/hogan.js/test/jquery.js new file mode 100755 index 0000000..8ccd0ea --- /dev/null +++ b/node_modules/hogan.js/test/jquery.js @@ -0,0 +1,9266 @@ +/*! + * jQuery JavaScript Library v1.7.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Nov 21 21:11:03 2011 -0500 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!memory; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + marginDiv, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
      a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = marginDiv = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + conMarginTop, ptlm, vb, style, html, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;"; + vb = "visibility:hidden;border:0;"; + style = "style='" + ptlm + "border:5px solid #000;padding:0;'"; + html = "
      " + + "" + + "
      "; + + container = document.createElement("div"); + container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
      t
      "; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Figure out if the W3C box model works as expected + div.innerHTML = ""; + div.style.width = div.style.paddingLeft = "1px"; + jQuery.boxModel = support.boxModel = div.offsetWidth === 2; + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
      "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.style.cssText = ptlm + vb; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + body.removeChild( container ); + div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + privateCache = thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, attr, name, + data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) { + attr = this[0].attributes; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( this[0], name, data[ name ] ); + } + } + jQuery._data( this[0], "parsedAttrs", true ); + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var self = jQuery( this ), + args = [ parts[0], value ]; + + self.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + jQuery.isNumeric( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise(); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + + // See #9699 for explanation of this approach (setting first, then removal) + jQuery.attr( elem, name, "" ); + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /\bhover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Determine handlers that should run if there are delegated events + // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on.call( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
      ", "
      " ], + thead: [ 1, "", "
      " ], + tr: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + col: [ 2, "", "
      " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and +
      +
      +
      +
      + + +
      +

      Templates

      +

      + Hogan.js was developed against the mustache test suite, so everything that holds true for templates as specified here, is also the case for hogan.js. +

      +

      + That means you get variables, sections, lambdas, partials, filters, and everything else you've come to expect from mustache templating - only much, much faster. +

      +
      +
      + +
      +
      +
      +
      + + +
      +

      Compiling

      +

      + Use hogan.compile() to precompile your templates into vanilla JS. +

      +

      + It's best to serve your templates precompiled whenever you can (rather than the raw templates), as parsing is the most time consuming operation. +

      +

      +

      +
      +
      + +
      +
      +
      +
      + + +
      +

      Rendering

      +

      + Once compiled, call the render() method with a context and optional partials object. +

      +

      + If supplying partials, you can compile them ahead of time, or pass string templates.

      +

      +

      +
      +
      + +
      + + + + + +
      + + + + + diff --git a/node_modules/hogan.js/web/stylesheets/layout.css b/node_modules/hogan.js/web/stylesheets/layout.css new file mode 100755 index 0000000..20e20cf --- /dev/null +++ b/node_modules/hogan.js/web/stylesheets/layout.css @@ -0,0 +1,206 @@ + +/* #Reset & Basics (Inspired by E. Meyers) +================================================== */ + html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; } + article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { + display: block; } + body { + line-height: 1; } + ol, ul { + list-style: none; } + blockquote, q { + quotes: none; } + blockquote:before, blockquote:after, + q:before, q:after { + content: ''; + content: none; } + table { + border-collapse: collapse; + border-spacing: 0; } + + +/* #Basic Styles +================================================== */ + body { + background: #fff; + font: 14px/24px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #000; + -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ + -webkit-text-size-adjust: 100%; + } + a { + color: #999113; + text-decoration: none; + } + a:hover { + color: #7b750e; + text-decoration: underline; + } + + +/* #Typography +================================================== */ + h1, h2, h3, h4, h5, h6 { + font-weight: bold; } + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } + h1 { font-size: 75px; line-height: 80px; margin-bottom: 14px;} + h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; } + h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; } + h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; } + h5 { font-size: 17px; line-height: 24px; } + h6 { font-size: 14px; line-height: 21px; } + p { margin-bottom: 22px; } + + +/* #Main styles +================================================== */ + +/* Hogan Hero */ +.hogan-hero { + position: relative; + background: #333; /* Old browsers */ + background: -moz-radial-gradient(center, ellipse cover, #333 0%, #000 100%); /* FF3.6+ */ + background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#333), color-stop(100%,#000)); /* Chrome,Safari4+ */ + background: -webkit-radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* Chrome10+,Safari5.1+ */ + background: -o-radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* Opera 12+ */ + background: -ms-radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* IE10+ */ + background: radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#333', endColorstr='#000',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ +} +.hogan-hero .container { + padding: 180px 0; +} +.hogan-hero h1 { + letter-spacing: -3px; + color: #fff; + position: relative; + margin-bottom: 5px; +} +.hogan-hero h3 { + max-width: 650px; + margin-bottom: 20px; + color: #fff; +} +.hogan-hero .noise, +.hogan-hero .stripes { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} +.hogan-hero .noise { + background: url(../images/noise.png) repeat; +} +.hogan-hero .stripes { + background: url(../images/stripes.png) repeat; +} + +/* Primary content container */ +.primary.container { + padding-top: 100px; +} + +/*Hogan divider */ +.hogan-divider { + padding-top: 60px; + border-bottom: 1px solid #ddd; + margin-bottom: 60px; + clear: both; + position: relative; +} +.hogan-icon { + width: 40px; + height: 30px; + position: absolute; + left: 50%; + top: 46px; + margin-left: -20px; + background: url('../images/small-hogan-icon.png') white no-repeat center center; +} + +/* Button style */ +.button { + display: inline-block; + cursor: pointer; + background: #dfd52e; + border-radius: 3px; + margin-bottom: 20px; + color: #000; + text-transform: uppercase; + text-decoration: none; + font-size: 15px; + padding: 0 34px; + line-height: 46px; + font-weight: bold; + -webkit-transition: background-color .3s ease-in-out; + -moz-transition: background-color .3s ease-in-out; + -o-transition: background-color .3s ease-in-out; + transition: background-color .3s ease-in-out; + +} +.button:hover { + text-decoration: inherit; + color: inherit; + background-color: #f5e810; +} + +/* Hogan footer */ +.hogan-footer { + border-top: 1px solid #ddd; + margin-top: 60px; + padding: 20px 0 40px; + color: #999; + font-size: 12px; +} +.hogan-footer .copyright { + float: left; +} +.hogan-footer .colophon { + float: right; +} + +pre, code { + background: #F8F8FF; + border: 1px solid #DDD; + padding: 5px 10px; + margin-bottom: 20px; + font-family: courier; + overflow: hidden; +} + +pre code { + border: 0; + padding: 0; + margin-bottom: 0; +} + + +/* #Media Queries +================================================== */ + + /* Smaller than standard 960 (devices and browsers) */ + @media only screen and (max-width: 959px) {} + + /* Tablet Portrait size to standard 960 (devices and browsers) */ + @media only screen and (min-width: 768px) and (max-width: 959px) {} + + /* All Mobile Sizes (devices and browser) */ + @media only screen and (max-width: 767px) { + .hogan-hero .container { + padding: 100px 0; + } + } + + /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ + @media only screen and (min-width: 480px) and (max-width: 767px) {} + + /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ + @media only screen and (max-width: 479px) {} + diff --git a/node_modules/hogan.js/web/stylesheets/skeleton.css b/node_modules/hogan.js/web/stylesheets/skeleton.css new file mode 100755 index 0000000..d0264a4 --- /dev/null +++ b/node_modules/hogan.js/web/stylesheets/skeleton.css @@ -0,0 +1,236 @@ +/* +* Skeleton V1.1 +* Copyright 2011, Dave Gamache +* www.getskeleton.com +* Free to use under the MIT license. +* http://www.opensource.org/licenses/mit-license.php +* 8/17/2011 +*/ + + +/* Table of Contents +================================================== + #Base 960 Grid + #Tablet (Portrait) + #Mobile (Portrait) + #Mobile (Landscape) + #Clearing */ + + + +/* #Base 960 Grid +================================================== */ + + .container { position: relative; width: 960px; margin: 0 auto; padding: 0; } + .column, .columns { float: left; display: inline; margin-left: 10px; margin-right: 10px; } + .row { margin-bottom: 20px; } + + /* Nested Column Classes */ + .column.alpha, .columns.alpha { margin-left: 0; } + .column.omega, .columns.omega { margin-right: 0; } + + /* Base Grid */ + .container .one.column { width: 40px; } + .container .two.columns { width: 100px; } + .container .three.columns { width: 160px; } + .container .four.columns { width: 220px; } + .container .five.columns { width: 280px; } + .container .six.columns { width: 340px; } + .container .seven.columns { width: 400px; } + .container .eight.columns { width: 460px; } + .container .nine.columns { width: 520px; } + .container .ten.columns { width: 580px; } + .container .eleven.columns { width: 640px; } + .container .twelve.columns { width: 700px; } + .container .thirteen.columns { width: 760px; } + .container .fourteen.columns { width: 820px; } + .container .fifteen.columns { width: 880px; } + .container .sixteen.columns { width: 940px; } + + .container .one-third.column { width: 300px; } + .container .two-thirds.column { width: 620px; } + + /* Offsets */ + .container .offset-by-one { padding-left: 60px; } + .container .offset-by-two { padding-left: 120px; } + .container .offset-by-three { padding-left: 180px; } + .container .offset-by-four { padding-left: 240px; } + .container .offset-by-five { padding-left: 300px; } + .container .offset-by-six { padding-left: 360px; } + .container .offset-by-seven { padding-left: 420px; } + .container .offset-by-eight { padding-left: 480px; } + .container .offset-by-nine { padding-left: 540px; } + .container .offset-by-ten { padding-left: 600px; } + .container .offset-by-eleven { padding-left: 660px; } + .container .offset-by-twelve { padding-left: 720px; } + .container .offset-by-thirteen { padding-left: 780px; } + .container .offset-by-fourteen { padding-left: 840px; } + .container .offset-by-fifteen { padding-left: 900px; } + + + +/* #Tablet (Portrait) +================================================== */ + + /* Note: Design for a width of 768px */ + + @media only screen and (min-width: 768px) and (max-width: 959px) { + .container { width: 768px; } + .container .column, + .container .columns { margin-left: 10px; margin-right: 10px; } + .column.alpha, .columns.alpha { margin-left: 0; margin-right: 10px; } + .column.omega, .columns.omega { margin-right: 0; margin-left: 10px; } + + .container .one.column { width: 28px; } + .container .two.columns { width: 76px; } + .container .three.columns { width: 124px; } + .container .four.columns { width: 172px; } + .container .five.columns { width: 220px; } + .container .six.columns { width: 268px; } + .container .seven.columns { width: 316px; } + .container .eight.columns { width: 364px; } + .container .nine.columns { width: 412px; } + .container .ten.columns { width: 460px; } + .container .eleven.columns { width: 508px; } + .container .twelve.columns { width: 556px; } + .container .thirteen.columns { width: 604px; } + .container .fourteen.columns { width: 652px; } + .container .fifteen.columns { width: 700px; } + .container .sixteen.columns { width: 748px; } + + .container .one-third.column { width: 236px; } + .container .two-thirds.column { width: 492px; } + + /* Offsets */ + .container .offset-by-one { padding-left: 48px; } + .container .offset-by-two { padding-left: 96px; } + .container .offset-by-three { padding-left: 144px; } + .container .offset-by-four { padding-left: 192px; } + .container .offset-by-five { padding-left: 240px; } + .container .offset-by-six { padding-left: 288px; } + .container .offset-by-seven { padding-left: 336px; } + .container .offset-by-eight { padding-left: 348px; } + .container .offset-by-nine { padding-left: 432px; } + .container .offset-by-ten { padding-left: 480px; } + .container .offset-by-eleven { padding-left: 528px; } + .container .offset-by-twelve { padding-left: 576px; } + .container .offset-by-thirteen { padding-left: 624px; } + .container .offset-by-fourteen { padding-left: 672px; } + .container .offset-by-fifteen { padding-left: 720px; } + } + + +/* #Mobile (Portrait) +================================================== */ + + /* Note: Design for a width of 320px */ + + @media only screen and (max-width: 767px) { + .container { width: 300px; } + .columns, .column { margin: 0; } + + .container .one.column, + .container .two.columns, + .container .three.columns, + .container .four.columns, + .container .five.columns, + .container .six.columns, + .container .seven.columns, + .container .eight.columns, + .container .nine.columns, + .container .ten.columns, + .container .eleven.columns, + .container .twelve.columns, + .container .thirteen.columns, + .container .fourteen.columns, + .container .fifteen.columns, + .container .sixteen.columns, + .container .one-third.column, + .container .two-thirds.column { width: 300px; } + + /* Offsets */ + .container .offset-by-one, + .container .offset-by-two, + .container .offset-by-three, + .container .offset-by-four, + .container .offset-by-five, + .container .offset-by-six, + .container .offset-by-seven, + .container .offset-by-eight, + .container .offset-by-nine, + .container .offset-by-ten, + .container .offset-by-eleven, + .container .offset-by-twelve, + .container .offset-by-thirteen, + .container .offset-by-fourteen, + .container .offset-by-fifteen { padding-left: 0; } + + } + + +/* #Mobile (Landscape) +================================================== */ + + /* Note: Design for a width of 480px */ + + @media only screen and (min-width: 480px) and (max-width: 767px) { + .container { width: 420px; } + .columns, .column { margin: 0; } + + .container .one.column, + .container .two.columns, + .container .three.columns, + .container .four.columns, + .container .five.columns, + .container .six.columns, + .container .seven.columns, + .container .eight.columns, + .container .nine.columns, + .container .ten.columns, + .container .eleven.columns, + .container .twelve.columns, + .container .thirteen.columns, + .container .fourteen.columns, + .container .fifteen.columns, + .container .sixteen.columns, + .container .one-third.column, + .container .two-thirds.column { width: 420px; } + } + + +/* #Clearing +================================================== */ + + /* Self Clearing Goodness */ + .container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; } + + /* Use clearfix class on parent to clear nested columns, + or wrap each row of columns in a
      */ + .clearfix:before, + .clearfix:after, + .row:before, + .row:after { + content: '\0020'; + display: block; + overflow: hidden; + visibility: hidden; + width: 0; + height: 0; } + .row:after, + .clearfix:after { + clear: both; } + .row, + .clearfix { + zoom: 1; } + + /* You can also use a
      to clear columns */ + .clear { + clear: both; + display: block; + overflow: hidden; + visibility: hidden; + width: 0; + height: 0; + } + + diff --git a/node_modules/hogan.js/wrappers/amd.js.mustache b/node_modules/hogan.js/wrappers/amd.js.mustache new file mode 100755 index 0000000..d91ef77 --- /dev/null +++ b/node_modules/hogan.js/wrappers/amd.js.mustache @@ -0,0 +1,21 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{{{template}}} +{{{compiler}}} + +if (typeof define === 'function' && define.amd) { + define(Hogan); +} diff --git a/node_modules/hogan.js/wrappers/common.js.mustache b/node_modules/hogan.js/wrappers/common.js.mustache new file mode 100755 index 0000000..e823e83 --- /dev/null +++ b/node_modules/hogan.js/wrappers/common.js.mustache @@ -0,0 +1,21 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{{{template}}} +{{{compiler}}} + +if (typeof module !== 'undefined' && module.exports) { + module.exports = Hogan; +} diff --git a/node_modules/hogan.js/wrappers/js.mustache b/node_modules/hogan.js/wrappers/js.mustache new file mode 100755 index 0000000..9f311f0 --- /dev/null +++ b/node_modules/hogan.js/wrappers/js.mustache @@ -0,0 +1,17 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{{{template}}} +{{{compiler}}} diff --git a/node_modules/hogan.js/wrappers/mustache.js.mustache b/node_modules/hogan.js/wrappers/mustache.js.mustache new file mode 100755 index 0000000..d3a3d70 --- /dev/null +++ b/node_modules/hogan.js/wrappers/mustache.js.mustache @@ -0,0 +1,64 @@ +/* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// A wrapper for compatibility with Mustache.js, quirks and all + +{{{template}}} +{{{compiler}}} + +var Mustache = (function (Hogan) { + + // Mustache.js has non-spec partial context behavior + function mustachePartial(name, context, partials, indent) { + var partialScope = this.f(name, context, partials, 0); + var cx = context; + if (partialScope) { + cx = cx.concat(partialScope); + } + + return Hogan.Template.prototype.rp.call(this, name, cx, partials, indent); + } + + var HoganTemplateWrapper = function(renderFunc, text, compiler){ + this.rp = mustachePartial; + Hogan.Template.call(this, renderFunc, text, compiler); + }; + HoganTemplateWrapper.prototype = Hogan.Template.prototype; + + // Add a wrapper for Hogan's generate method. Mustache and Hogan keep + // separate caches, and Mustache returns wrapped templates. + var wrapper; + var HoganWrapper = function(){ + this.cache = {}; + this.generate = function(code, text, options) { + return new HoganTemplateWrapper(new Function('c', 'p', 'i', code), text, wrapper); + } + }; + HoganWrapper.prototype = Hogan; + wrapper = new HoganWrapper(); + + return { + to_html: function(text, data, partials, sendFun) { + var template = wrapper.compile(text); + var result = template.render(data, partials); + if (!sendFun) { + return result; + } + + sendFun(result); + } + } + +})(Hogan); diff --git a/node_modules/nodecr/.npmignore b/node_modules/nodecr/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/nodecr/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/nodecr/Cakefile b/node_modules/nodecr/Cakefile new file mode 100644 index 0000000..c4b3504 --- /dev/null +++ b/node_modules/nodecr/Cakefile @@ -0,0 +1,236 @@ +task 'build:apps', 'Build apps script JS file', -> + if_coffee -> + ps = spawn("coffee", ["--output", JAVASCRIPTS_PATH,"-- compile",COFFEESCRIPTS_PATH]) + ps.stdout.on('data', log) + ps.stderr.on('data', log) + ps.on 'exit', (code)-> + if code != 0 + console.log 'failed'# ** Cakefile Template ** is a Template for a common Cakefile that you may use in a coffeescript nodejs project. +# +# It comes baked in with 5 tasks: +# +# * build - compiles your src directory to your lib directory +# * watch - watches any changes in your src directory and automatically compiles to the lib directory +# * test - runs mocha test framework, you can edit this task to use your favorite test framework +# * docs - generates annotated documentation using docco +# * clean - clean generated .js files +files = [ + 'lib' + 'src' +] + +fs = require 'fs' +{print} = require 'util' +{spawn, exec} = require 'child_process' + +try + which = require('which').sync +catch err + if process.platform.match(/^win/)? + console.log 'WARNING: the which module is required for windows\ntry: npm install which' + which = null + +# ANSI Terminal Colors +bold = '\x1b[0;1m' +green = '\x1b[0;32m' +reset = '\x1b[0m' +red = '\x1b[0;31m' + +# Cakefile Tasks +# +# ## *docs* +# +# Generate Annotated Documentation +# +# Usage +# +# ``` +# cake docs +# ``` +task 'docs', 'generate documentation', -> docco() + +# ## *build* +# +# Builds Source +# +# Usage +# +# ``` +# cake build +# ``` +task 'build', 'compile source', -> build -> log ":)", green + +# ## *watch* +# +# Builds your source whenever it changes +# +# Usage +# +# ``` +# cake watch +# ``` +task 'watch', 'compile and watch', -> build true, -> log ":-)", green + +# ## *test* +# +# Runs your test suite. +# +# Usage +# +# ``` +# cake test +# ``` +task 'test', 'run tests', -> build -> mocha -> log ":)", green + +# ## *clean* +# +# Cleans up generated js files +# +# Usage +# +# ``` +# cake clean +# ``` +task 'clean', 'clean generated files', -> clean -> log ";)", green + + +# Internal Functions +# +# ## *walk* +# +# **given** string as dir which represents a directory in relation to local directory +# **and** callback as done in the form of (err, results) +# **then** recurse through directory returning an array of files +# +# Examples +# +# ``` coffeescript +# walk 'src', (err, results) -> console.log results +# ``` +walk = (dir, done) -> + results = [] + fs.readdir dir, (err, list) -> + return done(err, []) if err + pending = list.length + return done(null, results) unless pending + for name in list + file = "#{dir}/#{name}" + try + stat = fs.statSync file + catch err + stat = null + if stat?.isDirectory() + walk file, (err, res) -> + results.push name for name in res + done(null, results) unless --pending + else + results.push file + done(null, results) unless --pending + +# ## *log* +# +# **given** string as a message +# **and** string as a color +# **and** optional string as an explanation +# **then** builds a statement and logs to console. +# +log = (message, color, explanation) -> console.log color + message + reset + ' ' + (explanation or '') + +# ## *launch* +# +# **given** string as a cmd +# **and** optional array and option flags +# **and** optional callback +# **then** spawn cmd with options +# **and** pipe to process stdout and stderr respectively +# **and** on child process exit emit callback if set and status is 0 +launch = (cmd, options=[], callback) -> + cmd = which(cmd) if which + app = spawn cmd, options + app.stdout.pipe(process.stdout) + app.stderr.pipe(process.stderr) + app.on 'exit', (status) -> callback?() if status is 0 + +# ## *build* +# +# **given** optional boolean as watch +# **and** optional function as callback +# **then** invoke launch passing coffee command +# **and** defaulted options to compile src to lib +build = (watch, callback) -> + if typeof watch is 'function' + callback = watch + watch = false + + options = ['-c', '-b', '-o' ] + options = options.concat files + options.unshift '-w' if watch + launch 'coffee', options, callback + +# ## *unlinkIfCoffeeFile* +# +# **given** string as file +# **and** file ends in '.coffee' +# **then** convert '.coffee' to '.js' +# **and** remove the result +unlinkIfCoffeeFile = (file) -> + if file.match /\.coffee$/ + fs.unlink file.replace(/\.coffee$/, '.js') + true + else false + +# ## *clean* +# +# **given** optional function as callback +# **then** loop through files variable +# **and** call unlinkIfCoffeeFile on each +clean = (callback) -> + try + for file in files + unless unlinkIfCoffeeFile file + walk file, (err, results) -> + for f in results + unlinkIfCoffeeFile f + + callback?() + catch err + +# ## *moduleExists* +# +# **given** name for module +# **when** trying to require module +# **and** not found +# **then* print not found message with install helper in red +# **and* return false if not found +moduleExists = (name) -> + try + require name + catch err + log "#{name} required: npm install #{name}", red + false + + +# ## *mocha* +# +# **given** optional array of option flags +# **and** optional function as callback +# **then** invoke launch passing mocha command +mocha = (options, callback) -> + #if moduleExists('mocha') + if typeof options is 'function' + callback = options + options = [] + # add coffee directive + options.push '--compilers' + options.push 'coffee:coffee-script' + + launch 'mocha', options, callback + +# ## *docco* +# +# **given** optional function as callback +# **then** invoke launch passing docco command +docco = (callback) -> + #if moduleExists('docco') + walk 'src', (err, files) -> launch 'docco', files, callback + diff --git a/node_modules/nodecr/README.md b/node_modules/nodecr/README.md new file mode 100644 index 0000000..260db21 --- /dev/null +++ b/node_modules/nodecr/README.md @@ -0,0 +1,56 @@ +# Tesseract for Node.js + +A simple wrapper for the Tesseract OCR package for Node.js + +## Installation +`npm install nodecr` + +## Versions +* **0.0.5**: Add possibility to override logger (quiet nodecr, see example below) +* **0.0.4**: Changed name to nodecr and published node module (formerly node-tesseract) +* **0.0.3**: Added support for custom preprocessors, OTB Preprocessor using ImageMagick 'convert' +* **0.0.2**: Refactored to support tesseract 3.01, added language parameter, config parameter, documentation +* **0.0.1**: Initial version from Desmond Morris + +## Usage + +```JavaScript +var nodecr = require('nodecr'); + +// Recognise text of any language in any format +nodecr.process(__dirname + '/path/to/image.jpg',function(err, text) { + if(err) { + console.error(err); + } else { + console.log(text); + } +}); + +// Recognise German text in a single uniform block of text +nodecr.process(__dirname + '/path/to/image.jpg',function(err, text) { + if(err) { + console.error(err); + } else { + console.log(text); + } +}, 'deu', 6); + +// Recognise text of any language in any format but preprocess the image +// with ImageMagick 'convert' (This requires ImageMagick to be installed) + +// uncomment this to quiet nodecr +//nodecr.log = function() {}; + +// You can write and use your own preprocessors easily, just have a look at src/nodecr.coffee +nodecr.process(__dirname + '/path/to/image.jpg',function(err, text) { + if(err) { + console.error(err); + } else { + console.log(text); + } + console.log(text); +}, null, null, null, nodecr.preprocessors.convert); +``` + +## License +MIT \ No newline at end of file diff --git a/node_modules/nodecr/lib/nodecr.js b/node_modules/nodecr/lib/nodecr.js new file mode 100644 index 0000000..3657406 --- /dev/null +++ b/node_modules/nodecr/lib/nodecr.js @@ -0,0 +1,172 @@ +// Generated by CoffeeScript 1.4.0 +var Tesseract, exec, fs, tesseract, tmp; + +exec = require('child_process').exec; + +fs = require('fs'); + +tmp = require('tmp'); + +/* +Attention: Tesseract 3.01 or higher is needed for this to work +*/ + + +Tesseract = (function() { + var ConvertPreprocessor; + + function Tesseract() {} + + /* + @param image Can be any format that your installed Leptonica library can process + (additional libraries might be required by Leptonica) + + @param callback A function pointer + this function is called after the recognition has taken place + with a possible error as first and the resulting recognized text as second parameter + + @param languageCode (Optional) a language code for the language to recognise + see http://code.google.com/p/tesseract-ocr/downloads/list for available languages (xxx.traineddata.gz) + any language you pass as an argument here must be unzipped into the tessdata directory beforehand + + @param pageSegMode (Optional) The page segmentation mode. + As of March 4, 2012 tesseract supports the following options: + + 0 = Orientation and script detection (OSD) only. + 1 = Automatic page segmentation with OSD. + 2 = Automatic page segmentation, but no OSD, or OCR + 3 = Fully automatic page segmentation, but no OSD. (Default) + 4 = Assume a single column of text of variable sizes. + 5 = Assume a single uniform block of vertically aligned text. + 6 = Assume a single uniform block of text. + 7 = Treat the image as a single text line. + 8 = Treat the image as a single word. + 9 = Treat the image as a single word in a circle. + 10 = Treat the image as a single character. + + See http://code.google.com/p/tesseract-ocr/source/browse/trunk/api/tesseractmain.cpp#95 for current state of options + + @param config (Optional) A config file name + */ + + + Tesseract.prototype.process = function(image, callback, languageCode, pageSegMode, config, preprocessor) { + var _this = this; + return (preprocessor || this.preprocessor)(image, function(err, processedImage, cleanup) { + var f; + if (err) { + callback(err, null); + return; + } + f = function(err, text) { + if (cleanup != null) { + _this.log("node-tesseract: Preprocessor cleanup"); + cleanup(); + } + callback(err, text); + }; + _this._runTesseract(processedImage, f, languageCode, pageSegMode, config); + }); + }; + + Tesseract.prototype._runTesseract = function(image, callback, languageCode, pageSegMode, config) { + var _this = this; + tmp.tmpName(function(err, output) { + var command; + if (err) { + callback(err, null); + return; + } + command = [_this.binary, image, output]; + if (languageCode) { + command.push('-l'); + command.push(languageCode); + } + if (typeof pageSegMode !== 'undefined' && pageSegMode !== null) { + command.push('-psm'); + command.push(pageSegMode); + } + if (config) { + command.push(config); + } + command = command.join(' '); + _this.log("node-tesseract: Running '" + command + "'"); + exec(command, function(err, stdout, stderr) { + var outputFile; + if (err) { + callback(err, null); + return; + } + outputFile = output + '.txt'; + fs.readFile(outputFile, function(err, data) { + if (!err) { + data = data.toString(_this.outputEncoding); + } + _this.log("node-tesseract: Deleting '" + outputFile + "'"); + fs.unlink(outputFile, function(err) {}); + callback(err, data); + }); + }); + }); + }; + + /* + A no-op preprocessor + + @param inputFile The file to process + @param callback The callback to call when the processing is done (1st argument error, 2nd the outputfile (the processed input file)) + */ + + + Tesseract.prototype.preprocessor = function(inputFile, callback) { + var cleanup, error, outputFile; + error = null; + outputFile = inputFile; + cleanup = function() {}; + callback(error, outputFile, cleanup); + }; + + Tesseract.prototype.log = function() { + console.log.apply(console, arguments); + }; + + Tesseract.prototype.binary = 'tesseract'; + + Tesseract.prototype.outputEncoding = 'UTF-8'; + + Tesseract.prototype.preprocessors = { + convert: ConvertPreprocessor = function(inputFile, callback) { + tesseract.log("node-tesseract: preprocessor: convert: Processing '" + inputFile + "'"); + tmp.tmpName({ + postfix: '.tif' + }, function(err, outputFile) { + var command; + if (err) { + callback(err, null); + return; + } + command = ['convert', '-type', 'Grayscale', '-resize', '200%', '-sharpen', '10', inputFile, outputFile].join(' '); + tesseract.log("node-tesseract: preprocessor: convert: Running '" + command + "'"); + exec(command, function(err, stdout, stderr) { + var cleanup; + if (err) { + callback(err, null); + } else { + cleanup = function() { + tesseract.log("node-tesseract: preprocessor: convert: Deleting '" + outputFile + "'"); + fs.unlink(outputFile, function(err) {}); + }; + callback(null, outputFile, cleanup); + } + }); + }); + } + }; + + return Tesseract; + +})(); + +tesseract = new Tesseract; + +module.exports = tesseract; diff --git a/node_modules/nodecr/node_modules/tmp/.npmignore b/node_modules/nodecr/node_modules/tmp/.npmignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/.npmignore @@ -0,0 +1 @@ +node_modules/ diff --git a/node_modules/nodecr/node_modules/tmp/.travis.yml b/node_modules/nodecr/node_modules/tmp/.travis.yml new file mode 100644 index 0000000..0175d82 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "0.6" + - "0.8" + - "0.10" diff --git a/node_modules/nodecr/node_modules/tmp/README.md b/node_modules/nodecr/node_modules/tmp/README.md new file mode 100644 index 0000000..3a1a509 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/README.md @@ -0,0 +1,162 @@ +# Tmp + +A simple temporary file and directory creator for [node.js.][1] + +[![Build Status](https://secure.travis-ci.org/raszi/node-tmp.png?branch=master)](http://travis-ci.org/raszi/node-tmp) + +## About + +The main difference between bruce's [node-temp][2] is that mine more +aggressively checks for the existence of the newly created temporary file and +creates the new file with `O_EXCL` instead of simple `O_CREAT | O_RDRW`, so it +is safer. + +The API is slightly different as well, Tmp does not yet provide synchronous +calls and all the parameters are optional. + +You can set whether you want to remove the temporary file on process exit or +not, and the destination directory can also be set. + +## How to install + +```bash +npm install tmp +``` + +## Usage + +### File creation + +Simple temporary file creation, the file will be unlinked on process exit. + +```javascript +var tmp = require('tmp'); + +tmp.file(function _tempFileCreated(err, path, fd) { + if (err) throw err; + + console.log("File: ", path); + console.log("Filedescriptor: ", fd); +}); +``` + +### Directory creation + +Simple temporary directory creation, it will be removed on process exit. + +If the directory still contains items on process exit, then it won't be removed. + +```javascript +var tmp = require('tmp'); + +tmp.dir(function _tempDirCreated(err, path) { + if (err) throw err; + + console.log("Dir: ", path); +}); +``` + +If you want to cleanup the directory even when there are entries in it, then +you can pass the `unsafeCleanup` option when creating it. + +### Filename generation + +It is possible with this library to generate a unique filename in the specified +directory. + +```javascript +var tmp = require('tmp'); + +tmp.tmpName(function _tempNameGenerated(err, path) { + if (err) throw err; + + console.log("Created temporary filename: ", path); +}); +``` + +## Advanced usage + +### File creation + +Creates a file with mode `0644`, prefix will be `prefix-` and postfix will be `.txt`. + +```javascript +var tmp = require('tmp'); + +tmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) { + if (err) throw err; + + console.log("File: ", path); + console.log("Filedescriptor: ", fd); +}); +``` + +### Directory creation + +Creates a directory with mode `0755`, prefix will be `myTmpDir_`. + +```javascript +var tmp = require('tmp'); + +tmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) { + if (err) throw err; + + console.log("Dir: ", path); +}); +``` + +### mkstemps like + +Creates a new temporary directory with mode `0700` and filename like `/tmp/tmp-nk2J1u`. + +```javascript +var tmp = require('tmp'); + +tmp.dir({ template: '/tmp/tmp-XXXXXX' }, function _tempDirCreated(err, path) { + if (err) throw err; + + console.log("Dir: ", path); +}); +``` + +### Filename generation + +The `tmpName()` function accepts the `prefix`, `postfix`, `dir`, etc. parameters also: + +```javascript +var tmp = require('tmp'); + +tmp.tmpName({ template: '/tmp/tmp-XXXXXX' }, function _tempNameGenerated(err, path) { + if (err) throw err; + + console.log("Created temporary filename: ", path); +}); +``` + +## Graceful cleanup + +One may want to cleanup the temporary files even when an uncaught exception +occurs. To enforce this, you can call the `setGracefulCleanup()` method: + +```javascript +var tmp = require('tmp'); + +tmp.setGracefulCleanup(); +``` + +## Options + +All options are optional :) + + * `mode`: the file mode to create with, it fallbacks to `0600` on file creation and `0700` on directory creation + * `prefix`: the optional prefix, fallbacks to `tmp-` if not provided + * `postfix`: the optional postfix, fallbacks to `.tmp` on file creation + * `template`: [`mkstemps`][3] like filename template, no default + * `dir`: the optional temporary directory, fallbacks to system default (guesses from environment) + * `tries`: how many times should the function try to get a unique filename before giving up, default `3` + * `keep`: signals that the temporary file or directory should not be deleted on exit, default is `false`, means delete + * `unsafeCleanup`: recursively removes the created temporary directory, even when it's not empty. default is `false` + +[1]: http://nodejs.org/ +[2]: https://github.com/bruce/node-temp +[3]: http://www.kernel.org/doc/man-pages/online/pages/man3/mkstemp.3.html diff --git a/node_modules/nodecr/node_modules/tmp/lib/tmp.js b/node_modules/nodecr/node_modules/tmp/lib/tmp.js new file mode 100644 index 0000000..73cb03c --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/lib/tmp.js @@ -0,0 +1,273 @@ +/*! + * Tmp + * + * Copyright (c) 2011-2013 KARASZI Istvan + * + * MIT Licensed + */ + +/** + * Module dependencies. + */ +var + fs = require('fs'), + path = require('path'), + os = require('os'), + exists = fs.exists || path.exists, + tmpDir = os.tmpDir || _getTMPDir, + _c = require('constants'); + +/** + * The working inner variables. + */ +var + // store the actual TMP directory + _TMP = tmpDir(), + + // the random characters to choose from + randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz", + randomCharsLength = randomChars.length, + + // this will hold the objects need to be removed on exit + _removeObjects = [], + + _gracefulCleanup = false, + _uncaughtException = false; + +/** + * Gets the temp directory. + * + * @return {String} + * @api private + */ +function _getTMPDir() { + var tmpNames = [ 'TMPDIR', 'TMP', 'TEMP' ]; + + for (var i = 0, length = tmpNames.length; i < length; i++) { + if (_isUndefined(process.env[tmpNames[i]])) continue; + + return process.env[tmpNames[i]]; + } + + // fallback to the default + return '/tmp'; +} + +/** + * Checks whether the `obj` parameter is defined or not. + * + * @param {Object} obj + * @return {Boolean} + * @api private + */ +function _isUndefined(obj) { + return typeof obj === 'undefined'; +} + +/** + * Parses the function arguments. + * + * This function helps to have optional arguments. + * + * @param {Object} options + * @param {Function} callback + * @api private + */ +function _parseArguments(options, callback) { + if (!callback || typeof callback != "function") { + callback = options; + options = {}; + } + + return [ options, callback ]; +} + +/** + * Gets a temporary file name. + * + * @param {Object} opts + * @param {Function} cb + * @api private + */ +function _getTmpName(options, callback) { + var + args = _parseArguments(options, callback), + opts = args[0], + cb = args[1], + template = opts.template, + templateDefined = !_isUndefined(template), + tries = opts.tries || 3; + + if (isNaN(tries) || tries < 0) + return cb(new Error('Invalid tries')); + + if (templateDefined && !template.match(/XXXXXX/)) + return cb(new Error('Invalid template provided')); + + function _getName() { + + // prefix and postfix + if (!templateDefined) { + var name = [ + (_isUndefined(opts.prefix)) ? 'tmp-' : opts.prefix, + process.pid, + (Math.random() * 0x1000000000).toString(36), + opts.postfix + ].join(''); + + return path.join(opts.dir || _TMP, name); + } + + // mkstemps like template + var chars = []; + + for (var i = 0; i < 6; i++) { + chars.push(randomChars.substr(Math.floor(Math.random() * randomCharsLength), 1)); + } + + return template.replace(/XXXXXX/, chars.join('')); + } + + (function _getUniqueName() { + var name = _getName(); + + // check whether the path exists then retry if needed + exists(name, function _pathExists(pathExists) { + if (pathExists) { + if (tries-- > 0) return _getUniqueName(); + + return cb(new Error('Could not get a unique tmp filename, max tries reached')); + } + + cb(null, name); + }); + }()); +} + +/** + * Creates and opens a temporary file. + * + * @param {Object} options + * @param {Function} callback + * @api public + */ +function _createTmpFile(options, callback) { + var + args = _parseArguments(options, callback), + opts = args[0], + cb = args[1]; + + opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix; + + // gets a temporary filename + _getTmpName(opts, function _tmpNameCreated(err, name) { + if (err) return cb(err); + + // create and open the file + fs.open(name, _c.O_CREAT | _c.O_EXCL | _c.O_RDWR, opts.mode || 0600, function _fileCreated(err, fd) { + if (err) return cb(err); + + if (!opts.keep) _removeObjects.unshift([ fs.unlinkSync, name ]); + + cb(null, name, fd); + }); + }); +} + +/** + * Removes files and folders in a directory recursively. + * + * @param {String} path + */ +function _rmdirRecursiveSync(dir) { + var files = fs.readdirSync(dir); + + for (var i = 0, length = files.length; i < length; i++) { + var file = path.join(dir, files[i]); + // lstat so we don't recurse into symlinked directories. + var stat = fs.lstatSync(file); + + if (stat.isDirectory()) { + _rmdirRecursiveSync(file); + } else { + fs.unlinkSync(file); + } + } + + fs.rmdirSync(dir); +} + +/** + * Creates a temporary directory. + * + * @param {Object} options + * @param {Function} callback + * @api public + */ +function _createTmpDir(options, callback) { + var + args = _parseArguments(options, callback), + opts = args[0], + cb = args[1]; + + // gets a temporary filename + _getTmpName(opts, function _tmpNameCreated(err, name) { + if (err) return cb(err); + + // create the directory + fs.mkdir(name, opts.mode || 0700, function _dirCreated(err) { + if (err) return cb(err); + + if (!opts.keep) { + if (opts.unsafeCleanup) { + _removeObjects.unshift([ _rmdirRecursiveSync, name ]); + } else { + _removeObjects.unshift([ fs.rmdirSync, name ]); + } + } + + cb(null, name); + }); + }); +} + +/** + * The garbage collector. + * + * @api private + */ +function _garbageCollector() { + if (_uncaughtException && !_gracefulCleanup) { + return; + } + + for (var i = 0, length = _removeObjects.length; i < length; i++) { + try { + _removeObjects[i][0].call(null, _removeObjects[i][1]); + } catch (e) { + // already removed? + } + } +} + +function _setGracefulCleanup() { + _gracefulCleanup = true; +} + +process.addListener('uncaughtException', function _uncaughtExceptionThrown( err ) { + _uncaughtException = true; + _garbageCollector(); + + throw err; +}); + +process.addListener('exit', function _exit() { + _garbageCollector(); +}); + +// exporting all the needed methods +module.exports.tmpdir = _TMP; +module.exports.dir = _createTmpDir; +module.exports.file = _createTmpFile; +module.exports.tmpName = _getTmpName; +module.exports.setGracefulCleanup = _setGracefulCleanup; diff --git a/node_modules/nodecr/node_modules/tmp/package.json b/node_modules/nodecr/node_modules/tmp/package.json new file mode 100644 index 0000000..6931597 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/package.json @@ -0,0 +1,52 @@ +{ + "name": "tmp", + "version": "0.0.21", + "description": "Temporary file and directory creator", + "author": { + "name": "KARASZI István", + "email": "github@spam.raszi.hu", + "url": "http://raszi.hu/" + }, + "homepage": "http://github.com/raszi/node-tmp", + "keywords": [ + "temporary", + "tmp", + "temp", + "tempdir", + "tempfile", + "tmpdir", + "tmpfile" + ], + "licenses": [ + { + "type": "MIT", + "url": "http://opensource.org/licenses/MIT" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/raszi/node-tmp.git" + }, + "bugs": { + "url": "http://github.com/raszi/node-tmp/issues" + }, + "main": "lib/tmp.js", + "scripts": { + "test": "vows test/*-test.js" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": {}, + "devDependencies": { + "vows": "~0.7.0" + }, + "readme": "# Tmp\n\nA simple temporary file and directory creator for [node.js.][1]\n\n[![Build Status](https://secure.travis-ci.org/raszi/node-tmp.png?branch=master)](http://travis-ci.org/raszi/node-tmp)\n\n## About\n\nThe main difference between bruce's [node-temp][2] is that mine more\naggressively checks for the existence of the newly created temporary file and\ncreates the new file with `O_EXCL` instead of simple `O_CREAT | O_RDRW`, so it\nis safer.\n\nThe API is slightly different as well, Tmp does not yet provide synchronous\ncalls and all the parameters are optional.\n\nYou can set whether you want to remove the temporary file on process exit or\nnot, and the destination directory can also be set.\n\n## How to install\n\n```bash\nnpm install tmp\n```\n\n## Usage\n\n### File creation\n\nSimple temporary file creation, the file will be unlinked on process exit.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.file(function _tempFileCreated(err, path, fd) {\n if (err) throw err;\n\n console.log(\"File: \", path);\n console.log(\"Filedescriptor: \", fd);\n});\n```\n\n### Directory creation\n\nSimple temporary directory creation, it will be removed on process exit.\n\nIf the directory still contains items on process exit, then it won't be removed.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.dir(function _tempDirCreated(err, path) {\n if (err) throw err;\n\n console.log(\"Dir: \", path);\n});\n```\n\nIf you want to cleanup the directory even when there are entries in it, then\nyou can pass the `unsafeCleanup` option when creating it.\n\n### Filename generation\n\nIt is possible with this library to generate a unique filename in the specified\ndirectory.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.tmpName(function _tempNameGenerated(err, path) {\n if (err) throw err;\n\n console.log(\"Created temporary filename: \", path);\n});\n```\n\n## Advanced usage\n\n### File creation\n\nCreates a file with mode `0644`, prefix will be `prefix-` and postfix will be `.txt`.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) {\n if (err) throw err;\n\n console.log(\"File: \", path);\n console.log(\"Filedescriptor: \", fd);\n});\n```\n\n### Directory creation\n\nCreates a directory with mode `0755`, prefix will be `myTmpDir_`.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) {\n if (err) throw err;\n\n console.log(\"Dir: \", path);\n});\n```\n\n### mkstemps like\n\nCreates a new temporary directory with mode `0700` and filename like `/tmp/tmp-nk2J1u`.\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.dir({ template: '/tmp/tmp-XXXXXX' }, function _tempDirCreated(err, path) {\n if (err) throw err;\n\n console.log(\"Dir: \", path);\n});\n```\n\n### Filename generation\n\nThe `tmpName()` function accepts the `prefix`, `postfix`, `dir`, etc. parameters also:\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.tmpName({ template: '/tmp/tmp-XXXXXX' }, function _tempNameGenerated(err, path) {\n if (err) throw err;\n\n console.log(\"Created temporary filename: \", path);\n});\n```\n\n## Graceful cleanup\n\nOne may want to cleanup the temporary files even when an uncaught exception\noccurs. To enforce this, you can call the `setGracefulCleanup()` method:\n\n```javascript\nvar tmp = require('tmp');\n\ntmp.setGracefulCleanup();\n```\n\n## Options\n\nAll options are optional :)\n\n * `mode`: the file mode to create with, it fallbacks to `0600` on file creation and `0700` on directory creation\n * `prefix`: the optional prefix, fallbacks to `tmp-` if not provided\n * `postfix`: the optional postfix, fallbacks to `.tmp` on file creation\n * `template`: [`mkstemps`][3] like filename template, no default\n * `dir`: the optional temporary directory, fallbacks to system default (guesses from environment)\n * `tries`: how many times should the function try to get a unique filename before giving up, default `3`\n * `keep`: signals that the temporary file or directory should not be deleted on exit, default is `false`, means delete\n * `unsafeCleanup`: recursively removes the created temporary directory, even when it's not empty. default is `false`\n\n[1]: http://nodejs.org/\n[2]: https://github.com/bruce/node-temp\n[3]: http://www.kernel.org/doc/man-pages/online/pages/man3/mkstemp.3.html\n", + "readmeFilename": "README.md", + "_id": "tmp@0.0.21", + "dist": { + "shasum": "a21030368b57f1f439baae7f8c4c9344fa776053" + }, + "_from": "tmp@>= 0.0.14", + "_resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.21.tgz" +} diff --git a/node_modules/nodecr/node_modules/tmp/test-all.sh b/node_modules/nodecr/node_modules/tmp/test-all.sh new file mode 100755 index 0000000..0fc4282 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test-all.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for node in node06 node08 node; do + echo "Testing with $(${node} --version)..." + ${node} node_modules/vows/bin/vows test/*test.js +done diff --git a/node_modules/nodecr/node_modules/tmp/test.js b/node_modules/nodecr/node_modules/tmp/test.js new file mode 100644 index 0000000..8058221 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test.js @@ -0,0 +1,6 @@ +process.on('uncaughtException', function ( err ) { + console.log('blah'); + throw err; +}); + +throw "on purpose" diff --git a/node_modules/nodecr/node_modules/tmp/test/base.js b/node_modules/nodecr/node_modules/tmp/test/base.js new file mode 100644 index 0000000..498d8fb --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/base.js @@ -0,0 +1,74 @@ +var + assert = require('assert'), + path = require('path'), + exec = require('child_process').exec; + +function _spawnTestWithError(testFile, params, cb) { + _spawnTest(true, testFile, params, cb); +} + +function _spawnTestWithoutError(testFile, params, cb) { + _spawnTest(false, testFile, params, cb); +} + +function _spawnTest(passError, testFile, params, cb) { + var + filename, + node_path = process.argv[0], + command = [ node_path, path.join(__dirname, testFile) ].concat(params).join(' '); + + exec(command, function _execDone(err, stdout, stderr) { + if (passError) { + if (err) { + return cb(err); + } else if (stderr.length > 0) { + return cb(stderr.toString()); + } + } + + return cb(null, stdout.toString()); + }); +} + +function _testStat(stat, mode) { + assert.equal(stat.uid, process.getuid(), 'should have the same UID'); + assert.equal(stat.gid, process.getgid(), 'should have the same GUID'); + assert.equal(stat.mode, mode); +} + +function _testPrefix(prefix) { + return function _testPrefixGenerated(err, name, fd) { + assert.equal(path.basename(name).slice(0, prefix.length), prefix, 'should have the provided prefix'); + }; +} + +function _testPostfix(postfix) { + return function _testPostfixGenerated(err, name, fd) { + assert.equal(name.slice(name.length - postfix.length, name.length), postfix, 'should have the provided postfix'); + }; +} + +function _testKeep(type, keep, cb) { + _spawnTestWithError('keep.js', [ type, keep ], cb); +} + +function _testGraceful(type, graceful, cb) { + _spawnTestWithoutError('graceful.js', [ type, graceful ], cb); +} + +function _assertName(err, name) { + assert.isString(name); + assert.isNotZero(name.length); +} + +function _testUnsafeCleanup(unsafe, cb) { + _spawnTestWithoutError('unsafe.js', [ 'dir', unsafe ], cb); +} + +module.exports.testStat = _testStat; +module.exports.testPrefix = _testPrefix; +module.exports.testPostfix = _testPostfix; +module.exports.testKeep = _testKeep; +module.exports.testGraceful = _testGraceful; +module.exports.assertName = _assertName; +module.exports.testUnsafeCleanup = _testUnsafeCleanup; diff --git a/node_modules/nodecr/node_modules/tmp/test/dir-test.js b/node_modules/nodecr/node_modules/tmp/test/dir-test.js new file mode 100644 index 0000000..9b89009 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/dir-test.js @@ -0,0 +1,183 @@ +var + vows = require('vows'), + assert = require('assert'), + + path = require('path'), + fs = require('fs'), + existsSync = fs.existsSync || path.existsSync, + + tmp = require('../lib/tmp.js'), + Test = require('./base.js'); + + +function _testDir(mode) { + return function _testDirGenerated(err, name) { + assert.ok(existsSync(name), 'should exist'); + + var stat = fs.statSync(name); + assert.ok(stat.isDirectory(), 'should be a directory'); + + Test.testStat(stat, mode); + }; +} + +vows.describe('Directory creation').addBatch({ + 'when using without parameters': { + topic: function () { + tmp.dir(this.callback); + }, + + 'should be a directory': _testDir(040700), + 'should have the default prefix': Test.testPrefix('tmp-') + }, + + 'when using with prefix': { + topic: function () { + tmp.dir({ prefix: 'something' }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a directory': _testDir(040700), + 'should have the provided prefix': Test.testPrefix('something') + }, + + 'when using with postfix': { + topic: function () { + tmp.dir({ postfix: '.txt' }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a directory': _testDir(040700), + 'should have the provided postfix': Test.testPostfix('.txt') + }, + + 'when using template': { + topic: function () { + tmp.dir({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') }, this.callback); + }, + + 'should not return with error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': _testDir(040700), + 'should have the provided prefix': Test.testPrefix('clike-'), + 'should have the provided postfix': Test.testPostfix('-postfix') + }, + + 'when using multiple options': { + topic: function () { + tmp.dir({ prefix: 'foo', postfix: 'bar', mode: 0750 }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a directory': _testDir(040750), + 'should have the provided prefix': Test.testPrefix('foo'), + 'should have the provided postfix': Test.testPostfix('bar') + }, + + 'when using multiple options and mode': { + topic: function () { + tmp.dir({ prefix: 'complicated', postfix: 'options', mode: 0755 }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a directory': _testDir(040755), + 'should have the provided prefix': Test.testPrefix('complicated'), + 'should have the provided postfix': Test.testPostfix('options') + }, + + 'no tries': { + topic: function () { + tmp.dir({ tries: -1 }, this.callback); + }, + + 'should return with an error': assert.isObject + }, + + 'keep testing': { + topic: function () { + Test.testKeep('dir', '1', this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a dir': function (err, name) { + _testDir(040700)(err, name); + fs.rmdirSync(name); + } + }, + + 'unlink testing': { + topic: function () { + Test.testKeep('dir', '0', this.callback); + }, + + 'should not return with error': assert.isNull, + 'should return with a name': Test.assertName, + 'should not exist': function (err, name) { + assert.ok(!existsSync(name), "Directory should be removed"); + } + }, + + 'non graceful testing': { + topic: function () { + Test.testGraceful('dir', '0', this.callback); + }, + + 'should not return with error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a dir': function (err, name) { + _testDir(040700)(err, name); + fs.rmdirSync(name); + } + }, + + 'graceful testing': { + topic: function () { + Test.testGraceful('dir', '1', this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should not exist': function (err, name) { + assert.ok(!existsSync(name), "Directory should be removed"); + } + }, + + 'unsafeCleanup === true': { + topic: function () { + Test.testUnsafeCleanup('1', this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should not exist': function (err, name) { + assert.ok(!existsSync(name), "Directory should be removed"); + }, + 'should remove symlinked dir': function(err, name) { + assert.ok( + !existsSync(name + '/symlinkme-target'), + 'should remove target' + ); + }, + 'should not remove contents of symlink dir': function(err, name) { + assert.ok( + existsSync(__dirname + '/symlinkme/file.js'), + 'should not remove symlinked directory\'s content' + ); + } + }, + + 'unsafeCleanup === false': { + topic: function () { + Test.testUnsafeCleanup('0', this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a directory': _testDir(040700) + } +}).exportTo(module); diff --git a/node_modules/nodecr/node_modules/tmp/test/file-test.js b/node_modules/nodecr/node_modules/tmp/test/file-test.js new file mode 100644 index 0000000..150ca11 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/file-test.js @@ -0,0 +1,165 @@ +var + vows = require('vows'), + assert = require('assert'), + + path = require('path'), + fs = require('fs'), + existsSync = fs.existsSync || path.existsSync, + + tmp = require('../lib/tmp.js'), + Test = require('./base.js'); + + +function _testFile(mode, fdTest) { + return function _testFileGenerated(err, name, fd) { + assert.ok(existsSync(name), 'should exist'); + + var stat = fs.statSync(name); + assert.equal(stat.size, 0, 'should have zero size'); + assert.ok(stat.isFile(), 'should be a file'); + + Test.testStat(stat, mode); + + // check with fstat as well (fd checking) + if (fdTest) { + var fstat = fs.fstatSync(fd); + assert.deepEqual(fstat, stat, 'fstat results should be the same'); + + var data = new Buffer('something'); + assert.equal(fs.writeSync(fd, data, 0, data.length, 0), data.length, 'should be writable'); + assert.ok(!fs.closeSync(fd), 'should not return with error'); + } + }; +} + +vows.describe('File creation').addBatch({ + 'when using without parameters': { + topic: function () { + tmp.file(this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': _testFile(0100600, true), + 'should have the default prefix': Test.testPrefix('tmp-'), + 'should have the default postfix': Test.testPostfix('.tmp') + }, + + 'when using with prefix': { + topic: function () { + tmp.file({ prefix: 'something' }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': _testFile(0100600, true), + 'should have the provided prefix': Test.testPrefix('something') + }, + + 'when using with postfix': { + topic: function () { + tmp.file({ postfix: '.txt' }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': _testFile(0100600, true), + 'should have the provided postfix': Test.testPostfix('.txt') + + }, + + 'when using template': { + topic: function () { + tmp.file({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': _testFile(0100600, true), + 'should have the provided prefix': Test.testPrefix('clike-'), + 'should have the provided postfix': Test.testPostfix('-postfix') + }, + + 'when using multiple options': { + topic: function () { + tmp.file({ prefix: 'foo', postfix: 'bar', mode: 0640 }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': _testFile(0100640, true), + 'should have the provided prefix': Test.testPrefix('foo'), + 'should have the provided postfix': Test.testPostfix('bar') + }, + + 'when using multiple options and mode': { + topic: function () { + tmp.file({ prefix: 'complicated', postfix: 'options', mode: 0644 }, this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': _testFile(0100644, true), + 'should have the provided prefix': Test.testPrefix('complicated'), + 'should have the provided postfix': Test.testPostfix('options') + }, + + 'no tries': { + topic: function () { + tmp.file({ tries: -1 }, this.callback); + }, + + 'should not be created': assert.isObject + }, + + 'keep testing': { + topic: function () { + Test.testKeep('file', '1', this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': function (err, name) { + _testFile(0100600, false)(err, name, null); + fs.unlinkSync(name); + } + }, + + 'unlink testing': { + topic: function () { + Test.testKeep('file', '0', this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should not exist': function (err, name) { + assert.ok(!existsSync(name), "File should be removed"); + } + }, + + 'non graceful testing': { + topic: function () { + Test.testGraceful('file', '0', this.callback); + }, + + 'should not return with error': assert.isNull, + 'should return with a name': Test.assertName, + 'should be a file': function (err, name) { + _testFile(0100600, false)(err, name, null); + fs.unlinkSync(name); + } + }, + + 'graceful testing': { + topic: function () { + Test.testGraceful('file', '1', this.callback); + }, + + 'should not return with an error': assert.isNull, + 'should return with a name': Test.assertName, + 'should not exist': function (err, name) { + assert.ok(!existsSync(name), "File should be removed"); + } + } + +}).exportTo(module); diff --git a/node_modules/nodecr/node_modules/tmp/test/graceful.js b/node_modules/nodecr/node_modules/tmp/test/graceful.js new file mode 100644 index 0000000..c898656 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/graceful.js @@ -0,0 +1,15 @@ +var + tmp = require('../lib/tmp'), + spawn = require('./spawn'); + +var graceful = spawn.arg; + +if (graceful) { + tmp.setGracefulCleanup(); +} + +spawn.tmpFunction(function (err, name) { + spawn.out(name, function () { + throw new Error("Thrown on purpose"); + }); +}); diff --git a/node_modules/nodecr/node_modules/tmp/test/keep.js b/node_modules/nodecr/node_modules/tmp/test/keep.js new file mode 100644 index 0000000..9538605 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/keep.js @@ -0,0 +1,11 @@ +var spawn = require('./spawn'); + +var keep = spawn.arg; + +spawn.tmpFunction({ keep: keep }, function (err, name) { + if (err) { + spawn.err(err, spawn.exit); + } else { + spawn.out(name, spawn.exit); + } +}); diff --git a/node_modules/nodecr/node_modules/tmp/test/name-test.js b/node_modules/nodecr/node_modules/tmp/test/name-test.js new file mode 100644 index 0000000..a242c21 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/name-test.js @@ -0,0 +1,82 @@ +var + vows = require('vows'), + assert = require('assert'), + + path = require('path'), + + tmp = require('../lib/tmp.js'), + Test = require('./base.js'); + +vows.describe('Name creation').addBatch({ + 'when using without parameters': { + topic: function () { + tmp.tmpName(this.callback); + }, + + 'should not return with error': assert.isNull, + 'should have the default prefix': Test.testPrefix('tmp-') + }, + + 'when using with prefix': { + topic: function () { + tmp.tmpName({ prefix: 'something' }, this.callback); + }, + + 'should not return with error': assert.isNull, + 'should have the provided prefix': Test.testPrefix('something') + }, + + 'when using with postfix': { + topic: function () { + tmp.tmpName({ postfix: '.txt' }, this.callback); + }, + + 'should not return with error': assert.isNull, + 'should have the provided postfix': Test.testPostfix('.txt') + + }, + + 'when using template': { + topic: function () { + tmp.tmpName({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') }, this.callback); + }, + + 'should not return with error': assert.isNull, + 'should have the provided prefix': Test.testPrefix('clike-'), + 'should have the provided postfix': Test.testPostfix('-postfix'), + 'should have template filled': function (err, name) { + assert.isTrue(/[a-zA-Z0-9]{6}/.test(name)); + } + }, + + 'when using multiple options': { + topic: function () { + tmp.tmpName({ prefix: 'foo', postfix: 'bar', tries: 5 }, this.callback); + }, + + 'should not return with error': assert.isNull, + 'should have the provided prefix': Test.testPrefix('foo'), + 'should have the provided postfix': Test.testPostfix('bar') + }, + + 'no tries': { + topic: function () { + tmp.tmpName({ tries: -1 }, this.callback); + }, + + 'should fail': function (err, name) { + assert.isObject(err); + } + }, + + 'tries not numeric': { + topic: function () { + tmp.tmpName({ tries: 'hello'}, this.callback); + }, + + 'should fail': function (err, name) { + assert.isObject(err); + } + } + +}).exportTo(module); diff --git a/node_modules/nodecr/node_modules/tmp/test/spawn.js b/node_modules/nodecr/node_modules/tmp/test/spawn.js new file mode 100644 index 0000000..6468eb3 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/spawn.js @@ -0,0 +1,32 @@ +var + fs = require('fs'), + tmp = require('../lib/tmp'); + +function _writeSync(stream, str, cb) { + var flushed = stream.write(str); + if (flushed) { + return cb(null); + } + + stream.once('drain', function _flushed() { + cb(null); + }); +} + +module.exports.out = function (str, cb) { + _writeSync(process.stdout, str, cb); +}; + +module.exports.err = function (str, cb) { + _writeSync(process.stderr, str, cb); +}; + +module.exports.exit = function () { + process.exit(0); +}; + +var type = process.argv[2]; +module.exports.tmpFunction = (type == 'file') ? tmp.file : tmp.dir; + +var arg = (process.argv[3] && parseInt(process.argv[3], 10) === 1) ? true : false; +module.exports.arg = arg; diff --git a/node_modules/nodecr/node_modules/tmp/test/symlinkme/file.js b/node_modules/nodecr/node_modules/tmp/test/symlinkme/file.js new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/nodecr/node_modules/tmp/test/unsafe.js b/node_modules/nodecr/node_modules/tmp/test/unsafe.js new file mode 100644 index 0000000..73e4fb3 --- /dev/null +++ b/node_modules/nodecr/node_modules/tmp/test/unsafe.js @@ -0,0 +1,30 @@ +var + fs = require('fs'), + join = require('path').join, + spawn = require('./spawn'); + +var unsafe = spawn.arg; +spawn.tmpFunction({ unsafeCleanup: unsafe }, function (err, name) { + if (err) { + spawn.err(err, spawn.exit); + return; + } + + try { + // file that should be removed + var fd = fs.openSync(join(name, 'should-be-removed.file'), 'w'); + fs.closeSync(fd); + + // in tree source + var symlinkSource = join(__dirname, 'symlinkme'); + // testing target + var symlinkTarget = join(name, 'symlinkme-target'); + + // symlink that should be removed but the contents should be preserved. + fs.symlinkSync(symlinkSource, symlinkTarget, 'dir'); + + spawn.out(name, spawn.exit); + } catch (e) { + spawn.err(e.toString(), spawn.exit); + } +}); diff --git a/node_modules/nodecr/package.json b/node_modules/nodecr/package.json new file mode 100644 index 0000000..cfd2dd5 --- /dev/null +++ b/node_modules/nodecr/package.json @@ -0,0 +1,35 @@ +{ + "name": "nodecr", + "version": "0.0.5", + "author": { + "name": "Joscha Feth", + "email": "joscha@feth.com" + }, + "description": "A simple wrapper for the Tesseract OCR package", + "main": "./lib/nodecr.js", + "repository": { + "type": "git", + "url": "https://github.com/joscha/nodecr/" + }, + "keywords": [ + "tesseract", + "ocr", + "text recognition" + ], + "dependencies": { + "tmp": ">= 0.0.14" + }, + "devDependencies": {}, + "license": "MIT", + "engine": { + "node": ">=0.6" + }, + "readme": "# Tesseract for Node.js\n\nA simple wrapper for the Tesseract OCR package for Node.js\n\n## Installation\n`npm install nodecr`\n\n## Versions\n* **0.0.5**: Add possibility to override logger (quiet nodecr, see example below)\n* **0.0.4**: Changed name to nodecr and published node module (formerly node-tesseract)\n* **0.0.3**: Added support for custom preprocessors, OTB Preprocessor using ImageMagick 'convert'\n* **0.0.2**: Refactored to support tesseract 3.01, added language parameter, config parameter, documentation\n* **0.0.1**: Initial version from Desmond Morris\n\n## Usage\n\n```JavaScript\nvar nodecr = require('nodecr');\n\n// Recognise text of any language in any format\nnodecr.process(__dirname + '/path/to/image.jpg',function(err, text) {\n\tif(err) {\n\t\tconsole.error(err);\n\t} else {\n\t\tconsole.log(text);\n\t}\n});\n\n// Recognise German text in a single uniform block of text\nnodecr.process(__dirname + '/path/to/image.jpg',function(err, text) {\n\tif(err) {\n\t\tconsole.error(err);\n\t} else {\n\t\tconsole.log(text);\n\t}\n}, 'deu', 6);\n\n// Recognise text of any language in any format but preprocess the image\n// with ImageMagick 'convert' (This requires ImageMagick to be installed)\n\n// uncomment this to quiet nodecr\n//nodecr.log = function() {};\n\n// You can write and use your own preprocessors easily, just have a look at src/nodecr.coffee\nnodecr.process(__dirname + '/path/to/image.jpg',function(err, text) {\n\tif(err) {\n\t\tconsole.error(err);\n\t} else {\n\t\tconsole.log(text);\n\t}\n\tconsole.log(text);\n}, null, null, null, nodecr.preprocessors.convert);\n```\n\n## License\nMIT", + "readmeFilename": "README.md", + "_id": "nodecr@0.0.5", + "dist": { + "shasum": "2a7e3c02e585146667f610d102e8e760e938b0bc" + }, + "_from": "nodecr@", + "_resolved": "https://registry.npmjs.org/nodecr/-/nodecr-0.0.5.tgz" +} diff --git a/node_modules/nodecr/src/nodecr.coffee b/node_modules/nodecr/src/nodecr.coffee new file mode 100644 index 0000000..0f1ec33 --- /dev/null +++ b/node_modules/nodecr/src/nodecr.coffee @@ -0,0 +1,173 @@ +exec = require('child_process').exec +fs = require 'fs' +tmp = require 'tmp' + +### +Attention: Tesseract 3.01 or higher is needed for this to work +### +class Tesseract + + ### + @param image Can be any format that your installed Leptonica library can process + (additional libraries might be required by Leptonica) + + @param callback A function pointer + this function is called after the recognition has taken place + with a possible error as first and the resulting recognized text as second parameter + + @param languageCode (Optional) a language code for the language to recognise + see http://code.google.com/p/tesseract-ocr/downloads/list for available languages (xxx.traineddata.gz) + any language you pass as an argument here must be unzipped into the tessdata directory beforehand + + @param pageSegMode (Optional) The page segmentation mode. + As of March 4, 2012 tesseract supports the following options: + + 0 = Orientation and script detection (OSD) only. + 1 = Automatic page segmentation with OSD. + 2 = Automatic page segmentation, but no OSD, or OCR + 3 = Fully automatic page segmentation, but no OSD. (Default) + 4 = Assume a single column of text of variable sizes. + 5 = Assume a single uniform block of vertically aligned text. + 6 = Assume a single uniform block of text. + 7 = Treat the image as a single text line. + 8 = Treat the image as a single word. + 9 = Treat the image as a single word in a circle. + 10 = Treat the image as a single character. + + See http://code.google.com/p/tesseract-ocr/source/browse/trunk/api/tesseractmain.cpp#95 for current state of options + + @param config (Optional) A config file name + ### + process: (image, callback, languageCode, pageSegMode, config, preprocessor) -> + (preprocessor or @preprocessor) image, (err, processedImage, cleanup) => + if err + # error in preprocessor + callback err, null + return + + f = (err, text) => + if cleanup? + @log "node-tesseract: Preprocessor cleanup" + cleanup() + callback err, text + return + + @_runTesseract processedImage, f, languageCode, pageSegMode, config + return + + _runTesseract: (image, callback, languageCode, pageSegMode, config) -> + + # generate output file name + tmp.tmpName (err, output) => + if err + # Something went wrong when generating the temporary filename + callback err, null + return + + # assemble tesseract command + command = [ + @binary + image + output + ] + if languageCode + command.push '-l' + command.push languageCode + + if typeof pageSegMode isnt 'undefined' and pageSegMode isnt null + command.push '-psm' + command.push pageSegMode + + command.push config if config + + command = command.join ' ' + + # Run the tesseract command + @log "node-tesseract: Running '#{command}'" + exec command, (err, stdout, stderr) => + if err + + # Something went wrong executing the assembled command + callback err, null + return + outputFile = output + '.txt' + fs.readFile outputFile, (err, data) => + + # There was no error, so get the text + data = data.toString @outputEncoding unless err + @log "node-tesseract: Deleting '#{outputFile}'" + fs.unlink outputFile, (err) -> + # ignore any errors here as it just means we have a temporary file left somewehere + + # We got the result (or an error) + callback err, data + return + return + return + return + + ### + A no-op preprocessor + + @param inputFile The file to process + @param callback The callback to call when the processing is done (1st argument error, 2nd the outputfile (the processed input file)) + ### + preprocessor: (inputFile, callback) -> + # the default preprocessor does nothing... + error = null + outputFile = inputFile + cleanup = -> + # clean up here + return + + # this gets called after the preprocessed image has been used + callback error, outputFile, cleanup + return + + log: -> + console.log.apply console, arguments + return + + binary: 'tesseract' + outputEncoding: 'UTF-8' + preprocessors: + convert: ConvertPreprocessor = (inputFile, callback) -> + tesseract.log "node-tesseract: preprocessor: convert: Processing '#{inputFile}'" + tmp.tmpName postfix: '.tif', (err, outputFile) -> + if err + # Something went wrong when generating the temporary filename + callback err, null + return + + command = [ + 'convert' + '-type' + 'Grayscale' + '-resize' + '200%' + '-sharpen' + '10' + inputFile + outputFile + ].join ' ' + tesseract.log "node-tesseract: preprocessor: convert: Running '#{command}'" + exec command, (err, stdout, stderr) -> + if err + # Something went wrong executing the convert command + callback err, null + else + cleanup = -> + tesseract.log "node-tesseract: preprocessor: convert: Deleting '#{outputFile}'" + fs.unlink outputFile, (err) -> + # ignore any errors here as it just means we have a temporary file left somewehere + return + return + + callback null, outputFile, cleanup + return + return + return + +tesseract = new Tesseract +# Exports +module.exports = tesseract \ No newline at end of file diff --git a/node_modules/nodecr/test/image.png b/node_modules/nodecr/test/image.png new file mode 100644 index 0000000..8d30d29 Binary files /dev/null and b/node_modules/nodecr/test/image.png differ diff --git a/node_modules/nodecr/test/test.js b/node_modules/nodecr/test/test.js new file mode 100644 index 0000000..bdaacbe --- /dev/null +++ b/node_modules/nodecr/test/test.js @@ -0,0 +1,13 @@ +var nodecr = require('../lib/nodecr'); + +// uncomment this to quiet nodecr +//nodecr.log = function() {}; + +nodecr.process(__dirname + '/image.png',function(err, text) { + if(err) { + console.error(err); + } else { + console.log("Result:"); + console.log(text); + } +}, null, null, null, nodecr.preprocessors.convert); \ No newline at end of file diff --git a/stop.png b/stop.png new file mode 100644 index 0000000..cbb1f64 Binary files /dev/null and b/stop.png differ diff --git a/test.png b/test.png new file mode 100644 index 0000000..a750073 Binary files /dev/null and b/test.png differ