Index: Dev/trunk/Gruntfile.js
===================================================================
--- Dev/trunk/Gruntfile.js	(revision 516)
+++ Dev/trunk/Gruntfile.js	(revision 517)
@@ -8,6 +8,9 @@
     // TASKS
 
+    // default task
     grunt.registerTask('default', ['compile']);
-    grunt.registerTask('compile', ['svn-ignore:compile'
+    // development
+    grunt.registerTask('compile', ['path-check:svn'
+                                  ,'svn-ignore:compile'
                                   ,'jshint:lint-sources'
                                   ,'htmlhint:lint'
@@ -22,4 +25,7 @@
                                 //,'amd-check' // too smart about plugins, r.js can't find them
                                   ]);
+    grunt.registerTask('run', ['path-check:foreman'
+                              ,'compile'
+                              ,'foreman:dev']);
     grunt.registerTask('build', ['compile'
                                 ,'clean:build'
@@ -27,8 +33,25 @@
                                 ,'dojo:build'
                                 ]);
-    grunt.registerTask('deploy', ['path-check:deploy',
-                                  'svninfo',
-                                  'build',
-                                  'git_deploy:deploy']);
+    grunt.registerTask('run-build', ['path-check:foreman'
+                                    ,'build'
+                                    ,'foreman:build']);
+    grunt.registerTask('deploy', ['path-check:svn'
+                                 ,'path-check:git'
+                                 ,'svninfo'
+                                 ,'build'
+                                 ,'git_deploy:deploy']);
+    // database management
+    grunt.registerTask('db-backup-cloud-to-dated-local',
+                       ['path-check:heroku'
+                       ,'heroku-config'
+                       ,'http:db-backup-cloud-to-dated-local']);
+    grunt.registerTask('db-pull-cloud-to-local',
+                       ['path-check:heroku'
+                       ,'heroku-config'
+                       ,'http:db-pull-cloud-to-local']);
+    grunt.registerTask('db-push-local-to-cloud',
+                       ['path-check:heroku'
+                       ,'heroku-config'
+                       ,'http:db-push-local-to-cloud']);
 
     // FILES AND FOLDERS
@@ -46,6 +69,9 @@
 
     // TASK CONFIG
-    
+
     grunt.initConfig({
+        localDbURL: "http://localhost:5984",
+        timestamp: "<%= grunt.template.today(\"UTC:yyyymmdd't'HHMMss'z'\") %>",
+
         'amd-check': {
             files: [ srcDir+'client/qed-client/**/*.js' ]
@@ -73,4 +99,16 @@
                                 releaseDir: '../../'+buildDir }}
         },
+        foreman: {
+            dev: {
+                options: {
+                    cwd: srcDir
+                }
+            },
+            build: {
+                options: {
+                    cwd: buildDir
+                }
+            }
+        },
         git_deploy: {
             deploy: {
@@ -83,4 +121,10 @@
             }
         },
+        'heroku-config': {
+            options: {
+                app: 'quod-erat',
+                keys: ['CLOUDANT_URL']
+            }
+        },
         htmlhint: {
             options: { htmlhintrc: srcDir+".htmlhintrc" },
@@ -89,4 +133,40 @@
                               src: ['client/*.html', 'client/qed-client/**/*.html'] }]}
         },
+        http: {
+            'db-backup-cloud-to-dated-local': {
+                options: {
+                    url: "<%= localDbURL %>/_replicate",
+                    method: 'POST',
+                    body: {
+                        source: "<%= herokuConfig.CLOUDANT_URL %>/qed",
+                        target: "qed-<%= timestamp %>",
+                        create_target: true
+                    },
+                    json: true
+                }
+            },
+            'db-pull-cloud-to-local': {
+                options: {
+                    url: "<%= localDbURL %>/_replicate",
+                    method: 'POST',
+                    body: {
+                        source: "<%= herokuConfig.CLOUDANT_URL %>/qed",
+                        target: "qed"
+                    },
+                    json: true
+                }
+            },
+            'db-push-local-to-cloud': {
+                options: {
+                    url: "<%= localDbURL %>/_replicate",
+                    method: 'POST',
+                    body: {
+                        source: "qed",
+                        target: "<%= herokuConfig.CLOUDANT_URL %>/qed"
+                    },
+                    json: true
+                }
+            }
+        },
         jshint: {
             'lint-sources': { options: { jshintrc: srcDir+".jshintrc" },
@@ -104,6 +184,15 @@
         },
         'path-check': {
-            'deploy': {
-                src: [ 'git', 'svn' ]
+            'heroku': {
+                src: ['heroku']
+            },
+            'foreman': {
+                src: ['foreman']
+            },
+            'svn': {
+                src: ['svn']
+            },
+            'git': {
+                src: ['git']
             }
         },
@@ -164,4 +253,5 @@
     grunt.loadNpmTasks('grunt-git-deploy');
     grunt.loadNpmTasks('grunt-htmlhint');
+    grunt.loadNpmTasks('grunt-http');
     grunt.loadNpmTasks('grunt-jsonlint');
     grunt.loadNpmTasks('grunt-path-check');
Index: Dev/trunk/db-backup-cloud-to-dated-local.sh
===================================================================
--- Dev/trunk/db-backup-cloud-to-dated-local.sh	(revision 516)
+++ 	(revision )
@@ -1,10 +1,0 @@
-#!/bin/sh
-
-. ./env.sh
-
-if [ -z "$CLOUDANT_URL" ]; then
-    echo "Cloudant URL is not defined in env.sh"
-    exit 1
-fi
-
-curl http://localhost:5984/_replicate -H "Content-Type: application/json" -d "{\"source\":\"$CLOUDANT_URL/qed\", \"target\":\"qed-`date +'%Y%m%dt%H%M%S'`\", \"create_target\":true}"
Index: Dev/trunk/db-pull-cloud-to-local.sh
===================================================================
--- Dev/trunk/db-pull-cloud-to-local.sh	(revision 516)
+++ 	(revision )
@@ -1,10 +1,0 @@
-#!/bin/sh
-
-. ./env.sh
-
-if [ -z "$CLOUDANT_URL" ]; then
-    echo "Cloudant URL is not defined in env.sh"
-    exit 1
-fi
-
-curl http://localhost:5984/_replicate -H "Content-Type: application/json" -d "{\"source\":\"$CLOUDANT_URL/qed\", \"target\":\"qed\"}"
Index: Dev/trunk/db-push-local-to-cloud.sh
===================================================================
--- Dev/trunk/db-push-local-to-cloud.sh	(revision 516)
+++ 	(revision )
@@ -1,10 +1,0 @@
-#!/bin/sh
-
-. ./env.sh
-
-if [ -z "$CLOUDANT_URL" ]; then
-    echo "Cloudant URL is not defined in env.sh"
-    exit 1
-fi
-
-curl http://localhost:5984/_replicate -H "Content-Type: application/json" -d "{\"target\":\"$CLOUDANT_URL/qed\", \"source\":\"qed\"}"
Index: Dev/trunk/env.sh
===================================================================
--- Dev/trunk/env.sh	(revision 516)
+++ 	(revision )
@@ -1,8 +1,0 @@
-#!/bin/sh
-
-DEPLOYURL=git@heroku.com:quod-erat.git
-DEPLOYDIR=quod-erat.git
-if [ -d "$DEPLOYDIR" ]; then
-    CLOUDANT_URL=`cd $DEPLOYDIR; heroku config:get CLOUDANT_URL`
-fi
-export DEPLOYURL DEPLOYDIR CLOUDANT_URL
Index: Dev/trunk/grunt-tasks/heroku.js
===================================================================
--- Dev/trunk/grunt-tasks/heroku.js	(revision 517)
+++ Dev/trunk/grunt-tasks/heroku.js	(revision 517)
@@ -0,0 +1,75 @@
+var _ = require('underscore')
+  , path = require('path');
+
+module.exports = function(grunt) {
+    
+    grunt.registerTask(
+        'heroku-config',
+        "Get config values from heroku app and put them in grunt.config.",
+        function(){
+            var done = this.async();
+            var options = this.options({
+                keys: [],
+                output: 'herokuConfig'
+            });
+            if ( !options.app ) {
+                done(new Error(("Must specify the app name.")));
+            } else {
+                if ( options.keys.length === 0 ) {
+                    grunt.log.warn("Did not specify any config keys.");
+                }
+                var tasks = _.map(options.keys, function(key){
+                    return _.partial(getConfigValue,options.app,key);
+                });
+                grunt.util.async.series(tasks,function(error,results){
+                    if ( error ) {
+                        done(error);
+                    } else {
+                        var herokuConfig = {};
+                        _.each(results,function(result){
+                            _.extend(herokuConfig,result);
+                        });
+                        grunt.config.set(options.output,herokuConfig);
+                        done();
+                    }
+                });
+            }
+        });
+
+    function getConfigValue(app,key,callback) {
+        grunt.util.spawn({
+            cmd: 'heroku',
+            args: ['config:get',key,'--app',app]
+        }, function(error,result){
+            if ( error ) {
+                callback(error);
+            } else {
+                var value = grunt.util.normalizelf(result.stdout)
+                            .split(grunt.util.linefeed)[0];
+                result = {};
+                result[key] = value;
+                callback(null,result);
+            }
+        });
+    }
+
+    grunt.registerMultiTask(
+        'foreman',
+        "Run a foreman command in a directory.",
+        function(){
+            var options = this.options({
+                cmd: 'start',
+                cwd: '.'
+            });
+            var done = this.async();
+            grunt.util.spawn({
+                cmd: 'foreman',
+                args: [options.cmd],
+                opts: {
+                    cwd: options.cwd,
+                    stdio: 'inherit'
+                }
+            }, done);
+        });
+
+};
Index: Dev/trunk/grunt-tasks/svn-ignore.js
===================================================================
--- Dev/trunk/grunt-tasks/svn-ignore.js	(revision 516)
+++ Dev/trunk/grunt-tasks/svn-ignore.js	(revision 517)
@@ -6,41 +6,43 @@
 module.exports = function(grunt) {
 
-    grunt.registerMultiTask('svn-ignore',
-                            "Makes sure the specified source files are ignored in Subversion.",
-                            function(){
-        var done = this.async();
+    grunt.registerMultiTask(
+        'svn-ignore',
+        "Makes sure the specified source files are ignored in Subversion.",
+        function(){
+            var done = this.async();
 
-        var tasks = _.chain(this.filesSrc)
-                     .groupBy(path.dirname)
-                     .map(function(files, dir) {
-                         return _.partial(updateSvnIgnore,
-                                          dir,
-                                          _.chain(files)
-                                           .map(path.basename)
-                                           .sortBy(_.identity)
-                                           .value());
-                     })
-                     .value();
+            var tasks = _.chain(this.filesSrc)
+                         .groupBy(path.dirname)
+                         .map(function(files, dir) {
+                             return _.partial(updateSvnIgnore,
+                                              dir,
+                                              _.chain(files)
+                                               .map(path.basename)
+                                               .sortBy(_.identity)
+                                               .value());
+                         })
+                         .value();
 
-        grunt.util.async.series(tasks,function(error, results){
-            done(error);
+            grunt.util.async.series(tasks,function(error, results){
+                done(error);
+            });
         });
-    });
 
-    grunt.registerMultiTask('svn-ignore-clean',
-                            "Clean generated ignore sections in Subversion.",
-                            function(){
-        var done = this.async();
+    grunt.registerMultiTask(
+        'svn-ignore-clean',
+        "Clean generated ignore sections in Subversion.",
+        function(){
+            var done = this.async();
 
-        var tasks = _.chain(this.filesSrc)
-                     .map(function(file) {
-                         return _.partial(clearSvnIgnore, file);
-                     })
-                     .value();
+            var tasks = _.chain(this.filesSrc)
+                         .map(function(file) {
+                             return _.partial(clearSvnIgnore, file);
+                         })
+                         .value();
 
-        grunt.util.async.series(tasks,function(error, results){
-            done(error);
+            grunt.util.async.series(tasks,function(error, results){
+                done(error);
+            });
         });
-    });
 
     function updateSvnIgnore(dir,files,callback) {
@@ -123,31 +125,28 @@
     
     function readSvnIgnore(dir,callback) {
-        return svnCommand('svn',
-                          ['propget', 'svn:ignore', dir],
-                          callback);
+        return svn(['propget', 'svn:ignore', dir],
+                   callback);
     }
 
     function writeSvnIgnore(dir,ignore,callback) {
-        return svnCommand('svn',
-                          ['propset', 'svn:ignore', ignore, dir],
-                          callback);
+        return svn(['propset', 'svn:ignore', ignore, dir],
+                   callback);
     }
     
     function deleteSvnIgnore(dir,callback) {
-        return svnCommand('svn',
-                          ['propdel', 'svn:ignore', dir],
-                          callback);
+        return svn(['propdel', 'svn:ignore', dir],
+                   callback);
     }
     
-    function svnCommand(cmd,args,callback) {
+    function svn(args,callback) {
         grunt.util.spawn({
-            cmd: cmd,
+            cmd: 'svn',
             args: (args || [])
-        }, function(error, result, code) {
+        }, function(error, result) {
             if ( error ) {
                 callback(error);
-                return;
+            } else {
+                callback(null,result.stdout);
             }
-            callback(null,result.stdout);
         });
     }
Index: Dev/trunk/node_modules/grunt-http/.jshintrc
===================================================================
--- Dev/trunk/node_modules/grunt-http/.jshintrc	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/.jshintrc	(revision 517)
@@ -0,0 +1,14 @@
+{
+  "curly": true,
+  "eqeqeq": true,
+  "immed": true,
+  "latedef": true,
+  "newcap": true,
+  "noarg": true,
+  "sub": true,
+  "undef": true,
+  "boss": true,
+  "eqnull": true,
+  "node": true,
+  "es5": true
+}
Index: Dev/trunk/node_modules/grunt-http/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/.npmignore	(revision 517)
@@ -0,0 +1,4 @@
+*.log
+*.swp
+node_modules
+tmp
Index: Dev/trunk/node_modules/grunt-http/Gruntfile.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/Gruntfile.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/Gruntfile.js	(revision 517)
@@ -0,0 +1,86 @@
+/*
+ * grunt-http
+ * https://github.com/johngeorgewright/grunt-contrib-http
+ *
+ * Copyright (c) 2013 John Wright
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+module.exports = function(grunt) {
+
+  // Project configuration.
+  grunt.initConfig({
+    jshint: {
+      all: [
+        'Gruntfile.js',
+        'tasks/*.js',
+        '<%= nodeunit.tests %>',
+      ],
+      options: {
+        jshintrc: '.jshintrc',
+      },
+    },
+
+    // Before generating any new files, remove any previously-created files.
+    clean: {
+      tests: ['tmp'],
+    },
+
+    // Configuration to be run (and then tested).
+    http: {
+      basic: {
+        options: {
+          url: 'http://www.j-g-w.info'
+        },
+        dest: 'tmp/basic.html'
+      },
+      closure: {
+        options: {
+          form: {
+            output_info: 'compiled_code',
+            output_format: 'text',
+            compilation_level: 'SIMPLE_OPTIMIZATIONS',
+            warning_level: 'default',
+          },
+          url: 'http://closure-compiler.appspot.com/compile',
+          method: 'POST',
+          sourceField: 'form.js_code'
+        },
+        files: {
+          'tmp/compiled.js': 'test/fixtures/not-compiled.js'
+        }
+      },
+      ignoreErrors: {
+        options: {
+          url: 'http://someurlthatdoesntexist.xx',
+          method: 'GET',
+          ignoreErrors: true
+        }
+      }
+    },
+
+    // Unit tests.
+    nodeunit: {
+      tests: ['test/*_test.js'],
+    },
+
+  });
+
+  // Actually load this plugin's task(s).
+  grunt.loadTasks('tasks');
+
+  // These plugins provide necessary tasks.
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('grunt-contrib-clean');
+  grunt.loadNpmTasks('grunt-contrib-nodeunit');
+
+  // Whenever the "test" task is run, first clean the "tmp" dir, then run this
+  // plugin's task(s), then test the result.
+  grunt.registerTask('test', ['clean', 'http', 'nodeunit']);
+
+  // By default, lint and run all tests.
+  grunt.registerTask('default', ['jshint', 'test']);
+
+};
Index: Dev/trunk/node_modules/grunt-http/LICENSE-MIT
===================================================================
--- Dev/trunk/node_modules/grunt-http/LICENSE-MIT	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/LICENSE-MIT	(revision 517)
@@ -0,0 +1,22 @@
+Copyright (c) 2013 John Wright
+
+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.
Index: Dev/trunk/node_modules/grunt-http/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/README.md	(revision 517)
@@ -0,0 +1,105 @@
+# grunt-http
+
+> Sends a HTTP request and deals with the response.
+
+[![NPM](https://nodei.co/npm/grunt-http.png)](https://nodei.co/npm/grunt-http)
+
+## Getting Started
+This plugin requires Grunt `~0.4.1`
+
+If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
+
+```shell
+npm install grunt-http --save-dev
+```
+
+Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
+
+```js
+grunt.loadNpmTasks('grunt-http');
+```
+
+## The "http" task
+
+### Overview
+In your project's Gruntfile, add a section named `http` to the data object passed into `grunt.initConfig()`.
+
+```js
+grunt.initConfig({
+  http: {
+    your_service: {
+      options: {
+        url: 'your/url.com',
+      },
+      dest: 'optional/file/to/save/response'
+    }
+  }
+})
+```
+
+If you add a source file, the contents will be added to the `body` option unless another field is specified in the `sourceField` option.
+
+### Options
+
+grunt-http uses the [request](https://github.com/mikeal/request) module under the hood, and apart from a couple specific to grunt-http options, the rest get passed straight to it. Here's a copy of the of the module's option docs. Otherwise, [go to the repo](https://github.com/mikeal/request) and have a look at what's it's capable of.
+
+- `uri || url` - fully qualified uri or a parsed url object from url.parse(). REQUIRED.
+- `qs` - object containing querystring values to be appended to the uri
+- `method` - http method, defaults to GET
+- `headers` - http headers, defaults to {}
+- `body` - entity body for PATCH, POST and PUT requests. Must be buffer or string.
+- `sourceField` - A field in the body or form to add the source files' contents to. Can contain full stops to separate object path. Ie "form.js\_code".
+- `form` - when passed an object this will set body but to a querystring representation of value and adds Content-type: application/x-www-form-urlencoded; charset=utf-8 header. When passed no option a FormData instance is returned that will be piped to request.
+- `auth` - A hash containing values user || username, password || pass, and sendImmediately (optional). [See more info here](https://github.com/mikeal/request#http-authentication).
+- `json` - sets body but to JSON representation of value and adds Content-type: application/json header. Additionally, parses the response body as json.
+- `multipart` - (experimental) array of objects which contains their own headers and body attribute. Sends multipart/related request. See example below.
+- `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true.
+- `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects. defaults to false.
+- `maxRedirects` - the maximum number of redirects to follow, defaults to 10.
+- `encoding` - Encoding to be used on setEncoding of response data. If set to null, the body is returned as a Buffer.
+- `pool` - A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets.
+- `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.
+- `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request
+- `proxy` - An HTTP proxy to be used. Support proxy Auth with Basic Auth the same way it's supported with the url parameter by embedding the auth info in the uri.
+- `oauth` - Options for OAuth HMAC-SHA1 signing. [See more info here](https://github.com/mikeal/request#oauth-signing).
+- `hawk` - Options for [Hawk signing](https://github.com/hueniverse/hawk). The credentials key must contain the necessary signing info, [see hawk docs for details](https://github.com/hueniverse/hawk#usage-example).
+- `strictSSL` - Set to true to require that SSL certificates be valid. Note: to use your own certificate authority, you need to specify an agent that was created with that ca as an option.
+- `jar` - Set to false if you don't want cookies to be remembered for future use or define your custom cookie jar ([see mikeal/request's examples section](https://github.com/mikeal/request#examples))
+- `aws` - object containing aws signing information, should have the properties key and secret as well as bucket unless you're specifying your bucket as part of the path, or you are making a request that doesn't use a bucket (i.e. GET Services)
+- `httpSignature` - Options for the [HTTP Signature Scheme](https://github.com/joyent/node-http-signature/blob/master/http_signing.md) using [Joyent's library](https://github.com/joyent/node-http-signature). The keyId and key properties must be specified. See the docs for other options.
+- `localAddress` - Local interface to bind for network connections.
+- `ignoreErrors` - Ignore the status code returned (if any).
+
+### Usage Examples
+
+#### Google Closure
+In this example, we're using google's closure service to compile a JS file.
+
+```js
+grunt.initConfig({
+  http: {
+    closure: {
+      options: {
+        url: 'http://closure-compiler.appspot.com/compile',
+        method: 'POST',
+        form: {
+          output_info: 'compiled_code',
+          output_format: 'text',
+          compilation_level: 'SIMPLE_OPTIMIZATIONS',
+          warning_level: 'default'
+        },
+        sourceField: 'form.js_code'
+      },
+      files: {
+        'build/main.js': 'src/main.js'
+      }
+    }
+  }
+});
+```
+
+## Contributing
+In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
+
+## [Release History](/johngeorgewright/grunt-http/releases)
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/.npmignore	(revision 517)
@@ -0,0 +1,2 @@
+tests
+node_modules
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/.travis.yml
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/.travis.yml	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/.travis.yml	(revision 517)
@@ -0,0 +1,12 @@
+language: node_js
+node_js:
+  - 0.8
+  - 0.10
+
+env:
+  - OPTIONALS=Y
+  - OPTIONALS=N
+
+install:
+  - if [[ "$OPTIONALS" == "Y" ]]; then npm install; fi
+  - if [[ "$OPTIONALS" == "N" ]]; then npm install --no-optional; fi
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/LICENSE	(revision 517)
@@ -0,0 +1,55 @@
+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:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+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
+
+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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/README.md	(revision 517)
@@ -0,0 +1,365 @@
+# Request -- Simplified HTTP client
+
+[![NPM](https://nodei.co/npm/request.png)](https://nodei.co/npm/request/)
+
+## Super simple to use
+
+Request is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.
+
+```javascript
+var request = require('request');
+request('http://www.google.com', function (error, response, body) {
+  if (!error && response.statusCode == 200) {
+    console.log(body) // Print the google web page.
+  }
+})
+```
+
+## Streaming
+
+You can stream any response to a file stream.
+
+```javascript
+request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
+```
+
+You can also stream a file to a PUT or POST request. This method will also check the file extension against a mapping of file extensions to content-types (in this case `application/json`) and use the proper `content-type` in the PUT request (if the headers donât already provide one).
+
+```javascript
+fs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))
+```
+
+Request can also `pipe` to itself. When doing so, `content-type` and `content-length` are preserved in the PUT headers.
+
+```javascript
+request.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))
+```
+
+Now letâs get fancy.
+
+```javascript
+http.createServer(function (req, resp) {
+  if (req.url === '/doodle.png') {
+    if (req.method === 'PUT') {
+      req.pipe(request.put('http://mysite.com/doodle.png'))
+    } else if (req.method === 'GET' || req.method === 'HEAD') {
+      request.get('http://mysite.com/doodle.png').pipe(resp)
+    }
+  }
+})
+```
+
+You can also `pipe()` from `http.ServerRequest` instances, as well as to `http.ServerResponse` instances. The HTTP method, headers, and entity-body data will be sent. Which means that, if you don't really care about security, you can do:
+
+```javascript
+http.createServer(function (req, resp) {
+  if (req.url === '/doodle.png') {
+    var x = request('http://mysite.com/doodle.png')
+    req.pipe(x)
+    x.pipe(resp)
+  }
+})
+```
+
+And since `pipe()` returns the destination stream in â¥ Node 0.5.x you can do one line proxying. :)
+
+```javascript
+req.pipe(request('http://mysite.com/doodle.png')).pipe(resp)
+```
+
+Also, none of this new functionality conflicts with requests previous features, it just expands them.
+
+```javascript
+var r = request.defaults({'proxy':'http://localproxy.com'})
+
+http.createServer(function (req, resp) {
+  if (req.url === '/doodle.png') {
+    r.get('http://google.com/doodle.png').pipe(resp)
+  }
+})
+```
+
+You can still use intermediate proxies, the requests will still follow HTTP forwards, etc.
+
+## Forms
+
+`request` supports `application/x-www-form-urlencoded` and `multipart/form-data` form uploads. For `multipart/related` refer to the `multipart` API.
+
+URL-encoded forms are simple.
+
+```javascript
+request.post('http://service.com/upload', {form:{key:'value'}})
+// or
+request.post('http://service.com/upload').form({key:'value'})
+```
+
+For `multipart/form-data` we use the [form-data](https://github.com/felixge/node-form-data) library by [@felixge](https://github.com/felixge). You donât need to worry about piping the form object or setting the headers, `request` will handle that for you.
+
+```javascript
+var r = request.post('http://service.com/upload')
+var form = r.form()
+form.append('my_field', 'my_value')
+form.append('my_buffer', new Buffer([1, 2, 3]))
+form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png'))
+form.append('remote_file', request('http://google.com/doodle.png'))
+```
+
+## HTTP Authentication
+
+```javascript
+request.get('http://some.server.com/').auth('username', 'password', false);
+// or
+request.get('http://some.server.com/', {
+  'auth': {
+    'user': 'username',
+    'pass': 'password',
+    'sendImmediately': false
+  }
+});
+```
+
+If passed as an option, `auth` should be a hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional).  The method form takes parameters `auth(username, password, sendImmediately)`.
+
+`sendImmediately` defaults to `true`, which causes a basic authentication header to be sent.  If `sendImmediately` is `false`, then `request` will retry with a proper authentication header after receiving a `401` response from the server (which must contain a `WWW-Authenticate` header indicating the required authentication method).
+
+Digest authentication is supported, but it only works with `sendImmediately` set to `false`; otherwise `request` will send basic authentication on the initial request, which will probably cause the request to fail.
+
+## OAuth Signing
+
+```javascript
+// Twitter OAuth
+var qs = require('querystring')
+  , oauth =
+    { callback: 'http://mysite.com/callback/'
+    , consumer_key: CONSUMER_KEY
+    , consumer_secret: CONSUMER_SECRET
+    }
+  , url = 'https://api.twitter.com/oauth/request_token'
+  ;
+request.post({url:url, oauth:oauth}, function (e, r, body) {
+  // Ideally, you would take the body in the response
+  // and construct a URL that a user clicks on (like a sign in button).
+  // The verifier is only available in the response after a user has
+  // verified with twitter that they are authorizing your app.
+  var access_token = qs.parse(body)
+    , oauth =
+      { consumer_key: CONSUMER_KEY
+      , consumer_secret: CONSUMER_SECRET
+      , token: access_token.oauth_token
+      , verifier: access_token.oauth_verifier
+      }
+    , url = 'https://api.twitter.com/oauth/access_token'
+    ;
+  request.post({url:url, oauth:oauth}, function (e, r, body) {
+    var perm_token = qs.parse(body)
+      , oauth =
+        { consumer_key: CONSUMER_KEY
+        , consumer_secret: CONSUMER_SECRET
+        , token: perm_token.oauth_token
+        , token_secret: perm_token.oauth_token_secret
+        }
+      , url = 'https://api.twitter.com/1.1/users/show.json?'
+      , params =
+        { screen_name: perm_token.screen_name
+        , user_id: perm_token.user_id
+        }
+      ;
+    url += qs.stringify(params)
+    request.get({url:url, oauth:oauth, json:true}, function (e, r, user) {
+      console.log(user)
+    })
+  })
+})
+```
+
+### Custom HTTP Headers
+
+HTTP Headers, such as `User-Agent`, can be set in the `options` object.
+In the example below, we call the github API to find out the number
+of stars and forks for the request repository. This requires a
+custom `User-Agent` header as well as https.
+
+```javascript
+var request = require('request');
+
+var options = {
+	url: 'https://api.github.com/repos/mikeal/request',
+	headers: {
+		'User-Agent': 'request'
+	}
+};
+
+function callback(error, response, body) {
+	if (!error && response.statusCode == 200) {
+		var info = JSON.parse(body);
+		console.log(info.stargazers_count + " Stars");
+		console.log(info.forks_count + " Forks");
+	}
+}
+
+request(options, callback);
+```
+
+### request(options, callback)
+
+The first argument can be either a `url` or an `options` object. The only required option is `uri`; all others are optional.
+
+* `uri` || `url` - fully qualified uri or a parsed url object from `url.parse()`
+* `qs` - object containing querystring values to be appended to the `uri`
+* `method` - http method (default: `"GET"`)
+* `headers` - http headers (default: `{}`)
+* `body` - entity body for PATCH, POST and PUT requests. Must be a `Buffer` or `String`.
+* `form` - when passed an object, this sets `body` to a querystring representation of value, and adds `Content-type: application/x-www-form-urlencoded; charset=utf-8` header. When passed no options, a `FormData` instance is returned (and is piped to request).
+* `auth` - A hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional).  See documentation above.
+* `json` - sets `body` but to JSON representation of value and adds `Content-type: application/json` header.  Additionally, parses the response body as JSON.
+* `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below.
+* `followRedirect` - follow HTTP 3xx responses as redirects (default: `true`)
+* `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects (default: `false`)
+* `maxRedirects` - the maximum number of redirects to follow (default: `10`)
+* `encoding` - Encoding to be used on `setEncoding` of response data. If `null`, the `body` is returned as a `Buffer`.
+* `pool` - A hash object containing the agents for these requests. If omitted, the request will use the global pool (which is set to node's default `maxSockets`)
+* `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.
+* `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request
+* `proxy` - An HTTP proxy to be used. Supports proxy Auth with Basic Auth, identical to support for the `url` parameter (by embedding the auth info in the `uri`)
+* `oauth` - Options for OAuth HMAC-SHA1 signing. See documentation above.
+* `hawk` - Options for [Hawk signing](https://github.com/hueniverse/hawk). The `credentials` key must contain the necessary signing info, [see hawk docs for details](https://github.com/hueniverse/hawk#usage-example).
+* `strictSSL` - If `true`, requires SSL certificates be valid. **Note:** to use your own certificate authority, you need to specify an agent that was created with that CA as an option.
+* `jar` - If `true`, remember cookies for future use (or define your custom cookie jar; see examples section)
+* `aws` - `object` containing AWS signing information. Should have the properties `key`, `secret`. Also requires the property `bucket`, unless youâre specifying your `bucket` as part of the path, or the request doesnât use a bucket (i.e. GET Services)
+* `httpSignature` - Options for the [HTTP Signature Scheme](https://github.com/joyent/node-http-signature/blob/master/http_signing.md) using [Joyent's library](https://github.com/joyent/node-http-signature). The `keyId` and `key` properties must be specified. See the docs for other options.
+* `localAddress` - Local interface to bind for network connections.
+
+
+The callback argument gets 3 arguments: 
+
+1. An `error` when applicable (usually from [`http.ClientRequest`](http://nodejs.org/api/http.html#http_class_http_clientrequest) object)
+2. An [`http.IncomingMessage`](http://nodejs.org/api/http.html#http_http_incomingmessage) object
+3. The third is the `response` body (`String` or `Buffer`, or JSON object if the `json` option is supplied)
+
+## Convenience methods
+
+There are also shorthand methods for different HTTP METHODs and some other conveniences.
+
+### request.defaults(options)
+
+This method returns a wrapper around the normal request API that defaults to whatever options you pass in to it.
+
+### request.put
+
+Same as `request()`, but defaults to `method: "PUT"`.
+
+```javascript
+request.put(url)
+```
+
+### request.patch
+
+Same as `request()`, but defaults to `method: "PATCH"`.
+
+```javascript
+request.patch(url)
+```
+
+### request.post
+
+Same as `request()`, but defaults to `method: "POST"`.
+
+```javascript
+request.post(url)
+```
+
+### request.head
+
+Same as request() but defaults to `method: "HEAD"`.
+
+```javascript
+request.head(url)
+```
+
+### request.del
+
+Same as `request()`, but defaults to `method: "DELETE"`.
+
+```javascript
+request.del(url)
+```
+
+### request.get
+
+Same as `request()` (for uniformity).
+
+```javascript
+request.get(url)
+```
+### request.cookie
+
+Function that creates a new cookie.
+
+```javascript
+request.cookie('cookie_string_here')
+```
+### request.jar
+
+Function that creates a new cookie jar.
+
+```javascript
+request.jar()
+```
+
+
+## Examples:
+
+```javascript
+  var request = require('request')
+    , rand = Math.floor(Math.random()*100000000).toString()
+    ;
+  request(
+    { method: 'PUT'
+    , uri: 'http://mikeal.iriscouch.com/testjs/' + rand
+    , multipart:
+      [ { 'content-type': 'application/json'
+        ,  body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})
+        }
+      , { body: 'I am an attachment' }
+      ]
+    }
+  , function (error, response, body) {
+      if(response.statusCode == 201){
+        console.log('document saved as: http://mikeal.iriscouch.com/testjs/'+ rand)
+      } else {
+        console.log('error: '+ response.statusCode)
+        console.log(body)
+      }
+    }
+  )
+```
+
+Cookies are disabled by default (else, they would be used in subsequent requests). To enable cookies, set `jar` to `true` (either in `defaults` or `options`).
+
+```javascript
+var request = request.defaults({jar: true})
+request('http://www.google.com', function () {
+  request('http://images.google.com')
+})
+```
+
+To use a custom cookie jar (instead `request`âs global cookie jar), set `jar` to an instance of `request.jar()` (either in `defaults` or `options`)
+
+```javascript
+var j = request.jar()
+var request = request.defaults({jar:j})
+request('http://www.google.com', function () {
+  request('http://images.google.com')
+})
+```
+
+OR
+
+```javascript
+var j = request.jar()
+var cookie = request.cookie('your_cookie_here')
+j.setCookie(cookie, uri);
+request({url: 'http://www.google.com', jar: j}, function () {
+  request('http://images.google.com')
+})
+```
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/dns-request.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/dns-request.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/dns-request.js	(revision 517)
@@ -0,0 +1,7 @@
+var request = require('request')
+  , dns = require('dns')
+  ;
+
+function wrap (fn) {
+  var
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/index.js	(revision 517)
@@ -0,0 +1,150 @@
+// Copyright 2010-2012 Mikeal Rogers
+//
+//    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 cookies = require('./lib/cookies')
+  , copy = require('./lib/copy')
+  , Request = require('./request')
+  ;
+
+
+
+// organize params for patch, post, put, head, del
+function initParams(uri, options, callback) {
+  if ((typeof options === 'function') && !callback) callback = options
+  if (options && typeof options === 'object') {
+    options.uri = uri
+  } else if (typeof uri === 'string') {
+    options = {uri:uri}
+  } else {
+    options = uri
+    uri = options.uri
+  }
+  return { uri: uri, options: options, callback: callback }
+}
+
+function request (uri, options, callback) {
+  if (typeof uri === 'undefined') throw new Error('undefined is not a valid uri or options object.')
+  if ((typeof options === 'function') && !callback) callback = options
+  if (options && typeof options === 'object') {
+    options.uri = uri
+  } else if (typeof uri === 'string') {
+    options = {uri:uri}
+  } else {
+    options = uri
+  }
+
+  options = copy(options)
+
+  if (callback) options.callback = callback
+  var r = new Request(options)
+  return r
+}
+
+module.exports = request
+
+request.Request = Request;
+
+request.debug = process.env.NODE_DEBUG && /request/.test(process.env.NODE_DEBUG)
+
+request.initParams = initParams
+
+request.defaults = function (options, requester) {
+  var def = function (method) {
+    var d = function (uri, opts, callback) {
+      var params = initParams(uri, opts, callback)
+      for (var i in options) {
+        if (params.options[i] === undefined) params.options[i] = options[i]
+      }
+      if(typeof requester === 'function') {
+        if(method === request) {
+          method = requester
+        } else {
+          params.options._requester = requester
+        }
+      }
+      return method(params.options, params.callback)
+    }
+    return d
+  }
+  var de = def(request)
+  de.get = def(request.get)
+  de.patch = def(request.patch)
+  de.post = def(request.post)
+  de.put = def(request.put)
+  de.head = def(request.head)
+  de.del = def(request.del)
+  de.cookie = def(request.cookie)
+  de.jar = request.jar
+  return de
+}
+
+function requester(params) {
+  if(typeof params.options._requester === 'function') {
+    return params.options._requester
+  } else {
+    return request
+  }
+}
+
+request.forever = function (agentOptions, optionsArg) {
+  var options = {}
+  if (optionsArg) {
+    for (var option in optionsArg) {
+      options[option] = optionsArg[option]
+    }
+  }
+  if (agentOptions) options.agentOptions = agentOptions
+  options.forever = true
+  return request.defaults(options)
+}
+
+request.get = request
+request.post = function (uri, options, callback) {
+  var params = initParams(uri, options, callback)
+  params.options.method = 'POST'
+  return requester(params)(params.uri || null, params.options, params.callback)
+}
+request.put = function (uri, options, callback) {
+  var params = initParams(uri, options, callback)
+  params.options.method = 'PUT'
+  return requester(params)(params.uri || null, params.options, params.callback)
+}
+request.patch = function (uri, options, callback) {
+  var params = initParams(uri, options, callback)
+  params.options.method = 'PATCH'
+  return requester(params)(params.uri || null, params.options, params.callback)
+}
+request.head = function (uri, options, callback) {
+  var params = initParams(uri, options, callback)
+  params.options.method = 'HEAD'
+  if (params.options.body ||
+      params.options.requestBodyStream ||
+      (params.options.json && typeof params.options.json !== 'boolean') ||
+      params.options.multipart) {
+    throw new Error("HTTP HEAD requests MUST NOT include a request body.")
+  }
+
+  return requester(params)(params.uri || null, params.options, params.callback)
+}
+request.del = function (uri, options, callback) {
+  var params = initParams(uri, options, callback)
+  params.options.method = 'DELETE'
+  return requester(params)(params.uri || null, params.options, params.callback)
+}
+request.jar = function () {
+  return cookies.jar();
+}
+request.cookie = function (str) {
+  return cookies.parse(str);
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/lib/cookies.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/lib/cookies.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/lib/cookies.js	(revision 517)
@@ -0,0 +1,36 @@
+var optional = require('./optional')
+  , tough = optional('tough-cookie')
+  , Cookie = tough && tough.Cookie
+  , CookieJar = tough && tough.CookieJar
+  ;
+
+exports.parse = function(str) {
+  if (str && str.uri) str = str.uri
+  if (typeof str !== 'string') throw new Error("The cookie function only accepts STRING as param")
+  if (!Cookie) {
+    return null;
+  }
+  return Cookie.parse(str)
+};
+
+// Adapt the sometimes-Async api of tough.CookieJar to our requirements
+function RequestJar() {
+  this._jar = new CookieJar();
+}
+RequestJar.prototype.setCookie = function(cookieOrStr, uri) {
+  return this._jar.setCookieSync(cookieOrStr, uri);
+};
+RequestJar.prototype.getCookieString = function(uri) {
+  return this._jar.getCookieStringSync(uri);
+};
+
+exports.jar = function() {
+  if (!CookieJar) {
+    // tough-cookie not loaded, return a stub object:
+    return {
+      setCookie: function(){},
+      getCookieString: function(){}
+    };
+  }
+  return new RequestJar();
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/lib/copy.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/lib/copy.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/lib/copy.js	(revision 517)
@@ -0,0 +1,8 @@
+module.exports =
+function copy (obj) {
+  var o = {}
+  Object.keys(obj).forEach(function (i) {
+    o[i] = obj[i]
+  })
+  return o
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/lib/debug.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/lib/debug.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/lib/debug.js	(revision 517)
@@ -0,0 +1,7 @@
+var util = require('util')
+
+module.exports =
+function debug () {
+  if (/\brequest\b/.test(process.env.NODE_DEBUG))
+    console.error('REQUEST %s', util.format.apply(util, arguments))
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/lib/getSafe.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/lib/getSafe.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/lib/getSafe.js	(revision 517)
@@ -0,0 +1,34 @@
+// Safe toJSON
+module.exports =
+function getSafe (self, uuid) {
+  if (typeof self === 'object' || typeof self === 'function') var safe = {}
+  if (Array.isArray(self)) var safe = []
+
+  var recurse = []
+
+  Object.defineProperty(self, uuid, {})
+
+  var attrs = Object.keys(self).filter(function (i) {
+    if (i === uuid) return false
+    if ( (typeof self[i] !== 'object' && typeof self[i] !== 'function') || self[i] === null) return true
+    return !(Object.getOwnPropertyDescriptor(self[i], uuid))
+  })
+
+
+  for (var i=0;i<attrs.length;i++) {
+    if ( (typeof self[attrs[i]] !== 'object' && typeof self[attrs[i]] !== 'function') ||
+          self[attrs[i]] === null
+        ) {
+      safe[attrs[i]] = self[attrs[i]]
+    } else {
+      recurse.push(attrs[i])
+      Object.defineProperty(self[attrs[i]], uuid, {})
+    }
+  }
+
+  for (var i=0;i<recurse.length;i++) {
+    safe[recurse[i]] = getSafe(self[recurse[i]], uuid)
+  }
+
+  return safe
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/lib/optional.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/lib/optional.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/lib/optional.js	(revision 517)
@@ -0,0 +1,5 @@
+module.exports = function(module) {
+  try {
+    return require(module);
+  } catch (e) {}
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/LICENSE	(revision 517)
@@ -0,0 +1,55 @@
+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:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+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
+
+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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/README.md	(revision 517)
@@ -0,0 +1,4 @@
+aws-sign
+========
+
+AWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/index.js	(revision 517)
@@ -0,0 +1,202 @@
+
+/*!
+ * knox - auth
+ * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var crypto = require('crypto')
+  , parse = require('url').parse
+  ;
+
+/**
+ * Valid keys.
+ */
+
+var keys = 
+  [ 'acl'
+  , 'location'
+  , 'logging'
+  , 'notification'
+  , 'partNumber'
+  , 'policy'
+  , 'requestPayment'
+  , 'torrent'
+  , 'uploadId'
+  , 'uploads'
+  , 'versionId'
+  , 'versioning'
+  , 'versions'
+  , 'website'
+  ]
+
+/**
+ * Return an "Authorization" header value with the given `options`
+ * in the form of "AWS <key>:<signature>"
+ *
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */
+
+function authorization (options) {
+  return 'AWS ' + options.key + ':' + sign(options)
+}
+
+module.exports = authorization
+module.exports.authorization = authorization
+
+/**
+ * Simple HMAC-SHA1 Wrapper
+ *
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */ 
+
+function hmacSha1 (options) {
+  return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64')
+}
+
+module.exports.hmacSha1 = hmacSha1
+
+/**
+ * Create a base64 sha1 HMAC for `options`. 
+ * 
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */
+
+function sign (options) {
+  options.message = stringToSign(options)
+  return hmacSha1(options)
+}
+module.exports.sign = sign
+
+/**
+ * Create a base64 sha1 HMAC for `options`. 
+ *
+ * Specifically to be used with S3 presigned URLs
+ * 
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */
+
+function signQuery (options) {
+  options.message = queryStringToSign(options)
+  return hmacSha1(options)
+}
+module.exports.signQuery= signQuery
+
+/**
+ * Return a string for sign() with the given `options`.
+ *
+ * Spec:
+ * 
+ *    <verb>\n
+ *    <md5>\n
+ *    <content-type>\n
+ *    <date>\n
+ *    [headers\n]
+ *    <resource>
+ *
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */
+
+function stringToSign (options) {
+  var headers = options.amazonHeaders || ''
+  if (headers) headers += '\n'
+  var r = 
+    [ options.verb
+    , options.md5
+    , options.contentType
+    , options.date ? options.date.toUTCString() : ''
+    , headers + options.resource
+    ]
+  return r.join('\n')
+}
+module.exports.queryStringToSign = stringToSign
+
+/**
+ * Return a string for sign() with the given `options`, but is meant exclusively
+ * for S3 presigned URLs
+ *
+ * Spec:
+ * 
+ *    <date>\n
+ *    <resource>
+ *
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */
+
+function queryStringToSign (options){
+  return 'GET\n\n\n' + options.date + '\n' + options.resource
+}
+module.exports.queryStringToSign = queryStringToSign
+
+/**
+ * Perform the following:
+ *
+ *  - ignore non-amazon headers
+ *  - lowercase fields
+ *  - sort lexicographically
+ *  - trim whitespace between ":"
+ *  - join with newline
+ *
+ * @param {Object} headers
+ * @return {String}
+ * @api private
+ */
+
+function canonicalizeHeaders (headers) {
+  var buf = []
+    , fields = Object.keys(headers)
+    ;
+  for (var i = 0, len = fields.length; i < len; ++i) {
+    var field = fields[i]
+      , val = headers[field]
+      , field = field.toLowerCase()
+      ;
+    if (0 !== field.indexOf('x-amz')) continue
+    buf.push(field + ':' + val)
+  }
+  return buf.sort().join('\n')
+}
+module.exports.canonicalizeHeaders = canonicalizeHeaders
+
+/**
+ * Perform the following:
+ *
+ *  - ignore non sub-resources
+ *  - sort lexicographically
+ *
+ * @param {String} resource
+ * @return {String}
+ * @api private
+ */
+
+function canonicalizeResource (resource) {
+  var url = parse(resource, true)
+    , path = url.pathname
+    , buf = []
+    ;
+
+  Object.keys(url.query).forEach(function(key){
+    if (!~keys.indexOf(key)) return
+    var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key])
+    buf.push(key + val)
+  })
+
+  return path + (buf.length ? '?' + buf.sort().join('&') : '')
+}
+module.exports.canonicalizeResource = canonicalizeResource
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/aws-sign2/package.json	(revision 517)
@@ -0,0 +1,28 @@
+{
+  "author": {
+    "name": "Mikeal Rogers",
+    "email": "mikeal.rogers@gmail.com",
+    "url": "http://www.futurealoof.com"
+  },
+  "name": "aws-sign2",
+  "description": "AWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module.",
+  "version": "0.5.0",
+  "repository": {
+    "url": "https://github.com/mikeal/aws-sign"
+  },
+  "main": "index.js",
+  "dependencies": {},
+  "devDependencies": {},
+  "optionalDependencies": {},
+  "engines": {
+    "node": "*"
+  },
+  "readme": "aws-sign\n========\n\nAWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module.\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/mikeal/aws-sign/issues"
+  },
+  "homepage": "https://github.com/mikeal/aws-sign",
+  "_id": "aws-sign2@0.5.0",
+  "_from": "aws-sign2@~0.5.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/LICENSE	(revision 517)
@@ -0,0 +1,55 @@
+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:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+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
+
+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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/README.md	(revision 517)
@@ -0,0 +1,4 @@
+forever-agent
+=============
+
+HTTP Agent that keeps socket connections alive between keep-alive requests. Formerly part of mikeal/request, now a standalone module.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/index.js	(revision 517)
@@ -0,0 +1,119 @@
+module.exports = ForeverAgent
+ForeverAgent.SSL = ForeverAgentSSL
+
+var util = require('util')
+  , Agent = require('http').Agent
+  , net = require('net')
+  , tls = require('tls')
+  , AgentSSL = require('https').Agent
+
+function ForeverAgent(options) {
+  var self = this
+  self.options = options || {}
+  self.requests = {}
+  self.sockets = {}
+  self.freeSockets = {}
+  self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets
+  self.minSockets = self.options.minSockets || ForeverAgent.defaultMinSockets
+  self.on('free', function(socket, host, port) {
+    var name = host + ':' + port
+    if (self.requests[name] && self.requests[name].length) {
+      self.requests[name].shift().onSocket(socket)
+    } else if (self.sockets[name].length < self.minSockets) {
+      if (!self.freeSockets[name]) self.freeSockets[name] = []
+      self.freeSockets[name].push(socket)
+      
+      // if an error happens while we don't use the socket anyway, meh, throw the socket away
+      var onIdleError = function() {
+        socket.destroy()
+      }
+      socket._onIdleError = onIdleError
+      socket.on('error', onIdleError)
+    } else {
+      // If there are no pending requests just destroy the
+      // socket and it will get removed from the pool. This
+      // gets us out of timeout issues and allows us to
+      // default to Connection:keep-alive.
+      socket.destroy()
+    }
+  })
+
+}
+util.inherits(ForeverAgent, Agent)
+
+ForeverAgent.defaultMinSockets = 5
+
+
+ForeverAgent.prototype.createConnection = net.createConnection
+ForeverAgent.prototype.addRequestNoreuse = Agent.prototype.addRequest
+ForeverAgent.prototype.addRequest = function(req, host, port) {
+  var name = host + ':' + port
+  if (this.freeSockets[name] && this.freeSockets[name].length > 0 && !req.useChunkedEncodingByDefault) {
+    var idleSocket = this.freeSockets[name].pop()
+    idleSocket.removeListener('error', idleSocket._onIdleError)
+    delete idleSocket._onIdleError
+    req._reusedSocket = true
+    req.onSocket(idleSocket)
+  } else {
+    this.addRequestNoreuse(req, host, port)
+  }
+}
+
+ForeverAgent.prototype.removeSocket = function(s, name, host, port) {
+  if (this.sockets[name]) {
+    var index = this.sockets[name].indexOf(s)
+    if (index !== -1) {
+      this.sockets[name].splice(index, 1)
+    }
+  } else if (this.sockets[name] && this.sockets[name].length === 0) {
+    // don't leak
+    delete this.sockets[name]
+    delete this.requests[name]
+  }
+  
+  if (this.freeSockets[name]) {
+    var index = this.freeSockets[name].indexOf(s)
+    if (index !== -1) {
+      this.freeSockets[name].splice(index, 1)
+      if (this.freeSockets[name].length === 0) {
+        delete this.freeSockets[name]
+      }
+    }
+  }
+
+  if (this.requests[name] && this.requests[name].length) {
+    // If we have pending requests and a socket gets closed a new one
+    // needs to be created to take over in the pool for the one that closed.
+    this.createSocket(name, host, port).emit('free')
+  }
+}
+
+function ForeverAgentSSL (options) {
+  ForeverAgent.call(this, options)
+}
+util.inherits(ForeverAgentSSL, ForeverAgent)
+
+ForeverAgentSSL.prototype.createConnection = createConnectionSSL
+ForeverAgentSSL.prototype.addRequestNoreuse = AgentSSL.prototype.addRequest
+
+function createConnectionSSL (port, host, options) {
+  if (typeof port === 'object') {
+    options = port;
+  } else if (typeof host === 'object') {
+    options = host;
+  } else if (typeof options === 'object') {
+    options = options;
+  } else {
+    options = {};
+  }
+
+  if (typeof port === 'number') {
+    options.port = port;
+  }
+
+  if (typeof host === 'string') {
+    options.host = host;
+  }
+
+  return tls.connect(options);
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/forever-agent/package.json	(revision 517)
@@ -0,0 +1,28 @@
+{
+  "author": {
+    "name": "Mikeal Rogers",
+    "email": "mikeal.rogers@gmail.com",
+    "url": "http://www.futurealoof.com"
+  },
+  "name": "forever-agent",
+  "description": "HTTP Agent that keeps socket connections alive between keep-alive requests. Formerly part of mikeal/request, now a standalone module.",
+  "version": "0.5.2",
+  "repository": {
+    "url": "https://github.com/mikeal/forever-agent"
+  },
+  "main": "index.js",
+  "dependencies": {},
+  "devDependencies": {},
+  "optionalDependencies": {},
+  "engines": {
+    "node": "*"
+  },
+  "readme": "forever-agent\n=============\n\nHTTP Agent that keeps socket connections alive between keep-alive requests. Formerly part of mikeal/request, now a standalone module.\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/mikeal/forever-agent/issues"
+  },
+  "homepage": "https://github.com/mikeal/forever-agent",
+  "_id": "forever-agent@0.5.2",
+  "_from": "forever-agent@~0.5.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/License
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/License	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/License	(revision 517)
@@ -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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/Readme.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/Readme.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/Readme.md	(revision 517)
@@ -0,0 +1,163 @@
+# Form-Data [![Build Status](https://travis-ci.org/felixge/node-form-data.png?branch=master)](https://travis-ci.org/felixge/node-form-data) [![Dependency Status](https://gemnasium.com/felixge/node-form-data.png)](https://gemnasium.com/felixge/node-form-data)
+
+A module to create readable ```"multipart/form-data"``` streams. Can be used to submit forms and file uploads to other web applications.
+
+The API of this module is inspired by the [XMLHttpRequest-2 FormData Interface][xhr2-fd].
+
+[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface
+[streams2-thing]: http://nodejs.org/api/stream.html#stream_compatibility_with_older_node_versions
+
+## Install
+
+```
+npm install form-data
+```
+
+## Usage
+
+In this example we are constructing a form with 3 fields that contain a string,
+a buffer and a file stream.
+
+``` javascript
+var FormData = require('form-data');
+var fs = require('fs');
+
+var form = new FormData();
+form.append('my_field', 'my value');
+form.append('my_buffer', new Buffer(10));
+form.append('my_file', fs.createReadStream('/foo/bar.jpg'));
+```
+
+Also you can use http-response stream:
+
+``` javascript
+var FormData = require('form-data');
+var http = require('http');
+
+var form = new FormData();
+
+http.request('http://nodejs.org/images/logo.png', function(response) {
+  form.append('my_field', 'my value');
+  form.append('my_buffer', new Buffer(10));
+  form.append('my_logo', response);
+});
+```
+
+Or @mikeal's request stream:
+
+``` javascript
+var FormData = require('form-data');
+var request = require('request');
+
+var form = new FormData();
+
+form.append('my_field', 'my value');
+form.append('my_buffer', new Buffer(10));
+form.append('my_logo', request('http://nodejs.org/images/logo.png'));
+```
+
+In order to submit this form to a web application, call ```submit(url, [callback])``` method:
+
+``` javascript
+form.submit('http://example.org/', function(err, res) {
+  // res â response object (http.IncomingMessage)  //
+  res.resume(); // for node-0.10.x
+});
+
+```
+
+For more advanced request manipulations ```submit()``` method returns ```http.ClientRequest``` object, or you can choose from one of the alternative submission methods.
+
+### Alternative submission methods
+
+You can use node's http client interface:
+
+``` javascript
+var http = require('http');
+
+var request = http.request({
+  method: 'post',
+  host: 'example.org',
+  path: '/upload',
+  headers: form.getHeaders()
+});
+
+form.pipe(request);
+
+request.on('response', function(res) {
+  console.log(res.statusCode);
+});
+```
+
+Or if you would prefer the `'Content-Length'` header to be set for you:
+
+``` javascript
+form.submit('example.org/upload', function(err, res) {
+  console.log(res.statusCode);
+});
+```
+
+To use custom headers and pre-known length in parts:
+
+``` javascript
+var CRLF = '\r\n';
+var form = new FormData();
+
+var options = {
+  header: CRLF + '--' + form.getBoundary() + CRLF + 'X-Custom-Header: 123' + CRLF + CRLF,
+  knownLength: 1
+};
+
+form.append('my_buffer', buffer, options);
+
+form.submit('http://example.com/', function(err, res) {
+  if (err) throw err;
+  console.log('Done');
+});
+```
+
+Form-Data can recognize and fetch all the required information from common types of streams (```fs.readStream```, ```http.response``` and ```mikeal's request```), for some other types of streams you'd need to provide "file"-related information manually:
+
+``` javascript
+someModule.stream(function(err, stdout, stderr) {
+  if (err) throw err;
+
+  var form = new FormData();
+
+  form.append('file', stdout, {
+    filename: 'unicycle.jpg',
+    contentType: 'image/jpg',
+    knownLength: 19806
+  });
+
+  form.submit('http://example.com/', function(err, res) {
+    if (err) throw err;
+    console.log('Done');
+  });
+});
+```
+
+For edge cases, like POST request to URL with query string or to pass HTTP auth credentials, object can be passed to `form.submit()` as first parameter:
+
+``` javascript
+form.submit({
+  host: 'example.com',
+  path: '/probably.php?extra=params',
+  auth: 'username:password'
+}, function(err, res) {
+  console.log(res.statusCode);
+});
+```
+
+## Notes
+
+- ```getLengthSync()``` method DOESN'T calculate length for streams, use ```knownLength``` options as workaround.
+- If it feels like FormData hangs after submit and you're on ```node-0.10```, please check [Compatibility with Older Node Versions][streams2-thing]
+
+## TODO
+
+- Add new streams (0.10) support and try really hard not to break it for 0.8.x.
+
+## License
+
+Form-Data is licensed under the MIT license.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/lib/form_data.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/lib/form_data.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/lib/form_data.js	(revision 517)
@@ -0,0 +1,325 @@
+var CombinedStream = require('combined-stream');
+var util = require('util');
+var path = require('path');
+var http = require('http');
+var https = require('https');
+var parseUrl = require('url').parse;
+var fs = require('fs');
+var mime = require('mime');
+var async = require('async');
+
+module.exports = FormData;
+function FormData() {
+  this._overheadLength = 0;
+  this._valueLength = 0;
+  this._lengthRetrievers = [];
+
+  CombinedStream.call(this);
+}
+util.inherits(FormData, CombinedStream);
+
+FormData.LINE_BREAK = '\r\n';
+
+FormData.prototype.append = function(field, value, options) {
+  options = options || {};
+
+  var append = CombinedStream.prototype.append.bind(this);
+
+  // all that streamy business can't handle numbers
+  if (typeof value == 'number') value = ''+value;
+
+  // https://github.com/felixge/node-form-data/issues/38
+  if (util.isArray(value)) {
+    // Please convert your array into string
+    // the way web server expects it
+    this._error(new Error('Arrays are not supported.'));
+    return;
+  }
+
+  var header = this._multiPartHeader(field, value, options);
+  var footer = this._multiPartFooter(field, value, options);
+
+  append(header);
+  append(value);
+  append(footer);
+
+  // pass along options.knownLength
+  this._trackLength(header, value, options);
+};
+
+FormData.prototype._trackLength = function(header, value, options) {
+  var valueLength = 0;
+
+  // used w/ getLengthSync(), when length is known.
+  // e.g. for streaming directly from a remote server,
+  // w/ a known file a size, and not wanting to wait for
+  // incoming file to finish to get its size.
+  if (options.knownLength != null) {
+    valueLength += +options.knownLength;
+  } else if (Buffer.isBuffer(value)) {
+    valueLength = value.length;
+  } else if (typeof value === 'string') {
+    valueLength = Buffer.byteLength(value);
+  }
+
+  this._valueLength += valueLength;
+
+  // @check why add CRLF? does this account for custom/multiple CRLFs?
+  this._overheadLength +=
+    Buffer.byteLength(header) +
+    + FormData.LINE_BREAK.length;
+
+  // empty or either doesn't have path or not an http response
+  if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) )) {
+    return;
+  }
+
+  // no need to bother with the length
+  if (!options.knownLength)
+  this._lengthRetrievers.push(function(next) {
+
+    if (value.hasOwnProperty('fd')) {
+      fs.stat(value.path, function(err, stat) {
+        if (err) {
+          next(err);
+          return;
+        }
+
+        next(null, stat.size);
+      });
+
+    // or http response
+    } else if (value.hasOwnProperty('httpVersion')) {
+      next(null, +value.headers['content-length']);
+
+    // or request stream http://github.com/mikeal/request
+    } else if (value.hasOwnProperty('httpModule')) {
+      // wait till response come back
+      value.on('response', function(response) {
+        value.pause();
+        next(null, +response.headers['content-length']);
+      });
+      value.resume();
+
+    // something else
+    } else {
+      next('Unknown stream');
+    }
+  });
+};
+
+FormData.prototype._multiPartHeader = function(field, value, options) {
+  var boundary = this.getBoundary();
+  var header = '';
+
+  // custom header specified (as string)?
+  // it becomes responsible for boundary
+  // (e.g. to handle extra CRLFs on .NET servers)
+  if (options.header != null) {
+    header = options.header;
+  } else {
+    header += '--' + boundary + FormData.LINE_BREAK +
+      'Content-Disposition: form-data; name="' + field + '"';
+
+    // fs- and request- streams have path property
+    // or use custom filename and/or contentType
+    // TODO: Use request's response mime-type
+    if (options.filename || value.path) {
+      header +=
+        '; filename="' + path.basename(options.filename || value.path) + '"' + FormData.LINE_BREAK +
+        'Content-Type: ' +  (options.contentType || mime.lookup(options.filename || value.path));
+
+    // http response has not
+    } else if (value.readable && value.hasOwnProperty('httpVersion')) {
+      header +=
+        '; filename="' + path.basename(value.client._httpMessage.path) + '"' + FormData.LINE_BREAK +
+        'Content-Type: ' + value.headers['content-type'];
+    }
+
+    header += FormData.LINE_BREAK + FormData.LINE_BREAK;
+  }
+
+  return header;
+};
+
+FormData.prototype._multiPartFooter = function(field, value, options) {
+  return function(next) {
+    var footer = FormData.LINE_BREAK;
+
+    var lastPart = (this._streams.length === 0);
+    if (lastPart) {
+      footer += this._lastBoundary();
+    }
+
+    next(footer);
+  }.bind(this);
+};
+
+FormData.prototype._lastBoundary = function() {
+  return '--' + this.getBoundary() + '--';
+};
+
+FormData.prototype.getHeaders = function(userHeaders) {
+  var formHeaders = {
+    'content-type': 'multipart/form-data; boundary=' + this.getBoundary()
+  };
+
+  for (var header in userHeaders) {
+    formHeaders[header.toLowerCase()] = userHeaders[header];
+  }
+
+  return formHeaders;
+}
+
+FormData.prototype.getCustomHeaders = function(contentType) {
+    contentType = contentType ? contentType : 'multipart/form-data';
+
+    var formHeaders = {
+        'content-type': contentType + '; boundary=' + this.getBoundary(),
+        'content-length': this.getLengthSync()
+    };
+
+    return formHeaders;
+}
+
+FormData.prototype.getBoundary = function() {
+  if (!this._boundary) {
+    this._generateBoundary();
+  }
+
+  return this._boundary;
+};
+
+FormData.prototype._generateBoundary = function() {
+  // This generates a 50 character boundary similar to those used by Firefox.
+  // They are optimized for boyer-moore parsing.
+  var boundary = '--------------------------';
+  for (var i = 0; i < 24; i++) {
+    boundary += Math.floor(Math.random() * 10).toString(16);
+  }
+
+  this._boundary = boundary;
+};
+
+// Note: getLengthSync DOESN'T calculate streams length
+// As workaround one can calculate file size manually
+// and add it as knownLength option
+FormData.prototype.getLengthSync = function(debug) {
+  var knownLength = this._overheadLength + this._valueLength;
+
+  // Don't get confused, there are 3 "internal" streams for each keyval pair
+  // so it basically checks if there is any value added to the form
+  if (this._streams.length) {
+    knownLength += this._lastBoundary().length;
+  }
+
+  // https://github.com/felixge/node-form-data/issues/40
+  if (this._lengthRetrievers.length) {
+    // Some async length retrivers are present
+    // therefore synchronous length calculation is false.
+    // Please use getLength(callback) to get proper length
+    this._error(new Error('Cannot calculate proper length in synchronous way.'));
+  }
+
+  return knownLength;
+};
+
+FormData.prototype.getLength = function(cb) {
+  var knownLength = this._overheadLength + this._valueLength;
+
+  if (this._streams.length) {
+    knownLength += this._lastBoundary().length;
+  }
+
+  if (!this._lengthRetrievers.length) {
+    process.nextTick(cb.bind(this, null, knownLength));
+    return;
+  }
+
+  async.parallel(this._lengthRetrievers, function(err, values) {
+    if (err) {
+      cb(err);
+      return;
+    }
+
+    values.forEach(function(length) {
+      knownLength += length;
+    });
+
+    cb(null, knownLength);
+  });
+};
+
+FormData.prototype.submit = function(params, cb) {
+
+  var request
+    , options
+    , defaults = {
+        method : 'post',
+        headers: this.getHeaders()
+    };
+
+  // parse provided url if it's string
+  // or treat it as options object
+  if (typeof params == 'string') {
+    params = parseUrl(params);
+
+    options = populate({
+      port: params.port,
+      path: params.pathname,
+      host: params.hostname
+    }, defaults);
+  }
+  else // use custom params
+  {
+    options = populate(params, defaults);
+    // if no port provided use default one
+    if (!options.port) {
+      options.port = options.protocol == 'https:' ? 443 : 80;
+    }
+  }
+
+  // https if specified, fallback to http in any other case
+  if (params.protocol == 'https:') {
+    request = https.request(options);
+  } else {
+    request = http.request(options);
+  }
+
+  // get content length and fire away
+  this.getLength(function(err, length) {
+
+    // TODO: Add chunked encoding when no length (if err)
+
+    // add content length
+    request.setHeader('Content-Length', length);
+
+    this.pipe(request);
+    if (cb) {
+      request.on('error', cb);
+      request.on('response', cb.bind(this, null));
+    }
+  }.bind(this));
+
+  return request;
+};
+
+FormData.prototype._error = function(err) {
+  if (this.error) return;
+
+  this.error = err;
+  this.pause();
+  this.emit('error', err);
+};
+
+/*
+ * Santa's little helpers
+ */
+
+// populates missing values
+function populate(dst, src) {
+  for (var prop in src) {
+    if (!dst[prop]) dst[prop] = src[prop];
+  }
+  return dst;
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/LICENSE	(revision 517)
@@ -0,0 +1,19 @@
+Copyright (c) 2010 Caolan McMahon
+
+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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/README.md	(revision 517)
@@ -0,0 +1,1425 @@
+# Async.js
+
+Async is a utility module which provides straight-forward, powerful functions
+for working with asynchronous JavaScript. Although originally designed for
+use with [node.js](http://nodejs.org), it can also be used directly in the
+browser. Also supports [component](https://github.com/component/component).
+
+Async provides around 20 functions that include the usual 'functional'
+suspects (map, reduce, filter, eachâŠ) as well as some common patterns
+for asynchronous control flow (parallel, series, waterfallâŠ). All these
+functions assume you follow the node.js convention of providing a single
+callback as the last argument of your async function.
+
+
+## Quick Examples
+
+```javascript
+async.map(['file1','file2','file3'], fs.stat, function(err, results){
+    // results is now an array of stats for each file
+});
+
+async.filter(['file1','file2','file3'], fs.exists, function(results){
+    // results now equals an array of the existing files
+});
+
+async.parallel([
+    function(){ ... },
+    function(){ ... }
+], callback);
+
+async.series([
+    function(){ ... },
+    function(){ ... }
+]);
+```
+
+There are many more functions available so take a look at the docs below for a
+full list. This module aims to be comprehensive, so if you feel anything is
+missing please create a GitHub issue for it.
+
+## Common Pitfalls
+
+### Binding a context to an iterator
+
+This section is really about bind, not about async. If you are wondering how to
+make async execute your iterators in a given context, or are confused as to why
+a method of another library isn't working as an iterator, study this example:
+
+```js
+// Here is a simple object with an (unnecessarily roundabout) squaring method
+var AsyncSquaringLibrary = {
+  squareExponent: 2,
+  square: function(number, callback){ 
+    var result = Math.pow(number, this.squareExponent);
+    setTimeout(function(){
+      callback(null, result);
+    }, 200);
+  }
+};
+
+async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result){
+  // result is [NaN, NaN, NaN]
+  // This fails because the `this.squareExponent` expression in the square
+  // function is not evaluated in the context of AsyncSquaringLibrary, and is
+  // therefore undefined.
+});
+
+async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result){
+  // result is [1, 4, 9]
+  // With the help of bind we can attach a context to the iterator before
+  // passing it to async. Now the square function will be executed in its 
+  // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent`
+  // will be as expected.
+});
+```
+
+## Download
+
+The source is available for download from
+[GitHub](http://github.com/caolan/async).
+Alternatively, you can install using Node Package Manager (npm):
+
+    npm install async
+
+__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 29.6kb Uncompressed
+
+## In the Browser
+
+So far it's been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:
+
+```html
+<script type="text/javascript" src="async.js"></script>
+<script type="text/javascript">
+
+    async.map(data, asyncProcess, function(err, results){
+        alert(results);
+    });
+
+</script>
+```
+
+## Documentation
+
+### Collections
+
+* [each](#each)
+* [eachSeries](#eachSeries)
+* [eachLimit](#eachLimit)
+* [map](#map)
+* [mapSeries](#mapSeries)
+* [mapLimit](#mapLimit)
+* [filter](#filter)
+* [filterSeries](#filterSeries)
+* [reject](#reject)
+* [rejectSeries](#rejectSeries)
+* [reduce](#reduce)
+* [reduceRight](#reduceRight)
+* [detect](#detect)
+* [detectSeries](#detectSeries)
+* [sortBy](#sortBy)
+* [some](#some)
+* [every](#every)
+* [concat](#concat)
+* [concatSeries](#concatSeries)
+
+### Control Flow
+
+* [series](#series)
+* [parallel](#parallel)
+* [parallelLimit](#parallellimittasks-limit-callback)
+* [whilst](#whilst)
+* [doWhilst](#doWhilst)
+* [until](#until)
+* [doUntil](#doUntil)
+* [forever](#forever)
+* [waterfall](#waterfall)
+* [compose](#compose)
+* [applyEach](#applyEach)
+* [applyEachSeries](#applyEachSeries)
+* [queue](#queue)
+* [cargo](#cargo)
+* [auto](#auto)
+* [iterator](#iterator)
+* [apply](#apply)
+* [nextTick](#nextTick)
+* [times](#times)
+* [timesSeries](#timesSeries)
+
+### Utils
+
+* [memoize](#memoize)
+* [unmemoize](#unmemoize)
+* [log](#log)
+* [dir](#dir)
+* [noConflict](#noConflict)
+
+
+## Collections
+
+<a name="forEach" />
+<a name="each" />
+### each(arr, iterator, callback)
+
+Applies an iterator function to each item in an array, in parallel.
+The iterator is called with an item from the list and a callback for when it
+has finished. If the iterator passes an error to this callback, the main
+callback for the each function is immediately called with the error.
+
+Note, that since this function applies the iterator to each item in parallel
+there is no guarantee that the iterator functions will complete in order.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* iterator(item, callback) - A function to apply to each item in the array.
+  The iterator is passed a callback(err) which must be called once it has 
+  completed. If no error has occured, the callback should be run without 
+  arguments or with an explicit null argument.
+* callback(err) - A callback which is called after all the iterator functions
+  have finished, or an error has occurred.
+
+__Example__
+
+```js
+// assuming openFiles is an array of file names and saveFile is a function
+// to save the modified contents of that file:
+
+async.each(openFiles, saveFile, function(err){
+    // if any of the saves produced an error, err would equal that error
+});
+```
+
+---------------------------------------
+
+<a name="forEachSeries" />
+<a name="eachSeries" />
+### eachSeries(arr, iterator, callback)
+
+The same as each only the iterator is applied to each item in the array in
+series. The next iterator is only called once the current one has completed
+processing. This means the iterator functions will complete in order.
+
+
+---------------------------------------
+
+<a name="forEachLimit" />
+<a name="eachLimit" />
+### eachLimit(arr, limit, iterator, callback)
+
+The same as each only no more than "limit" iterators will be simultaneously 
+running at any time.
+
+Note that the items are not processed in batches, so there is no guarantee that
+ the first "limit" iterator functions will complete before any others are 
+started.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* limit - The maximum number of iterators to run at any time.
+* iterator(item, callback) - A function to apply to each item in the array.
+  The iterator is passed a callback(err) which must be called once it has 
+  completed. If no error has occured, the callback should be run without 
+  arguments or with an explicit null argument.
+* callback(err) - A callback which is called after all the iterator functions
+  have finished, or an error has occurred.
+
+__Example__
+
+```js
+// Assume documents is an array of JSON objects and requestApi is a
+// function that interacts with a rate-limited REST api.
+
+async.eachLimit(documents, 20, requestApi, function(err){
+    // if any of the saves produced an error, err would equal that error
+});
+```
+
+---------------------------------------
+
+<a name="map" />
+### map(arr, iterator, callback)
+
+Produces a new array of values by mapping each value in the given array through
+the iterator function. The iterator is called with an item from the array and a
+callback for when it has finished processing. The callback takes 2 arguments, 
+an error and the transformed item from the array. If the iterator passes an
+error to this callback, the main callback for the map function is immediately
+called with the error.
+
+Note, that since this function applies the iterator to each item in parallel
+there is no guarantee that the iterator functions will complete in order, however
+the results array will be in the same order as the original array.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* iterator(item, callback) - A function to apply to each item in the array.
+  The iterator is passed a callback(err, transformed) which must be called once 
+  it has completed with an error (which can be null) and a transformed item.
+* callback(err, results) - A callback which is called after all the iterator
+  functions have finished, or an error has occurred. Results is an array of the
+  transformed items from the original array.
+
+__Example__
+
+```js
+async.map(['file1','file2','file3'], fs.stat, function(err, results){
+    // results is now an array of stats for each file
+});
+```
+
+---------------------------------------
+
+<a name="mapSeries" />
+### mapSeries(arr, iterator, callback)
+
+The same as map only the iterator is applied to each item in the array in
+series. The next iterator is only called once the current one has completed
+processing. The results array will be in the same order as the original.
+
+
+---------------------------------------
+
+<a name="mapLimit" />
+### mapLimit(arr, limit, iterator, callback)
+
+The same as map only no more than "limit" iterators will be simultaneously 
+running at any time.
+
+Note that the items are not processed in batches, so there is no guarantee that
+ the first "limit" iterator functions will complete before any others are 
+started.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* limit - The maximum number of iterators to run at any time.
+* iterator(item, callback) - A function to apply to each item in the array.
+  The iterator is passed a callback(err, transformed) which must be called once 
+  it has completed with an error (which can be null) and a transformed item.
+* callback(err, results) - A callback which is called after all the iterator
+  functions have finished, or an error has occurred. Results is an array of the
+  transformed items from the original array.
+
+__Example__
+
+```js
+async.mapLimit(['file1','file2','file3'], 1, fs.stat, function(err, results){
+    // results is now an array of stats for each file
+});
+```
+
+---------------------------------------
+
+<a name="filter" />
+### filter(arr, iterator, callback)
+
+__Alias:__ select
+
+Returns a new array of all the values which pass an async truth test.
+_The callback for each iterator call only accepts a single argument of true or
+false, it does not accept an error argument first!_ This is in-line with the
+way node libraries work with truth tests like fs.exists. This operation is
+performed in parallel, but the results array will be in the same order as the
+original.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* iterator(item, callback) - A truth test to apply to each item in the array.
+  The iterator is passed a callback(truthValue) which must be called with a 
+  boolean argument once it has completed.
+* callback(results) - A callback which is called after all the iterator
+  functions have finished.
+
+__Example__
+
+```js
+async.filter(['file1','file2','file3'], fs.exists, function(results){
+    // results now equals an array of the existing files
+});
+```
+
+---------------------------------------
+
+<a name="filterSeries" />
+### filterSeries(arr, iterator, callback)
+
+__alias:__ selectSeries
+
+The same as filter only the iterator is applied to each item in the array in
+series. The next iterator is only called once the current one has completed
+processing. The results array will be in the same order as the original.
+
+---------------------------------------
+
+<a name="reject" />
+### reject(arr, iterator, callback)
+
+The opposite of filter. Removes values that pass an async truth test.
+
+---------------------------------------
+
+<a name="rejectSeries" />
+### rejectSeries(arr, iterator, callback)
+
+The same as reject, only the iterator is applied to each item in the array
+in series.
+
+
+---------------------------------------
+
+<a name="reduce" />
+### reduce(arr, memo, iterator, callback)
+
+__aliases:__ inject, foldl
+
+Reduces a list of values into a single value using an async iterator to return
+each successive step. Memo is the initial state of the reduction. This
+function only operates in series. For performance reasons, it may make sense to
+split a call to this function into a parallel map, then use the normal
+Array.prototype.reduce on the results. This function is for situations where
+each step in the reduction needs to be async, if you can get the data before
+reducing it then it's probably a good idea to do so.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* memo - The initial state of the reduction.
+* iterator(memo, item, callback) - A function applied to each item in the
+  array to produce the next step in the reduction. The iterator is passed a
+  callback(err, reduction) which accepts an optional error as its first 
+  argument, and the state of the reduction as the second. If an error is 
+  passed to the callback, the reduction is stopped and the main callback is 
+  immediately called with the error.
+* callback(err, result) - A callback which is called after all the iterator
+  functions have finished. Result is the reduced value.
+
+__Example__
+
+```js
+async.reduce([1,2,3], 0, function(memo, item, callback){
+    // pointless async:
+    process.nextTick(function(){
+        callback(null, memo + item)
+    });
+}, function(err, result){
+    // result is now equal to the last value of memo, which is 6
+});
+```
+
+---------------------------------------
+
+<a name="reduceRight" />
+### reduceRight(arr, memo, iterator, callback)
+
+__Alias:__ foldr
+
+Same as reduce, only operates on the items in the array in reverse order.
+
+
+---------------------------------------
+
+<a name="detect" />
+### detect(arr, iterator, callback)
+
+Returns the first value in a list that passes an async truth test. The
+iterator is applied in parallel, meaning the first iterator to return true will
+fire the detect callback with that result. That means the result might not be
+the first item in the original array (in terms of order) that passes the test.
+
+If order within the original array is important then look at detectSeries.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* iterator(item, callback) - A truth test to apply to each item in the array.
+  The iterator is passed a callback(truthValue) which must be called with a 
+  boolean argument once it has completed.
+* callback(result) - A callback which is called as soon as any iterator returns
+  true, or after all the iterator functions have finished. Result will be
+  the first item in the array that passes the truth test (iterator) or the
+  value undefined if none passed.
+
+__Example__
+
+```js
+async.detect(['file1','file2','file3'], fs.exists, function(result){
+    // result now equals the first file in the list that exists
+});
+```
+
+---------------------------------------
+
+<a name="detectSeries" />
+### detectSeries(arr, iterator, callback)
+
+The same as detect, only the iterator is applied to each item in the array
+in series. This means the result is always the first in the original array (in
+terms of array order) that passes the truth test.
+
+
+---------------------------------------
+
+<a name="sortBy" />
+### sortBy(arr, iterator, callback)
+
+Sorts a list by the results of running each value through an async iterator.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* iterator(item, callback) - A function to apply to each item in the array.
+  The iterator is passed a callback(err, sortValue) which must be called once it
+  has completed with an error (which can be null) and a value to use as the sort
+  criteria.
+* callback(err, results) - A callback which is called after all the iterator
+  functions have finished, or an error has occurred. Results is the items from
+  the original array sorted by the values returned by the iterator calls.
+
+__Example__
+
+```js
+async.sortBy(['file1','file2','file3'], function(file, callback){
+    fs.stat(file, function(err, stats){
+        callback(err, stats.mtime);
+    });
+}, function(err, results){
+    // results is now the original array of files sorted by
+    // modified date
+});
+```
+
+---------------------------------------
+
+<a name="some" />
+### some(arr, iterator, callback)
+
+__Alias:__ any
+
+Returns true if at least one element in the array satisfies an async test.
+_The callback for each iterator call only accepts a single argument of true or
+false, it does not accept an error argument first!_ This is in-line with the
+way node libraries work with truth tests like fs.exists. Once any iterator
+call returns true, the main callback is immediately called.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* iterator(item, callback) - A truth test to apply to each item in the array.
+  The iterator is passed a callback(truthValue) which must be called with a 
+  boolean argument once it has completed.
+* callback(result) - A callback which is called as soon as any iterator returns
+  true, or after all the iterator functions have finished. Result will be
+  either true or false depending on the values of the async tests.
+
+__Example__
+
+```js
+async.some(['file1','file2','file3'], fs.exists, function(result){
+    // if result is true then at least one of the files exists
+});
+```
+
+---------------------------------------
+
+<a name="every" />
+### every(arr, iterator, callback)
+
+__Alias:__ all
+
+Returns true if every element in the array satisfies an async test.
+_The callback for each iterator call only accepts a single argument of true or
+false, it does not accept an error argument first!_ This is in-line with the
+way node libraries work with truth tests like fs.exists.
+
+__Arguments__
+
+* arr - An array to iterate over.
+* iterator(item, callback) - A truth test to apply to each item in the array.
+  The iterator is passed a callback(truthValue) which must be called with a 
+  boolean argument once it has completed.
+* callback(result) - A callback which is called after all the iterator
+  functions have finished. Result will be either true or false depending on
+  the values of the async tests.
+
+__Example__
+
+```js
+async.every(['file1','file2','file3'], fs.exists, function(result){
+    // if result is true then every file exists
+});
+```
+
+---------------------------------------
+
+<a name="concat" />
+### concat(arr, iterator, callback)
+
+Applies an iterator to each item in a list, concatenating the results. Returns the
+concatenated list. The iterators are called in parallel, and the results are
+concatenated as they return. There is no guarantee that the results array will
+be returned in the original order of the arguments passed to the iterator function.
+
+__Arguments__
+
+* arr - An array to iterate over
+* iterator(item, callback) - A function to apply to each item in the array.
+  The iterator is passed a callback(err, results) which must be called once it 
+  has completed with an error (which can be null) and an array of results.
+* callback(err, results) - A callback which is called after all the iterator
+  functions have finished, or an error has occurred. Results is an array containing
+  the concatenated results of the iterator function.
+
+__Example__
+
+```js
+async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){
+    // files is now a list of filenames that exist in the 3 directories
+});
+```
+
+---------------------------------------
+
+<a name="concatSeries" />
+### concatSeries(arr, iterator, callback)
+
+Same as async.concat, but executes in series instead of parallel.
+
+
+## Control Flow
+
+<a name="series" />
+### series(tasks, [callback])
+
+Run an array of functions in series, each one running once the previous
+function has completed. If any functions in the series pass an error to its
+callback, no more functions are run and the callback for the series is
+immediately called with the value of the error. Once the tasks have completed,
+the results are passed to the final callback as an array.
+
+It is also possible to use an object instead of an array. Each property will be
+run as a function and the results will be passed to the final callback as an object
+instead of an array. This can be a more readable way of handling results from
+async.series.
+
+
+__Arguments__
+
+* tasks - An array or object containing functions to run, each function is passed
+  a callback(err, result) it must call on completion with an error (which can
+  be null) and an optional result value.
+* callback(err, results) - An optional callback to run once all the functions
+  have completed. This function gets a results array (or object) containing all 
+  the result arguments passed to the task callbacks.
+
+__Example__
+
+```js
+async.series([
+    function(callback){
+        // do some stuff ...
+        callback(null, 'one');
+    },
+    function(callback){
+        // do some more stuff ...
+        callback(null, 'two');
+    }
+],
+// optional callback
+function(err, results){
+    // results is now equal to ['one', 'two']
+});
+
+
+// an example using an object instead of an array
+async.series({
+    one: function(callback){
+        setTimeout(function(){
+            callback(null, 1);
+        }, 200);
+    },
+    two: function(callback){
+        setTimeout(function(){
+            callback(null, 2);
+        }, 100);
+    }
+},
+function(err, results) {
+    // results is now equal to: {one: 1, two: 2}
+});
+```
+
+---------------------------------------
+
+<a name="parallel" />
+### parallel(tasks, [callback])
+
+Run an array of functions in parallel, without waiting until the previous
+function has completed. If any of the functions pass an error to its
+callback, the main callback is immediately called with the value of the error.
+Once the tasks have completed, the results are passed to the final callback as an
+array.
+
+It is also possible to use an object instead of an array. Each property will be
+run as a function and the results will be passed to the final callback as an object
+instead of an array. This can be a more readable way of handling results from
+async.parallel.
+
+
+__Arguments__
+
+* tasks - An array or object containing functions to run, each function is passed 
+  a callback(err, result) it must call on completion with an error (which can
+  be null) and an optional result value.
+* callback(err, results) - An optional callback to run once all the functions
+  have completed. This function gets a results array (or object) containing all 
+  the result arguments passed to the task callbacks.
+
+__Example__
+
+```js
+async.parallel([
+    function(callback){
+        setTimeout(function(){
+            callback(null, 'one');
+        }, 200);
+    },
+    function(callback){
+        setTimeout(function(){
+            callback(null, 'two');
+        }, 100);
+    }
+],
+// optional callback
+function(err, results){
+    // the results array will equal ['one','two'] even though
+    // the second function had a shorter timeout.
+});
+
+
+// an example using an object instead of an array
+async.parallel({
+    one: function(callback){
+        setTimeout(function(){
+            callback(null, 1);
+        }, 200);
+    },
+    two: function(callback){
+        setTimeout(function(){
+            callback(null, 2);
+        }, 100);
+    }
+},
+function(err, results) {
+    // results is now equals to: {one: 1, two: 2}
+});
+```
+
+---------------------------------------
+
+<a name="parallel" />
+### parallelLimit(tasks, limit, [callback])
+
+The same as parallel only the tasks are executed in parallel with a maximum of "limit" 
+tasks executing at any time.
+
+Note that the tasks are not executed in batches, so there is no guarantee that 
+the first "limit" tasks will complete before any others are started.
+
+__Arguments__
+
+* tasks - An array or object containing functions to run, each function is passed 
+  a callback(err, result) it must call on completion with an error (which can
+  be null) and an optional result value.
+* limit - The maximum number of tasks to run at any time.
+* callback(err, results) - An optional callback to run once all the functions
+  have completed. This function gets a results array (or object) containing all 
+  the result arguments passed to the task callbacks.
+
+---------------------------------------
+
+<a name="whilst" />
+### whilst(test, fn, callback)
+
+Repeatedly call fn, while test returns true. Calls the callback when stopped,
+or an error occurs.
+
+__Arguments__
+
+* test() - synchronous truth test to perform before each execution of fn.
+* fn(callback) - A function to call each time the test passes. The function is
+  passed a callback(err) which must be called once it has completed with an 
+  optional error argument.
+* callback(err) - A callback which is called after the test fails and repeated
+  execution of fn has stopped.
+
+__Example__
+
+```js
+var count = 0;
+
+async.whilst(
+    function () { return count < 5; },
+    function (callback) {
+        count++;
+        setTimeout(callback, 1000);
+    },
+    function (err) {
+        // 5 seconds have passed
+    }
+);
+```
+
+---------------------------------------
+
+<a name="doWhilst" />
+### doWhilst(fn, test, callback)
+
+The post check version of whilst. To reflect the difference in the order of operations `test` and `fn` arguments are switched. `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.
+
+---------------------------------------
+
+<a name="until" />
+### until(test, fn, callback)
+
+Repeatedly call fn, until test returns true. Calls the callback when stopped,
+or an error occurs.
+
+The inverse of async.whilst.
+
+---------------------------------------
+
+<a name="doUntil" />
+### doUntil(fn, test, callback)
+
+Like doWhilst except the test is inverted. Note the argument ordering differs from `until`.
+
+---------------------------------------
+
+<a name="forever" />
+### forever(fn, callback)
+
+Calls the asynchronous function 'fn' repeatedly, in series, indefinitely.
+If an error is passed to fn's callback then 'callback' is called with the
+error, otherwise it will never be called.
+
+---------------------------------------
+
+<a name="waterfall" />
+### waterfall(tasks, [callback])
+
+Runs an array of functions in series, each passing their results to the next in
+the array. However, if any of the functions pass an error to the callback, the
+next function is not executed and the main callback is immediately called with
+the error.
+
+__Arguments__
+
+* tasks - An array of functions to run, each function is passed a 
+  callback(err, result1, result2, ...) it must call on completion. The first
+  argument is an error (which can be null) and any further arguments will be 
+  passed as arguments in order to the next task.
+* callback(err, [results]) - An optional callback to run once all the functions
+  have completed. This will be passed the results of the last task's callback.
+
+
+
+__Example__
+
+```js
+async.waterfall([
+    function(callback){
+        callback(null, 'one', 'two');
+    },
+    function(arg1, arg2, callback){
+        callback(null, 'three');
+    },
+    function(arg1, callback){
+        // arg1 now equals 'three'
+        callback(null, 'done');
+    }
+], function (err, result) {
+   // result now equals 'done'    
+});
+```
+
+---------------------------------------
+<a name="compose" />
+### compose(fn1, fn2...)
+
+Creates a function which is a composition of the passed asynchronous
+functions. Each function consumes the return value of the function that
+follows. Composing functions f(), g() and h() would produce the result of
+f(g(h())), only this version uses callbacks to obtain the return values.
+
+Each function is executed with the `this` binding of the composed function.
+
+__Arguments__
+
+* functions... - the asynchronous functions to compose
+
+
+__Example__
+
+```js
+function add1(n, callback) {
+    setTimeout(function () {
+        callback(null, n + 1);
+    }, 10);
+}
+
+function mul3(n, callback) {
+    setTimeout(function () {
+        callback(null, n * 3);
+    }, 10);
+}
+
+var add1mul3 = async.compose(mul3, add1);
+
+add1mul3(4, function (err, result) {
+   // result now equals 15
+});
+```
+
+---------------------------------------
+<a name="applyEach" />
+### applyEach(fns, args..., callback)
+
+Applies the provided arguments to each function in the array, calling the
+callback after all functions have completed. If you only provide the first
+argument then it will return a function which lets you pass in the
+arguments as if it were a single function call.
+
+__Arguments__
+
+* fns - the asynchronous functions to all call with the same arguments
+* args... - any number of separate arguments to pass to the function
+* callback - the final argument should be the callback, called when all
+  functions have completed processing
+
+
+__Example__
+
+```js
+async.applyEach([enableSearch, updateSchema], 'bucket', callback);
+
+// partial application example:
+async.each(
+    buckets,
+    async.applyEach([enableSearch, updateSchema]),
+    callback
+);
+```
+
+---------------------------------------
+
+<a name="applyEachSeries" />
+### applyEachSeries(arr, iterator, callback)
+
+The same as applyEach only the functions are applied in series.
+
+---------------------------------------
+
+<a name="queue" />
+### queue(worker, concurrency)
+
+Creates a queue object with the specified concurrency. Tasks added to the
+queue will be processed in parallel (up to the concurrency limit). If all
+workers are in progress, the task is queued until one is available. Once
+a worker has completed a task, the task's callback is called.
+
+__Arguments__
+
+* worker(task, callback) - An asynchronous function for processing a queued
+  task, which must call its callback(err) argument when finished, with an 
+  optional error as an argument.
+* concurrency - An integer for determining how many worker functions should be
+  run in parallel.
+
+__Queue objects__
+
+The queue object returned by this function has the following properties and
+methods:
+
+* length() - a function returning the number of items waiting to be processed.
+* concurrency - an integer for determining how many worker functions should be
+  run in parallel. This property can be changed after a queue is created to
+  alter the concurrency on-the-fly.
+* push(task, [callback]) - add a new task to the queue, the callback is called
+  once the worker has finished processing the task.
+  instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.
+* unshift(task, [callback]) - add a new task to the front of the queue.
+* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued
+* empty - a callback that is called when the last item from the queue is given to a worker
+* drain - a callback that is called when the last item from the queue has returned from the worker
+
+__Example__
+
+```js
+// create a queue object with concurrency 2
+
+var q = async.queue(function (task, callback) {
+    console.log('hello ' + task.name);
+    callback();
+}, 2);
+
+
+// assign a callback
+q.drain = function() {
+    console.log('all items have been processed');
+}
+
+// add some items to the queue
+
+q.push({name: 'foo'}, function (err) {
+    console.log('finished processing foo');
+});
+q.push({name: 'bar'}, function (err) {
+    console.log('finished processing bar');
+});
+
+// add some items to the queue (batch-wise)
+
+q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {
+    console.log('finished processing bar');
+});
+
+// add some items to the front of the queue
+
+q.unshift({name: 'bar'}, function (err) {
+    console.log('finished processing bar');
+});
+```
+
+---------------------------------------
+
+<a name="cargo" />
+### cargo(worker, [payload])
+
+Creates a cargo object with the specified payload. Tasks added to the
+cargo will be processed altogether (up to the payload limit). If the
+worker is in progress, the task is queued until it is available. Once
+the worker has completed some tasks, each callback of those tasks is called.
+
+__Arguments__
+
+* worker(tasks, callback) - An asynchronous function for processing an array of
+  queued tasks, which must call its callback(err) argument when finished, with 
+  an optional error as an argument.
+* payload - An optional integer for determining how many tasks should be
+  processed per round; if omitted, the default is unlimited.
+
+__Cargo objects__
+
+The cargo object returned by this function has the following properties and
+methods:
+
+* length() - a function returning the number of items waiting to be processed.
+* payload - an integer for determining how many tasks should be
+  process per round. This property can be changed after a cargo is created to
+  alter the payload on-the-fly.
+* push(task, [callback]) - add a new task to the queue, the callback is called
+  once the worker has finished processing the task.
+  instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.
+* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued
+* empty - a callback that is called when the last item from the queue is given to a worker
+* drain - a callback that is called when the last item from the queue has returned from the worker
+
+__Example__
+
+```js
+// create a cargo object with payload 2
+
+var cargo = async.cargo(function (tasks, callback) {
+    for(var i=0; i<tasks.length; i++){
+      console.log('hello ' + tasks[i].name);
+    }
+    callback();
+}, 2);
+
+
+// add some items
+
+cargo.push({name: 'foo'}, function (err) {
+    console.log('finished processing foo');
+});
+cargo.push({name: 'bar'}, function (err) {
+    console.log('finished processing bar');
+});
+cargo.push({name: 'baz'}, function (err) {
+    console.log('finished processing baz');
+});
+```
+
+---------------------------------------
+
+<a name="auto" />
+### auto(tasks, [callback])
+
+Determines the best order for running functions based on their requirements.
+Each function can optionally depend on other functions being completed first,
+and each function is run as soon as its requirements are satisfied. If any of
+the functions pass an error to their callback, that function will not complete
+(so any other functions depending on it will not run) and the main callback
+will be called immediately with the error. Functions also receive an object
+containing the results of functions which have completed so far.
+
+Note, all functions are called with a results object as a second argument, 
+so it is unsafe to pass functions in the tasks object which cannot handle the
+extra argument. For example, this snippet of code:
+
+```js
+async.auto({
+  readData: async.apply(fs.readFile, 'data.txt', 'utf-8')
+}, callback);
+```
+
+will have the effect of calling readFile with the results object as the last
+argument, which will fail:
+
+```js
+fs.readFile('data.txt', 'utf-8', cb, {});
+```
+
+Instead, wrap the call to readFile in a function which does not forward the 
+results object:
+
+```js
+async.auto({
+  readData: function(cb, results){
+    fs.readFile('data.txt', 'utf-8', cb);
+  }
+}, callback);
+```
+
+__Arguments__
+
+* tasks - An object literal containing named functions or an array of
+  requirements, with the function itself the last item in the array. The key
+  used for each function or array is used when specifying requirements. The 
+  function receives two arguments: (1) a callback(err, result) which must be 
+  called when finished, passing an error (which can be null) and the result of 
+  the function's execution, and (2) a results object, containing the results of
+  the previously executed functions.
+* callback(err, results) - An optional callback which is called when all the
+  tasks have been completed. The callback will receive an error as an argument
+  if any tasks pass an error to their callback. Results will always be passed
+	but if an error occurred, no other tasks will be performed, and the results
+	object will only contain partial results.
+  
+
+__Example__
+
+```js
+async.auto({
+    get_data: function(callback){
+        // async code to get some data
+    },
+    make_folder: function(callback){
+        // async code to create a directory to store a file in
+        // this is run at the same time as getting the data
+    },
+    write_file: ['get_data', 'make_folder', function(callback){
+        // once there is some data and the directory exists,
+        // write the data to a file in the directory
+        callback(null, filename);
+    }],
+    email_link: ['write_file', function(callback, results){
+        // once the file is written let's email a link to it...
+        // results.write_file contains the filename returned by write_file.
+    }]
+});
+```
+
+This is a fairly trivial example, but to do this using the basic parallel and
+series functions would look like this:
+
+```js
+async.parallel([
+    function(callback){
+        // async code to get some data
+    },
+    function(callback){
+        // async code to create a directory to store a file in
+        // this is run at the same time as getting the data
+    }
+],
+function(err, results){
+    async.series([
+        function(callback){
+            // once there is some data and the directory exists,
+            // write the data to a file in the directory
+        },
+        function(callback){
+            // once the file is written let's email a link to it...
+        }
+    ]);
+});
+```
+
+For a complicated series of async tasks using the auto function makes adding
+new tasks much easier and makes the code more readable.
+
+
+---------------------------------------
+
+<a name="iterator" />
+### iterator(tasks)
+
+Creates an iterator function which calls the next function in the array,
+returning a continuation to call the next one after that. It's also possible to
+'peek' the next iterator by doing iterator.next().
+
+This function is used internally by the async module but can be useful when
+you want to manually control the flow of functions in series.
+
+__Arguments__
+
+* tasks - An array of functions to run.
+
+__Example__
+
+```js
+var iterator = async.iterator([
+    function(){ sys.p('one'); },
+    function(){ sys.p('two'); },
+    function(){ sys.p('three'); }
+]);
+
+node> var iterator2 = iterator();
+'one'
+node> var iterator3 = iterator2();
+'two'
+node> iterator3();
+'three'
+node> var nextfn = iterator2.next();
+node> nextfn();
+'three'
+```
+
+---------------------------------------
+
+<a name="apply" />
+### apply(function, arguments..)
+
+Creates a continuation function with some arguments already applied, a useful
+shorthand when combined with other control flow functions. Any arguments
+passed to the returned function are added to the arguments originally passed
+to apply.
+
+__Arguments__
+
+* function - The function you want to eventually apply all arguments to.
+* arguments... - Any number of arguments to automatically apply when the
+  continuation is called.
+
+__Example__
+
+```js
+// using apply
+
+async.parallel([
+    async.apply(fs.writeFile, 'testfile1', 'test1'),
+    async.apply(fs.writeFile, 'testfile2', 'test2'),
+]);
+
+
+// the same process without using apply
+
+async.parallel([
+    function(callback){
+        fs.writeFile('testfile1', 'test1', callback);
+    },
+    function(callback){
+        fs.writeFile('testfile2', 'test2', callback);
+    }
+]);
+```
+
+It's possible to pass any number of additional arguments when calling the
+continuation:
+
+```js
+node> var fn = async.apply(sys.puts, 'one');
+node> fn('two', 'three');
+one
+two
+three
+```
+
+---------------------------------------
+
+<a name="nextTick" />
+### nextTick(callback)
+
+Calls the callback on a later loop around the event loop. In node.js this just
+calls process.nextTick, in the browser it falls back to setImmediate(callback)
+if available, otherwise setTimeout(callback, 0), which means other higher priority
+events may precede the execution of the callback.
+
+This is used internally for browser-compatibility purposes.
+
+__Arguments__
+
+* callback - The function to call on a later loop around the event loop.
+
+__Example__
+
+```js
+var call_order = [];
+async.nextTick(function(){
+    call_order.push('two');
+    // call_order now equals ['one','two']
+});
+call_order.push('one')
+```
+
+<a name="times" />
+### times(n, callback)
+
+Calls the callback n times and accumulates results in the same manner
+you would use with async.map.
+
+__Arguments__
+
+* n - The number of times to run the function.
+* callback - The function to call n times.
+
+__Example__
+
+```js
+// Pretend this is some complicated async factory
+var createUser = function(id, callback) {
+  callback(null, {
+    id: 'user' + id
+  })
+}
+// generate 5 users
+async.times(5, function(n, next){
+    createUser(n, function(err, user) {
+      next(err, user)
+    })
+}, function(err, users) {
+  // we should now have 5 users
+});
+```
+
+<a name="timesSeries" />
+### timesSeries(n, callback)
+
+The same as times only the iterator is applied to each item in the array in
+series. The next iterator is only called once the current one has completed
+processing. The results array will be in the same order as the original.
+
+
+## Utils
+
+<a name="memoize" />
+### memoize(fn, [hasher])
+
+Caches the results of an async function. When creating a hash to store function
+results against, the callback is omitted from the hash and an optional hash
+function can be used.
+
+The cache of results is exposed as the `memo` property of the function returned
+by `memoize`.
+
+__Arguments__
+
+* fn - the function you to proxy and cache results from.
+* hasher - an optional function for generating a custom hash for storing
+  results, it has all the arguments applied to it apart from the callback, and
+  must be synchronous.
+
+__Example__
+
+```js
+var slow_fn = function (name, callback) {
+    // do something
+    callback(null, result);
+};
+var fn = async.memoize(slow_fn);
+
+// fn can now be used as if it were slow_fn
+fn('some name', function () {
+    // callback
+});
+```
+
+<a name="unmemoize" />
+### unmemoize(fn)
+
+Undoes a memoized function, reverting it to the original, unmemoized
+form. Comes handy in tests.
+
+__Arguments__
+
+* fn - the memoized function
+
+<a name="log" />
+### log(function, arguments)
+
+Logs the result of an async function to the console. Only works in node.js or
+in browsers that support console.log and console.error (such as FF and Chrome).
+If multiple arguments are returned from the async function, console.log is
+called on each argument in order.
+
+__Arguments__
+
+* function - The function you want to eventually apply all arguments to.
+* arguments... - Any number of arguments to apply to the function.
+
+__Example__
+
+```js
+var hello = function(name, callback){
+    setTimeout(function(){
+        callback(null, 'hello ' + name);
+    }, 1000);
+};
+```
+```js
+node> async.log(hello, 'world');
+'hello world'
+```
+
+---------------------------------------
+
+<a name="dir" />
+### dir(function, arguments)
+
+Logs the result of an async function to the console using console.dir to
+display the properties of the resulting object. Only works in node.js or
+in browsers that support console.dir and console.error (such as FF and Chrome).
+If multiple arguments are returned from the async function, console.dir is
+called on each argument in order.
+
+__Arguments__
+
+* function - The function you want to eventually apply all arguments to.
+* arguments... - Any number of arguments to apply to the function.
+
+__Example__
+
+```js
+var hello = function(name, callback){
+    setTimeout(function(){
+        callback(null, {hello: name});
+    }, 1000);
+};
+```
+```js
+node> async.dir(hello, 'world');
+{hello: 'world'}
+```
+
+---------------------------------------
+
+<a name="noConflict" />
+### noConflict()
+
+Changes the value of async back to its original value, returning a reference to the
+async object.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/component.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/component.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/component.json	(revision 517)
@@ -0,0 +1,11 @@
+{
+  "name": "async",
+  "repo": "caolan/async",
+  "description": "Higher-order functions and common patterns for asynchronous code",
+  "version": "0.1.23",
+  "keywords": [],
+  "dependencies": {},
+  "development": {},
+  "main": "lib/async.js",
+  "scripts": [ "lib/async.js" ]
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/lib/async.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/lib/async.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/lib/async.js	(revision 517)
@@ -0,0 +1,958 @@
+/*global setImmediate: false, setTimeout: false, console: false */
+(function () {
+
+    var async = {};
+
+    // global on the server, window in the browser
+    var root, previous_async;
+
+    root = this;
+    if (root != null) {
+      previous_async = root.async;
+    }
+
+    async.noConflict = function () {
+        root.async = previous_async;
+        return async;
+    };
+
+    function only_once(fn) {
+        var called = false;
+        return function() {
+            if (called) throw new Error("Callback was already called.");
+            called = true;
+            fn.apply(root, arguments);
+        }
+    }
+
+    //// cross-browser compatiblity functions ////
+
+    var _each = function (arr, iterator) {
+        if (arr.forEach) {
+            return arr.forEach(iterator);
+        }
+        for (var i = 0; i < arr.length; i += 1) {
+            iterator(arr[i], i, arr);
+        }
+    };
+
+    var _map = function (arr, iterator) {
+        if (arr.map) {
+            return arr.map(iterator);
+        }
+        var results = [];
+        _each(arr, function (x, i, a) {
+            results.push(iterator(x, i, a));
+        });
+        return results;
+    };
+
+    var _reduce = function (arr, iterator, memo) {
+        if (arr.reduce) {
+            return arr.reduce(iterator, memo);
+        }
+        _each(arr, function (x, i, a) {
+            memo = iterator(memo, x, i, a);
+        });
+        return memo;
+    };
+
+    var _keys = function (obj) {
+        if (Object.keys) {
+            return Object.keys(obj);
+        }
+        var keys = [];
+        for (var k in obj) {
+            if (obj.hasOwnProperty(k)) {
+                keys.push(k);
+            }
+        }
+        return keys;
+    };
+
+    //// exported async module functions ////
+
+    //// nextTick implementation with browser-compatible fallback ////
+    if (typeof process === 'undefined' || !(process.nextTick)) {
+        if (typeof setImmediate === 'function') {
+            async.nextTick = function (fn) {
+                // not a direct alias for IE10 compatibility
+                setImmediate(fn);
+            };
+            async.setImmediate = async.nextTick;
+        }
+        else {
+            async.nextTick = function (fn) {
+                setTimeout(fn, 0);
+            };
+            async.setImmediate = async.nextTick;
+        }
+    }
+    else {
+        async.nextTick = process.nextTick;
+        if (typeof setImmediate !== 'undefined') {
+            async.setImmediate = function (fn) {
+              // not a direct alias for IE10 compatibility
+              setImmediate(fn);
+            };
+        }
+        else {
+            async.setImmediate = async.nextTick;
+        }
+    }
+
+    async.each = function (arr, iterator, callback) {
+        callback = callback || function () {};
+        if (!arr.length) {
+            return callback();
+        }
+        var completed = 0;
+        _each(arr, function (x) {
+            iterator(x, only_once(function (err) {
+                if (err) {
+                    callback(err);
+                    callback = function () {};
+                }
+                else {
+                    completed += 1;
+                    if (completed >= arr.length) {
+                        callback(null);
+                    }
+                }
+            }));
+        });
+    };
+    async.forEach = async.each;
+
+    async.eachSeries = function (arr, iterator, callback) {
+        callback = callback || function () {};
+        if (!arr.length) {
+            return callback();
+        }
+        var completed = 0;
+        var iterate = function () {
+            iterator(arr[completed], function (err) {
+                if (err) {
+                    callback(err);
+                    callback = function () {};
+                }
+                else {
+                    completed += 1;
+                    if (completed >= arr.length) {
+                        callback(null);
+                    }
+                    else {
+                        iterate();
+                    }
+                }
+            });
+        };
+        iterate();
+    };
+    async.forEachSeries = async.eachSeries;
+
+    async.eachLimit = function (arr, limit, iterator, callback) {
+        var fn = _eachLimit(limit);
+        fn.apply(null, [arr, iterator, callback]);
+    };
+    async.forEachLimit = async.eachLimit;
+
+    var _eachLimit = function (limit) {
+
+        return function (arr, iterator, callback) {
+            callback = callback || function () {};
+            if (!arr.length || limit <= 0) {
+                return callback();
+            }
+            var completed = 0;
+            var started = 0;
+            var running = 0;
+
+            (function replenish () {
+                if (completed >= arr.length) {
+                    return callback();
+                }
+
+                while (running < limit && started < arr.length) {
+                    started += 1;
+                    running += 1;
+                    iterator(arr[started - 1], function (err) {
+                        if (err) {
+                            callback(err);
+                            callback = function () {};
+                        }
+                        else {
+                            completed += 1;
+                            running -= 1;
+                            if (completed >= arr.length) {
+                                callback();
+                            }
+                            else {
+                                replenish();
+                            }
+                        }
+                    });
+                }
+            })();
+        };
+    };
+
+
+    var doParallel = function (fn) {
+        return function () {
+            var args = Array.prototype.slice.call(arguments);
+            return fn.apply(null, [async.each].concat(args));
+        };
+    };
+    var doParallelLimit = function(limit, fn) {
+        return function () {
+            var args = Array.prototype.slice.call(arguments);
+            return fn.apply(null, [_eachLimit(limit)].concat(args));
+        };
+    };
+    var doSeries = function (fn) {
+        return function () {
+            var args = Array.prototype.slice.call(arguments);
+            return fn.apply(null, [async.eachSeries].concat(args));
+        };
+    };
+
+
+    var _asyncMap = function (eachfn, arr, iterator, callback) {
+        var results = [];
+        arr = _map(arr, function (x, i) {
+            return {index: i, value: x};
+        });
+        eachfn(arr, function (x, callback) {
+            iterator(x.value, function (err, v) {
+                results[x.index] = v;
+                callback(err);
+            });
+        }, function (err) {
+            callback(err, results);
+        });
+    };
+    async.map = doParallel(_asyncMap);
+    async.mapSeries = doSeries(_asyncMap);
+    async.mapLimit = function (arr, limit, iterator, callback) {
+        return _mapLimit(limit)(arr, iterator, callback);
+    };
+
+    var _mapLimit = function(limit) {
+        return doParallelLimit(limit, _asyncMap);
+    };
+
+    // reduce only has a series version, as doing reduce in parallel won't
+    // work in many situations.
+    async.reduce = function (arr, memo, iterator, callback) {
+        async.eachSeries(arr, function (x, callback) {
+            iterator(memo, x, function (err, v) {
+                memo = v;
+                callback(err);
+            });
+        }, function (err) {
+            callback(err, memo);
+        });
+    };
+    // inject alias
+    async.inject = async.reduce;
+    // foldl alias
+    async.foldl = async.reduce;
+
+    async.reduceRight = function (arr, memo, iterator, callback) {
+        var reversed = _map(arr, function (x) {
+            return x;
+        }).reverse();
+        async.reduce(reversed, memo, iterator, callback);
+    };
+    // foldr alias
+    async.foldr = async.reduceRight;
+
+    var _filter = function (eachfn, arr, iterator, callback) {
+        var results = [];
+        arr = _map(arr, function (x, i) {
+            return {index: i, value: x};
+        });
+        eachfn(arr, function (x, callback) {
+            iterator(x.value, function (v) {
+                if (v) {
+                    results.push(x);
+                }
+                callback();
+            });
+        }, function (err) {
+            callback(_map(results.sort(function (a, b) {
+                return a.index - b.index;
+            }), function (x) {
+                return x.value;
+            }));
+        });
+    };
+    async.filter = doParallel(_filter);
+    async.filterSeries = doSeries(_filter);
+    // select alias
+    async.select = async.filter;
+    async.selectSeries = async.filterSeries;
+
+    var _reject = function (eachfn, arr, iterator, callback) {
+        var results = [];
+        arr = _map(arr, function (x, i) {
+            return {index: i, value: x};
+        });
+        eachfn(arr, function (x, callback) {
+            iterator(x.value, function (v) {
+                if (!v) {
+                    results.push(x);
+                }
+                callback();
+            });
+        }, function (err) {
+            callback(_map(results.sort(function (a, b) {
+                return a.index - b.index;
+            }), function (x) {
+                return x.value;
+            }));
+        });
+    };
+    async.reject = doParallel(_reject);
+    async.rejectSeries = doSeries(_reject);
+
+    var _detect = function (eachfn, arr, iterator, main_callback) {
+        eachfn(arr, function (x, callback) {
+            iterator(x, function (result) {
+                if (result) {
+                    main_callback(x);
+                    main_callback = function () {};
+                }
+                else {
+                    callback();
+                }
+            });
+        }, function (err) {
+            main_callback();
+        });
+    };
+    async.detect = doParallel(_detect);
+    async.detectSeries = doSeries(_detect);
+
+    async.some = function (arr, iterator, main_callback) {
+        async.each(arr, function (x, callback) {
+            iterator(x, function (v) {
+                if (v) {
+                    main_callback(true);
+                    main_callback = function () {};
+                }
+                callback();
+            });
+        }, function (err) {
+            main_callback(false);
+        });
+    };
+    // any alias
+    async.any = async.some;
+
+    async.every = function (arr, iterator, main_callback) {
+        async.each(arr, function (x, callback) {
+            iterator(x, function (v) {
+                if (!v) {
+                    main_callback(false);
+                    main_callback = function () {};
+                }
+                callback();
+            });
+        }, function (err) {
+            main_callback(true);
+        });
+    };
+    // all alias
+    async.all = async.every;
+
+    async.sortBy = function (arr, iterator, callback) {
+        async.map(arr, function (x, callback) {
+            iterator(x, function (err, criteria) {
+                if (err) {
+                    callback(err);
+                }
+                else {
+                    callback(null, {value: x, criteria: criteria});
+                }
+            });
+        }, function (err, results) {
+            if (err) {
+                return callback(err);
+            }
+            else {
+                var fn = function (left, right) {
+                    var a = left.criteria, b = right.criteria;
+                    return a < b ? -1 : a > b ? 1 : 0;
+                };
+                callback(null, _map(results.sort(fn), function (x) {
+                    return x.value;
+                }));
+            }
+        });
+    };
+
+    async.auto = function (tasks, callback) {
+        callback = callback || function () {};
+        var keys = _keys(tasks);
+        if (!keys.length) {
+            return callback(null);
+        }
+
+        var results = {};
+
+        var listeners = [];
+        var addListener = function (fn) {
+            listeners.unshift(fn);
+        };
+        var removeListener = function (fn) {
+            for (var i = 0; i < listeners.length; i += 1) {
+                if (listeners[i] === fn) {
+                    listeners.splice(i, 1);
+                    return;
+                }
+            }
+        };
+        var taskComplete = function () {
+            _each(listeners.slice(0), function (fn) {
+                fn();
+            });
+        };
+
+        addListener(function () {
+            if (_keys(results).length === keys.length) {
+                callback(null, results);
+                callback = function () {};
+            }
+        });
+
+        _each(keys, function (k) {
+            var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
+            var taskCallback = function (err) {
+                var args = Array.prototype.slice.call(arguments, 1);
+                if (args.length <= 1) {
+                    args = args[0];
+                }
+                if (err) {
+                    var safeResults = {};
+                    _each(_keys(results), function(rkey) {
+                        safeResults[rkey] = results[rkey];
+                    });
+                    safeResults[k] = args;
+                    callback(err, safeResults);
+                    // stop subsequent errors hitting callback multiple times
+                    callback = function () {};
+                }
+                else {
+                    results[k] = args;
+                    async.setImmediate(taskComplete);
+                }
+            };
+            var requires = task.slice(0, Math.abs(task.length - 1)) || [];
+            var ready = function () {
+                return _reduce(requires, function (a, x) {
+                    return (a && results.hasOwnProperty(x));
+                }, true) && !results.hasOwnProperty(k);
+            };
+            if (ready()) {
+                task[task.length - 1](taskCallback, results);
+            }
+            else {
+                var listener = function () {
+                    if (ready()) {
+                        removeListener(listener);
+                        task[task.length - 1](taskCallback, results);
+                    }
+                };
+                addListener(listener);
+            }
+        });
+    };
+
+    async.waterfall = function (tasks, callback) {
+        callback = callback || function () {};
+        if (tasks.constructor !== Array) {
+          var err = new Error('First argument to waterfall must be an array of functions');
+          return callback(err);
+        }
+        if (!tasks.length) {
+            return callback();
+        }
+        var wrapIterator = function (iterator) {
+            return function (err) {
+                if (err) {
+                    callback.apply(null, arguments);
+                    callback = function () {};
+                }
+                else {
+                    var args = Array.prototype.slice.call(arguments, 1);
+                    var next = iterator.next();
+                    if (next) {
+                        args.push(wrapIterator(next));
+                    }
+                    else {
+                        args.push(callback);
+                    }
+                    async.setImmediate(function () {
+                        iterator.apply(null, args);
+                    });
+                }
+            };
+        };
+        wrapIterator(async.iterator(tasks))();
+    };
+
+    var _parallel = function(eachfn, tasks, callback) {
+        callback = callback || function () {};
+        if (tasks.constructor === Array) {
+            eachfn.map(tasks, function (fn, callback) {
+                if (fn) {
+                    fn(function (err) {
+                        var args = Array.prototype.slice.call(arguments, 1);
+                        if (args.length <= 1) {
+                            args = args[0];
+                        }
+                        callback.call(null, err, args);
+                    });
+                }
+            }, callback);
+        }
+        else {
+            var results = {};
+            eachfn.each(_keys(tasks), function (k, callback) {
+                tasks[k](function (err) {
+                    var args = Array.prototype.slice.call(arguments, 1);
+                    if (args.length <= 1) {
+                        args = args[0];
+                    }
+                    results[k] = args;
+                    callback(err);
+                });
+            }, function (err) {
+                callback(err, results);
+            });
+        }
+    };
+
+    async.parallel = function (tasks, callback) {
+        _parallel({ map: async.map, each: async.each }, tasks, callback);
+    };
+
+    async.parallelLimit = function(tasks, limit, callback) {
+        _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
+    };
+
+    async.series = function (tasks, callback) {
+        callback = callback || function () {};
+        if (tasks.constructor === Array) {
+            async.mapSeries(tasks, function (fn, callback) {
+                if (fn) {
+                    fn(function (err) {
+                        var args = Array.prototype.slice.call(arguments, 1);
+                        if (args.length <= 1) {
+                            args = args[0];
+                        }
+                        callback.call(null, err, args);
+                    });
+                }
+            }, callback);
+        }
+        else {
+            var results = {};
+            async.eachSeries(_keys(tasks), function (k, callback) {
+                tasks[k](function (err) {
+                    var args = Array.prototype.slice.call(arguments, 1);
+                    if (args.length <= 1) {
+                        args = args[0];
+                    }
+                    results[k] = args;
+                    callback(err);
+                });
+            }, function (err) {
+                callback(err, results);
+            });
+        }
+    };
+
+    async.iterator = function (tasks) {
+        var makeCallback = function (index) {
+            var fn = function () {
+                if (tasks.length) {
+                    tasks[index].apply(null, arguments);
+                }
+                return fn.next();
+            };
+            fn.next = function () {
+                return (index < tasks.length - 1) ? makeCallback(index + 1): null;
+            };
+            return fn;
+        };
+        return makeCallback(0);
+    };
+
+    async.apply = function (fn) {
+        var args = Array.prototype.slice.call(arguments, 1);
+        return function () {
+            return fn.apply(
+                null, args.concat(Array.prototype.slice.call(arguments))
+            );
+        };
+    };
+
+    var _concat = function (eachfn, arr, fn, callback) {
+        var r = [];
+        eachfn(arr, function (x, cb) {
+            fn(x, function (err, y) {
+                r = r.concat(y || []);
+                cb(err);
+            });
+        }, function (err) {
+            callback(err, r);
+        });
+    };
+    async.concat = doParallel(_concat);
+    async.concatSeries = doSeries(_concat);
+
+    async.whilst = function (test, iterator, callback) {
+        if (test()) {
+            iterator(function (err) {
+                if (err) {
+                    return callback(err);
+                }
+                async.whilst(test, iterator, callback);
+            });
+        }
+        else {
+            callback();
+        }
+    };
+
+    async.doWhilst = function (iterator, test, callback) {
+        iterator(function (err) {
+            if (err) {
+                return callback(err);
+            }
+            if (test()) {
+                async.doWhilst(iterator, test, callback);
+            }
+            else {
+                callback();
+            }
+        });
+    };
+
+    async.until = function (test, iterator, callback) {
+        if (!test()) {
+            iterator(function (err) {
+                if (err) {
+                    return callback(err);
+                }
+                async.until(test, iterator, callback);
+            });
+        }
+        else {
+            callback();
+        }
+    };
+
+    async.doUntil = function (iterator, test, callback) {
+        iterator(function (err) {
+            if (err) {
+                return callback(err);
+            }
+            if (!test()) {
+                async.doUntil(iterator, test, callback);
+            }
+            else {
+                callback();
+            }
+        });
+    };
+
+    async.queue = function (worker, concurrency) {
+        if (concurrency === undefined) {
+            concurrency = 1;
+        }
+        function _insert(q, data, pos, callback) {
+          if(data.constructor !== Array) {
+              data = [data];
+          }
+          _each(data, function(task) {
+              var item = {
+                  data: task,
+                  callback: typeof callback === 'function' ? callback : null
+              };
+
+              if (pos) {
+                q.tasks.unshift(item);
+              } else {
+                q.tasks.push(item);
+              }
+
+              if (q.saturated && q.tasks.length === concurrency) {
+                  q.saturated();
+              }
+              async.setImmediate(q.process);
+          });
+        }
+
+        var workers = 0;
+        var q = {
+            tasks: [],
+            concurrency: concurrency,
+            saturated: null,
+            empty: null,
+            drain: null,
+            push: function (data, callback) {
+              _insert(q, data, false, callback);
+            },
+            unshift: function (data, callback) {
+              _insert(q, data, true, callback);
+            },
+            process: function () {
+                if (workers < q.concurrency && q.tasks.length) {
+                    var task = q.tasks.shift();
+                    if (q.empty && q.tasks.length === 0) {
+                        q.empty();
+                    }
+                    workers += 1;
+                    var next = function () {
+                        workers -= 1;
+                        if (task.callback) {
+                            task.callback.apply(task, arguments);
+                        }
+                        if (q.drain && q.tasks.length + workers === 0) {
+                            q.drain();
+                        }
+                        q.process();
+                    };
+                    var cb = only_once(next);
+                    worker(task.data, cb);
+                }
+            },
+            length: function () {
+                return q.tasks.length;
+            },
+            running: function () {
+                return workers;
+            }
+        };
+        return q;
+    };
+
+    async.cargo = function (worker, payload) {
+        var working     = false,
+            tasks       = [];
+
+        var cargo = {
+            tasks: tasks,
+            payload: payload,
+            saturated: null,
+            empty: null,
+            drain: null,
+            push: function (data, callback) {
+                if(data.constructor !== Array) {
+                    data = [data];
+                }
+                _each(data, function(task) {
+                    tasks.push({
+                        data: task,
+                        callback: typeof callback === 'function' ? callback : null
+                    });
+                    if (cargo.saturated && tasks.length === payload) {
+                        cargo.saturated();
+                    }
+                });
+                async.setImmediate(cargo.process);
+            },
+            process: function process() {
+                if (working) return;
+                if (tasks.length === 0) {
+                    if(cargo.drain) cargo.drain();
+                    return;
+                }
+
+                var ts = typeof payload === 'number'
+                            ? tasks.splice(0, payload)
+                            : tasks.splice(0);
+
+                var ds = _map(ts, function (task) {
+                    return task.data;
+                });
+
+                if(cargo.empty) cargo.empty();
+                working = true;
+                worker(ds, function () {
+                    working = false;
+
+                    var args = arguments;
+                    _each(ts, function (data) {
+                        if (data.callback) {
+                            data.callback.apply(null, args);
+                        }
+                    });
+
+                    process();
+                });
+            },
+            length: function () {
+                return tasks.length;
+            },
+            running: function () {
+                return working;
+            }
+        };
+        return cargo;
+    };
+
+    var _console_fn = function (name) {
+        return function (fn) {
+            var args = Array.prototype.slice.call(arguments, 1);
+            fn.apply(null, args.concat([function (err) {
+                var args = Array.prototype.slice.call(arguments, 1);
+                if (typeof console !== 'undefined') {
+                    if (err) {
+                        if (console.error) {
+                            console.error(err);
+                        }
+                    }
+                    else if (console[name]) {
+                        _each(args, function (x) {
+                            console[name](x);
+                        });
+                    }
+                }
+            }]));
+        };
+    };
+    async.log = _console_fn('log');
+    async.dir = _console_fn('dir');
+    /*async.info = _console_fn('info');
+    async.warn = _console_fn('warn');
+    async.error = _console_fn('error');*/
+
+    async.memoize = function (fn, hasher) {
+        var memo = {};
+        var queues = {};
+        hasher = hasher || function (x) {
+            return x;
+        };
+        var memoized = function () {
+            var args = Array.prototype.slice.call(arguments);
+            var callback = args.pop();
+            var key = hasher.apply(null, args);
+            if (key in memo) {
+                callback.apply(null, memo[key]);
+            }
+            else if (key in queues) {
+                queues[key].push(callback);
+            }
+            else {
+                queues[key] = [callback];
+                fn.apply(null, args.concat([function () {
+                    memo[key] = arguments;
+                    var q = queues[key];
+                    delete queues[key];
+                    for (var i = 0, l = q.length; i < l; i++) {
+                      q[i].apply(null, arguments);
+                    }
+                }]));
+            }
+        };
+        memoized.memo = memo;
+        memoized.unmemoized = fn;
+        return memoized;
+    };
+
+    async.unmemoize = function (fn) {
+      return function () {
+        return (fn.unmemoized || fn).apply(null, arguments);
+      };
+    };
+
+    async.times = function (count, iterator, callback) {
+        var counter = [];
+        for (var i = 0; i < count; i++) {
+            counter.push(i);
+        }
+        return async.map(counter, iterator, callback);
+    };
+
+    async.timesSeries = function (count, iterator, callback) {
+        var counter = [];
+        for (var i = 0; i < count; i++) {
+            counter.push(i);
+        }
+        return async.mapSeries(counter, iterator, callback);
+    };
+
+    async.compose = function (/* functions... */) {
+        var fns = Array.prototype.reverse.call(arguments);
+        return function () {
+            var that = this;
+            var args = Array.prototype.slice.call(arguments);
+            var callback = args.pop();
+            async.reduce(fns, args, function (newargs, fn, cb) {
+                fn.apply(that, newargs.concat([function () {
+                    var err = arguments[0];
+                    var nextargs = Array.prototype.slice.call(arguments, 1);
+                    cb(err, nextargs);
+                }]))
+            },
+            function (err, results) {
+                callback.apply(that, [err].concat(results));
+            });
+        };
+    };
+
+    var _applyEach = function (eachfn, fns /*args...*/) {
+        var go = function () {
+            var that = this;
+            var args = Array.prototype.slice.call(arguments);
+            var callback = args.pop();
+            return eachfn(fns, function (fn, cb) {
+                fn.apply(that, args.concat([cb]));
+            },
+            callback);
+        };
+        if (arguments.length > 2) {
+            var args = Array.prototype.slice.call(arguments, 2);
+            return go.apply(this, args);
+        }
+        else {
+            return go;
+        }
+    };
+    async.applyEach = doParallel(_applyEach);
+    async.applyEachSeries = doSeries(_applyEach);
+
+    async.forever = function (fn, callback) {
+        function next(err) {
+            if (err) {
+                if (callback) {
+                    return callback(err);
+                }
+                throw err;
+            }
+            fn(next);
+        }
+        next();
+    };
+
+    // AMD / RequireJS
+    if (typeof define !== 'undefined' && define.amd) {
+        define([], function () {
+            return async;
+        });
+    }
+    // Node.js
+    else if (typeof module !== 'undefined' && module.exports) {
+        module.exports = async;
+    }
+    // included directly via <script> tag
+    else {
+        root.async = async;
+    }
+
+}());
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/async/package.json	(revision 517)
@@ -0,0 +1,43 @@
+{
+  "name": "async",
+  "description": "Higher-order functions and common patterns for asynchronous code",
+  "main": "./lib/async",
+  "author": {
+    "name": "Caolan McMahon"
+  },
+  "version": "0.2.10",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/caolan/async.git"
+  },
+  "bugs": {
+    "url": "https://github.com/caolan/async/issues"
+  },
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://github.com/caolan/async/raw/master/LICENSE"
+    }
+  ],
+  "devDependencies": {
+    "nodeunit": ">0.0.0",
+    "uglify-js": "1.2.x",
+    "nodelint": ">0.0.0"
+  },
+  "jam": {
+    "main": "lib/async.js",
+    "include": [
+      "lib/async.js",
+      "README.md",
+      "LICENSE"
+    ]
+  },
+  "scripts": {
+    "test": "nodeunit test/test-async.js"
+  },
+  "readme": "# Async.js\n\nAsync is a utility module which provides straight-forward, powerful functions\nfor working with asynchronous JavaScript. Although originally designed for\nuse with [node.js](http://nodejs.org), it can also be used directly in the\nbrowser. Also supports [component](https://github.com/component/component).\n\nAsync provides around 20 functions that include the usual 'functional'\nsuspects (map, reduce, filter, eachâŠ) as well as some common patterns\nfor asynchronous control flow (parallel, series, waterfallâŠ). All these\nfunctions assume you follow the node.js convention of providing a single\ncallback as the last argument of your async function.\n\n\n## Quick Examples\n\n```javascript\nasync.map(['file1','file2','file3'], fs.stat, function(err, results){\n    // results is now an array of stats for each file\n});\n\nasync.filter(['file1','file2','file3'], fs.exists, function(results){\n    // results now equals an array of the existing files\n});\n\nasync.parallel([\n    function(){ ... },\n    function(){ ... }\n], callback);\n\nasync.series([\n    function(){ ... },\n    function(){ ... }\n]);\n```\n\nThere are many more functions available so take a look at the docs below for a\nfull list. This module aims to be comprehensive, so if you feel anything is\nmissing please create a GitHub issue for it.\n\n## Common Pitfalls\n\n### Binding a context to an iterator\n\nThis section is really about bind, not about async. If you are wondering how to\nmake async execute your iterators in a given context, or are confused as to why\na method of another library isn't working as an iterator, study this example:\n\n```js\n// Here is a simple object with an (unnecessarily roundabout) squaring method\nvar AsyncSquaringLibrary = {\n  squareExponent: 2,\n  square: function(number, callback){ \n    var result = Math.pow(number, this.squareExponent);\n    setTimeout(function(){\n      callback(null, result);\n    }, 200);\n  }\n};\n\nasync.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result){\n  // result is [NaN, NaN, NaN]\n  // This fails because the `this.squareExponent` expression in the square\n  // function is not evaluated in the context of AsyncSquaringLibrary, and is\n  // therefore undefined.\n});\n\nasync.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result){\n  // result is [1, 4, 9]\n  // With the help of bind we can attach a context to the iterator before\n  // passing it to async. Now the square function will be executed in its \n  // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent`\n  // will be as expected.\n});\n```\n\n## Download\n\nThe source is available for download from\n[GitHub](http://github.com/caolan/async).\nAlternatively, you can install using Node Package Manager (npm):\n\n    npm install async\n\n__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 29.6kb Uncompressed\n\n## In the Browser\n\nSo far it's been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:\n\n```html\n<script type=\"text/javascript\" src=\"async.js\"></script>\n<script type=\"text/javascript\">\n\n    async.map(data, asyncProcess, function(err, results){\n        alert(results);\n    });\n\n</script>\n```\n\n## Documentation\n\n### Collections\n\n* [each](#each)\n* [eachSeries](#eachSeries)\n* [eachLimit](#eachLimit)\n* [map](#map)\n* [mapSeries](#mapSeries)\n* [mapLimit](#mapLimit)\n* [filter](#filter)\n* [filterSeries](#filterSeries)\n* [reject](#reject)\n* [rejectSeries](#rejectSeries)\n* [reduce](#reduce)\n* [reduceRight](#reduceRight)\n* [detect](#detect)\n* [detectSeries](#detectSeries)\n* [sortBy](#sortBy)\n* [some](#some)\n* [every](#every)\n* [concat](#concat)\n* [concatSeries](#concatSeries)\n\n### Control Flow\n\n* [series](#series)\n* [parallel](#parallel)\n* [parallelLimit](#parallellimittasks-limit-callback)\n* [whilst](#whilst)\n* [doWhilst](#doWhilst)\n* [until](#until)\n* [doUntil](#doUntil)\n* [forever](#forever)\n* [waterfall](#waterfall)\n* [compose](#compose)\n* [applyEach](#applyEach)\n* [applyEachSeries](#applyEachSeries)\n* [queue](#queue)\n* [cargo](#cargo)\n* [auto](#auto)\n* [iterator](#iterator)\n* [apply](#apply)\n* [nextTick](#nextTick)\n* [times](#times)\n* [timesSeries](#timesSeries)\n\n### Utils\n\n* [memoize](#memoize)\n* [unmemoize](#unmemoize)\n* [log](#log)\n* [dir](#dir)\n* [noConflict](#noConflict)\n\n\n## Collections\n\n<a name=\"forEach\" />\n<a name=\"each\" />\n### each(arr, iterator, callback)\n\nApplies an iterator function to each item in an array, in parallel.\nThe iterator is called with an item from the list and a callback for when it\nhas finished. If the iterator passes an error to this callback, the main\ncallback for the each function is immediately called with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n  The iterator is passed a callback(err) which must be called once it has \n  completed. If no error has occured, the callback should be run without \n  arguments or with an explicit null argument.\n* callback(err) - A callback which is called after all the iterator functions\n  have finished, or an error has occurred.\n\n__Example__\n\n```js\n// assuming openFiles is an array of file names and saveFile is a function\n// to save the modified contents of that file:\n\nasync.each(openFiles, saveFile, function(err){\n    // if any of the saves produced an error, err would equal that error\n});\n```\n\n---------------------------------------\n\n<a name=\"forEachSeries\" />\n<a name=\"eachSeries\" />\n### eachSeries(arr, iterator, callback)\n\nThe same as each only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. This means the iterator functions will complete in order.\n\n\n---------------------------------------\n\n<a name=\"forEachLimit\" />\n<a name=\"eachLimit\" />\n### eachLimit(arr, limit, iterator, callback)\n\nThe same as each only no more than \"limit\" iterators will be simultaneously \nrunning at any time.\n\nNote that the items are not processed in batches, so there is no guarantee that\n the first \"limit\" iterator functions will complete before any others are \nstarted.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* limit - The maximum number of iterators to run at any time.\n* iterator(item, callback) - A function to apply to each item in the array.\n  The iterator is passed a callback(err) which must be called once it has \n  completed. If no error has occured, the callback should be run without \n  arguments or with an explicit null argument.\n* callback(err) - A callback which is called after all the iterator functions\n  have finished, or an error has occurred.\n\n__Example__\n\n```js\n// Assume documents is an array of JSON objects and requestApi is a\n// function that interacts with a rate-limited REST api.\n\nasync.eachLimit(documents, 20, requestApi, function(err){\n    // if any of the saves produced an error, err would equal that error\n});\n```\n\n---------------------------------------\n\n<a name=\"map\" />\n### map(arr, iterator, callback)\n\nProduces a new array of values by mapping each value in the given array through\nthe iterator function. The iterator is called with an item from the array and a\ncallback for when it has finished processing. The callback takes 2 arguments, \nan error and the transformed item from the array. If the iterator passes an\nerror to this callback, the main callback for the map function is immediately\ncalled with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order, however\nthe results array will be in the same order as the original array.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n  The iterator is passed a callback(err, transformed) which must be called once \n  it has completed with an error (which can be null) and a transformed item.\n* callback(err, results) - A callback which is called after all the iterator\n  functions have finished, or an error has occurred. Results is an array of the\n  transformed items from the original array.\n\n__Example__\n\n```js\nasync.map(['file1','file2','file3'], fs.stat, function(err, results){\n    // results is now an array of stats for each file\n});\n```\n\n---------------------------------------\n\n<a name=\"mapSeries\" />\n### mapSeries(arr, iterator, callback)\n\nThe same as map only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n\n---------------------------------------\n\n<a name=\"mapLimit\" />\n### mapLimit(arr, limit, iterator, callback)\n\nThe same as map only no more than \"limit\" iterators will be simultaneously \nrunning at any time.\n\nNote that the items are not processed in batches, so there is no guarantee that\n the first \"limit\" iterator functions will complete before any others are \nstarted.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* limit - The maximum number of iterators to run at any time.\n* iterator(item, callback) - A function to apply to each item in the array.\n  The iterator is passed a callback(err, transformed) which must be called once \n  it has completed with an error (which can be null) and a transformed item.\n* callback(err, results) - A callback which is called after all the iterator\n  functions have finished, or an error has occurred. Results is an array of the\n  transformed items from the original array.\n\n__Example__\n\n```js\nasync.mapLimit(['file1','file2','file3'], 1, fs.stat, function(err, results){\n    // results is now an array of stats for each file\n});\n```\n\n---------------------------------------\n\n<a name=\"filter\" />\n### filter(arr, iterator, callback)\n\n__Alias:__ select\n\nReturns a new array of all the values which pass an async truth test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists. This operation is\nperformed in parallel, but the results array will be in the same order as the\noriginal.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n  The iterator is passed a callback(truthValue) which must be called with a \n  boolean argument once it has completed.\n* callback(results) - A callback which is called after all the iterator\n  functions have finished.\n\n__Example__\n\n```js\nasync.filter(['file1','file2','file3'], fs.exists, function(results){\n    // results now equals an array of the existing files\n});\n```\n\n---------------------------------------\n\n<a name=\"filterSeries\" />\n### filterSeries(arr, iterator, callback)\n\n__alias:__ selectSeries\n\nThe same as filter only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n---------------------------------------\n\n<a name=\"reject\" />\n### reject(arr, iterator, callback)\n\nThe opposite of filter. Removes values that pass an async truth test.\n\n---------------------------------------\n\n<a name=\"rejectSeries\" />\n### rejectSeries(arr, iterator, callback)\n\nThe same as reject, only the iterator is applied to each item in the array\nin series.\n\n\n---------------------------------------\n\n<a name=\"reduce\" />\n### reduce(arr, memo, iterator, callback)\n\n__aliases:__ inject, foldl\n\nReduces a list of values into a single value using an async iterator to return\neach successive step. Memo is the initial state of the reduction. This\nfunction only operates in series. For performance reasons, it may make sense to\nsplit a call to this function into a parallel map, then use the normal\nArray.prototype.reduce on the results. This function is for situations where\neach step in the reduction needs to be async, if you can get the data before\nreducing it then it's probably a good idea to do so.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* memo - The initial state of the reduction.\n* iterator(memo, item, callback) - A function applied to each item in the\n  array to produce the next step in the reduction. The iterator is passed a\n  callback(err, reduction) which accepts an optional error as its first \n  argument, and the state of the reduction as the second. If an error is \n  passed to the callback, the reduction is stopped and the main callback is \n  immediately called with the error.\n* callback(err, result) - A callback which is called after all the iterator\n  functions have finished. Result is the reduced value.\n\n__Example__\n\n```js\nasync.reduce([1,2,3], 0, function(memo, item, callback){\n    // pointless async:\n    process.nextTick(function(){\n        callback(null, memo + item)\n    });\n}, function(err, result){\n    // result is now equal to the last value of memo, which is 6\n});\n```\n\n---------------------------------------\n\n<a name=\"reduceRight\" />\n### reduceRight(arr, memo, iterator, callback)\n\n__Alias:__ foldr\n\nSame as reduce, only operates on the items in the array in reverse order.\n\n\n---------------------------------------\n\n<a name=\"detect\" />\n### detect(arr, iterator, callback)\n\nReturns the first value in a list that passes an async truth test. The\niterator is applied in parallel, meaning the first iterator to return true will\nfire the detect callback with that result. That means the result might not be\nthe first item in the original array (in terms of order) that passes the test.\n\nIf order within the original array is important then look at detectSeries.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n  The iterator is passed a callback(truthValue) which must be called with a \n  boolean argument once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n  true, or after all the iterator functions have finished. Result will be\n  the first item in the array that passes the truth test (iterator) or the\n  value undefined if none passed.\n\n__Example__\n\n```js\nasync.detect(['file1','file2','file3'], fs.exists, function(result){\n    // result now equals the first file in the list that exists\n});\n```\n\n---------------------------------------\n\n<a name=\"detectSeries\" />\n### detectSeries(arr, iterator, callback)\n\nThe same as detect, only the iterator is applied to each item in the array\nin series. This means the result is always the first in the original array (in\nterms of array order) that passes the truth test.\n\n\n---------------------------------------\n\n<a name=\"sortBy\" />\n### sortBy(arr, iterator, callback)\n\nSorts a list by the results of running each value through an async iterator.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n  The iterator is passed a callback(err, sortValue) which must be called once it\n  has completed with an error (which can be null) and a value to use as the sort\n  criteria.\n* callback(err, results) - A callback which is called after all the iterator\n  functions have finished, or an error has occurred. Results is the items from\n  the original array sorted by the values returned by the iterator calls.\n\n__Example__\n\n```js\nasync.sortBy(['file1','file2','file3'], function(file, callback){\n    fs.stat(file, function(err, stats){\n        callback(err, stats.mtime);\n    });\n}, function(err, results){\n    // results is now the original array of files sorted by\n    // modified date\n});\n```\n\n---------------------------------------\n\n<a name=\"some\" />\n### some(arr, iterator, callback)\n\n__Alias:__ any\n\nReturns true if at least one element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists. Once any iterator\ncall returns true, the main callback is immediately called.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n  The iterator is passed a callback(truthValue) which must be called with a \n  boolean argument once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n  true, or after all the iterator functions have finished. Result will be\n  either true or false depending on the values of the async tests.\n\n__Example__\n\n```js\nasync.some(['file1','file2','file3'], fs.exists, function(result){\n    // if result is true then at least one of the files exists\n});\n```\n\n---------------------------------------\n\n<a name=\"every\" />\n### every(arr, iterator, callback)\n\n__Alias:__ all\n\nReturns true if every element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n  The iterator is passed a callback(truthValue) which must be called with a \n  boolean argument once it has completed.\n* callback(result) - A callback which is called after all the iterator\n  functions have finished. Result will be either true or false depending on\n  the values of the async tests.\n\n__Example__\n\n```js\nasync.every(['file1','file2','file3'], fs.exists, function(result){\n    // if result is true then every file exists\n});\n```\n\n---------------------------------------\n\n<a name=\"concat\" />\n### concat(arr, iterator, callback)\n\nApplies an iterator to each item in a list, concatenating the results. Returns the\nconcatenated list. The iterators are called in parallel, and the results are\nconcatenated as they return. There is no guarantee that the results array will\nbe returned in the original order of the arguments passed to the iterator function.\n\n__Arguments__\n\n* arr - An array to iterate over\n* iterator(item, callback) - A function to apply to each item in the array.\n  The iterator is passed a callback(err, results) which must be called once it \n  has completed with an error (which can be null) and an array of results.\n* callback(err, results) - A callback which is called after all the iterator\n  functions have finished, or an error has occurred. Results is an array containing\n  the concatenated results of the iterator function.\n\n__Example__\n\n```js\nasync.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){\n    // files is now a list of filenames that exist in the 3 directories\n});\n```\n\n---------------------------------------\n\n<a name=\"concatSeries\" />\n### concatSeries(arr, iterator, callback)\n\nSame as async.concat, but executes in series instead of parallel.\n\n\n## Control Flow\n\n<a name=\"series\" />\n### series(tasks, [callback])\n\nRun an array of functions in series, each one running once the previous\nfunction has completed. If any functions in the series pass an error to its\ncallback, no more functions are run and the callback for the series is\nimmediately called with the value of the error. Once the tasks have completed,\nthe results are passed to the final callback as an array.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.series.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed\n  a callback(err, result) it must call on completion with an error (which can\n  be null) and an optional result value.\n* callback(err, results) - An optional callback to run once all the functions\n  have completed. This function gets a results array (or object) containing all \n  the result arguments passed to the task callbacks.\n\n__Example__\n\n```js\nasync.series([\n    function(callback){\n        // do some stuff ...\n        callback(null, 'one');\n    },\n    function(callback){\n        // do some more stuff ...\n        callback(null, 'two');\n    }\n],\n// optional callback\nfunction(err, results){\n    // results is now equal to ['one', 'two']\n});\n\n\n// an example using an object instead of an array\nasync.series({\n    one: function(callback){\n        setTimeout(function(){\n            callback(null, 1);\n        }, 200);\n    },\n    two: function(callback){\n        setTimeout(function(){\n            callback(null, 2);\n        }, 100);\n    }\n},\nfunction(err, results) {\n    // results is now equal to: {one: 1, two: 2}\n});\n```\n\n---------------------------------------\n\n<a name=\"parallel\" />\n### parallel(tasks, [callback])\n\nRun an array of functions in parallel, without waiting until the previous\nfunction has completed. If any of the functions pass an error to its\ncallback, the main callback is immediately called with the value of the error.\nOnce the tasks have completed, the results are passed to the final callback as an\narray.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.parallel.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed \n  a callback(err, result) it must call on completion with an error (which can\n  be null) and an optional result value.\n* callback(err, results) - An optional callback to run once all the functions\n  have completed. This function gets a results array (or object) containing all \n  the result arguments passed to the task callbacks.\n\n__Example__\n\n```js\nasync.parallel([\n    function(callback){\n        setTimeout(function(){\n            callback(null, 'one');\n        }, 200);\n    },\n    function(callback){\n        setTimeout(function(){\n            callback(null, 'two');\n        }, 100);\n    }\n],\n// optional callback\nfunction(err, results){\n    // the results array will equal ['one','two'] even though\n    // the second function had a shorter timeout.\n});\n\n\n// an example using an object instead of an array\nasync.parallel({\n    one: function(callback){\n        setTimeout(function(){\n            callback(null, 1);\n        }, 200);\n    },\n    two: function(callback){\n        setTimeout(function(){\n            callback(null, 2);\n        }, 100);\n    }\n},\nfunction(err, results) {\n    // results is now equals to: {one: 1, two: 2}\n});\n```\n\n---------------------------------------\n\n<a name=\"parallel\" />\n### parallelLimit(tasks, limit, [callback])\n\nThe same as parallel only the tasks are executed in parallel with a maximum of \"limit\" \ntasks executing at any time.\n\nNote that the tasks are not executed in batches, so there is no guarantee that \nthe first \"limit\" tasks will complete before any others are started.\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed \n  a callback(err, result) it must call on completion with an error (which can\n  be null) and an optional result value.\n* limit - The maximum number of tasks to run at any time.\n* callback(err, results) - An optional callback to run once all the functions\n  have completed. This function gets a results array (or object) containing all \n  the result arguments passed to the task callbacks.\n\n---------------------------------------\n\n<a name=\"whilst\" />\n### whilst(test, fn, callback)\n\nRepeatedly call fn, while test returns true. Calls the callback when stopped,\nor an error occurs.\n\n__Arguments__\n\n* test() - synchronous truth test to perform before each execution of fn.\n* fn(callback) - A function to call each time the test passes. The function is\n  passed a callback(err) which must be called once it has completed with an \n  optional error argument.\n* callback(err) - A callback which is called after the test fails and repeated\n  execution of fn has stopped.\n\n__Example__\n\n```js\nvar count = 0;\n\nasync.whilst(\n    function () { return count < 5; },\n    function (callback) {\n        count++;\n        setTimeout(callback, 1000);\n    },\n    function (err) {\n        // 5 seconds have passed\n    }\n);\n```\n\n---------------------------------------\n\n<a name=\"doWhilst\" />\n### doWhilst(fn, test, callback)\n\nThe post check version of whilst. To reflect the difference in the order of operations `test` and `fn` arguments are switched. `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.\n\n---------------------------------------\n\n<a name=\"until\" />\n### until(test, fn, callback)\n\nRepeatedly call fn, until test returns true. Calls the callback when stopped,\nor an error occurs.\n\nThe inverse of async.whilst.\n\n---------------------------------------\n\n<a name=\"doUntil\" />\n### doUntil(fn, test, callback)\n\nLike doWhilst except the test is inverted. Note the argument ordering differs from `until`.\n\n---------------------------------------\n\n<a name=\"forever\" />\n### forever(fn, callback)\n\nCalls the asynchronous function 'fn' repeatedly, in series, indefinitely.\nIf an error is passed to fn's callback then 'callback' is called with the\nerror, otherwise it will never be called.\n\n---------------------------------------\n\n<a name=\"waterfall\" />\n### waterfall(tasks, [callback])\n\nRuns an array of functions in series, each passing their results to the next in\nthe array. However, if any of the functions pass an error to the callback, the\nnext function is not executed and the main callback is immediately called with\nthe error.\n\n__Arguments__\n\n* tasks - An array of functions to run, each function is passed a \n  callback(err, result1, result2, ...) it must call on completion. The first\n  argument is an error (which can be null) and any further arguments will be \n  passed as arguments in order to the next task.\n* callback(err, [results]) - An optional callback to run once all the functions\n  have completed. This will be passed the results of the last task's callback.\n\n\n\n__Example__\n\n```js\nasync.waterfall([\n    function(callback){\n        callback(null, 'one', 'two');\n    },\n    function(arg1, arg2, callback){\n        callback(null, 'three');\n    },\n    function(arg1, callback){\n        // arg1 now equals 'three'\n        callback(null, 'done');\n    }\n], function (err, result) {\n   // result now equals 'done'    \n});\n```\n\n---------------------------------------\n<a name=\"compose\" />\n### compose(fn1, fn2...)\n\nCreates a function which is a composition of the passed asynchronous\nfunctions. Each function consumes the return value of the function that\nfollows. Composing functions f(), g() and h() would produce the result of\nf(g(h())), only this version uses callbacks to obtain the return values.\n\nEach function is executed with the `this` binding of the composed function.\n\n__Arguments__\n\n* functions... - the asynchronous functions to compose\n\n\n__Example__\n\n```js\nfunction add1(n, callback) {\n    setTimeout(function () {\n        callback(null, n + 1);\n    }, 10);\n}\n\nfunction mul3(n, callback) {\n    setTimeout(function () {\n        callback(null, n * 3);\n    }, 10);\n}\n\nvar add1mul3 = async.compose(mul3, add1);\n\nadd1mul3(4, function (err, result) {\n   // result now equals 15\n});\n```\n\n---------------------------------------\n<a name=\"applyEach\" />\n### applyEach(fns, args..., callback)\n\nApplies the provided arguments to each function in the array, calling the\ncallback after all functions have completed. If you only provide the first\nargument then it will return a function which lets you pass in the\narguments as if it were a single function call.\n\n__Arguments__\n\n* fns - the asynchronous functions to all call with the same arguments\n* args... - any number of separate arguments to pass to the function\n* callback - the final argument should be the callback, called when all\n  functions have completed processing\n\n\n__Example__\n\n```js\nasync.applyEach([enableSearch, updateSchema], 'bucket', callback);\n\n// partial application example:\nasync.each(\n    buckets,\n    async.applyEach([enableSearch, updateSchema]),\n    callback\n);\n```\n\n---------------------------------------\n\n<a name=\"applyEachSeries\" />\n### applyEachSeries(arr, iterator, callback)\n\nThe same as applyEach only the functions are applied in series.\n\n---------------------------------------\n\n<a name=\"queue\" />\n### queue(worker, concurrency)\n\nCreates a queue object with the specified concurrency. Tasks added to the\nqueue will be processed in parallel (up to the concurrency limit). If all\nworkers are in progress, the task is queued until one is available. Once\na worker has completed a task, the task's callback is called.\n\n__Arguments__\n\n* worker(task, callback) - An asynchronous function for processing a queued\n  task, which must call its callback(err) argument when finished, with an \n  optional error as an argument.\n* concurrency - An integer for determining how many worker functions should be\n  run in parallel.\n\n__Queue objects__\n\nThe queue object returned by this function has the following properties and\nmethods:\n\n* length() - a function returning the number of items waiting to be processed.\n* concurrency - an integer for determining how many worker functions should be\n  run in parallel. This property can be changed after a queue is created to\n  alter the concurrency on-the-fly.\n* push(task, [callback]) - add a new task to the queue, the callback is called\n  once the worker has finished processing the task.\n  instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.\n* unshift(task, [callback]) - add a new task to the front of the queue.\n* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued\n* empty - a callback that is called when the last item from the queue is given to a worker\n* drain - a callback that is called when the last item from the queue has returned from the worker\n\n__Example__\n\n```js\n// create a queue object with concurrency 2\n\nvar q = async.queue(function (task, callback) {\n    console.log('hello ' + task.name);\n    callback();\n}, 2);\n\n\n// assign a callback\nq.drain = function() {\n    console.log('all items have been processed');\n}\n\n// add some items to the queue\n\nq.push({name: 'foo'}, function (err) {\n    console.log('finished processing foo');\n});\nq.push({name: 'bar'}, function (err) {\n    console.log('finished processing bar');\n});\n\n// add some items to the queue (batch-wise)\n\nq.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {\n    console.log('finished processing bar');\n});\n\n// add some items to the front of the queue\n\nq.unshift({name: 'bar'}, function (err) {\n    console.log('finished processing bar');\n});\n```\n\n---------------------------------------\n\n<a name=\"cargo\" />\n### cargo(worker, [payload])\n\nCreates a cargo object with the specified payload. Tasks added to the\ncargo will be processed altogether (up to the payload limit). If the\nworker is in progress, the task is queued until it is available. Once\nthe worker has completed some tasks, each callback of those tasks is called.\n\n__Arguments__\n\n* worker(tasks, callback) - An asynchronous function for processing an array of\n  queued tasks, which must call its callback(err) argument when finished, with \n  an optional error as an argument.\n* payload - An optional integer for determining how many tasks should be\n  processed per round; if omitted, the default is unlimited.\n\n__Cargo objects__\n\nThe cargo object returned by this function has the following properties and\nmethods:\n\n* length() - a function returning the number of items waiting to be processed.\n* payload - an integer for determining how many tasks should be\n  process per round. This property can be changed after a cargo is created to\n  alter the payload on-the-fly.\n* push(task, [callback]) - add a new task to the queue, the callback is called\n  once the worker has finished processing the task.\n  instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.\n* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued\n* empty - a callback that is called when the last item from the queue is given to a worker\n* drain - a callback that is called when the last item from the queue has returned from the worker\n\n__Example__\n\n```js\n// create a cargo object with payload 2\n\nvar cargo = async.cargo(function (tasks, callback) {\n    for(var i=0; i<tasks.length; i++){\n      console.log('hello ' + tasks[i].name);\n    }\n    callback();\n}, 2);\n\n\n// add some items\n\ncargo.push({name: 'foo'}, function (err) {\n    console.log('finished processing foo');\n});\ncargo.push({name: 'bar'}, function (err) {\n    console.log('finished processing bar');\n});\ncargo.push({name: 'baz'}, function (err) {\n    console.log('finished processing baz');\n});\n```\n\n---------------------------------------\n\n<a name=\"auto\" />\n### auto(tasks, [callback])\n\nDetermines the best order for running functions based on their requirements.\nEach function can optionally depend on other functions being completed first,\nand each function is run as soon as its requirements are satisfied. If any of\nthe functions pass an error to their callback, that function will not complete\n(so any other functions depending on it will not run) and the main callback\nwill be called immediately with the error. Functions also receive an object\ncontaining the results of functions which have completed so far.\n\nNote, all functions are called with a results object as a second argument, \nso it is unsafe to pass functions in the tasks object which cannot handle the\nextra argument. For example, this snippet of code:\n\n```js\nasync.auto({\n  readData: async.apply(fs.readFile, 'data.txt', 'utf-8')\n}, callback);\n```\n\nwill have the effect of calling readFile with the results object as the last\nargument, which will fail:\n\n```js\nfs.readFile('data.txt', 'utf-8', cb, {});\n```\n\nInstead, wrap the call to readFile in a function which does not forward the \nresults object:\n\n```js\nasync.auto({\n  readData: function(cb, results){\n    fs.readFile('data.txt', 'utf-8', cb);\n  }\n}, callback);\n```\n\n__Arguments__\n\n* tasks - An object literal containing named functions or an array of\n  requirements, with the function itself the last item in the array. The key\n  used for each function or array is used when specifying requirements. The \n  function receives two arguments: (1) a callback(err, result) which must be \n  called when finished, passing an error (which can be null) and the result of \n  the function's execution, and (2) a results object, containing the results of\n  the previously executed functions.\n* callback(err, results) - An optional callback which is called when all the\n  tasks have been completed. The callback will receive an error as an argument\n  if any tasks pass an error to their callback. Results will always be passed\n\tbut if an error occurred, no other tasks will be performed, and the results\n\tobject will only contain partial results.\n  \n\n__Example__\n\n```js\nasync.auto({\n    get_data: function(callback){\n        // async code to get some data\n    },\n    make_folder: function(callback){\n        // async code to create a directory to store a file in\n        // this is run at the same time as getting the data\n    },\n    write_file: ['get_data', 'make_folder', function(callback){\n        // once there is some data and the directory exists,\n        // write the data to a file in the directory\n        callback(null, filename);\n    }],\n    email_link: ['write_file', function(callback, results){\n        // once the file is written let's email a link to it...\n        // results.write_file contains the filename returned by write_file.\n    }]\n});\n```\n\nThis is a fairly trivial example, but to do this using the basic parallel and\nseries functions would look like this:\n\n```js\nasync.parallel([\n    function(callback){\n        // async code to get some data\n    },\n    function(callback){\n        // async code to create a directory to store a file in\n        // this is run at the same time as getting the data\n    }\n],\nfunction(err, results){\n    async.series([\n        function(callback){\n            // once there is some data and the directory exists,\n            // write the data to a file in the directory\n        },\n        function(callback){\n            // once the file is written let's email a link to it...\n        }\n    ]);\n});\n```\n\nFor a complicated series of async tasks using the auto function makes adding\nnew tasks much easier and makes the code more readable.\n\n\n---------------------------------------\n\n<a name=\"iterator\" />\n### iterator(tasks)\n\nCreates an iterator function which calls the next function in the array,\nreturning a continuation to call the next one after that. It's also possible to\n'peek' the next iterator by doing iterator.next().\n\nThis function is used internally by the async module but can be useful when\nyou want to manually control the flow of functions in series.\n\n__Arguments__\n\n* tasks - An array of functions to run.\n\n__Example__\n\n```js\nvar iterator = async.iterator([\n    function(){ sys.p('one'); },\n    function(){ sys.p('two'); },\n    function(){ sys.p('three'); }\n]);\n\nnode> var iterator2 = iterator();\n'one'\nnode> var iterator3 = iterator2();\n'two'\nnode> iterator3();\n'three'\nnode> var nextfn = iterator2.next();\nnode> nextfn();\n'three'\n```\n\n---------------------------------------\n\n<a name=\"apply\" />\n### apply(function, arguments..)\n\nCreates a continuation function with some arguments already applied, a useful\nshorthand when combined with other control flow functions. Any arguments\npassed to the returned function are added to the arguments originally passed\nto apply.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to automatically apply when the\n  continuation is called.\n\n__Example__\n\n```js\n// using apply\n\nasync.parallel([\n    async.apply(fs.writeFile, 'testfile1', 'test1'),\n    async.apply(fs.writeFile, 'testfile2', 'test2'),\n]);\n\n\n// the same process without using apply\n\nasync.parallel([\n    function(callback){\n        fs.writeFile('testfile1', 'test1', callback);\n    },\n    function(callback){\n        fs.writeFile('testfile2', 'test2', callback);\n    }\n]);\n```\n\nIt's possible to pass any number of additional arguments when calling the\ncontinuation:\n\n```js\nnode> var fn = async.apply(sys.puts, 'one');\nnode> fn('two', 'three');\none\ntwo\nthree\n```\n\n---------------------------------------\n\n<a name=\"nextTick\" />\n### nextTick(callback)\n\nCalls the callback on a later loop around the event loop. In node.js this just\ncalls process.nextTick, in the browser it falls back to setImmediate(callback)\nif available, otherwise setTimeout(callback, 0), which means other higher priority\nevents may precede the execution of the callback.\n\nThis is used internally for browser-compatibility purposes.\n\n__Arguments__\n\n* callback - The function to call on a later loop around the event loop.\n\n__Example__\n\n```js\nvar call_order = [];\nasync.nextTick(function(){\n    call_order.push('two');\n    // call_order now equals ['one','two']\n});\ncall_order.push('one')\n```\n\n<a name=\"times\" />\n### times(n, callback)\n\nCalls the callback n times and accumulates results in the same manner\nyou would use with async.map.\n\n__Arguments__\n\n* n - The number of times to run the function.\n* callback - The function to call n times.\n\n__Example__\n\n```js\n// Pretend this is some complicated async factory\nvar createUser = function(id, callback) {\n  callback(null, {\n    id: 'user' + id\n  })\n}\n// generate 5 users\nasync.times(5, function(n, next){\n    createUser(n, function(err, user) {\n      next(err, user)\n    })\n}, function(err, users) {\n  // we should now have 5 users\n});\n```\n\n<a name=\"timesSeries\" />\n### timesSeries(n, callback)\n\nThe same as times only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n\n## Utils\n\n<a name=\"memoize\" />\n### memoize(fn, [hasher])\n\nCaches the results of an async function. When creating a hash to store function\nresults against, the callback is omitted from the hash and an optional hash\nfunction can be used.\n\nThe cache of results is exposed as the `memo` property of the function returned\nby `memoize`.\n\n__Arguments__\n\n* fn - the function you to proxy and cache results from.\n* hasher - an optional function for generating a custom hash for storing\n  results, it has all the arguments applied to it apart from the callback, and\n  must be synchronous.\n\n__Example__\n\n```js\nvar slow_fn = function (name, callback) {\n    // do something\n    callback(null, result);\n};\nvar fn = async.memoize(slow_fn);\n\n// fn can now be used as if it were slow_fn\nfn('some name', function () {\n    // callback\n});\n```\n\n<a name=\"unmemoize\" />\n### unmemoize(fn)\n\nUndoes a memoized function, reverting it to the original, unmemoized\nform. Comes handy in tests.\n\n__Arguments__\n\n* fn - the memoized function\n\n<a name=\"log\" />\n### log(function, arguments)\n\nLogs the result of an async function to the console. Only works in node.js or\nin browsers that support console.log and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.log is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n```js\nvar hello = function(name, callback){\n    setTimeout(function(){\n        callback(null, 'hello ' + name);\n    }, 1000);\n};\n```\n```js\nnode> async.log(hello, 'world');\n'hello world'\n```\n\n---------------------------------------\n\n<a name=\"dir\" />\n### dir(function, arguments)\n\nLogs the result of an async function to the console using console.dir to\ndisplay the properties of the resulting object. Only works in node.js or\nin browsers that support console.dir and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.dir is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n```js\nvar hello = function(name, callback){\n    setTimeout(function(){\n        callback(null, {hello: name});\n    }, 1000);\n};\n```\n```js\nnode> async.dir(hello, 'world');\n{hello: 'world'}\n```\n\n---------------------------------------\n\n<a name=\"noConflict\" />\n### noConflict()\n\nChanges the value of async back to its original value, returning a reference to the\nasync object.\n",
+  "readmeFilename": "README.md",
+  "homepage": "https://github.com/caolan/async",
+  "_id": "async@0.2.10",
+  "_from": "async@~0.2.9"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/.npmignore	(revision 517)
@@ -0,0 +1,3 @@
+*.un~
+/node_modules
+/test/tmp
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/License
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/License	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/License	(revision 517)
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Debuggable Limited <felix@debuggable.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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/Makefile
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/Makefile	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/Makefile	(revision 517)
@@ -0,0 +1,7 @@
+SHELL := /bin/bash
+
+test:
+	@./test/run.js
+
+.PHONY: test
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/Readme.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/Readme.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/Readme.md	(revision 517)
@@ -0,0 +1,132 @@
+# combined-stream
+
+A stream that emits multiple other streams one after another.
+
+## Installation
+
+``` bash
+npm install combined-stream
+```
+
+## Usage
+
+Here is a simple example that shows how you can use combined-stream to combine
+two files into one:
+
+``` javascript
+var CombinedStream = require('combined-stream');
+var fs = require('fs');
+
+var combinedStream = CombinedStream.create();
+combinedStream.append(fs.createReadStream('file1.txt'));
+combinedStream.append(fs.createReadStream('file2.txt'));
+
+combinedStream.pipe(fs.createWriteStream('combined.txt'));
+```
+
+While the example above works great, it will pause all source streams until
+they are needed. If you don't want that to happen, you can set `pauseStreams`
+to `false`:
+
+``` javascript
+var CombinedStream = require('combined-stream');
+var fs = require('fs');
+
+var combinedStream = CombinedStream.create({pauseStreams: false});
+combinedStream.append(fs.createReadStream('file1.txt'));
+combinedStream.append(fs.createReadStream('file2.txt'));
+
+combinedStream.pipe(fs.createWriteStream('combined.txt'));
+```
+
+However, what if you don't have all the source streams yet, or you don't want
+to allocate the resources (file descriptors, memory, etc.) for them right away?
+Well, in that case you can simply provide a callback that supplies the stream
+by calling a `next()` function:
+
+``` javascript
+var CombinedStream = require('combined-stream');
+var fs = require('fs');
+
+var combinedStream = CombinedStream.create();
+combinedStream.append(function(next) {
+  next(fs.createReadStream('file1.txt'));
+});
+combinedStream.append(function(next) {
+  next(fs.createReadStream('file2.txt'));
+});
+
+combinedStream.pipe(fs.createWriteStream('combined.txt'));
+```
+
+## API
+
+### CombinedStream.create([options])
+
+Returns a new combined stream object. Available options are:
+
+* `maxDataSize`
+* `pauseStreams`
+
+The effect of those options is described below.
+
+### combinedStream.pauseStreams = true
+
+Whether to apply back pressure to the underlaying streams. If set to `false`,
+the underlaying streams will never be paused. If set to `true`, the
+underlaying streams will be paused right after being appended, as well as when
+`delayedStream.pipe()` wants to throttle.
+
+### combinedStream.maxDataSize = 2 * 1024 * 1024
+
+The maximum amount of bytes (or characters) to buffer for all source streams.
+If this value is exceeded, `combinedStream` emits an `'error'` event.
+
+### combinedStream.dataSize = 0
+
+The amount of bytes (or characters) currently buffered by `combinedStream`.
+
+### combinedStream.append(stream)
+
+Appends the given `stream` to the combinedStream object. If `pauseStreams` is
+set to `true, this stream will also be paused right away.
+
+`streams` can also be a function that takes one parameter called `next`. `next`
+is a function that must be invoked in order to provide the `next` stream, see
+example above.
+
+Regardless of how the `stream` is appended, combined-stream always attaches an
+`'error'` listener to it, so you don't have to do that manually.
+
+Special case: `stream` can also be a String or Buffer.
+
+### combinedStream.write(data)
+
+You should not call this, `combinedStream` takes care of piping the appended
+streams into itself for you.
+
+### combinedStream.resume()
+
+Causes `combinedStream` to start drain the streams it manages. The function is
+idempotent, and also emits a `'resume'` event each time which usually goes to
+the stream that is currently being drained.
+
+### combinedStream.pause();
+
+If `combinedStream.pauseStreams` is set to `false`, this does nothing.
+Otherwise a `'pause'` event is emitted, this goes to the stream that is
+currently being drained, so you can use it to apply back pressure.
+
+### combinedStream.end();
+
+Sets `combinedStream.writable` to false, emits an `'end'` event, and removes
+all streams from the queue.
+
+### combinedStream.destroy();
+
+Same as `combinedStream.end()`, except it emits a `'close'` event instead of
+`'end'`.
+
+## License
+
+combined-stream is licensed under the MIT license.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/lib/combined_stream.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/lib/combined_stream.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/lib/combined_stream.js	(revision 517)
@@ -0,0 +1,185 @@
+var util = require('util');
+var Stream = require('stream').Stream;
+var DelayedStream = require('delayed-stream');
+
+module.exports = CombinedStream;
+function CombinedStream() {
+  this.writable = false;
+  this.readable = true;
+  this.dataSize = 0;
+  this.maxDataSize = 2 * 1024 * 1024;
+  this.pauseStreams = true;
+
+  this._released = false;
+  this._streams = [];
+  this._currentStream = null;
+}
+util.inherits(CombinedStream, Stream);
+
+CombinedStream.create = function(options) {
+  var combinedStream = new this();
+
+  options = options || {};
+  for (var option in options) {
+    combinedStream[option] = options[option];
+  }
+
+  return combinedStream;
+};
+
+CombinedStream.isStreamLike = function(stream) {
+  return (typeof stream !== 'function')
+    && (typeof stream !== 'string')
+    && (typeof stream !== 'boolean')    
+    && (typeof stream !== 'number')
+    && (!Buffer.isBuffer(stream));
+};
+
+CombinedStream.prototype.append = function(stream) {
+  var isStreamLike = CombinedStream.isStreamLike(stream);
+
+  if (isStreamLike) {
+    if (!(stream instanceof DelayedStream)) {
+      stream.on('data', this._checkDataSize.bind(this));
+
+      stream = DelayedStream.create(stream, {
+        maxDataSize: Infinity,
+        pauseStream: this.pauseStreams,
+      });
+    }
+
+    this._handleErrors(stream);
+
+    if (this.pauseStreams) {
+      stream.pause();
+    }
+  }
+
+  this._streams.push(stream);
+  return this;
+};
+
+CombinedStream.prototype.pipe = function(dest, options) {
+  Stream.prototype.pipe.call(this, dest, options);
+  this.resume();
+};
+
+CombinedStream.prototype._getNext = function() {
+  this._currentStream = null;
+  var stream = this._streams.shift();
+
+
+  if (typeof stream == 'undefined') {
+    this.end();
+    return;
+  }
+
+  if (typeof stream !== 'function') {
+    this._pipeNext(stream);
+    return;
+  }
+
+  var getStream = stream;
+  getStream(function(stream) {
+    var isStreamLike = CombinedStream.isStreamLike(stream);
+    if (isStreamLike) {
+      stream.on('data', this._checkDataSize.bind(this));
+      this._handleErrors(stream);
+    }
+
+    this._pipeNext(stream);
+  }.bind(this));
+};
+
+CombinedStream.prototype._pipeNext = function(stream) {
+  this._currentStream = stream;
+
+  var isStreamLike = CombinedStream.isStreamLike(stream);
+  if (isStreamLike) {
+    stream.on('end', this._getNext.bind(this))
+    stream.pipe(this, {end: false});
+    return;
+  }
+
+  var value = stream;
+  this.write(value);
+  this._getNext();
+};
+
+CombinedStream.prototype._handleErrors = function(stream) {
+  var self = this;
+  stream.on('error', function(err) {
+    self._emitError(err);
+  });
+};
+
+CombinedStream.prototype.write = function(data) {
+  this.emit('data', data);
+};
+
+CombinedStream.prototype.pause = function() {
+  if (!this.pauseStreams) {
+    return;
+  }
+
+  this.emit('pause');
+};
+
+CombinedStream.prototype.resume = function() {
+  if (!this._released) {
+    this._released = true;
+    this.writable = true;
+    this._getNext();
+  }
+
+  this.emit('resume');
+};
+
+CombinedStream.prototype.end = function() {
+  this._reset();
+  this.emit('end');
+};
+
+CombinedStream.prototype.destroy = function() {
+  this._reset();
+  this.emit('close');
+};
+
+CombinedStream.prototype._reset = function() {
+  this.writable = false;
+  this._streams = [];
+  this._currentStream = null;
+};
+
+CombinedStream.prototype._checkDataSize = function() {
+  this._updateDataSize();
+  if (this.dataSize <= this.maxDataSize) {
+    return;
+  }
+
+  var message =
+    'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.'
+  this._emitError(new Error(message));
+};
+
+CombinedStream.prototype._updateDataSize = function() {
+  this.dataSize = 0;
+
+  var self = this;
+  this._streams.forEach(function(stream) {
+    if (!stream.dataSize) {
+      return;
+    }
+
+    self.dataSize += stream.dataSize;
+  });
+
+  if (this._currentStream && this._currentStream.dataSize) {
+    this.dataSize += this._currentStream.dataSize;
+  }
+};
+
+CombinedStream.prototype._emitError = function(err) {
+  this._reset();
+  this.emit('error', err);
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/.npmignore	(revision 517)
@@ -0,0 +1,2 @@
+*.un~
+/node_modules/*
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/License
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/License	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/License	(revision 517)
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Debuggable Limited <felix@debuggable.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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Makefile
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Makefile	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Makefile	(revision 517)
@@ -0,0 +1,7 @@
+SHELL := /bin/bash
+
+test:
+	@./test/run.js
+
+.PHONY: test
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Readme.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Readme.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Readme.md	(revision 517)
@@ -0,0 +1,154 @@
+# delayed-stream
+
+Buffers events from a stream until you are ready to handle them.
+
+## Installation
+
+``` bash
+npm install delayed-stream
+```
+
+## Usage
+
+The following example shows how to write a http echo server that delays its
+response by 1000 ms.
+
+``` javascript
+var DelayedStream = require('delayed-stream');
+var http = require('http');
+
+http.createServer(function(req, res) {
+  var delayed = DelayedStream.create(req);
+
+  setTimeout(function() {
+    res.writeHead(200);
+    delayed.pipe(res);
+  }, 1000);
+});
+```
+
+If you are not using `Stream#pipe`, you can also manually release the buffered
+events by calling `delayedStream.resume()`:
+
+``` javascript
+var delayed = DelayedStream.create(req);
+
+setTimeout(function() {
+  // Emit all buffered events and resume underlaying source
+  delayed.resume();
+}, 1000);
+```
+
+## Implementation
+
+In order to use this meta stream properly, here are a few things you should
+know about the implementation.
+
+### Event Buffering / Proxying
+
+All events of the `source` stream are hijacked by overwriting the `source.emit`
+method. Until node implements a catch-all event listener, this is the only way.
+
+However, delayed-stream still continues to emit all events it captures on the
+`source`, regardless of whether you have released the delayed stream yet or
+not.
+
+Upon creation, delayed-stream captures all `source` events and stores them in
+an internal event buffer. Once `delayedStream.release()` is called, all
+buffered events are emitted on the `delayedStream`, and the event buffer is
+cleared. After that, delayed-stream merely acts as a proxy for the underlaying
+source.
+
+### Error handling
+
+Error events on `source` are buffered / proxied just like any other events.
+However, `delayedStream.create` attaches a no-op `'error'` listener to the
+`source`. This way you only have to handle errors on the `delayedStream`
+object, rather than in two places.
+
+### Buffer limits
+
+delayed-stream provides a `maxDataSize` property that can be used to limit
+the amount of data being buffered. In order to protect you from bad `source`
+streams that don't react to `source.pause()`, this feature is enabled by
+default.
+
+## API
+
+### DelayedStream.create(source, [options])
+
+Returns a new `delayedStream`. Available options are:
+
+* `pauseStream`
+* `maxDataSize`
+
+The description for those properties can be found below.
+
+### delayedStream.source
+
+The `source` stream managed by this object. This is useful if you are
+passing your `delayedStream` around, and you still want to access properties
+on the `source` object.
+
+### delayedStream.pauseStream = true
+
+Whether to pause the underlaying `source` when calling
+`DelayedStream.create()`. Modifying this property afterwards has no effect.
+
+### delayedStream.maxDataSize = 1024 * 1024
+
+The amount of data to buffer before emitting an `error`.
+
+If the underlaying source is emitting `Buffer` objects, the `maxDataSize`
+refers to bytes.
+
+If the underlaying source is emitting JavaScript strings, the size refers to
+characters.
+
+If you know what you are doing, you can set this property to `Infinity` to
+disable this feature. You can also modify this property during runtime.
+
+### delayedStream.maxDataSize = 1024 * 1024
+
+The amount of data to buffer before emitting an `error`.
+
+If the underlaying source is emitting `Buffer` objects, the `maxDataSize`
+refers to bytes.
+
+If the underlaying source is emitting JavaScript strings, the size refers to
+characters.
+
+If you know what you are doing, you can set this property to `Infinity` to
+disable this feature.
+
+### delayedStream.dataSize = 0
+
+The amount of data buffered so far.
+
+### delayedStream.readable
+
+An ECMA5 getter that returns the value of `source.readable`.
+
+### delayedStream.resume()
+
+If the `delayedStream` has not been released so far, `delayedStream.release()`
+is called.
+
+In either case, `source.resume()` is called.
+
+### delayedStream.pause()
+
+Calls `source.pause()`.
+
+### delayedStream.pipe(dest)
+
+Calls `delayedStream.resume()` and then proxies the arguments to `source.pipe`.
+
+### delayedStream.release()
+
+Emits and clears all events that have been buffered up so far. This does not
+resume the underlaying source, use `delayedStream.resume()` instead.
+
+## License
+
+delayed-stream is licensed under the MIT license.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js	(revision 517)
@@ -0,0 +1,99 @@
+var Stream = require('stream').Stream;
+var util = require('util');
+
+module.exports = DelayedStream;
+function DelayedStream() {
+  this.source = null;
+  this.dataSize = 0;
+  this.maxDataSize = 1024 * 1024;
+  this.pauseStream = true;
+
+  this._maxDataSizeExceeded = false;
+  this._released = false;
+  this._bufferedEvents = [];
+}
+util.inherits(DelayedStream, Stream);
+
+DelayedStream.create = function(source, options) {
+  var delayedStream = new this();
+
+  options = options || {};
+  for (var option in options) {
+    delayedStream[option] = options[option];
+  }
+
+  delayedStream.source = source;
+
+  var realEmit = source.emit;
+  source.emit = function() {
+    delayedStream._handleEmit(arguments);
+    return realEmit.apply(source, arguments);
+  };
+
+  source.on('error', function() {});
+  if (delayedStream.pauseStream) {
+    source.pause();
+  }
+
+  return delayedStream;
+};
+
+DelayedStream.prototype.__defineGetter__('readable', function() {
+  return this.source.readable;
+});
+
+DelayedStream.prototype.resume = function() {
+  if (!this._released) {
+    this.release();
+  }
+
+  this.source.resume();
+};
+
+DelayedStream.prototype.pause = function() {
+  this.source.pause();
+};
+
+DelayedStream.prototype.release = function() {
+  this._released = true;
+
+  this._bufferedEvents.forEach(function(args) {
+    this.emit.apply(this, args);
+  }.bind(this));
+  this._bufferedEvents = [];
+};
+
+DelayedStream.prototype.pipe = function() {
+  var r = Stream.prototype.pipe.apply(this, arguments);
+  this.resume();
+  return r;
+};
+
+DelayedStream.prototype._handleEmit = function(args) {
+  if (this._released) {
+    this.emit.apply(this, args);
+    return;
+  }
+
+  if (args[0] === 'data') {
+    this.dataSize += args[1].length;
+    this._checkIfMaxDataSizeExceeded();
+  }
+
+  this._bufferedEvents.push(args);
+};
+
+DelayedStream.prototype._checkIfMaxDataSizeExceeded = function() {
+  if (this._maxDataSizeExceeded) {
+    return;
+  }
+
+  if (this.dataSize <= this.maxDataSize) {
+    return;
+  }
+
+  this._maxDataSizeExceeded = true;
+  var message =
+    'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.'
+  this.emit('error', new Error(message));
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/package.json	(revision 517)
@@ -0,0 +1,31 @@
+{
+  "author": {
+    "name": "Felix GeisendÃ¶rfer",
+    "email": "felix@debuggable.com",
+    "url": "http://debuggable.com/"
+  },
+  "name": "delayed-stream",
+  "description": "Buffers events from a stream until you are ready to handle them.",
+  "version": "0.0.5",
+  "homepage": "https://github.com/felixge/node-delayed-stream",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/felixge/node-delayed-stream.git"
+  },
+  "main": "./lib/delayed_stream",
+  "engines": {
+    "node": ">=0.4.0"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "fake": "0.2.0",
+    "far": "0.0.1"
+  },
+  "readme": "# delayed-stream\n\nBuffers events from a stream until you are ready to handle them.\n\n## Installation\n\n``` bash\nnpm install delayed-stream\n```\n\n## Usage\n\nThe following example shows how to write a http echo server that delays its\nresponse by 1000 ms.\n\n``` javascript\nvar DelayedStream = require('delayed-stream');\nvar http = require('http');\n\nhttp.createServer(function(req, res) {\n  var delayed = DelayedStream.create(req);\n\n  setTimeout(function() {\n    res.writeHead(200);\n    delayed.pipe(res);\n  }, 1000);\n});\n```\n\nIf you are not using `Stream#pipe`, you can also manually release the buffered\nevents by calling `delayedStream.resume()`:\n\n``` javascript\nvar delayed = DelayedStream.create(req);\n\nsetTimeout(function() {\n  // Emit all buffered events and resume underlaying source\n  delayed.resume();\n}, 1000);\n```\n\n## Implementation\n\nIn order to use this meta stream properly, here are a few things you should\nknow about the implementation.\n\n### Event Buffering / Proxying\n\nAll events of the `source` stream are hijacked by overwriting the `source.emit`\nmethod. Until node implements a catch-all event listener, this is the only way.\n\nHowever, delayed-stream still continues to emit all events it captures on the\n`source`, regardless of whether you have released the delayed stream yet or\nnot.\n\nUpon creation, delayed-stream captures all `source` events and stores them in\nan internal event buffer. Once `delayedStream.release()` is called, all\nbuffered events are emitted on the `delayedStream`, and the event buffer is\ncleared. After that, delayed-stream merely acts as a proxy for the underlaying\nsource.\n\n### Error handling\n\nError events on `source` are buffered / proxied just like any other events.\nHowever, `delayedStream.create` attaches a no-op `'error'` listener to the\n`source`. This way you only have to handle errors on the `delayedStream`\nobject, rather than in two places.\n\n### Buffer limits\n\ndelayed-stream provides a `maxDataSize` property that can be used to limit\nthe amount of data being buffered. In order to protect you from bad `source`\nstreams that don't react to `source.pause()`, this feature is enabled by\ndefault.\n\n## API\n\n### DelayedStream.create(source, [options])\n\nReturns a new `delayedStream`. Available options are:\n\n* `pauseStream`\n* `maxDataSize`\n\nThe description for those properties can be found below.\n\n### delayedStream.source\n\nThe `source` stream managed by this object. This is useful if you are\npassing your `delayedStream` around, and you still want to access properties\non the `source` object.\n\n### delayedStream.pauseStream = true\n\nWhether to pause the underlaying `source` when calling\n`DelayedStream.create()`. Modifying this property afterwards has no effect.\n\n### delayedStream.maxDataSize = 1024 * 1024\n\nThe amount of data to buffer before emitting an `error`.\n\nIf the underlaying source is emitting `Buffer` objects, the `maxDataSize`\nrefers to bytes.\n\nIf the underlaying source is emitting JavaScript strings, the size refers to\ncharacters.\n\nIf you know what you are doing, you can set this property to `Infinity` to\ndisable this feature. You can also modify this property during runtime.\n\n### delayedStream.maxDataSize = 1024 * 1024\n\nThe amount of data to buffer before emitting an `error`.\n\nIf the underlaying source is emitting `Buffer` objects, the `maxDataSize`\nrefers to bytes.\n\nIf the underlaying source is emitting JavaScript strings, the size refers to\ncharacters.\n\nIf you know what you are doing, you can set this property to `Infinity` to\ndisable this feature.\n\n### delayedStream.dataSize = 0\n\nThe amount of data buffered so far.\n\n### delayedStream.readable\n\nAn ECMA5 getter that returns the value of `source.readable`.\n\n### delayedStream.resume()\n\nIf the `delayedStream` has not been released so far, `delayedStream.release()`\nis called.\n\nIn either case, `source.resume()` is called.\n\n### delayedStream.pause()\n\nCalls `source.pause()`.\n\n### delayedStream.pipe(dest)\n\nCalls `delayedStream.resume()` and then proxies the arguments to `source.pipe`.\n\n### delayedStream.release()\n\nEmits and clears all events that have been buffered up so far. This does not\nresume the underlaying source, use `delayedStream.resume()` instead.\n\n## License\n\ndelayed-stream is licensed under the MIT license.\n",
+  "readmeFilename": "Readme.md",
+  "bugs": {
+    "url": "https://github.com/felixge/node-delayed-stream/issues"
+  },
+  "_id": "delayed-stream@0.0.5",
+  "_from": "delayed-stream@0.0.5"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/common.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/common.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/common.js	(revision 517)
@@ -0,0 +1,6 @@
+var common = module.exports;
+
+common.DelayedStream = require('..');
+common.assert = require('assert');
+common.fake = require('fake');
+common.PORT = 49252;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-http-upload.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-http-upload.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-http-upload.js	(revision 517)
@@ -0,0 +1,38 @@
+var common = require('../common');
+var assert = common.assert;
+var DelayedStream = common.DelayedStream;
+var http = require('http');
+
+var UPLOAD = new Buffer(10 * 1024 * 1024);
+
+var server = http.createServer(function(req, res) {
+  var delayed = DelayedStream.create(req, {maxDataSize: UPLOAD.length});
+
+  setTimeout(function() {
+    res.writeHead(200);
+    delayed.pipe(res);
+  }, 10);
+});
+server.listen(common.PORT, function() {
+  var request = http.request({
+    method: 'POST',
+    port: common.PORT,
+  });
+
+  request.write(UPLOAD);
+  request.end();
+
+  request.on('response', function(res) {
+    var received = 0;
+    res
+      .on('data', function(chunk) {
+        received += chunk.length;
+      })
+      .on('end', function() {
+        assert.equal(received, UPLOAD.length);
+        server.close();
+      });
+  });
+});
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-auto-pause.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-auto-pause.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-auto-pause.js	(revision 517)
@@ -0,0 +1,21 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var DelayedStream = common.DelayedStream;
+var Stream = require('stream').Stream;
+
+(function testAutoPause() {
+  var source = new Stream();
+
+  fake.expect(source, 'pause', 1);
+  var delayedStream = DelayedStream.create(source);
+  fake.verify();
+})();
+
+(function testDisableAutoPause() {
+  var source = new Stream();
+  fake.expect(source, 'pause', 0);
+
+  var delayedStream = DelayedStream.create(source, {pauseStream: false});
+  fake.verify();
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-pause.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-pause.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-pause.js	(revision 517)
@@ -0,0 +1,14 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var DelayedStream = common.DelayedStream;
+var Stream = require('stream').Stream;
+
+(function testDelayEventsUntilResume() {
+  var source = new Stream();
+  var delayedStream = DelayedStream.create(source, {pauseStream: false});
+
+  fake.expect(source, 'pause');
+  delayedStream.pause();
+  fake.verify();
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream.js	(revision 517)
@@ -0,0 +1,48 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var DelayedStream = common.DelayedStream;
+var Stream = require('stream').Stream;
+
+(function testDelayEventsUntilResume() {
+  var source = new Stream();
+  var delayedStream = DelayedStream.create(source, {pauseStream: false});
+
+  // delayedStream must not emit until we resume
+  fake.expect(delayedStream, 'emit', 0);
+
+  // but our original source must emit
+  var params = [];
+  source.on('foo', function(param) {
+    params.push(param);
+  });
+
+  source.emit('foo', 1);
+  source.emit('foo', 2);
+
+  // Make sure delayedStream did not emit, and source did
+  assert.deepEqual(params, [1, 2]);
+  fake.verify();
+
+  // After resume, delayedStream must playback all events
+  fake
+    .stub(delayedStream, 'emit')
+    .times(Infinity)
+    .withArg(1, 'newListener');
+  fake.expect(delayedStream, 'emit', ['foo', 1]);
+  fake.expect(delayedStream, 'emit', ['foo', 2]);
+  fake.expect(source, 'resume');
+
+  delayedStream.resume();
+  fake.verify();
+
+  // Calling resume again will delegate to source
+  fake.expect(source, 'resume');
+  delayedStream.resume();
+  fake.verify();
+
+  // Emitting more events directly leads to them being emitted
+  fake.expect(delayedStream, 'emit', ['foo', 3]);
+  source.emit('foo', 3);
+  fake.verify();
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-handle-source-errors.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-handle-source-errors.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-handle-source-errors.js	(revision 517)
@@ -0,0 +1,15 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var DelayedStream = common.DelayedStream;
+var Stream = require('stream').Stream;
+
+(function testHandleSourceErrors() {
+  var source = new Stream();
+  var delayedStream = DelayedStream.create(source, {pauseStream: false});
+
+  // We deal with this by attaching a no-op listener to 'error' on the source
+  // when creating a new DelayedStream. This way error events on the source
+  // won't throw.
+  source.emit('error', new Error('something went wrong'));
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-max-data-size.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-max-data-size.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-max-data-size.js	(revision 517)
@@ -0,0 +1,18 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var DelayedStream = common.DelayedStream;
+var Stream = require('stream').Stream;
+
+(function testMaxDataSize() {
+  var source = new Stream();
+  var delayedStream = DelayedStream.create(source, {maxDataSize: 1024, pauseStream: false});
+
+  source.emit('data', new Buffer(1024));
+
+  fake
+    .expect(delayedStream, 'emit')
+    .withArg(1, 'error');
+  source.emit('data', new Buffer(1));
+  fake.verify();
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-pipe-resumes.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-pipe-resumes.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-pipe-resumes.js	(revision 517)
@@ -0,0 +1,13 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var DelayedStream = common.DelayedStream;
+var Stream = require('stream').Stream;
+
+(function testPipeReleases() {
+  var source = new Stream();
+  var delayedStream = DelayedStream.create(source, {pauseStream: false});
+
+  fake.expect(delayedStream, 'resume');
+  delayedStream.pipe(new Stream());
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-proxy-readable.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-proxy-readable.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-proxy-readable.js	(revision 517)
@@ -0,0 +1,13 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var DelayedStream = common.DelayedStream;
+var Stream = require('stream').Stream;
+
+(function testProxyReadableProperty() {
+  var source = new Stream();
+  var delayedStream = DelayedStream.create(source, {pauseStream: false});
+
+  source.readable = fake.value('source.readable');
+  assert.strictEqual(delayedStream.readable, source.readable);
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/run.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/run.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/run.js	(revision 517)
@@ -0,0 +1,7 @@
+#!/usr/bin/env node
+var far = require('far').create();
+
+far.add(__dirname);
+far.include(/test-.*\.js$/);
+
+far.execute();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/package.json	(revision 517)
@@ -0,0 +1,32 @@
+{
+  "author": {
+    "name": "Felix GeisendÃ¶rfer",
+    "email": "felix@debuggable.com",
+    "url": "http://debuggable.com/"
+  },
+  "name": "combined-stream",
+  "description": "A stream that emits multiple other streams one after another.",
+  "version": "0.0.4",
+  "homepage": "https://github.com/felixge/node-combined-stream",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/felixge/node-combined-stream.git"
+  },
+  "main": "./lib/combined_stream",
+  "engines": {
+    "node": "*"
+  },
+  "dependencies": {
+    "delayed-stream": "0.0.5"
+  },
+  "devDependencies": {
+    "far": "0.0.1"
+  },
+  "readme": "# combined-stream\n\nA stream that emits multiple other streams one after another.\n\n## Installation\n\n``` bash\nnpm install combined-stream\n```\n\n## Usage\n\nHere is a simple example that shows how you can use combined-stream to combine\ntwo files into one:\n\n``` javascript\nvar CombinedStream = require('combined-stream');\nvar fs = require('fs');\n\nvar combinedStream = CombinedStream.create();\ncombinedStream.append(fs.createReadStream('file1.txt'));\ncombinedStream.append(fs.createReadStream('file2.txt'));\n\ncombinedStream.pipe(fs.createWriteStream('combined.txt'));\n```\n\nWhile the example above works great, it will pause all source streams until\nthey are needed. If you don't want that to happen, you can set `pauseStreams`\nto `false`:\n\n``` javascript\nvar CombinedStream = require('combined-stream');\nvar fs = require('fs');\n\nvar combinedStream = CombinedStream.create({pauseStreams: false});\ncombinedStream.append(fs.createReadStream('file1.txt'));\ncombinedStream.append(fs.createReadStream('file2.txt'));\n\ncombinedStream.pipe(fs.createWriteStream('combined.txt'));\n```\n\nHowever, what if you don't have all the source streams yet, or you don't want\nto allocate the resources (file descriptors, memory, etc.) for them right away?\nWell, in that case you can simply provide a callback that supplies the stream\nby calling a `next()` function:\n\n``` javascript\nvar CombinedStream = require('combined-stream');\nvar fs = require('fs');\n\nvar combinedStream = CombinedStream.create();\ncombinedStream.append(function(next) {\n  next(fs.createReadStream('file1.txt'));\n});\ncombinedStream.append(function(next) {\n  next(fs.createReadStream('file2.txt'));\n});\n\ncombinedStream.pipe(fs.createWriteStream('combined.txt'));\n```\n\n## API\n\n### CombinedStream.create([options])\n\nReturns a new combined stream object. Available options are:\n\n* `maxDataSize`\n* `pauseStreams`\n\nThe effect of those options is described below.\n\n### combinedStream.pauseStreams = true\n\nWhether to apply back pressure to the underlaying streams. If set to `false`,\nthe underlaying streams will never be paused. If set to `true`, the\nunderlaying streams will be paused right after being appended, as well as when\n`delayedStream.pipe()` wants to throttle.\n\n### combinedStream.maxDataSize = 2 * 1024 * 1024\n\nThe maximum amount of bytes (or characters) to buffer for all source streams.\nIf this value is exceeded, `combinedStream` emits an `'error'` event.\n\n### combinedStream.dataSize = 0\n\nThe amount of bytes (or characters) currently buffered by `combinedStream`.\n\n### combinedStream.append(stream)\n\nAppends the given `stream` to the combinedStream object. If `pauseStreams` is\nset to `true, this stream will also be paused right away.\n\n`streams` can also be a function that takes one parameter called `next`. `next`\nis a function that must be invoked in order to provide the `next` stream, see\nexample above.\n\nRegardless of how the `stream` is appended, combined-stream always attaches an\n`'error'` listener to it, so you don't have to do that manually.\n\nSpecial case: `stream` can also be a String or Buffer.\n\n### combinedStream.write(data)\n\nYou should not call this, `combinedStream` takes care of piping the appended\nstreams into itself for you.\n\n### combinedStream.resume()\n\nCauses `combinedStream` to start drain the streams it manages. The function is\nidempotent, and also emits a `'resume'` event each time which usually goes to\nthe stream that is currently being drained.\n\n### combinedStream.pause();\n\nIf `combinedStream.pauseStreams` is set to `false`, this does nothing.\nOtherwise a `'pause'` event is emitted, this goes to the stream that is\ncurrently being drained, so you can use it to apply back pressure.\n\n### combinedStream.end();\n\nSets `combinedStream.writable` to false, emits an `'end'` event, and removes\nall streams from the queue.\n\n### combinedStream.destroy();\n\nSame as `combinedStream.end()`, except it emits a `'close'` event instead of\n`'end'`.\n\n## License\n\ncombined-stream is licensed under the MIT license.\n",
+  "readmeFilename": "Readme.md",
+  "bugs": {
+    "url": "https://github.com/felixge/node-combined-stream/issues"
+  },
+  "_id": "combined-stream@0.0.4",
+  "_from": "combined-stream@~0.0.4"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/common.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/common.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/common.js	(revision 517)
@@ -0,0 +1,23 @@
+var common = module.exports;
+
+var path = require('path');
+var fs = require('fs');
+var root = path.join(__dirname, '..');
+
+common.dir = {
+  fixture: root + '/test/fixture',
+  tmp: root + '/test/tmp',
+};
+
+// Create tmp directory if it does not exist
+// Not using fs.exists so as to be node 0.6.x compatible
+try {
+  fs.statSync(common.dir.tmp);
+}
+catch (e) {
+  // Dir does not exist
+  fs.mkdirSync(common.dir.tmp);
+}
+
+common.CombinedStream = require(root);
+common.assert = require('assert');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file1.txt
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file1.txt	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file1.txt	(revision 517)
@@ -0,0 +1,256 @@
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
+10101010101010101010101010101010101010101010101010101010101010101010101010101010
+01010101010101010101010101010101010101010101010101010101010101010101010101010101
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file2.txt
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file2.txt	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file2.txt	(revision 517)
@@ -0,0 +1,256 @@
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
+20202020202020202020202020202020202020202020202020202020202020202020202020202020
+02020202020202020202020202020202020202020202020202020202020202020202020202020202
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-callback-streams.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-callback-streams.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-callback-streams.js	(revision 517)
@@ -0,0 +1,27 @@
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+var fs = require('fs');
+
+var FILE1 = common.dir.fixture + '/file1.txt';
+var FILE2 = common.dir.fixture + '/file2.txt';
+var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2);
+
+(function testDelayedStreams() {
+  var combinedStream = CombinedStream.create();
+  combinedStream.append(function(next) {
+    next(fs.createReadStream(FILE1));
+  });
+  combinedStream.append(function(next) {
+    next(fs.createReadStream(FILE2));
+  });
+
+  var tmpFile = common.dir.tmp + '/combined.txt';
+  var dest = fs.createWriteStream(tmpFile);
+  combinedStream.pipe(dest);
+
+  dest.on('end', function() {
+    var written = fs.readFileSync(tmpFile, 'utf8');
+    assert.strictEqual(written, EXPECTED);
+  });
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-data-size.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-data-size.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-data-size.js	(revision 517)
@@ -0,0 +1,34 @@
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+
+(function testDataSizeGetter() {
+  var combinedStream = CombinedStream.create();
+
+  assert.strictEqual(combinedStream.dataSize, 0);
+
+  // Test one stream
+  combinedStream._streams.push({dataSize: 10});
+  combinedStream._updateDataSize();
+  assert.strictEqual(combinedStream.dataSize, 10);
+
+  // Test two streams
+  combinedStream._streams.push({dataSize: 23});
+  combinedStream._updateDataSize();
+  assert.strictEqual(combinedStream.dataSize, 33);
+
+  // Test currentStream
+  combinedStream._currentStream = {dataSize: 20};
+  combinedStream._updateDataSize();
+  assert.strictEqual(combinedStream.dataSize, 53);
+
+  // Test currentStream without dataSize
+  combinedStream._currentStream = {};
+  combinedStream._updateDataSize();
+  assert.strictEqual(combinedStream.dataSize, 33);
+
+  // Test stream function
+  combinedStream._streams.push(function() {});
+  combinedStream._updateDataSize();
+  assert.strictEqual(combinedStream.dataSize, 33);
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams-and-buffers-and-strings.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams-and-buffers-and-strings.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams-and-buffers-and-strings.js	(revision 517)
@@ -0,0 +1,38 @@
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+var fs = require('fs');
+
+var FILE1 = common.dir.fixture + '/file1.txt';
+var BUFFER = new Buffer('Bacon is delicious');
+var FILE2 = common.dir.fixture + '/file2.txt';
+var STRING = 'The â¬ kicks the $\'s ass!';
+
+var EXPECTED =
+  fs.readFileSync(FILE1)
+  + BUFFER
+  + fs.readFileSync(FILE2)
+  + STRING;
+var GOT;
+
+(function testDelayedStreams() {
+  var combinedStream = CombinedStream.create();
+  combinedStream.append(fs.createReadStream(FILE1));
+  combinedStream.append(BUFFER);
+  combinedStream.append(fs.createReadStream(FILE2));
+  combinedStream.append(function(next) {
+    next(STRING);
+  });
+
+  var tmpFile = common.dir.tmp + '/combined-file1-buffer-file2-string.txt';
+  var dest = fs.createWriteStream(tmpFile);
+  combinedStream.pipe(dest);
+
+  dest.on('close', function() {
+    GOT = fs.readFileSync(tmpFile, 'utf8');
+  });
+})();
+
+process.on('exit', function() {
+  assert.strictEqual(GOT, EXPECTED);
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams.js	(revision 517)
@@ -0,0 +1,35 @@
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+var fs = require('fs');
+
+var FILE1 = common.dir.fixture + '/file1.txt';
+var FILE2 = common.dir.fixture + '/file2.txt';
+var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2);
+var GOT;
+
+(function testDelayedStreams() {
+  var combinedStream = CombinedStream.create();
+  combinedStream.append(fs.createReadStream(FILE1));
+  combinedStream.append(fs.createReadStream(FILE2));
+
+  var stream1 = combinedStream._streams[0];
+  var stream2 = combinedStream._streams[1];
+
+  stream1.on('end', function() {
+    assert.equal(stream2.dataSize, 0);
+  });
+
+  var tmpFile = common.dir.tmp + '/combined.txt';
+  var dest = fs.createWriteStream(tmpFile);
+  combinedStream.pipe(dest);
+
+  dest.on('close', function() {
+    GOT = fs.readFileSync(tmpFile, 'utf8');
+  });
+})();
+
+process.on('exit', function() {
+  console.error(GOT.length, EXPECTED.length);
+  assert.strictEqual(GOT, EXPECTED);
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-empty-string.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-empty-string.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-empty-string.js	(revision 517)
@@ -0,0 +1,39 @@
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+var util = require('util');
+var Stream = require('stream').Stream;
+
+var s = CombinedStream.create();
+
+
+function StringStream(){
+  this.writable=true;
+  this.str=""
+}
+util.inherits(StringStream,Stream);
+
+StringStream.prototype.write=function(chunk,encoding){
+  this.str+=chunk.toString();
+  this.emit('data',chunk);
+}
+
+StringStream.prototype.end=function(chunk,encoding){
+  this.emit('end');
+}
+
+StringStream.prototype.toString=function(){
+  return this.str;
+}
+
+
+s.append("foo.");
+s.append("");
+s.append("bar");
+
+var ss = new StringStream();
+
+s.pipe(ss);
+s.resume();
+
+assert.equal(ss.toString(),"foo.bar");
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-is-stream-like.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-is-stream-like.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-is-stream-like.js	(revision 517)
@@ -0,0 +1,17 @@
+var fs = require('fs');
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+var FILE1 = common.dir.fixture + '/file1.txt';
+var fileStream = fs.createReadStream(FILE1);
+
+var foo = function(){};
+
+(function testIsStreamLike() {
+  assert(! CombinedStream.isStreamLike(true));
+  assert(! CombinedStream.isStreamLike("I am a string"));
+  assert(! CombinedStream.isStreamLike(7));
+  assert(! CombinedStream.isStreamLike(foo));
+
+  assert(CombinedStream.isStreamLike(fileStream));
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-max-data-size.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-max-data-size.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-max-data-size.js	(revision 517)
@@ -0,0 +1,24 @@
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+var fs = require('fs');
+
+var FILE1 = common.dir.fixture + '/file1.txt';
+var FILE2 = common.dir.fixture + '/file2.txt';
+var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2);
+
+(function testDelayedStreams() {
+  var combinedStream = CombinedStream.create({pauseStreams: false, maxDataSize: 20736});
+  combinedStream.append(fs.createReadStream(FILE1));
+  combinedStream.append(fs.createReadStream(FILE2));
+
+  var gotErr = null;
+  combinedStream.on('error', function(err) {
+    gotErr = err;
+  });
+
+  process.on('exit', function() {
+    assert.ok(gotErr);
+    assert.ok(gotErr.message.match(/bytes/));
+  });
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-unpaused-streams.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-unpaused-streams.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-unpaused-streams.js	(revision 517)
@@ -0,0 +1,30 @@
+var common = require('../common');
+var assert = common.assert;
+var CombinedStream = common.CombinedStream;
+var fs = require('fs');
+
+var FILE1 = common.dir.fixture + '/file1.txt';
+var FILE2 = common.dir.fixture + '/file2.txt';
+var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2);
+
+(function testDelayedStreams() {
+  var combinedStream = CombinedStream.create({pauseStreams: false});
+  combinedStream.append(fs.createReadStream(FILE1));
+  combinedStream.append(fs.createReadStream(FILE2));
+
+  var stream1 = combinedStream._streams[0];
+  var stream2 = combinedStream._streams[1];
+
+  stream1.on('end', function() {
+    assert.ok(stream2.dataSize > 0);
+  });
+
+  var tmpFile = common.dir.tmp + '/combined.txt';
+  var dest = fs.createWriteStream(tmpFile);
+  combinedStream.pipe(dest);
+
+  dest.on('end', function() {
+    var written = fs.readFileSync(tmpFile, 'utf8');
+    assert.strictEqual(written, EXPECTED);
+  });
+})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/run.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/run.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/run.js	(revision 517)
@@ -0,0 +1,7 @@
+#!/usr/bin/env node
+var far = require('far').create();
+
+far.add(__dirname);
+far.include(/test-.*\.js$/);
+
+far.execute();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/form-data/package.json	(revision 517)
@@ -0,0 +1,46 @@
+{
+  "author": {
+    "name": "Felix GeisendÃ¶rfer",
+    "email": "felix@debuggable.com",
+    "url": "http://debuggable.com/"
+  },
+  "name": "form-data",
+  "description": "A module to create readable \"multipart/form-data\" streams.  Can be used to submit forms and file uploads to other web applications.",
+  "version": "0.1.2",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/felixge/node-form-data.git"
+  },
+  "main": "./lib/form_data",
+  "scripts": {
+    "test": "node test/run.js"
+  },
+  "engines": {
+    "node": ">= 0.6"
+  },
+  "dependencies": {
+    "combined-stream": "~0.0.4",
+    "mime": "~1.2.11",
+    "async": "~0.2.9"
+  },
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://raw.github.com/felixge/node-form-data/master/License"
+    }
+  ],
+  "devDependencies": {
+    "fake": "~0.2.2",
+    "far": "~0.0.7",
+    "formidable": "~1.0.14",
+    "request": "~2.27.0"
+  },
+  "readme": "# Form-Data [![Build Status](https://travis-ci.org/felixge/node-form-data.png?branch=master)](https://travis-ci.org/felixge/node-form-data) [![Dependency Status](https://gemnasium.com/felixge/node-form-data.png)](https://gemnasium.com/felixge/node-form-data)\n\nA module to create readable ```\"multipart/form-data\"``` streams. Can be used to submit forms and file uploads to other web applications.\n\nThe API of this module is inspired by the [XMLHttpRequest-2 FormData Interface][xhr2-fd].\n\n[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface\n[streams2-thing]: http://nodejs.org/api/stream.html#stream_compatibility_with_older_node_versions\n\n## Install\n\n```\nnpm install form-data\n```\n\n## Usage\n\nIn this example we are constructing a form with 3 fields that contain a string,\na buffer and a file stream.\n\n``` javascript\nvar FormData = require('form-data');\nvar fs = require('fs');\n\nvar form = new FormData();\nform.append('my_field', 'my value');\nform.append('my_buffer', new Buffer(10));\nform.append('my_file', fs.createReadStream('/foo/bar.jpg'));\n```\n\nAlso you can use http-response stream:\n\n``` javascript\nvar FormData = require('form-data');\nvar http = require('http');\n\nvar form = new FormData();\n\nhttp.request('http://nodejs.org/images/logo.png', function(response) {\n  form.append('my_field', 'my value');\n  form.append('my_buffer', new Buffer(10));\n  form.append('my_logo', response);\n});\n```\n\nOr @mikeal's request stream:\n\n``` javascript\nvar FormData = require('form-data');\nvar request = require('request');\n\nvar form = new FormData();\n\nform.append('my_field', 'my value');\nform.append('my_buffer', new Buffer(10));\nform.append('my_logo', request('http://nodejs.org/images/logo.png'));\n```\n\nIn order to submit this form to a web application, call ```submit(url, [callback])``` method:\n\n``` javascript\nform.submit('http://example.org/', function(err, res) {\n  // res â response object (http.IncomingMessage)  //\n  res.resume(); // for node-0.10.x\n});\n\n```\n\nFor more advanced request manipulations ```submit()``` method returns ```http.ClientRequest``` object, or you can choose from one of the alternative submission methods.\n\n### Alternative submission methods\n\nYou can use node's http client interface:\n\n``` javascript\nvar http = require('http');\n\nvar request = http.request({\n  method: 'post',\n  host: 'example.org',\n  path: '/upload',\n  headers: form.getHeaders()\n});\n\nform.pipe(request);\n\nrequest.on('response', function(res) {\n  console.log(res.statusCode);\n});\n```\n\nOr if you would prefer the `'Content-Length'` header to be set for you:\n\n``` javascript\nform.submit('example.org/upload', function(err, res) {\n  console.log(res.statusCode);\n});\n```\n\nTo use custom headers and pre-known length in parts:\n\n``` javascript\nvar CRLF = '\\r\\n';\nvar form = new FormData();\n\nvar options = {\n  header: CRLF + '--' + form.getBoundary() + CRLF + 'X-Custom-Header: 123' + CRLF + CRLF,\n  knownLength: 1\n};\n\nform.append('my_buffer', buffer, options);\n\nform.submit('http://example.com/', function(err, res) {\n  if (err) throw err;\n  console.log('Done');\n});\n```\n\nForm-Data can recognize and fetch all the required information from common types of streams (```fs.readStream```, ```http.response``` and ```mikeal's request```), for some other types of streams you'd need to provide \"file\"-related information manually:\n\n``` javascript\nsomeModule.stream(function(err, stdout, stderr) {\n  if (err) throw err;\n\n  var form = new FormData();\n\n  form.append('file', stdout, {\n    filename: 'unicycle.jpg',\n    contentType: 'image/jpg',\n    knownLength: 19806\n  });\n\n  form.submit('http://example.com/', function(err, res) {\n    if (err) throw err;\n    console.log('Done');\n  });\n});\n```\n\nFor edge cases, like POST request to URL with query string or to pass HTTP auth credentials, object can be passed to `form.submit()` as first parameter:\n\n``` javascript\nform.submit({\n  host: 'example.com',\n  path: '/probably.php?extra=params',\n  auth: 'username:password'\n}, function(err, res) {\n  console.log(res.statusCode);\n});\n```\n\n## Notes\n\n- ```getLengthSync()``` method DOESN'T calculate length for streams, use ```knownLength``` options as workaround.\n- If it feels like FormData hangs after submit and you're on ```node-0.10```, please check [Compatibility with Older Node Versions][streams2-thing]\n\n## TODO\n\n- Add new streams (0.10) support and try really hard not to break it for 0.8.x.\n\n## License\n\nForm-Data is licensed under the MIT license.\n",
+  "readmeFilename": "Readme.md",
+  "bugs": {
+    "url": "https://github.com/felixge/node-form-data/issues"
+  },
+  "homepage": "https://github.com/felixge/node-form-data",
+  "_id": "form-data@0.1.2",
+  "_from": "form-data@~0.1.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/.npmignore	(revision 517)
@@ -0,0 +1,18 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/.travis.yml
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/.travis.yml	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/.travis.yml	(revision 517)
@@ -0,0 +1,5 @@
+language: node_js
+
+node_js:
+  - 0.10
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/LICENSE	(revision 517)
@@ -0,0 +1,24 @@
+Copyright (c) 2012-2013, Eran Hammer.
+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 name of Eran Hammer 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 ERAN HAMMER 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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/Makefile
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/Makefile	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/Makefile	(revision 517)
@@ -0,0 +1,10 @@
+test:
+	@node node_modules/lab/bin/lab
+test-cov: 
+	@node node_modules/lab/bin/lab -r threshold -t 100
+test-cov-html:
+	@node node_modules/lab/bin/lab -r html -o coverage.html
+complexity:
+	@node node_modules/complexity-report/src/cli.js -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/README.md	(revision 517)
@@ -0,0 +1,627 @@
+![hawk Logo](https://raw.github.com/hueniverse/hawk/master/images/hawk.png)
+
+<img align="right" src="https://raw.github.com/hueniverse/hawk/master/images/logo.png" /> **Hawk** is an HTTP authentication scheme using a message authentication code (MAC) algorithm to provide partial
+HTTP request cryptographic verification. For more complex use cases such as access delegation, see [Oz](https://github.com/hueniverse/oz).
+
+Current version: **1.0**
+
+[![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk)
+
+# Table of Content
+
+- [**Introduction**](#introduction)
+  - [Replay Protection](#replay-protection)
+  - [Usage Example](#usage-example)
+  - [Protocol Example](#protocol-example)
+    - [Payload Validation](#payload-validation)
+    - [Response Payload Validation](#response-payload-validation)
+  - [Browser Support and Considerations](#browser-support-and-considerations)
+<p></p>
+- [**Single URI Authorization**](#single-uri-authorization)
+  - [Usage Example](#bewit-usage-example)
+<p></p>
+- [**Security Considerations**](#security-considerations)
+  - [MAC Keys Transmission](#mac-keys-transmission)
+  - [Confidentiality of Requests](#confidentiality-of-requests)
+  - [Spoofing by Counterfeit Servers](#spoofing-by-counterfeit-servers)
+  - [Plaintext Storage of Credentials](#plaintext-storage-of-credentials)
+  - [Entropy of Keys](#entropy-of-keys)
+  - [Coverage Limitations](#coverage-limitations)
+  - [Future Time Manipulation](#future-time-manipulation)
+  - [Client Clock Poisoning](#client-clock-poisoning)
+  - [Bewit Limitations](#bewit-limitations)
+  - [Host Header Forgery](#host-header-forgery)
+<p></p>
+- [**Frequently Asked Questions**](#frequently-asked-questions)
+<p></p>
+- [**Acknowledgements**](#acknowledgements)
+
+# Introduction
+
+**Hawk** is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with
+partial cryptographic verification of the request and response, covering the HTTP method, request URI, host,
+and optionally the request payload.
+
+Similar to the HTTP [Digest access authentication schemes](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** uses a set of
+client credentials which include an identifier (e.g. username) and key (e.g. password). Likewise, just as with the Digest scheme,
+the key is never included in authenticated requests. Instead, it is used to calculate a request MAC value which is
+included in its place.
+
+However, **Hawk** has several differences from Digest. In particular, while both use a nonce to limit the possibility of
+replay attacks, in **Hawk** the client generates the nonce and uses it in combination with a timestamp, leading to less
+"chattiness" (interaction with the server).
+
+Also unlike Digest, this scheme is not intended to protect the key itself (the password in Digest) because
+the client and server must both have access to the key material in the clear.
+
+The primary design goals of this scheme are to:
+* simplify and improve HTTP authentication for services that are unwilling or unable to deploy TLS for all resources,
+* secure credentials against leakage (e.g., when the client uses some form of dynamic configuration to determine where
+  to send an authenticated request), and
+* avoid the exposure of credentials sent to a malicious server over an unauthenticated secure channel due to client
+  failure to validate the server's identity as part of its TLS handshake.
+
+In addition, **Hawk** supports a method for granting third-parties temporary access to individual resources using
+a query parameter called _bewit_ (in falconry, a leather strap used to attach a tracking device to the leg of a hawk).
+
+The **Hawk** scheme requires the establishment of a shared symmetric key between the client and the server,
+which is beyond the scope of this module. Typically, the shared credentials are established via an initial
+TLS-protected phase or derived from some other shared confidential information available to both the client
+and the server.
+
+
+## Replay Protection
+
+Without replay protection, an attacker can use a compromised (but otherwise valid and authenticated) request more 
+than once, gaining access to a protected resource. To mitigate this, clients include both a nonce and a timestamp when 
+making requests. This gives the server enough information to prevent replay attacks.
+
+The nonce is generated by the client, and is a string unique across all requests with the same timestamp and
+key identifier combination. 
+
+The timestamp enables the server to restrict the validity period of the credentials where requests occuring afterwards
+are rejected. It also removes the need for the server to retain an unbounded number of nonce values for future checks.
+By default, **Hawk** uses a time window of 1 minute to allow for time skew between the client and server (which in
+practice translates to a maximum of 2 minutes as the skew can be positive or negative).
+
+Using a timestamp requires the client's clock to be in sync with the server's clock. **Hawk** requires both the client
+clock and the server clock to use NTP to ensure synchronization. However, given the limitations of some client types
+(e.g. browsers) to deploy NTP, the server provides the client with its current time (in seconds precision) in response
+to a bad timestamp.
+
+There is no expectation that the client will adjust its system clock to match the server (in fact, this would be a
+potential attack vector). Instead, the client only uses the server's time to calculate an offset used only
+for communications with that particular server. The protocol rewards clients with synchronized clocks by reducing
+the number of round trips required to authenticate the first request.
+
+
+## Usage Example
+
+Server code:
+
+```javascript
+var Http = require('http');
+var Hawk = require('hawk');
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+    var credentials = {
+        key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+        algorithm: 'sha256',
+        user: 'Steve'
+    };
+
+    return callback(null, credentials);
+};
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+    // Authenticate incoming request
+
+    Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+        // Prepare response
+
+        var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
+        var headers = { 'Content-Type': 'text/plain' };
+
+        // Generate Server-Authorization response header
+
+        var header = Hawk.server.header(credentials, artifacts, { payload: payload, contentType: headers['Content-Type'] });
+        headers['Server-Authorization'] = header;
+
+        // Send the response back
+
+        res.writeHead(!err ? 200 : 401, headers);
+        res.end(payload);
+    });
+};
+
+// Start server
+
+Http.createServer(handler).listen(8000, 'example.com');
+```
+
+Client code:
+
+```javascript
+var Request = require('request');
+var Hawk = require('hawk');
+
+
+// Client credentials
+
+var credentials = {
+    id: 'dh37fgj492je',
+    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+    algorithm: 'sha256'
+}
+
+// Request options
+
+var requestOptions = {
+    uri: 'http://example.com:8000/resource/1?b=1&a=2',
+    method: 'GET',
+    headers: {}
+};
+
+// Generate Authorization request header
+
+var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });
+requestOptions.headers.Authorization = header.field;
+
+// Send authenticated request
+
+Request(requestOptions, function (error, response, body) {
+
+    // Authenticate the server's response
+
+    var isValid = Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });
+
+    // Output results
+
+    console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
+});
+```
+
+**Hawk** utilized the [**SNTP**](https://github.com/hueniverse/sntp) module for time sync management. By default, the local
+machine time is used. To automatically retrieve and synchronice the clock within the application, use the SNTP 'start()' method.
+
+```javascript
+Hawk.sntp.start();
+```
+
+
+## Protocol Example
+
+The client attempts to access a protected resource without authentication, sending the following HTTP request to
+the resource server:
+
+```
+GET /resource/1?b=1&a=2 HTTP/1.1
+Host: example.com:8000
+```
+
+The resource server returns an authentication challenge.
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Hawk
+```
+
+The client has previously obtained a set of **Hawk** credentials for accessing resources on the "http://example.com/"
+server. The **Hawk** credentials issued to the client include the following attributes:
+
+* Key identifier: dh37fgj492je
+* Key: werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn
+* Algorithm: sha256
+
+The client generates the authentication header by calculating a timestamp (e.g. the number of seconds since January 1,
+1970 00:00:00 GMT), generating a nonce, and constructing the normalized request string (each value followed by a newline
+character):
+
+```
+hawk.1.header
+1353832234
+j4h3g2
+GET
+/resource/1?b=1&a=2
+example.com
+8000
+
+some-app-ext-data
+
+```
+
+The request MAC is calculated using HMAC with the specified hash algorithm "sha256" and the key over the normalized request string.
+The result is base64-encoded to produce the request MAC:
+
+```
+6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=
+```
+
+The client includes the **Hawk** key identifier, timestamp, nonce, application specific data, and request MAC with the request using
+the HTTP `Authorization` request header field:
+
+```
+GET /resource/1?b=1&a=2 HTTP/1.1
+Host: example.com:8000
+Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="
+```
+
+The server validates the request by calculating the request MAC again based on the request received and verifies the validity
+and scope of the **Hawk** credentials. If valid, the server responds with the requested resource.
+
+
+### Payload Validation
+
+**Hawk** provides optional payload validation. When generating the authentication header, the client calculates a payload hash
+using the specified hash algorithm. The hash is calculated over the concatenated value of (each followed by a newline character):
+* `hawk.1.payload`
+* the content-type in lowercase, without any parameters (e.g. `application/json`)
+* the request payload prior to any content encoding (the exact representation requirements should be specified by the server for payloads other than simple single-part ascii to ensure interoperability)
+
+For example:
+
+* Payload: `Thank you for flying Hawk`
+* Content Type: `text/plain`
+* Hash (sha256): `Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=`
+
+Results in the following input to the payload hash function (newline terminated values):
+
+```
+hawk.1.payload
+text/plain
+Thank you for flying Hawk
+
+```
+
+Which produces the following hash value:
+
+```
+Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
+```
+
+The client constructs the normalized request string (newline terminated values):
+
+```
+hawk.1.header
+1353832234
+j4h3g2
+POST
+/resource/1?a=1&b=2
+example.com
+8000
+Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
+some-app-ext-data
+
+```
+
+Then calculates the request MAC and includes the **Hawk** key identifier, timestamp, nonce, payload hash, application specific data,
+and request MAC, with the request using the HTTP `Authorization` request header field:
+
+```
+POST /resource/1?a=1&b=2 HTTP/1.1
+Host: example.com:8000
+Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="
+```
+
+It is up to the server if and when it validates the payload for any given request, based solely on it's security policy
+and the nature of the data included.
+
+If the payload is available at the time of authentication, the server uses the hash value provided by the client to construct
+the normalized string and validates the MAC. If the MAC is valid, the server calculates the payload hash and compares the value
+with the provided payload hash in the header. In many cases, checking the MAC first is faster than calculating the payload hash.
+
+However, if the payload is not available at authentication time (e.g. too large to fit in memory, streamed elsewhere, or processed
+at a different stage in the application), the server may choose to defer payload validation for later by retaining the hash value
+provided by the client after validating the MAC.
+
+It is important to note that MAC validation does not mean the hash value provided by the client is valid, only that the value
+included in the header was not modified. Without calculating the payload hash on the server and comparing it to the value provided
+by the client, the payload may be modified by an attacker.
+
+
+## Response Payload Validation
+
+**Hawk** provides partial response payload validation. The server includes the `Server-Authorization` response header which enables the
+client to authenticate the response and ensure it is talking to the right server. **Hawk** defines the HTTP `Server-Authorization` header
+as a response header using the exact same syntax as the `Authorization` request header field.
+
+The header is contructed using the same process as the client's request header. The server uses the same credentials and other
+artifacts provided by the client to constructs the normalized request string. The `ext` and `hash` values are replaced with
+new values based on the server response. The rest as identical to those used by the client.
+
+The result MAC digest is included with the optional `hash` and `ext` values:
+
+```
+Server-Authorization: Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"
+```
+
+
+## Browser Support and Considerations
+
+A browser script is provided for including using a `<script>` tag in [lib/browser.js](/lib/browser.js).
+
+**Hawk** relies on the _Server-Authorization_ and _WWW-Authenticate_ headers in its response to communicate with the client.
+Therefore, in case of CORS requests, it is important to consider sending _Access-Control-Expose-Headers_ with the value
+_"WWW-Authenticate, Server-Authorization"_ on each response from your server. As explained in the
+[specifications](http://www.w3.org/TR/cors/#access-control-expose-headers-response-header), it will indicate that these headers
+can safely be accessed by the client (using getResponseHeader() on the XmlHttpRequest object). Otherwise you will be met with a
+["simple response header"](http://www.w3.org/TR/cors/#simple-response-header) which excludes these fields and would prevent the
+Hawk client from authenticating the requests.You can read more about the why and how in this
+[article](http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server)
+
+
+# Single URI Authorization
+
+There are cases in which limited and short-term access to a protected resource is granted to a third party which does not
+have access to the shared credentials. For example, displaying a protected image on a web page accessed by anyone. **Hawk**
+provides limited support for such URIs in the form of a _bewit_ - a URI query parameter appended to the request URI which contains
+the necessary credentials to authenticate the request.
+
+Because of the significant security risks involved in issuing such access, bewit usage is purposely limited only to GET requests
+and for a finite period of time. Both the client and server can issue bewit credentials, however, the server should not use the same
+credentials as the client to maintain clear traceability as to who issued which credentials.
+
+In order to simplify implementation, bewit credentials do not support single-use policy and can be replayed multiple times within
+the granted access timeframe. 
+
+
+## Bewit Usage Example
+
+Server code:
+
+```javascript
+var Http = require('http');
+var Hawk = require('hawk');
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+    var credentials = {
+        key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+        algorithm: 'sha256'
+    };
+
+    return callback(null, credentials);
+};
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+    Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+        res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });
+        res.end(!err ? 'Access granted' : 'Shoosh!');
+    });
+};
+
+Http.createServer(handler).listen(8000, 'example.com');
+```
+
+Bewit code generation:
+
+```javascript
+var Request = require('request');
+var Hawk = require('hawk');
+
+
+// Client credentials
+
+var credentials = {
+    id: 'dh37fgj492je',
+    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+    algorithm: 'sha256'
+}
+
+// Generate bewit
+
+var duration = 60 * 5;      // 5 Minutes
+var bewit = Hawk.uri.getBewit('http://example.com:8080/resource/1?b=1&a=2', { credentials: credentials, ttlSec: duration, ext: 'some-app-data' });
+var uri = 'http://example.com:8000/resource/1?b=1&a=2' + '&bewit=' + bewit;
+```
+
+
+# Security Considerations
+
+The greatest sources of security risks are usually found not in **Hawk** but in the policies and procedures surrounding its use.
+Implementers are strongly encouraged to assess how this module addresses their security requirements. This section includes
+an incomplete list of security considerations that must be reviewed and understood before deploying **Hawk** on the server.
+Many of the protections provided in **Hawk** depends on whether and how they are used.
+
+### MAC Keys Transmission
+
+**Hawk** does not provide any mechanism for obtaining or transmitting the set of shared credentials required. Any mechanism used
+to obtain **Hawk** credentials must ensure that these transmissions are protected using transport-layer mechanisms such as TLS.
+
+### Confidentiality of Requests
+
+While **Hawk** provides a mechanism for verifying the integrity of HTTP requests, it provides no guarantee of request
+confidentiality. Unless other precautions are taken, eavesdroppers will have full access to the request content. Servers should
+carefully consider the types of data likely to be sent as part of such requests, and employ transport-layer security mechanisms
+to protect sensitive resources.
+
+### Spoofing by Counterfeit Servers
+
+**Hawk** provides limited verification of the server authenticity. When receiving a response back from the server, the server
+may choose to include a response `Server-Authorization` header which the client can use to verify the response. However, it is up to
+the server to determine when such measure is included, to up to the client to enforce that policy.
+
+A hostile party could take advantage of this by intercepting the client's requests and returning misleading or otherwise
+incorrect responses. Service providers should consider such attacks when developing services using this protocol, and should
+require transport-layer security for any requests where the authenticity of the resource server or of server responses is an issue.
+
+### Plaintext Storage of Credentials
+
+The **Hawk** key functions the same way passwords do in traditional authentication systems. In order to compute the request MAC,
+the server must have access to the key in plaintext form. This is in contrast, for example, to modern operating systems, which
+store only a one-way hash of user credentials.
+
+If an attacker were to gain access to these keys - or worse, to the server's database of all such keys - he or she would be able
+to perform any action on behalf of any resource owner. Accordingly, it is critical that servers protect these keys from unauthorized
+access.
+
+### Entropy of Keys
+
+Unless a transport-layer security protocol is used, eavesdroppers will have full access to authenticated requests and request
+MAC values, and will thus be able to mount offline brute-force attacks to recover the key used. Servers should be careful to
+assign keys which are long enough, and random enough, to resist such attacks for at least the length of time that the **Hawk**
+credentials are valid.
+
+For example, if the credentials are valid for two weeks, servers should ensure that it is not possible to mount a brute force
+attack that recovers the key in less than two weeks. Of course, servers are urged to err on the side of caution, and use the
+longest key reasonable.
+
+It is equally important that the pseudo-random number generator (PRNG) used to generate these keys be of sufficiently high
+quality. Many PRNG implementations generate number sequences that may appear to be random, but which nevertheless exhibit
+patterns or other weaknesses which make cryptanalysis or brute force attacks easier. Implementers should be careful to use
+cryptographically secure PRNGs to avoid these problems.
+
+### Coverage Limitations
+
+The request MAC only covers the HTTP `Host` header and optionally the `Content-Type` header. It does not cover any other headers
+which can often affect how the request body is interpreted by the server. If the server behavior is influenced by the presence
+or value of such headers, an attacker can manipulate the request headers without being detected. Implementers should use the
+`ext` feature to pass application-specific information via the `Authorization` header which is protected by the request MAC.
+
+The response authentication, when performed, only covers the response payload, content-type, and the request information 
+provided by the client in it's request (method, resource, timestamp, nonce, etc.). It does not cover the HTTP status code or
+any other response header field (e.g. Location) which can affect the client's behaviour.
+
+### Future Time Manipulation
+
+The protocol relies on a clock sync between the client and server. To accomplish this, the server informs the client of its
+current time when an invalid timestamp is received.
+
+If an attacker is able to manipulate this information and cause the client to use an incorrect time, it would be able to cause
+the client to generate authenticated requests using time in the future. Such requests will fail when sent by the client, and will
+not likely leave a trace on the server (given the common implementation of nonce, if at all enforced). The attacker will then
+be able to replay the request at the correct time without detection.
+
+The client must only use the time information provided by the server if:
+* it was delivered over a TLS connection and the server identity has been verified, or
+* the `tsm` MAC digest calculated using the same client credentials over the timestamp has been verified.
+
+### Client Clock Poisoning
+
+When receiving a request with a bad timestamp, the server provides the client with its current time. The client must never use
+the time received from the server to adjust its own clock, and must only use it to calculate an offset for communicating with
+that particular server.
+
+### Bewit Limitations
+
+Special care must be taken when issuing bewit credentials to third parties. Bewit credentials are valid until expiration and cannot
+be revoked or limited without using other means. Whatever resource they grant access to will be completely exposed to anyone with
+access to the bewit credentials which act as bearer credentials for that particular resource. While bewit usage is limited to GET
+requests only and therefore cannot be used to perform transactions or change server state, it can still be used to expose private
+and sensitive information.
+
+### Host Header Forgery
+
+Hawk validates the incoming request MAC against the incoming HTTP Host header. However, unless the optional `host` and `port`
+options are used with `server.authenticate()`, a malicous client can mint new host names pointing to the server's IP address and
+use that to craft an attack by sending a valid request that's meant for another hostname than the one used by the server. Server
+implementors must manually verify that the host header received matches their expectation (or use the options mentioned above).
+
+# Frequently Asked Questions
+
+### Where is the protocol specification?
+
+If you are looking for some prose explaining how all this works, **this is it**. **Hawk** is being developed as an open source
+project instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification. Not sure about
+something? Open an issue!
+
+### Is it done?
+
+At if version 0.10.0, **Hawk** is feature-complete. However, until this module reaches version 1.0.0 it is considered experimental
+and is likely to change. This also means your feedback and contribution are very welcome. Feel free to open issues with questions
+and suggestions.
+
+### Where can I find **Hawk** implementations in other languages?
+
+**Hawk**'s only reference implementation is provided in JavaScript as a node.js module. However, others are actively porting it to other
+platforms. There is already a [PHP](https://github.com/alexbilbie/PHP-Hawk),
+[.NET](https://github.com/pcibraro/hawknet), and [JAVA](https://github.com/wealdtech/hawk) libraries available. The full list
+is maintained [here](https://github.com/hueniverse/hawk/issues?labels=port). Please add an issue if you are working on another
+port. A cross-platform test-suite is in the works.
+
+### Why isn't the algorithm part of the challenge or dynamically negotiated?
+
+The algorithm used is closely related to the key issued as different algorithms require different key sizes (and other
+requirements). While some keys can be used for multiple algorithm, the protocol is designed to closely bind the key and algorithm
+together as part of the issued credentials.
+
+### Why is Host and Content-Type the only headers covered by the request MAC?
+
+It is really hard to include other headers. Headers can be changed by proxies and other intermediaries and there is no
+well-established way to normalize them. Many platforms change the case of header field names and values. The only
+straight-forward solution is to include the headers in some blob (say, base64 encoded JSON) and include that with the request,
+an approach taken by JWT and other such formats. However, that design violates the HTTP header boundaries, repeats information,
+and introduces other security issues because firewalls will not be aware of these "hidden" headers. In addition, any information
+repeated must be compared to the duplicated information in the header and therefore only moves the problem elsewhere.
+
+### Why not just use HTTP Digest?
+
+Digest requires pre-negotiation to establish a nonce. This means you can't just make a request - you must first send
+a protocol handshake to the server. This pattern has become unacceptable for most web services, especially mobile
+where extra round-trip are costly.
+
+### Why bother with all this nonce and timestamp business?
+
+**Hawk** is an attempt to find a reasonable, practical compromise between security and usability. OAuth 1.0 got timestamp
+and nonces halfway right but failed when it came to scalability and consistent developer experience. **Hawk** addresses
+it by requiring the client to sync its clock, but provides it with tools to accomplish it.
+
+In general, replay protection is a matter of application-specific threat model. It is less of an issue on a TLS-protected
+system where the clients are implemented using best practices and are under the control of the server. Instead of dropping
+replay protection, **Hawk** offers a required time window and an optional nonce verification. Together, it provides developers
+with the ability to decide how to enforce their security policy without impacting the client's implementation.
+
+### What are `app` and `dlg` in the authorization header and normalized mac string?
+
+The original motivation for **Hawk** was to replace the OAuth 1.0 use cases. This included both a simple client-server mode which
+this module is specifically designed for, and a delegated access mode which is being developed separately in
+[Oz](https://github.com/hueniverse/oz). In addition to the **Hawk** use cases, Oz requires another attribute: the application id `app`.
+This provides binding between the credentials and the application in a way that prevents an attacker from tricking an application
+to use credentials issued to someone else. It also has an optional 'delegated-by' attribute `dlg` which is the application id of the
+application the credentials were directly issued to. The goal of these two additions is to allow Oz to utilize **Hawk** directly,
+but with the additional security of delegated credentials.
+
+### What is the purpose of the static strings used in each normalized MAC input?
+
+When calculating a hash or MAC, a static prefix (tag) is added. The prefix is used to prevent MAC values from being
+used or reused for a purpose other than what they were created for (i.e. prevents switching MAC values between a request,
+response, and a bewit use cases). It also protects against expliots created after a potential change in how the protocol
+creates the normalized string. For example, if a future version would switch the order of nonce and timestamp, it
+can create an exploit opportunity for cases where the nonce is similar in format to a timestamp.
+
+### Does **Hawk** have anything to do with OAuth?
+
+Short answer: no.
+
+**Hawk** was originally proposed as the OAuth MAC Token specification. However, the OAuth working group in its consistent
+incompetence failed to produce a final, usable solution to address one of the most popular use cases of OAuth 1.0 - using it
+to authenticate simple client-server transactions (i.e. two-legged). As you can guess, the OAuth working group is still hard
+at work to produce more garbage.
+
+**Hawk** provides a simple HTTP authentication scheme for making client-server requests. It does not address the OAuth use case
+of delegating access to a third party. If you are looking for an OAuth alternative, check out [Oz](https://github.com/hueniverse/oz).
+
+
+# Acknowledgements
+
+**Hawk** is a derivative work of the [HTTP MAC Authentication Scheme](http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05) proposal
+co-authored by Ben Adida, Adam Barth, and Eran Hammer, which in turn was based on the OAuth 1.0 community specification.
+
+Special thanks to Ben Laurie for his always insightful feedback and advice.
+
+The **Hawk** logo was created by [Chris Carrasco](http://chriscarrasco.com).
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/example/usage.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/example/usage.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/example/usage.js	(revision 517)
@@ -0,0 +1,78 @@
+// Load modules
+
+var Http = require('http');
+var Request = require('request');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {
+    credentials: {
+        dh37fgj492je: {
+            id: 'dh37fgj492je',                                             // Required by Hawk.client.header 
+            key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+            algorithm: 'sha256',
+            user: 'Steve'
+        }
+    }
+};
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+    return callback(null, internals.credentials[id]);
+};
+
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+    Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+        var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
+        var headers = {
+            'Content-Type': 'text/plain',
+            'Server-Authorization': Hawk.server.header(credentials, artifacts, { payload: payload, contentType: 'text/plain' })
+        };
+
+        res.writeHead(!err ? 200 : 401, headers);
+        res.end(payload);
+    });
+};
+
+Http.createServer(handler).listen(8000, '127.0.0.1');
+
+
+// Send unauthenticated request
+
+Request('http://127.0.0.1:8000/resource/1?b=1&a=2', function (error, response, body) {
+
+    console.log(response.statusCode + ': ' + body);
+});
+
+
+// Send authenticated request
+
+credentialsFunc('dh37fgj492je', function (err, credentials) {
+
+    var header = Hawk.client.header('http://127.0.0.1:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'and welcome!' });
+    var options = {
+        uri: 'http://127.0.0.1:8000/resource/1?b=1&a=2',
+        method: 'GET',
+        headers: {
+            authorization: header.field
+        }
+    };
+
+    Request(options, function (error, response, body) {
+
+        var isValid = Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });
+        console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
+        process.exit(0);
+    });
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/index.js	(revision 517)
@@ -0,0 +1,1 @@
+module.exports = require('./lib');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/browser.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/browser.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/browser.js	(revision 517)
@@ -0,0 +1,485 @@
+/*
+    HTTP Hawk Authentication Scheme
+    Copyright (c) 2012-2013, Eran Hammer <eran@hueniverse.com>
+    MIT Licensed
+*/
+
+
+// Declare namespace
+
+var hawk = {};
+
+
+// Export if used as a module
+
+if (typeof module !== "undefined" && module.exports) {
+    module.exports = hawk;
+}
+
+hawk.client = {
+
+    // Generate an Authorization header for a given request
+
+    /*
+        uri: 'http://example.com/resource?a=b'
+        method: HTTP verb (e.g. 'GET', 'POST')
+        options: {
+    
+            // Required
+    
+            credentials: {
+                id: 'dh37fgj492je',
+                key: 'aoijedoaijsdlaksjdl',
+                algorithm: 'sha256'                                 // 'sha1', 'sha256'
+            },
+    
+            // Optional
+    
+            ext: 'application-specific',                        // Application specific data sent via the ext attribute
+            timestamp: Date.now() / 1000,                       // A pre-calculated timestamp in seconds
+            nonce: '2334f34f',                                  // A pre-generated nonce
+            localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
+            payload: '{"some":"payload"}',                      // UTF-8 encoded string for body hash generation (ignored if hash provided)
+            contentType: 'application/json',                    // Payload content-type (ignored if hash provided)
+            hash: 'U4MKKSmiVxk37JCCrAVIjV=',                    // Pre-calculated payload hash
+            app: '24s23423f34dx',                               // Oz application id
+            dlg: '234sz34tww3sd'                                // Oz delegated-by application id
+        }
+    */
+
+    header: function (uri, method, options) {
+
+        var result = {
+            field: '',
+            artifacts: {}
+        };
+
+        // Validate inputs
+
+        if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') ||
+            !method || typeof method !== 'string' ||
+            !options || typeof options !== 'object') {
+
+            return result;
+        }
+
+        // Application time
+
+        var timestamp = options.timestamp || Math.floor((hawk.utils.now() + (options.localtimeOffsetMsec || 0)) / 1000)
+
+        // Validate credentials
+
+        var credentials = options.credentials;
+        if (!credentials ||
+            !credentials.id ||
+            !credentials.key ||
+            !credentials.algorithm) {
+
+            // Invalid credential object
+            return result;
+        }
+
+        if (hawk.crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+            return result;
+        }
+
+        // Parse URI
+
+        if (typeof uri === 'string') {
+            uri = hawk.utils.parseUri(uri);
+        }
+
+        // Calculate signature
+
+        var artifacts = {
+            ts: timestamp,
+            nonce: options.nonce || hawk.utils.randomString(6),
+            method: method,
+            resource: uri.relative,
+            host: uri.hostname,
+            port: uri.port,
+            hash: options.hash,
+            ext: options.ext,
+            app: options.app,
+            dlg: options.dlg
+        };
+
+        result.artifacts = artifacts;
+
+        // Calculate payload hash
+
+        if (!artifacts.hash &&
+            options.hasOwnProperty('payload')) {
+
+            artifacts.hash = hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+        }
+
+        var mac = hawk.crypto.calculateMac('header', credentials, artifacts);
+
+        // Construct header
+
+        var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== '';       // Other falsey values allowed
+        var header = 'Hawk id="' + credentials.id +
+                     '", ts="' + artifacts.ts +
+                     '", nonce="' + artifacts.nonce +
+                     (artifacts.hash ? '", hash="' + artifacts.hash : '') +
+                     (hasExt ? '", ext="' + hawk.utils.escapeHeaderAttribute(artifacts.ext) : '') +
+                     '", mac="' + mac + '"';
+
+        if (artifacts.app) {
+            header += ', app="' + artifacts.app +
+                      (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"';
+        }
+
+        result.field = header;
+
+        return result;
+    },
+
+
+    // Validate server response
+
+    /*
+        request:    object created via 'new XMLHttpRequest()' after response received
+        artifacts:  object recieved from header().artifacts
+        options: {
+            payload:    optional payload received
+            required:   specifies if a Server-Authorization header is required. Defaults to 'false'
+        }
+    */
+
+    authenticate: function (request, credentials, artifacts, options) {
+
+        options = options || {};
+
+        if (request.getResponseHeader('www-authenticate')) {
+
+            // Parse HTTP WWW-Authenticate header
+
+            var attributes = hawk.utils.parseAuthorizationHeader(request.getResponseHeader('www-authenticate'), ['ts', 'tsm', 'error']);
+            if (!attributes) {
+                return false;
+            }
+
+            if (attributes.ts) {
+                var tsm = hawk.crypto.calculateTsMac(attributes.ts, credentials);
+                if (tsm !== attributes.tsm) {
+                    return false;
+                }
+
+                hawk.utils.setNtpOffset(attributes.ts - Math.floor(Date.now() / 1000));     // Keep offset at 1 second precision
+            }
+        }
+
+        // Parse HTTP Server-Authorization header
+
+        if (!request.getResponseHeader('server-authorization') &&
+            !options.required) {
+
+            return true;
+        }
+
+        var attributes = hawk.utils.parseAuthorizationHeader(request.getResponseHeader('server-authorization'), ['mac', 'ext', 'hash']);
+        if (!attributes) {
+            return false;
+        }
+
+        var modArtifacts = {
+            ts: artifacts.ts,
+            nonce: artifacts.nonce,
+            method: artifacts.method,
+            resource: artifacts.resource,
+            host: artifacts.host,
+            port: artifacts.port,
+            hash: attributes.hash,
+            ext: attributes.ext,
+            app: artifacts.app,
+            dlg: artifacts.dlg
+        };
+
+        var mac = hawk.crypto.calculateMac('response', credentials, modArtifacts);
+        if (mac !== attributes.mac) {
+            return false;
+        }
+
+        if (!options.hasOwnProperty('payload')) {
+            return true;
+        }
+
+        if (!attributes.hash) {
+            return false;
+        }
+
+        var calculatedHash = hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, request.getResponseHeader('content-type'));
+        return (calculatedHash === attributes.hash);
+    },
+
+    message: function (host, port, message, options) {
+
+        // Validate inputs
+
+        if (!host || typeof host !== 'string' ||
+            !port || typeof port !== 'number' ||
+            message === null || message === undefined || typeof message !== 'string' ||
+            !options || typeof options !== 'object') {
+
+            return null;
+        }
+
+        // Application time
+
+        var timestamp = options.timestamp || Math.floor((hawk.utils.now() + (options.localtimeOffsetMsec || 0)) / 1000)
+
+        // Validate credentials
+
+        var credentials = options.credentials;
+        if (!credentials ||
+            !credentials.id ||
+            !credentials.key ||
+            !credentials.algorithm) {
+
+            // Invalid credential object
+            return null;
+        }
+
+        if (hawk.crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+            return null;
+        }
+
+        // Calculate signature
+
+        var artifacts = {
+            ts: timestamp,
+            nonce: options.nonce || hawk.utils.randomString(6),
+            host: host,
+            port: port,
+            hash: hawk.crypto.calculatePayloadHash(message, credentials.algorithm)
+        };
+
+        // Construct authorization
+
+        var result = {
+            id: credentials.id,
+            ts: artifacts.ts,
+            nonce: artifacts.nonce,
+            hash: artifacts.hash,
+            mac: hawk.crypto.calculateMac('message', credentials, artifacts)
+        };
+
+        return result;
+    }
+};
+
+
+hawk.crypto = {
+
+    headerVersion: '1',
+
+    algorithms: ['sha1', 'sha256'],
+
+    calculateMac: function (type, credentials, options) {
+
+        var normalized = hawk.crypto.generateNormalizedString(type, options);
+
+        var hmac = CryptoJS['Hmac' + credentials.algorithm.toUpperCase()](normalized, credentials.key);
+        return hmac.toString(CryptoJS.enc.Base64);
+    },
+
+    generateNormalizedString: function (type, options) {
+
+        var normalized = 'hawk.' + hawk.crypto.headerVersion + '.' + type + '\n' +
+                         options.ts + '\n' +
+                         options.nonce + '\n' +
+                         (options.method || '').toUpperCase() + '\n' +
+                         (options.resource || '') + '\n' +
+                         options.host.toLowerCase() + '\n' +
+                         options.port + '\n' +
+                         (options.hash || '') + '\n';
+
+        if (options.ext) {
+            normalized += options.ext.replace('\\', '\\\\').replace('\n', '\\n');
+        }
+
+        normalized += '\n';
+
+        if (options.app) {
+            normalized += options.app + '\n' +
+                          (options.dlg || '') + '\n';
+        }
+
+        return normalized;
+    },
+
+    calculatePayloadHash: function (payload, algorithm, contentType) {
+
+        var hash = CryptoJS.algo[algorithm.toUpperCase()].create();
+        hash.update('hawk.' + hawk.crypto.headerVersion + '.payload\n');
+        hash.update(hawk.utils.parseContentType(contentType) + '\n');
+        hash.update(payload || '');
+        hash.update('\n');
+        return hash.finalize().toString(CryptoJS.enc.Base64);
+    },
+
+    calculateTsMac: function (ts, credentials) {
+
+        var hash = CryptoJS['Hmac' + credentials.algorithm.toUpperCase()]('hawk.' + hawk.crypto.headerVersion + '.ts\n' + ts + '\n', credentials.key);
+        return hash.toString(CryptoJS.enc.Base64);
+    }
+};
+
+
+hawk.utils = {
+
+    storage: {                                      // localStorage compatible interface
+        _cache: {},
+        setItem: function (key, value) {
+
+            hawk.utils.storage._cache[key] = value;
+        },
+        getItem: function (key) {
+
+            return hawk.utils.storage._cache[key];
+        }
+    },
+
+    setStorage: function (storage) {
+
+        var ntpOffset = hawk.utils.getNtpOffset() || 0;
+        hawk.utils.storage = storage;
+        hawk.utils.setNtpOffset(ntpOffset);
+    },
+
+    setNtpOffset: function (offset) {
+
+        hawk.utils.storage.setItem('hawk_ntp_offset', offset);
+    },
+
+    getNtpOffset: function () {
+
+        return parseInt(hawk.utils.storage.getItem('hawk_ntp_offset') || '0', 10);
+    },
+
+    now: function () {
+
+        return Date.now() + hawk.utils.getNtpOffset();
+    },
+
+    escapeHeaderAttribute: function (attribute) {
+
+        return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');
+    },
+
+    parseContentType: function (header) {
+
+        if (!header) {
+            return '';
+        }
+
+        return header.split(';')[0].trim().toLowerCase();
+    },
+
+    parseAuthorizationHeader: function (header, keys) {
+
+        if (!header) {
+            return null;
+        }
+
+        var headerParts = header.match(/^(\w+)(?:\s+(.*))?$/);       // Header: scheme[ something]
+        if (!headerParts) {
+            return null;
+        }
+
+        var scheme = headerParts[1];
+        if (scheme.toLowerCase() !== 'hawk') {
+            return null;
+        }
+
+        var attributesString = headerParts[2];
+        if (!attributesString) {
+            return null;
+        }
+
+        var attributes = {};
+        var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) {
+
+            // Check valid attribute names
+
+            if (keys.indexOf($1) === -1) {
+                return;
+            }
+
+            // Allowed attribute value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9
+
+            if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === null) {
+                return;
+            }
+
+            // Check for duplicates
+
+            if (attributes.hasOwnProperty($1)) {
+                return;
+            }
+
+            attributes[$1] = $2;
+            return '';
+        });
+
+        if (verify !== '') {
+            return null;
+        }
+
+        return attributes;
+    },
+
+    randomString: function (size) {
+
+        var randomSource = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+        var len = randomSource.length;
+
+        var result = [];
+        for (var i = 0; i < size; ++i) {
+            result[i] = randomSource[Math.floor(Math.random() * len)];
+        }
+
+        return result.join('');
+    },
+
+    parseUri: function (input) {
+
+        // Based on: parseURI 1.2.2
+        // http://blog.stevenlevithan.com/archives/parseuri
+        // (c) Steven Levithan <stevenlevithan.com>
+        // MIT License
+
+        var keys = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'hostname', 'port', 'resource', 'relative', 'pathname', 'directory', 'file', 'query', 'fragment'];
+
+        var uriRegex = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?(((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?)(?:#(.*))?)/;
+        var uriByNumber = uriRegex.exec(input);
+        var uri = {};
+
+        var i = 15;
+        while (i--) {
+            uri[keys[i]] = uriByNumber[i] || '';
+        }
+
+        if (uri.port === null ||
+            uri.port === '') {
+
+            uri.port = (uri.protocol.toLowerCase() === 'http' ? '80' : (uri.protocol.toLowerCase() === 'https' ? '443' : ''));
+        }
+
+        return uri;
+    }
+};
+
+
+// Based on: Crypto-JS v3.1.2
+// Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
+// http://code.google.com/p/crypto-js/
+// http://code.google.com/p/crypto-js/wiki/License
+
+var CryptoJS=CryptoJS||function(h,r){var k={},l=k.lib={},n=function(){},f=l.Base={extend:function(a){n.prototype=this;var b=new n;a&&b.mixIn(a);b.hasOwnProperty("init")||(b.init=function(){b.$super.init.apply(this,arguments)});b.init.prototype=b;b.$super=this;return b},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var b in a)a.hasOwnProperty(b)&&(this[b]=a[b]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},j=l.WordArray=f.extend({init:function(a,b){a=this.words=a||[];this.sigBytes=b!=r?b:4*a.length},toString:function(a){return(a||s).stringify(this)},concat:function(a){var b=this.words,d=a.words,c=this.sigBytes;a=a.sigBytes;this.clamp();if(c%4)for(var e=0;e<a;e++)b[c+e>>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((c+e)%4);else if(65535<d.length)for(e=0;e<a;e+=4)b[c+e>>>2]=d[e>>>2];else b.push.apply(b,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,b=this.sigBytes;a[b>>>2]&=4294967295<<32-8*(b%4);a.length=h.ceil(b/4)},clone:function(){var a=f.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var b=[],d=0;d<a;d+=4)b.push(4294967296*h.random()|0);return new j.init(b,a)}}),m=k.enc={},s=m.Hex={stringify:function(a){var b=a.words;a=a.sigBytes;for(var d=[],c=0;c<a;c++){var e=b[c>>>2]>>>24-8*(c%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c<b;c+=2)d[c>>>3]|=parseInt(a.substr(c,2),16)<<24-4*(c%8);return new j.init(d,b/2)}},p=m.Latin1={stringify:function(a){var b=a.words;a=a.sigBytes;for(var d=[],c=0;c<a;c++)d.push(String.fromCharCode(b[c>>>2]>>>24-8*(c%4)&255));return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c<b;c++)d[c>>>2]|=(a.charCodeAt(c)&255)<<24-8*(c%4);return new j.init(d,b)}},t=m.Utf8={stringify:function(a){try{return decodeURIComponent(escape(p.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data");}},parse:function(a){return p.parse(unescape(encodeURIComponent(a)))}},q=l.BufferedBlockAlgorithm=f.extend({reset:function(){this._data=new j.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=t.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,d=b.words,c=b.sigBytes,e=this.blockSize,f=c/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;c=h.min(4*a,c);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);b.sigBytes-=c}return new j.init(g,c)},clone:function(){var a=f.clone.call(this);a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:f.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,d){return(new a.init(d)).finalize(b)}},_createHmacHelper:function(a){return function(b,d){return(new u.HMAC.init(a,d)).finalize(b)}}});var u=k.algo={};return k}(Math);
+(function () { var k = CryptoJS, b = k.lib, m = b.WordArray, l = b.Hasher, d = [], b = k.algo.SHA1 = l.extend({ _doReset: function () { this._hash = new m.init([1732584193, 4023233417, 2562383102, 271733878, 3285377520]) }, _doProcessBlock: function (n, p) { for (var a = this._hash.words, e = a[0], f = a[1], h = a[2], j = a[3], b = a[4], c = 0; 80 > c; c++) { if (16 > c) d[c] = n[p + c] | 0; else { var g = d[c - 3] ^ d[c - 8] ^ d[c - 14] ^ d[c - 16]; d[c] = g << 1 | g >>> 31 } g = (e << 5 | e >>> 27) + b + d[c]; g = 20 > c ? g + ((f & h | ~f & j) + 1518500249) : 40 > c ? g + ((f ^ h ^ j) + 1859775393) : 60 > c ? g + ((f & h | f & j | h & j) - 1894007588) : g + ((f ^ h ^ j) - 899497514); b = j; j = h; h = f << 30 | f >>> 2; f = e; e = g } a[0] = a[0] + e | 0; a[1] = a[1] + f | 0; a[2] = a[2] + h | 0; a[3] = a[3] + j | 0; a[4] = a[4] + b | 0 }, _doFinalize: function () { var b = this._data, d = b.words, a = 8 * this._nDataBytes, e = 8 * b.sigBytes; d[e >>> 5] |= 128 << 24 - e % 32; d[(e + 64 >>> 9 << 4) + 14] = Math.floor(a / 4294967296); d[(e + 64 >>> 9 << 4) + 15] = a; b.sigBytes = 4 * d.length; this._process(); return this._hash }, clone: function () { var b = l.clone.call(this); b._hash = this._hash.clone(); return b } }); k.SHA1 = l._createHelper(b); k.HmacSHA1 = l._createHmacHelper(b) })();
+(function (k) { for (var g = CryptoJS, h = g.lib, v = h.WordArray, j = h.Hasher, h = g.algo, s = [], t = [], u = function (q) { return 4294967296 * (q - (q | 0)) | 0 }, l = 2, b = 0; 64 > b;) { var d; a: { d = l; for (var w = k.sqrt(d), r = 2; r <= w; r++) if (!(d % r)) { d = !1; break a } d = !0 } d && (8 > b && (s[b] = u(k.pow(l, 0.5))), t[b] = u(k.pow(l, 1 / 3)), b++); l++ } var n = [], h = h.SHA256 = j.extend({ _doReset: function () { this._hash = new v.init(s.slice(0)) }, _doProcessBlock: function (q, h) { for (var a = this._hash.words, c = a[0], d = a[1], b = a[2], k = a[3], f = a[4], g = a[5], j = a[6], l = a[7], e = 0; 64 > e; e++) { if (16 > e) n[e] = q[h + e] | 0; else { var m = n[e - 15], p = n[e - 2]; n[e] = ((m << 25 | m >>> 7) ^ (m << 14 | m >>> 18) ^ m >>> 3) + n[e - 7] + ((p << 15 | p >>> 17) ^ (p << 13 | p >>> 19) ^ p >>> 10) + n[e - 16] } m = l + ((f << 26 | f >>> 6) ^ (f << 21 | f >>> 11) ^ (f << 7 | f >>> 25)) + (f & g ^ ~f & j) + t[e] + n[e]; p = ((c << 30 | c >>> 2) ^ (c << 19 | c >>> 13) ^ (c << 10 | c >>> 22)) + (c & d ^ c & b ^ d & b); l = j; j = g; g = f; f = k + m | 0; k = b; b = d; d = c; c = m + p | 0 } a[0] = a[0] + c | 0; a[1] = a[1] + d | 0; a[2] = a[2] + b | 0; a[3] = a[3] + k | 0; a[4] = a[4] + f | 0; a[5] = a[5] + g | 0; a[6] = a[6] + j | 0; a[7] = a[7] + l | 0 }, _doFinalize: function () { var d = this._data, b = d.words, a = 8 * this._nDataBytes, c = 8 * d.sigBytes; b[c >>> 5] |= 128 << 24 - c % 32; b[(c + 64 >>> 9 << 4) + 14] = k.floor(a / 4294967296); b[(c + 64 >>> 9 << 4) + 15] = a; d.sigBytes = 4 * b.length; this._process(); return this._hash }, clone: function () { var b = j.clone.call(this); b._hash = this._hash.clone(); return b } }); g.SHA256 = j._createHelper(h); g.HmacSHA256 = j._createHmacHelper(h) })(Math);
+(function(){var c=CryptoJS,k=c.enc.Utf8;c.algo.HMAC=c.lib.Base.extend({init:function(a,b){a=this._hasher=new a.init;"string"==typeof b&&(b=k.parse(b));var c=a.blockSize,e=4*c;b.sigBytes>e&&(b=a.finalize(b));b.clamp();for(var f=this._oKey=b.clone(),g=this._iKey=b.clone(),h=f.words,j=g.words,d=0;d<c;d++)h[d]^=1549556828,j[d]^=909522486;f.sigBytes=g.sigBytes=e;this.reset()},reset:function(){var a=this._hasher;a.reset();a.update(this._iKey)},update:function(a){this._hasher.update(a);return this},finalize:function(a){var b=this._hasher;a=b.finalize(a);b.reset();return b.finalize(this._oKey.clone().concat(a))}})})();
+(function(){var h=CryptoJS,j=h.lib.WordArray;h.enc.Base64={stringify:function(b){var e=b.words,f=b.sigBytes,c=this._map;b.clamp();b=[];for(var a=0;a<f;a+=3)for(var d=(e[a>>>2]>>>24-8*(a%4)&255)<<16|(e[a+1>>>2]>>>24-8*((a+1)%4)&255)<<8|e[a+2>>>2]>>>24-8*((a+2)%4)&255,g=0;4>g&&a+0.75*g<f;g++)b.push(c.charAt(d>>>6*(3-g)&63));if(e=c.charAt(64))for(;b.length%4;)b.push(e);return b.join("")},parse:function(b){var e=b.length,f=this._map,c=f.charAt(64);c&&(c=b.indexOf(c),-1!=c&&(e=c));for(var c=[],a=0,d=0;d<e;d++)if(d%4){var g=f.indexOf(b.charAt(d-1))<<2*(d%4),h=f.indexOf(b.charAt(d))>>>6-2*(d%4);c[a>>>2]|=(g|h)<<24-8*(a%4);a++}return j.create(c,a)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/client.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/client.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/client.js	(revision 517)
@@ -0,0 +1,367 @@
+// Load modules
+
+var Url = require('url');
+var Hoek = require('hoek');
+var Cryptiles = require('cryptiles');
+var Crypto = require('./crypto');
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Generate an Authorization header for a given request
+
+/*
+    uri: 'http://example.com/resource?a=b' or object from Url.parse()
+    method: HTTP verb (e.g. 'GET', 'POST')
+    options: {
+
+        // Required
+
+        credentials: {
+            id: 'dh37fgj492je',
+            key: 'aoijedoaijsdlaksjdl',
+            algorithm: 'sha256'                                 // 'sha1', 'sha256'
+        },
+
+        // Optional
+
+        ext: 'application-specific',                        // Application specific data sent via the ext attribute
+        timestamp: Date.now(),                              // A pre-calculated timestamp
+        nonce: '2334f34f',                                  // A pre-generated nonce
+        localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
+        payload: '{"some":"payload"}',                      // UTF-8 encoded string for body hash generation (ignored if hash provided)
+        contentType: 'application/json',                    // Payload content-type (ignored if hash provided)
+        hash: 'U4MKKSmiVxk37JCCrAVIjV=',                    // Pre-calculated payload hash
+        app: '24s23423f34dx',                               // Oz application id
+        dlg: '234sz34tww3sd'                                // Oz delegated-by application id
+    }
+*/
+
+exports.header = function (uri, method, options) {
+
+    var result = {
+        field: '',
+        artifacts: {}
+    };
+
+    // Validate inputs
+
+    if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') ||
+        !method || typeof method !== 'string' ||
+        !options || typeof options !== 'object') {
+
+        return result;
+    }
+
+    // Application time
+
+    var timestamp = options.timestamp || Math.floor((Utils.now() + (options.localtimeOffsetMsec || 0)) / 1000)
+
+    // Validate credentials
+
+    var credentials = options.credentials;
+    if (!credentials ||
+        !credentials.id ||
+        !credentials.key ||
+        !credentials.algorithm) {
+
+        // Invalid credential object
+        return result;
+    }
+
+    if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+        return result;
+    }
+
+    // Parse URI
+
+    if (typeof uri === 'string') {
+        uri = Url.parse(uri);
+    }
+
+    // Calculate signature
+
+    var artifacts = {
+        ts: timestamp,
+        nonce: options.nonce || Cryptiles.randomString(6),
+        method: method,
+        resource: uri.pathname + (uri.search || ''),                            // Maintain trailing '?'
+        host: uri.hostname,
+        port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
+        hash: options.hash,
+        ext: options.ext,
+        app: options.app,
+        dlg: options.dlg
+    };
+
+    result.artifacts = artifacts;
+
+    // Calculate payload hash
+
+    if (!artifacts.hash &&
+        options.hasOwnProperty('payload')) {
+
+        artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+    }
+
+    var mac = Crypto.calculateMac('header', credentials, artifacts);
+
+    // Construct header
+
+    var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== '';       // Other falsey values allowed
+    var header = 'Hawk id="' + credentials.id +
+                 '", ts="' + artifacts.ts +
+                 '", nonce="' + artifacts.nonce +
+                 (artifacts.hash ? '", hash="' + artifacts.hash : '') +
+                 (hasExt ? '", ext="' + Utils.escapeHeaderAttribute(artifacts.ext) : '') +
+                 '", mac="' + mac + '"';
+
+    if (artifacts.app) {
+        header += ', app="' + artifacts.app +
+                  (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"';
+    }
+
+    result.field = header;
+
+    return result;
+};
+
+
+// Validate server response
+
+/*
+    res:        node's response object
+    artifacts:  object recieved from header().artifacts
+    options: {
+        payload:    optional payload received
+        required:   specifies if a Server-Authorization header is required. Defaults to 'false'
+    }
+*/
+
+exports.authenticate = function (res, credentials, artifacts, options) {
+
+    artifacts = Hoek.clone(artifacts);
+    options = options || {};
+
+    if (res.headers['www-authenticate']) {
+
+        // Parse HTTP WWW-Authenticate header
+
+        var attributes = Utils.parseAuthorizationHeader(res.headers['www-authenticate'], ['ts', 'tsm', 'error']);
+        if (attributes instanceof Error) {
+            return false;
+        }
+
+        if (attributes.ts) {
+            var tsm = Crypto.calculateTsMac(attributes.ts, credentials);
+            if (tsm !== attributes.tsm) {
+                return false;
+            }
+        }
+    }
+
+    // Parse HTTP Server-Authorization header
+
+    if (!res.headers['server-authorization'] &&
+        !options.required) {
+
+        return true;
+    }
+
+    var attributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']);
+    if (attributes instanceof Error) {
+        return false;
+    }
+
+    artifacts.ext = attributes.ext;
+    artifacts.hash = attributes.hash;
+
+    var mac = Crypto.calculateMac('response', credentials, artifacts);
+    if (mac !== attributes.mac) {
+        return false;
+    }
+
+    if (!options.hasOwnProperty('payload')) {
+        return true;
+    }
+
+    if (!attributes.hash) {
+        return false;
+    }
+
+    var calculatedHash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, res.headers['content-type']);
+    return (calculatedHash === attributes.hash);
+};
+
+
+// Generate a bewit value for a given URI
+
+/*
+ * credentials is an object with the following keys: 'id, 'key', 'algorithm'.
+ * options is an object with the following optional keys: 'ext', 'localtimeOffsetMsec'
+ */
+/*
+    uri: 'http://example.com/resource?a=b' or object from Url.parse()
+    options: {
+
+        // Required
+
+        credentials: {
+            id: 'dh37fgj492je',
+            key: 'aoijedoaijsdlaksjdl',
+            algorithm: 'sha256'                             // 'sha1', 'sha256'
+        },
+        ttlSec: 60 * 60,                                    // TTL in seconds
+
+        // Optional
+
+        ext: 'application-specific',                        // Application specific data sent via the ext attribute
+        localtimeOffsetMsec: 400                            // Time offset to sync with server time
+    };
+*/
+
+exports.getBewit = function (uri, options) {
+
+    // Validate inputs
+
+    if (!uri ||
+        (typeof uri !== 'string' && typeof uri !== 'object') ||
+        !options ||
+        typeof options !== 'object' ||
+        !options.ttlSec) {
+
+        return '';
+    }
+
+    options.ext = (options.ext === null || options.ext === undefined ? '' : options.ext);       // Zero is valid value
+
+    // Application time
+
+    var now = Utils.now() + (options.localtimeOffsetMsec || 0);
+
+    // Validate credentials
+
+    var credentials = options.credentials;
+    if (!credentials ||
+        !credentials.id ||
+        !credentials.key ||
+        !credentials.algorithm) {
+
+        return '';
+    }
+
+    if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+        return '';
+    }
+
+    // Parse URI
+
+    if (typeof uri === 'string') {
+        uri = Url.parse(uri);
+    }
+
+    // Calculate signature
+
+    var exp = Math.floor(now / 1000) + options.ttlSec;
+    var mac = Crypto.calculateMac('bewit', credentials, {
+        ts: exp,
+        nonce: '',
+        method: 'GET',
+        resource: uri.pathname + (uri.search || ''),                            // Maintain trailing '?'
+        host: uri.hostname,
+        port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
+        ext: options.ext
+    });
+
+    // Construct bewit: id\exp\mac\ext
+
+    var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + options.ext;
+    return Utils.base64urlEncode(bewit);
+};
+
+
+// Generate an authorization string for a message
+
+/*
+    host: 'example.com',
+    port: 8000,
+    message: '{"some":"payload"}',                          // UTF-8 encoded string for body hash generation
+    options: {
+
+        // Required
+
+        credentials: {
+            id: 'dh37fgj492je',
+            key: 'aoijedoaijsdlaksjdl',
+            algorithm: 'sha256'                             // 'sha1', 'sha256'
+        },
+
+        // Optional
+
+        timestamp: Date.now(),                              // A pre-calculated timestamp
+        nonce: '2334f34f',                                  // A pre-generated nonce
+        localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
+    }
+*/
+
+exports.message = function (host, port, message, options) {
+
+    // Validate inputs
+
+    if (!host || typeof host !== 'string' ||
+        !port || typeof port !== 'number' ||
+        message === null || message === undefined || typeof message !== 'string' ||
+        !options || typeof options !== 'object') {
+
+        return null;
+    }
+
+    // Application time
+
+    var timestamp = options.timestamp || Math.floor((Utils.now() + (options.localtimeOffsetMsec || 0)) / 1000)
+
+    // Validate credentials
+
+    var credentials = options.credentials;
+    if (!credentials ||
+        !credentials.id ||
+        !credentials.key ||
+        !credentials.algorithm) {
+
+        // Invalid credential object
+        return null;
+    }
+
+    if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+        return null;
+    }
+
+    // Calculate signature
+
+    var artifacts = {
+        ts: timestamp,
+        nonce: options.nonce || Cryptiles.randomString(6),
+        host: host,
+        port: port,
+        hash: Crypto.calculatePayloadHash(message, credentials.algorithm)
+    };
+
+    // Construct authorization
+
+    var result = {
+        id: credentials.id,
+        ts: artifacts.ts,
+        nonce: artifacts.nonce,
+        hash: artifacts.hash,
+        mac: Crypto.calculateMac('message', credentials, artifacts)
+    };
+
+    return result;
+};
+
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/crypto.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/crypto.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/crypto.js	(revision 517)
@@ -0,0 +1,111 @@
+// Load modules
+
+var Crypto = require('crypto');
+var Url = require('url');
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// MAC normalization format version
+
+exports.headerVersion = '1';                        // Prevent comparison of mac values generated with different normalized string formats
+
+
+// Supported HMAC algorithms
+
+exports.algorithms = ['sha1', 'sha256'];
+
+
+// Calculate the request MAC
+
+/*
+    type: 'header',                                 // 'header', 'bewit', 'response'
+    credentials: {
+        key: 'aoijedoaijsdlaksjdl',
+        algorithm: 'sha256'                         // 'sha1', 'sha256'
+    },
+    options: {
+        method: 'GET',
+        resource: '/resource?a=1&b=2',
+        host: 'example.com',
+        port: 8080,
+        ts: 1357718381034,
+        nonce: 'd3d345f',
+        hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=',
+        ext: 'app-specific-data',
+        app: 'hf48hd83qwkj',                        // Application id (Oz)
+        dlg: 'd8djwekds9cj'                         // Delegated by application id (Oz), requires options.app
+    }
+*/
+
+exports.calculateMac = function (type, credentials, options) {
+
+    var normalized = exports.generateNormalizedString(type, options);
+
+    var hmac = Crypto.createHmac(credentials.algorithm, credentials.key).update(normalized);
+    var digest = hmac.digest('base64');
+    return digest;
+};
+
+
+exports.generateNormalizedString = function (type, options) {
+
+    var normalized = 'hawk.' + exports.headerVersion + '.' + type + '\n' +
+                     options.ts + '\n' +
+                     options.nonce + '\n' +
+                     (options.method || '').toUpperCase() + '\n' +
+                     (options.resource || '') + '\n' +
+                     options.host.toLowerCase() + '\n' +
+                     options.port + '\n' +
+                     (options.hash || '') + '\n';
+
+    if (options.ext) {
+        normalized += options.ext.replace('\\', '\\\\').replace('\n', '\\n');
+    }
+
+    normalized += '\n';
+
+    if (options.app) {
+        normalized += options.app + '\n' +
+                      (options.dlg || '') + '\n';
+    }
+
+    return normalized;
+};
+
+
+exports.calculatePayloadHash = function (payload, algorithm, contentType) {
+
+    var hash = exports.initializePayloadHash(algorithm, contentType);
+    hash.update(payload || '');
+    return exports.finalizePayloadHash(hash);
+};
+
+
+exports.initializePayloadHash = function (algorithm, contentType) {
+
+    var hash = Crypto.createHash(algorithm);
+    hash.update('hawk.' + exports.headerVersion + '.payload\n');
+    hash.update(Utils.parseContentType(contentType) + '\n');
+    return hash;
+};
+
+
+exports.finalizePayloadHash = function (hash) {
+
+    hash.update('\n');
+    return hash.digest('base64');
+};
+
+
+exports.calculateTsMac = function (ts, credentials) {
+
+    var hmac = Crypto.createHmac(credentials.algorithm, credentials.key);
+    hmac.update('hawk.' + exports.headerVersion + '.ts\n' + ts + '\n');
+    return hmac.digest('base64');
+};
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/index.js	(revision 517)
@@ -0,0 +1,15 @@
+// Export sub-modules
+
+exports.error = exports.Error = require('boom');
+exports.sntp = require('sntp');
+exports.server = require('./server');
+exports.client = require('./client');
+exports.crypto = require('./crypto');
+exports.utils = require('./utils');
+
+exports.uri = {
+    authenticate: exports.server.authenticateBewit,
+    getBewit: exports.client.getBewit
+};
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/server.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/server.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/server.js	(revision 517)
@@ -0,0 +1,524 @@
+// Load modules
+
+var Boom = require('boom');
+var Hoek = require('hoek');
+var Cryptiles = require('cryptiles');
+var Crypto = require('./crypto');
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Hawk authentication
+
+/*
+   req:                 node's HTTP request object or an object as follows:
+  
+                        var request = {
+                            method: 'GET',
+                            url: '/resource/4?a=1&b=2',
+                            host: 'example.com',
+                            port: 8080,
+                            authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="'
+                        };
+  
+   credentialsFunc:     required function to lookup the set of Hawk credentials based on the provided credentials id.
+                        The credentials include the MAC key, MAC algorithm, and other attributes (such as username)
+                        needed by the application. This function is the equivalent of verifying the username and
+                        password in Basic authentication.
+  
+                        var credentialsFunc = function (id, callback) {
+    
+                            // Lookup credentials in database
+                            db.lookup(id, function (err, item) {
+    
+                                if (err || !item) {
+                                    return callback(err);
+                                }
+    
+                                var credentials = {
+                                    // Required
+                                    key: item.key,
+                                    algorithm: item.algorithm,
+                                    // Application specific
+                                    user: item.user
+                                };
+    
+                                return callback(null, credentials);
+                            });
+                        };
+  
+   options: {
+
+        hostHeaderName:        optional header field name, used to override the default 'Host' header when used
+                               behind a cache of a proxy. Apache2 changes the value of the 'Host' header while preserving
+                               the original (which is what the module must verify) in the 'x-forwarded-host' header field.
+                               Only used when passed a node Http.ServerRequest object.
+  
+        nonceFunc:             optional nonce validation function. The function signature is function(nonce, ts, callback)
+                               where 'callback' must be called using the signature function(err).
+  
+        timestampSkewSec:      optional number of seconds of permitted clock skew for incoming timestamps. Defaults to 60 seconds.
+                               Provides a +/- skew which means actual allowed window is double the number of seconds.
+  
+        localtimeOffsetMsec:   optional local clock time offset express in a number of milliseconds (positive or negative).
+                               Defaults to 0.
+  
+        payload:               optional payload for validation. The client calculates the hash value and includes it via the 'hash'
+                               header attribute. The server always ensures the value provided has been included in the request
+                               MAC. When this option is provided, it validates the hash value itself. Validation is done by calculating
+                               a hash value over the entire payload (assuming it has already be normalized to the same format and
+                               encoding used by the client to calculate the hash on request). If the payload is not available at the time
+                               of authentication, the authenticatePayload() method can be used by passing it the credentials and
+                               attributes.hash returned in the authenticate callback.
+
+        host:                  optional host name override. Only used when passed a node request object.
+        port:                  optional port override. Only used when passed a node request object.
+    }
+
+    callback: function (err, credentials, artifacts) { }
+ */
+
+exports.authenticate = function (req, credentialsFunc, options, callback) {
+
+    callback = Utils.nextTick(callback);
+    
+    // Default options
+
+    options.nonceFunc = options.nonceFunc || function (nonce, ts, nonceCallback) { return nonceCallback(); };   // No validation
+    options.timestampSkewSec = options.timestampSkewSec || 60;                                                  // 60 seconds
+
+    // Application time
+
+    var now = Utils.now() + (options.localtimeOffsetMsec || 0);                 // Measure now before any other processing
+
+    // Convert node Http request object to a request configuration object
+
+    var request = Utils.parseRequest(req, options);
+    if (request instanceof Error) {
+        return callback(Boom.badRequest(request.message));
+    }
+
+    // Parse HTTP Authorization header
+
+    var attributes = Utils.parseAuthorizationHeader(request.authorization);
+    if (attributes instanceof Error) {
+        return callback(attributes);
+    }
+
+    // Construct artifacts container
+
+    var artifacts = {
+        method: request.method,
+        host: request.host,
+        port: request.port,
+        resource: request.url,
+        ts: attributes.ts,
+        nonce: attributes.nonce,
+        hash: attributes.hash,
+        ext: attributes.ext,
+        app: attributes.app,
+        dlg: attributes.dlg,
+        mac: attributes.mac,
+        id: attributes.id
+    };
+
+    // Verify required header attributes
+
+    if (!attributes.id ||
+        !attributes.ts ||
+        !attributes.nonce ||
+        !attributes.mac) {
+
+        return callback(Boom.badRequest('Missing attributes'), null, artifacts);
+    }
+
+    // Fetch Hawk credentials
+
+    credentialsFunc(attributes.id, function (err, credentials) {
+
+        if (err) {
+            return callback(err, credentials || null, artifacts);
+        }
+
+        if (!credentials) {
+            return callback(Boom.unauthorized('Unknown credentials', 'Hawk'), null, artifacts);
+        }
+
+        if (!credentials.key ||
+            !credentials.algorithm) {
+
+            return callback(Boom.internal('Invalid credentials'), credentials, artifacts);
+        }
+
+        if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+            return callback(Boom.internal('Unknown algorithm'), credentials, artifacts);
+        }
+
+        // Calculate MAC
+
+        var mac = Crypto.calculateMac('header', credentials, artifacts);
+        if (!Cryptiles.fixedTimeComparison(mac, attributes.mac)) {
+            return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials, artifacts);
+        }
+
+        // Check payload hash
+
+        if (options.payload !== null &&
+            options.payload !== undefined) {       // '' is valid
+
+            if (!attributes.hash) {
+                return callback(Boom.unauthorized('Missing required payload hash', 'Hawk'), credentials, artifacts);
+            }
+
+            var hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, request.contentType);
+            if (!Cryptiles.fixedTimeComparison(hash, attributes.hash)) {
+                return callback(Boom.unauthorized('Bad payload hash', 'Hawk'), credentials, artifacts);
+            }
+        }
+
+        // Check nonce
+
+        options.nonceFunc(attributes.nonce, attributes.ts, function (err) {
+
+            if (err) {
+                return callback(Boom.unauthorized('Invalid nonce', 'Hawk'), credentials, artifacts);
+            }
+
+            // Check timestamp staleness
+
+            if (Math.abs((attributes.ts * 1000) - now) > (options.timestampSkewSec * 1000)) {
+                var fresh = Math.floor((Utils.now() + (options.localtimeOffsetMsec || 0)) / 1000);            // Get fresh now
+                var tsm = Crypto.calculateTsMac(fresh, credentials);
+                return callback(Boom.unauthorized('Stale timestamp', 'Hawk', { ts: fresh, tsm: tsm }), credentials, artifacts);
+            }
+
+            // Successful authentication
+
+            return callback(null, credentials, artifacts);
+        });
+    });
+};
+
+
+// Authenticate payload hash - used when payload cannot be provided during authenticate()
+
+/*
+    payload:        raw request payload
+    credentials:    from authenticate callback
+    artifacts:      from authenticate callback
+    contentType:    req.headers['content-type']
+*/
+
+exports.authenticatePayload = function (payload, credentials, artifacts, contentType) {
+
+    var calculatedHash = Crypto.calculatePayloadHash(payload, credentials.algorithm, contentType);
+    return Cryptiles.fixedTimeComparison(calculatedHash, artifacts.hash);
+};
+
+
+// Generate a Server-Authorization header for a given response
+
+/*
+    credentials: {},                                        // Object received from authenticate()
+    artifacts: {}                                           // Object received from authenticate(); 'mac', 'hash', and 'ext' - ignored
+    options: {
+        ext: 'application-specific',                        // Application specific data sent via the ext attribute
+        payload: '{"some":"payload"}',                      // UTF-8 encoded string for body hash generation (ignored if hash provided)
+        contentType: 'application/json',                    // Payload content-type (ignored if hash provided)
+        hash: 'U4MKKSmiVxk37JCCrAVIjV='                     // Pre-calculated payload hash
+    }
+*/
+
+exports.header = function (credentials, artifacts, options) {
+
+    // Prepare inputs
+
+    options = options || {};
+
+    if (!artifacts ||
+        typeof artifacts !== 'object' ||
+        typeof options !== 'object') {
+
+        return '';
+    }
+
+    artifacts = Hoek.clone(artifacts);
+    delete artifacts.mac;
+    artifacts.hash = options.hash;
+    artifacts.ext = options.ext;
+
+    // Validate credentials
+
+    if (!credentials ||
+        !credentials.key ||
+        !credentials.algorithm) {
+
+        // Invalid credential object
+        return '';
+    }
+
+    if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+        return '';
+    }
+
+    // Calculate payload hash
+
+    if (!artifacts.hash &&
+        options.hasOwnProperty('payload')) {
+
+        artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+    }
+
+    var mac = Crypto.calculateMac('response', credentials, artifacts);
+
+    // Construct header
+
+    var header = 'Hawk mac="' + mac + '"' +
+                 (artifacts.hash ? ', hash="' + artifacts.hash + '"' : '');
+
+    if (artifacts.ext !== null &&
+        artifacts.ext !== undefined &&
+        artifacts.ext !== '') {                       // Other falsey values allowed
+
+        header += ', ext="' + Utils.escapeHeaderAttribute(artifacts.ext) + '"';
+    }
+
+    return header;
+};
+
+
+/*
+ * Arguments and options are the same as authenticate() with the exception that the only supported options are:
+ * 'hostHeaderName', 'localtimeOffsetMsec', 'host', 'port'
+ */
+
+exports.authenticateBewit = function (req, credentialsFunc, options, callback) {
+
+    callback = Utils.nextTick(callback);
+
+    // Application time
+
+    var now = Utils.now() + (options.localtimeOffsetMsec || 0);
+
+    // Convert node Http request object to a request configuration object
+
+    var request = Utils.parseRequest(req, options);
+    if (request instanceof Error) {
+        return callback(Boom.badRequest(request.message));
+    }
+
+    // Extract bewit
+
+    //                                 1     2             3           4     
+    var resource = request.url.match(/^(\/.*)([\?&])bewit\=([^&$]*)(?:&(.+))?$/);
+    if (!resource) {
+        return callback(Boom.unauthorized(null, 'Hawk'));
+    }
+
+    // Bewit not empty
+
+    if (!resource[3]) {
+        return callback(Boom.unauthorized('Empty bewit', 'Hawk'));
+    }
+
+    // Verify method is GET
+
+    if (request.method !== 'GET' &&
+        request.method !== 'HEAD') {
+
+        return callback(Boom.unauthorized('Invalid method', 'Hawk'));
+    }
+
+    // No other authentication
+
+    if (request.authorization) {
+        return callback(Boom.badRequest('Multiple authentications', 'Hawk'));
+    }
+
+    // Parse bewit
+
+    var bewitString = Utils.base64urlDecode(resource[3]);
+    if (bewitString instanceof Error) {
+        return callback(Boom.badRequest('Invalid bewit encoding'));
+    }
+
+    // Bewit format: id\exp\mac\ext ('\' is used because it is a reserved header attribute character)
+
+    var bewitParts = bewitString.split('\\');
+    if (!bewitParts ||
+        bewitParts.length !== 4) {
+
+        return callback(Boom.badRequest('Invalid bewit structure'));
+    }
+
+    var bewit = {
+        id: bewitParts[0],
+        exp: parseInt(bewitParts[1], 10),
+        mac: bewitParts[2],
+        ext: bewitParts[3] || ''
+    };
+
+    if (!bewit.id ||
+        !bewit.exp ||
+        !bewit.mac) {
+
+        return callback(Boom.badRequest('Missing bewit attributes'));
+    }
+
+    // Construct URL without bewit
+
+    var url = resource[1];
+    if (resource[4]) {
+        url += resource[2] + resource[4];
+    }
+
+    // Check expiration
+
+    if (bewit.exp * 1000 <= now) {
+        return callback(Boom.unauthorized('Access expired', 'Hawk'), null, bewit);
+    }
+
+    // Fetch Hawk credentials
+
+    credentialsFunc(bewit.id, function (err, credentials) {
+
+        if (err) {
+            return callback(err, credentials || null, bewit.ext);
+        }
+
+        if (!credentials) {
+            return callback(Boom.unauthorized('Unknown credentials', 'Hawk'), null, bewit);
+        }
+
+        if (!credentials.key ||
+            !credentials.algorithm) {
+
+            return callback(Boom.internal('Invalid credentials'), credentials, bewit);
+        }
+
+        if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+            return callback(Boom.internal('Unknown algorithm'), credentials, bewit);
+        }
+
+        // Calculate MAC
+
+        var mac = Crypto.calculateMac('bewit', credentials, {
+            ts: bewit.exp,
+            nonce: '',
+            method: 'GET',
+            resource: url,
+            host: request.host,
+            port: request.port,
+            ext: bewit.ext
+        });
+
+        if (!Cryptiles.fixedTimeComparison(mac, bewit.mac)) {
+            return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials, bewit);
+        }
+
+        // Successful authentication
+
+        return callback(null, credentials, bewit);
+    });
+};
+
+
+/*
+ *  options are the same as authenticate() with the exception that the only supported options are:
+ * 'nonceFunc', 'timestampSkewSec', 'localtimeOffsetMsec'
+ */
+
+exports.authenticateMessage = function (host, port, message, authorization, credentialsFunc, options, callback) {
+
+    callback = Utils.nextTick(callback);
+    
+    // Default options
+
+    options.nonceFunc = options.nonceFunc || function (nonce, ts, nonceCallback) { return nonceCallback(); };   // No validation
+    options.timestampSkewSec = options.timestampSkewSec || 60;                                                  // 60 seconds
+
+    // Application time
+
+    var now = Utils.now() + (options.localtimeOffsetMsec || 0);                 // Measure now before any other processing
+
+    // Validate authorization
+    
+    if (!authorization.id ||
+        !authorization.ts ||
+        !authorization.nonce ||
+        !authorization.hash ||
+        !authorization.mac) {
+        
+            return callback(Boom.badRequest('Invalid authorization'))
+    }
+
+    // Fetch Hawk credentials
+
+    credentialsFunc(authorization.id, function (err, credentials) {
+
+        if (err) {
+            return callback(err, credentials || null);
+        }
+
+        if (!credentials) {
+            return callback(Boom.unauthorized('Unknown credentials', 'Hawk'));
+        }
+
+        if (!credentials.key ||
+            !credentials.algorithm) {
+
+            return callback(Boom.internal('Invalid credentials'), credentials);
+        }
+
+        if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+            return callback(Boom.internal('Unknown algorithm'), credentials);
+        }
+
+        // Construct artifacts container
+
+        var artifacts = {
+            ts: authorization.ts,
+            nonce: authorization.nonce,
+            host: host,
+            port: port,
+            hash: authorization.hash
+        };
+
+        // Calculate MAC
+
+        var mac = Crypto.calculateMac('message', credentials, artifacts);
+        if (!Cryptiles.fixedTimeComparison(mac, authorization.mac)) {
+            return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials);
+        }
+
+        // Check payload hash
+
+        var hash = Crypto.calculatePayloadHash(message, credentials.algorithm);
+        if (!Cryptiles.fixedTimeComparison(hash, authorization.hash)) {
+            return callback(Boom.unauthorized('Bad message hash', 'Hawk'), credentials);
+        }
+
+        // Check nonce
+
+        options.nonceFunc(authorization.nonce, authorization.ts, function (err) {
+
+            if (err) {
+                return callback(Boom.unauthorized('Invalid nonce', 'Hawk'), credentials);
+            }
+
+            // Check timestamp staleness
+
+            if (Math.abs((authorization.ts * 1000) - now) > (options.timestampSkewSec * 1000)) {
+                return callback(Boom.unauthorized('Stale timestamp'), credentials);
+            }
+
+            // Successful authentication
+
+            return callback(null, credentials);
+        });
+    });
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/utils.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/utils.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/lib/utils.js	(revision 517)
@@ -0,0 +1,183 @@
+// Load modules
+
+var Hoek = require('hoek');
+var Sntp = require('sntp');
+var Boom = require('boom');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Import Hoek Utilities
+
+internals.import = function () {
+
+    for (var i in Hoek) {
+        if (Hoek.hasOwnProperty(i)) {
+            exports[i] = Hoek[i];
+        }
+    }
+};
+
+internals.import();
+
+
+// Hawk version
+
+exports.version = function () {
+
+    return exports.loadPackage(__dirname + '/..').version;
+};
+
+
+// Extract host and port from request
+
+exports.parseHost = function (req, hostHeaderName) {
+
+    hostHeaderName = (hostHeaderName ? hostHeaderName.toLowerCase() : 'host');
+    var hostHeader = req.headers[hostHeaderName];
+    if (!hostHeader) {
+        return null;
+    }
+
+    var hostHeaderRegex;
+    if (hostHeader[0] === '[') {
+        hostHeaderRegex = /^(?:(?:\r\n)?\s)*(\[[^\]]+\])(?::(\d+))?(?:(?:\r\n)?\s)*$/;      // IPv6
+    }
+    else {
+        hostHeaderRegex = /^(?:(?:\r\n)?\s)*([^:]+)(?::(\d+))?(?:(?:\r\n)?\s)*$/;           // IPv4, hostname
+    }
+    
+    var hostParts = hostHeader.match(hostHeaderRegex);
+
+    if (!hostParts ||
+        hostParts.length !== 3 ||
+        !hostParts[1]) {
+
+        return null;
+    }
+
+    return {
+        name: hostParts[1],
+        port: (hostParts[2] ? hostParts[2] : (req.connection && req.connection.encrypted ? 443 : 80))
+    };
+};
+
+
+// Parse Content-Type header content
+
+exports.parseContentType = function (header) {
+
+    if (!header) {
+        return '';
+    }
+
+    return header.split(';')[0].trim().toLowerCase();
+};
+
+
+// Convert node's  to request configuration object
+
+exports.parseRequest = function (req, options) {
+
+    if (!req.headers) {
+        return req;
+    }
+    
+    // Obtain host and port information
+
+    if (!options.host || !options.port) {
+        var host = exports.parseHost(req, options.hostHeaderName);
+        if (!host) {
+            return new Error('Invalid Host header');
+        }
+    }
+
+    var request = {
+        method: req.method,
+        url: req.url,
+        host: options.host || host.name,
+        port: options.port || host.port,
+        authorization: req.headers.authorization,
+        contentType: req.headers['content-type'] || ''
+    };
+
+    return request;
+};
+
+
+exports.now = function () {
+
+    return Sntp.now();
+};
+
+
+// Parse Hawk HTTP Authorization header
+
+exports.parseAuthorizationHeader = function (header, keys) {
+
+    keys = keys || ['id', 'ts', 'nonce', 'hash', 'ext', 'mac', 'app', 'dlg'];
+
+    if (!header) {
+        return Boom.unauthorized(null, 'Hawk');
+    }
+
+    var headerParts = header.match(/^(\w+)(?:\s+(.*))?$/);       // Header: scheme[ something]
+    if (!headerParts) {
+        return Boom.badRequest('Invalid header syntax');
+    }
+
+    var scheme = headerParts[1];
+    if (scheme.toLowerCase() !== 'hawk') {
+        return Boom.unauthorized(null, 'Hawk');
+    }
+
+    var attributesString = headerParts[2];
+    if (!attributesString) {
+        return Boom.badRequest('Invalid header syntax');
+    }
+
+    var attributes = {};
+    var errorMessage = '';
+    var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) {
+
+        // Check valid attribute names
+
+        if (keys.indexOf($1) === -1) {
+            errorMessage = 'Unknown attribute: ' + $1;
+            return;
+        }
+
+        // Allowed attribute value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9
+
+        if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === null) {
+            errorMessage = 'Bad attribute value: ' + $1;
+            return;
+        }
+
+        // Check for duplicates
+
+        if (attributes.hasOwnProperty($1)) {
+            errorMessage = 'Duplicate attribute: ' + $1;
+            return;
+        }
+
+        attributes[$1] = $2;
+        return '';
+    });
+
+    if (verify !== '') {
+        return Boom.badRequest(errorMessage || 'Bad header format');
+    }
+
+    return attributes;
+};
+
+
+exports.unauthorized = function (message) {
+
+    return Boom.unauthorized(message, 'Hawk');
+};
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/.npmignore	(revision 517)
@@ -0,0 +1,18 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/.travis.yml
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/.travis.yml	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/.travis.yml	(revision 517)
@@ -0,0 +1,5 @@
+language: node_js
+
+node_js:
+  - 0.10
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/LICENSE	(revision 517)
@@ -0,0 +1,24 @@
+Copyright (c) 2012-2013, Walmart.
+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 name of Walmart 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 WALMART 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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/Makefile
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/Makefile	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/Makefile	(revision 517)
@@ -0,0 +1,11 @@
+test:
+	@node node_modules/lab/bin/lab
+test-cov: 
+	@node node_modules/lab/bin/lab -r threshold -t 100
+test-cov-html:
+	@node node_modules/lab/bin/lab -r html -o coverage.html
+complexity:
+	@node node_modules/complexity-report/src/cli.js -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/README.md	(revision 517)
@@ -0,0 +1,6 @@
+<a href="https://github.com/spumko"><img src="https://raw.github.com/spumko/spumko/master/images/from.png" align="right" /></a>
+![boom Logo](https://raw.github.com/spumko/boom/master/images/boom.png)
+
+HTTP-friendly error objects
+
+[![Build Status](https://secure.travis-ci.org/spumko/boom.png)](http://travis-ci.org/spumko/boom)
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/index.js	(revision 517)
@@ -0,0 +1,1 @@
+module.exports = require('./lib');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js	(revision 517)
@@ -0,0 +1,207 @@
+// Load modules
+
+var Http = require('http');
+var NodeUtil = require('util');
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports = module.exports = internals.Boom = function (/* (new Error) or (code, message) */) {
+
+    var self = this;
+
+    Hoek.assert(this.constructor === internals.Boom, 'Error must be instantiated using new');
+
+    Error.call(this);
+    this.isBoom = true;
+
+    this.response = {
+        code: 0,
+        payload: {},
+        headers: {}
+        // type: 'content-type'
+    };
+
+    if (arguments[0] instanceof Error) {
+
+        // Error
+
+        var error = arguments[0];
+
+        this.data = error;
+        this.response.code = error.code || 500;
+        if (error.message) {
+            this.message = error.message;
+        }
+    }
+    else {
+
+        // code, message
+
+        var code = arguments[0];
+        var message = arguments[1];
+
+        Hoek.assert(!isNaN(parseFloat(code)) && isFinite(code) && code >= 400, 'First argument must be a number (400+)');
+
+        this.response.code = code;
+        if (message) {
+            this.message = message;
+        }
+    }
+
+    // Response format
+
+    this.reformat();
+
+    return this;
+};
+
+NodeUtil.inherits(internals.Boom, Error);
+
+
+internals.Boom.prototype.reformat = function () {
+
+    this.response.payload.code = this.response.code;
+    this.response.payload.error = Http.STATUS_CODES[this.response.code] || 'Unknown';
+    if (this.message) {
+        this.response.payload.message = Hoek.escapeHtml(this.message);         // Prevent XSS from error message
+    }
+};
+
+
+// Utilities
+
+internals.Boom.badRequest = function (message) {
+
+    return new internals.Boom(400, message);
+};
+
+
+internals.Boom.unauthorized = function (message, scheme, attributes) {          // Or function (message, wwwAuthenticate[])
+
+    var err = new internals.Boom(401, message);
+
+    if (!scheme) {
+        return err;
+    }
+
+    var wwwAuthenticate = '';
+
+    if (typeof scheme === 'string') {
+
+        // function (message, scheme, attributes)
+
+        wwwAuthenticate = scheme;
+        if (attributes) {
+            var names = Object.keys(attributes);
+            for (var i = 0, il = names.length; i < il; ++i) {
+                if (i) {
+                    wwwAuthenticate += ',';
+                }
+
+                var value = attributes[names[i]];
+                if (value === null ||
+                    value === undefined) {              // Value can be zero
+
+                    value = '';
+                }
+                wwwAuthenticate += ' ' + names[i] + '="' + Hoek.escapeHeaderAttribute(value.toString()) + '"';
+            }
+        }
+
+        if (message) {
+            if (attributes) {
+                wwwAuthenticate += ',';
+            }
+            wwwAuthenticate += ' error="' + Hoek.escapeHeaderAttribute(message) + '"';
+        }
+        else {
+            err.isMissing = true;
+        }
+    }
+    else {
+
+        // function (message, wwwAuthenticate[])
+
+        var wwwArray = scheme;
+        for (var i = 0, il = wwwArray.length; i < il; ++i) {
+            if (i) {
+                wwwAuthenticate += ', ';
+            }
+
+            wwwAuthenticate += wwwArray[i];
+        }
+    }
+
+    err.response.headers['WWW-Authenticate'] = wwwAuthenticate;
+
+    return err;
+};
+
+
+internals.Boom.clientTimeout = function (message) {
+
+    return new internals.Boom(408, message);
+};
+
+
+internals.Boom.serverTimeout = function (message) {
+
+    return new internals.Boom(503, message);
+};
+
+
+internals.Boom.forbidden = function (message) {
+
+    return new internals.Boom(403, message);
+};
+
+
+internals.Boom.notFound = function (message) {
+
+    return new internals.Boom(404, message);
+};
+
+
+internals.Boom.internal = function (message, data) {
+
+    var err = new internals.Boom(500, message);
+
+    if (data && data.stack) {
+        err.trace = data.stack.split('\n');
+        err.outterTrace = Hoek.displayStack(1);
+    }
+    else {
+        err.trace = Hoek.displayStack(1);
+    }
+
+    err.data = data;
+    err.response.payload.message = 'An internal server error occurred';                     // Hide actual error from user
+
+    return err;
+};
+
+
+internals.Boom.passThrough = function (code, payload, contentType, headers) {
+
+    var err = new internals.Boom(500, 'Pass-through');                                      // 500 code is only used to initialize
+
+    err.data = {
+        code: code,
+        payload: payload,
+        type: contentType
+    };
+
+    err.response.code = code;
+    err.response.type = contentType;
+    err.response.headers = headers;
+    err.response.payload = payload;
+
+    return err;
+};
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/package.json	(revision 517)
@@ -0,0 +1,47 @@
+{
+  "name": "boom",
+  "description": "HTTP-friendly error objects",
+  "version": "0.4.2",
+  "author": {
+    "name": "Eran Hammer",
+    "email": "eran@hueniverse.com",
+    "url": "http://hueniverse.com"
+  },
+  "contributors": [],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/spumko/boom"
+  },
+  "main": "index",
+  "keywords": [
+    "error",
+    "http"
+  ],
+  "engines": {
+    "node": ">=0.8.0"
+  },
+  "dependencies": {
+    "hoek": "0.9.x"
+  },
+  "devDependencies": {
+    "lab": "0.1.x",
+    "complexity-report": "0.x.x"
+  },
+  "scripts": {
+    "test": "make test-cov"
+  },
+  "licenses": [
+    {
+      "type": "BSD",
+      "url": "http://github.com/spumko/boom/raw/master/LICENSE"
+    }
+  ],
+  "readme": "<a href=\"https://github.com/spumko\"><img src=\"https://raw.github.com/spumko/spumko/master/images/from.png\" align=\"right\" /></a>\n![boom Logo](https://raw.github.com/spumko/boom/master/images/boom.png)\n\nHTTP-friendly error objects\n\n[![Build Status](https://secure.travis-ci.org/spumko/boom.png)](http://travis-ci.org/spumko/boom)\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/spumko/boom/issues"
+  },
+  "homepage": "https://github.com/spumko/boom",
+  "_id": "boom@0.4.2",
+  "_from": "boom@0.4.x"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/test/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/test/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/boom/test/index.js	(revision 517)
@@ -0,0 +1,245 @@
+// Load modules
+
+var Lab = require('lab');
+var Boom = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Boom', function () {
+
+    it('returns an error with info when constructed using another error', function (done) {
+
+        var error = new Error('ka-boom');
+        error.xyz = 123;
+        var err = new Boom(error);
+        expect(err.data.xyz).to.equal(123);
+        expect(err.message).to.equal('ka-boom');
+        expect(err.response).to.deep.equal({
+            code: 500,
+            payload: {
+                code: 500,
+                error: 'Internal Server Error',
+                message: 'ka-boom'
+            },
+            headers: {}
+        });
+        done();
+    });
+
+    describe('#isBoom', function () {
+
+        it('returns true for Boom object', function (done) {
+
+            expect(Boom.badRequest().isBoom).to.equal(true);
+            done();
+        });
+
+        it('returns false for Error object', function (done) {
+
+            expect(new Error().isBoom).to.not.exist;
+            done();
+        });
+    });
+
+    describe('#badRequest', function () {
+
+        it('returns a 400 error code', function (done) {
+
+            expect(Boom.badRequest().response.code).to.equal(400);
+            done();
+        });
+
+        it('sets the message with the passed in message', function (done) {
+
+            expect(Boom.badRequest('my message').message).to.equal('my message');
+            done();
+        });
+    });
+
+    describe('#unauthorized', function () {
+
+        it('returns a 401 error code', function (done) {
+
+            var err = Boom.unauthorized();
+            expect(err.response.code).to.equal(401);
+            expect(err.response.headers).to.deep.equal({});
+            done();
+        });
+
+        it('sets the message with the passed in message', function (done) {
+
+            expect(Boom.unauthorized('my message').message).to.equal('my message');
+            done();
+        });
+
+        it('returns a WWW-Authenticate header when passed a scheme', function (done) {
+
+            var err = Boom.unauthorized('boom', 'Test');
+            expect(err.response.code).to.equal(401);
+            expect(err.response.headers['WWW-Authenticate']).to.equal('Test error="boom"');
+            done();
+        });
+
+        it('returns a WWW-Authenticate header when passed a scheme and attributes', function (done) {
+
+            var err = Boom.unauthorized('boom', 'Test', { a: 1, b: 'something', c: null, d: 0 });
+            expect(err.response.code).to.equal(401);
+            expect(err.response.headers['WWW-Authenticate']).to.equal('Test a="1", b="something", c="", d="0", error="boom"');
+            done();
+        });
+
+        it('sets the isMissing flag when error message is empty', function (done) {
+
+            var err = Boom.unauthorized('', 'Basic');
+            expect(err.isMissing).to.equal(true);
+            done();
+        });
+
+        it('does not set the isMissing flag when error message is not empty', function (done) {
+
+            var err = Boom.unauthorized('message', 'Basic');
+            expect(err.isMissing).to.equal(undefined);
+            done();
+        });
+
+        it('sets a WWW-Authenticate when passed as an array', function (done) {
+
+            var err = Boom.unauthorized('message', ['Basic', 'Example e="1"', 'Another x="3", y="4"']);
+            expect(err.response.headers['WWW-Authenticate']).to.equal('Basic, Example e="1", Another x="3", y="4"');
+            done();
+        });
+    });
+
+    describe('#clientTimeout', function () {
+
+        it('returns a 408 error code', function (done) {
+
+            expect(Boom.clientTimeout().response.code).to.equal(408);
+            done();
+        });
+
+        it('sets the message with the passed in message', function (done) {
+
+            expect(Boom.clientTimeout('my message').message).to.equal('my message');
+            done();
+        });
+    });
+
+    describe('#serverTimeout', function () {
+
+        it('returns a 503 error code', function (done) {
+
+            expect(Boom.serverTimeout().response.code).to.equal(503);
+            done();
+        });
+
+        it('sets the message with the passed in message', function (done) {
+
+            expect(Boom.serverTimeout('my message').message).to.equal('my message');
+            done();
+        });
+    });
+
+    describe('#forbidden', function () {
+
+        it('returns a 403 error code', function (done) {
+
+            expect(Boom.forbidden().response.code).to.equal(403);
+            done();
+        });
+
+        it('sets the message with the passed in message', function (done) {
+
+            expect(Boom.forbidden('my message').message).to.equal('my message');
+            done();
+        });
+    });
+
+    describe('#notFound', function () {
+
+        it('returns a 404 error code', function (done) {
+
+            expect(Boom.notFound().response.code).to.equal(404);
+            done();
+        });
+
+        it('sets the message with the passed in message', function (done) {
+
+            expect(Boom.notFound('my message').message).to.equal('my message');
+            done();
+        });
+    });
+
+    describe('#internal', function () {
+
+        it('returns a 500 error code', function (done) {
+
+            expect(Boom.internal().response.code).to.equal(500);
+            done();
+        });
+
+        it('sets the message with the passed in message', function (done) {
+
+            var err = Boom.internal('my message');
+            expect(err.message).to.equal('my message');
+            expect(err.response.payload.message).to.equal('An internal server error occurred');
+            done();
+        });
+
+        it('passes data on the callback if its passed in', function (done) {
+
+            expect(Boom.internal('my message', { my: 'data' }).data.my).to.equal('data');
+            done();
+        });
+
+        it('uses passed in stack if its available', function (done) {
+
+            var error = new Error();
+            error.stack = 'my stack line\nmy second stack line';
+            expect(Boom.internal('my message', error).trace[0]).to.equal('my stack line');
+            done();
+        });
+    });
+
+    describe('#passThrough', function () {
+
+        it('returns a pass-through error', function (done) {
+
+            var err = Boom.passThrough(499, { a: 1 }, 'application/text', { 'X-Test': 'Boom' });
+            expect(err.response.code).to.equal(499);
+            expect(err.message).to.equal('Pass-through');
+            expect(err.response).to.deep.equal({
+                code: 499,
+                payload: { a: 1 },
+                headers: { 'X-Test': 'Boom' },
+                type: 'application/text'
+            });
+            done();
+        });
+    });
+
+    describe('#reformat', function () {
+
+        it('encodes any HTML markup in the response payload', function (done) {
+
+            var boom = new Boom(new Error('<script>alert(1)</script>'));
+            expect(boom.response.payload.message).to.not.contain('<script>');
+            done();
+        });
+    });
+});
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/.npmignore	(revision 517)
@@ -0,0 +1,18 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/.travis.yml
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/.travis.yml	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/.travis.yml	(revision 517)
@@ -0,0 +1,5 @@
+language: node_js
+
+node_js:
+  - 0.10
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/LICENSE	(revision 517)
@@ -0,0 +1,24 @@
+Copyright (c) 2012-2013, Eran Hammer.
+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 name of Eran Hammer 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 ERAN HAMMER 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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/Makefile
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/Makefile	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/Makefile	(revision 517)
@@ -0,0 +1,11 @@
+test:
+	@./node_modules/.bin/lab
+test-cov: 
+	@./node_modules/.bin/lab -r threshold -t 100
+test-cov-html:
+	@./node_modules/.bin/lab -r html -o coverage.html
+complexity:
+	@./node_modules/.bin/cr -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/README.md	(revision 517)
@@ -0,0 +1,6 @@
+cryptiles
+=========
+
+General purpose crypto utilities
+
+[![Build Status](https://secure.travis-ci.org/hueniverse/cryptiles.png)](http://travis-ci.org/hueniverse/cryptiles)
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/index.js	(revision 517)
@@ -0,0 +1,1 @@
+module.exports = require('./lib');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js	(revision 517)
@@ -0,0 +1,68 @@
+// Load modules
+
+var Crypto = require('crypto');
+var Boom = require('boom');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Generate a cryptographically strong pseudo-random data
+
+exports.randomString = function (size) {
+
+    var buffer = exports.randomBits((size + 1) * 6);
+    if (buffer instanceof Error) {
+        return buffer;
+    }
+
+    var string = buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
+    return string.slice(0, size);
+};
+
+
+exports.randomBits = function (bits) {
+
+    if (!bits ||
+        bits < 0) {
+
+        return Boom.internal('Invalid random bits count');
+    }
+
+    var bytes = Math.ceil(bits / 8);
+    try {
+        return Crypto.randomBytes(bytes);
+    }
+    catch (err) {
+        return Boom.internal('Failed generating random bits: ' + err.message);
+    }
+};
+
+
+// Compare two strings using fixed time algorithm (to prevent time-based analysis of MAC digest match)
+
+exports.fixedTimeComparison = function (a, b) {
+
+    if (typeof a !== 'string' ||
+        typeof b !== 'string') {
+
+        return false;
+    }
+
+    var mismatch = (a.length === b.length ? 0 : 1);
+    if (mismatch) {
+        b = a;
+    }
+
+    for (var i = 0, il = a.length; i < il; ++i) {
+        var ac = a.charCodeAt(i);
+        var bc = b.charCodeAt(i);
+        mismatch += (ac === bc ? 0 : 1);
+    }
+
+    return (mismatch === 0);
+};
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json	(revision 517)
@@ -0,0 +1,48 @@
+{
+  "name": "cryptiles",
+  "description": "General purpose crypto utilities",
+  "version": "0.2.2",
+  "author": {
+    "name": "Eran Hammer",
+    "email": "eran@hueniverse.com",
+    "url": "http://hueniverse.com"
+  },
+  "contributors": [],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hueniverse/cryptiles"
+  },
+  "main": "index",
+  "keywords": [
+    "cryptography",
+    "security",
+    "utilites"
+  ],
+  "engines": {
+    "node": ">=0.8.0"
+  },
+  "dependencies": {
+    "boom": "0.4.x"
+  },
+  "devDependencies": {
+    "lab": "0.1.x",
+    "complexity-report": "0.x.x"
+  },
+  "scripts": {
+    "test": "make test-cov"
+  },
+  "licenses": [
+    {
+      "type": "BSD",
+      "url": "http://github.com/hueniverse/cryptiles/raw/master/LICENSE"
+    }
+  ],
+  "readme": "cryptiles\n=========\n\nGeneral purpose crypto utilities\n\n[![Build Status](https://secure.travis-ci.org/hueniverse/cryptiles.png)](http://travis-ci.org/hueniverse/cryptiles)\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/hueniverse/cryptiles/issues"
+  },
+  "homepage": "https://github.com/hueniverse/cryptiles",
+  "_id": "cryptiles@0.2.2",
+  "_from": "cryptiles@0.2.x"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/test/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/test/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/cryptiles/test/index.js	(revision 517)
@@ -0,0 +1,101 @@
+// Load modules
+
+var Lab = require('lab');
+var Cryptiles = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Cryptiles', function () {
+
+    describe('#randomString', function () {
+
+        it('should generate the right length string', function (done) {
+
+            for (var i = 1; i <= 1000; ++i) {
+                expect(Cryptiles.randomString(i).length).to.equal(i);
+            }
+
+            done();
+        });
+
+        it('returns an error on invalid bits size', function (done) {
+
+            expect(Cryptiles.randomString(99999999999999999999).message).to.equal('Failed generating random bits: Argument #1 must be number > 0');
+            done();
+        });
+    });
+
+    describe('#randomBits', function () {
+
+        it('returns an error on invalid input', function (done) {
+
+            expect(Cryptiles.randomBits(0).message).to.equal('Invalid random bits count');
+            done();
+        });
+    });
+
+    describe('#fixedTimeComparison', function () {
+
+        var a = Cryptiles.randomString(50000);
+        var b = Cryptiles.randomString(150000);
+
+        it('should take the same amount of time comparing different string sizes', function (done) {
+
+            var now = Date.now();
+            Cryptiles.fixedTimeComparison(b, a);
+            var t1 = Date.now() - now;
+
+            now = Date.now();
+            Cryptiles.fixedTimeComparison(b, b);
+            var t2 = Date.now() - now;
+
+            expect(t2 - t1).to.be.within(-20, 20);
+            done();
+        });
+
+        it('should return true for equal strings', function (done) {
+
+            expect(Cryptiles.fixedTimeComparison(a, a)).to.equal(true);
+            done();
+        });
+
+        it('should return false for different strings (size, a < b)', function (done) {
+
+            expect(Cryptiles.fixedTimeComparison(a, a + 'x')).to.equal(false);
+            done();
+        });
+
+        it('should return false for different strings (size, a > b)', function (done) {
+
+            expect(Cryptiles.fixedTimeComparison(a + 'x', a)).to.equal(false);
+            done();
+        });
+
+        it('should return false for different strings (size, a = b)', function (done) {
+
+            expect(Cryptiles.fixedTimeComparison(a + 'x', a + 'y')).to.equal(false);
+            done();
+        });
+
+        it('should return false when not a string', function (done) {
+
+            expect(Cryptiles.fixedTimeComparison('x', null)).to.equal(false);
+            done();
+        });
+    });
+});
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/.npmignore	(revision 517)
@@ -0,0 +1,18 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+complexity.md
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/.travis.yml
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/.travis.yml	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/.travis.yml	(revision 517)
@@ -0,0 +1,5 @@
+language: node_js
+
+node_js:
+  - 0.10
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/LICENSE	(revision 517)
@@ -0,0 +1,33 @@
+Copyright (c) 2011-2013, Walmart.
+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 name of Walmart 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 WALMART 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.
+
+
+                                  *   *   *
+
+
+Portions of this project were initially based on Postmile, Copyright (c) 2011, Yahoo Inc.
+Postmile is published at https://github.com/yahoo/postmile and its licensing terms are
+published at https://github.com/yahoo/postmile/blob/master/LICENSE.
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/Makefile
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/Makefile	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/Makefile	(revision 517)
@@ -0,0 +1,10 @@
+test:
+	@node node_modules/lab/bin/lab
+test-cov: 
+	@node node_modules/lab/bin/lab -r threshold -t 100
+test-cov-html:
+	@node node_modules/lab/bin/lab -r html -o coverage.html
+complexity:
+	@node node_modules/complexity-report/src/cli.js -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/README.md	(revision 517)
@@ -0,0 +1,436 @@
+<a href="https://github.com/spumko"><img src="https://raw.github.com/spumko/spumko/master/images/from.png" align="right" /></a>
+![hoek Logo](https://raw.github.com/spumko/hoek/master/images/hoek.png)
+
+General purpose node utilities
+
+[![Build Status](https://secure.travis-ci.org/spumko/hoek.png)](http://travis-ci.org/spumko/hoek)
+
+# Table of Contents
+
+* [Introduction](#introduction "Introduction")
+* [Object](#object "Object")
+  * [clone](#cloneobj "clone")
+  * [merge](#mergetarget-source-isnulloverride-ismergearrays "merge")
+  * [applyToDefaults](#applytodefaultsdefaults-options "applyToDefaults")
+  * [unique](#uniquearray-key "unique")
+  * [mapToObject](#maptoobjectarray-key "mapToObject")
+  * [intersect](#intersectarray1-array2 "intersect")
+  * [matchKeys](#matchkeysobj-keys "matchKeys")
+  * [flatten](#flattenarray-target "flatten")
+  * [removeKeys](#removekeysobject-keys "removeKeys")
+  * [reach](#reachobj-chain "reach")
+  * [inheritAsync](#inheritasyncself-obj-keys "inheritAsync")
+  * [rename](#renameobj-from-to "rename")
+* [Timer](#timer "Timer")
+* [Binary Encoding/Decoding](#binary "Binary Encoding/Decoding")
+  * [base64urlEncode](#binary64urlEncodevalue "binary64urlEncode")
+  * [base64urlDecode](#binary64urlDecodevalue "binary64urlDecode")
+* [Escaping Characters](#escaped "Escaping Characters")
+  * [escapeHtml](#escapeHtmlstring "escapeHtml")
+  * [escapeHeaderAttribute](#escapeHeaderAttributeattribute "escapeHeaderAttribute")
+  * [escapeRegex](#escapeRegexstring "escapeRegex")
+* [Errors](#errors "Errors")
+  * [assert](#assertmessage "assert")
+  * [abort](#abortmessage "abort")
+  * [displayStack](#displayStackslice "displayStack")
+  * [callStack](#callStackslice "callStack")
+  * [toss](#tosscondition "toss")
+* [Load files](#load-files "Load Files")
+  * [loadPackage](#loadPackagedir "loadpackage")
+  * [loadDirModules](#loadDirModulespath-excludefiles-target "loaddirmodules")
+
+
+
+# Introduction
+
+The *Hoek* general purpose node utilities library is used to aid in a variety of manners. It comes with useful methods for Arrays (clone, merge, applyToDefaults), Objects (removeKeys, copy), Asserting and more. 
+
+For example, to use Hoek to set configuration with default options:
+```javascript
+var Hoek = require('hoek');
+
+var default = {url : "www.github.com", port : "8000", debug : true}
+
+var config = Hoek.applyToDefaults(default, {port : "3000", admin : true});
+
+// In this case, config would be { url: 'www.github.com', port: '3000', debug: true, admin: true }
+```
+
+Under each of the sections (such as Array), there are subsections which correspond to Hoek methods. Each subsection will explain how to use the corresponding method. In each js excerpt below, the var Hoek = require('hoek') is omitted for brevity.
+
+## Object
+
+Hoek provides several helpful methods for objects and arrays.
+
+### clone(obj)
+
+This method is used to clone an object or an array. A *deep copy* is made (duplicates everything, including values that are objects). 
+
+```javascript
+
+var nestedObj = {
+        w: /^something$/ig,
+        x: {
+            a: [1, 2, 3],
+            b: 123456,
+            c: new Date()
+        },
+        y: 'y',
+        z: new Date()
+    };
+
+var copy = Hoek.clone(nestedObj);
+
+copy.x.b = 100;
+
+console.log(copy.y)        // results in 'y'
+console.log(nestedObj.x.b) // results in 123456
+console.log(copy.x.b)      // results in 100
+```
+
+### merge(target, source, isNullOverride, isMergeArrays)
+isNullOverride, isMergeArrays default to true
+
+Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied
+
+
+```javascript
+
+var target = {a: 1, b : 2}
+var source = {a: 0, c: 5}
+var source2 = {a: null, c: 5}
+
+var targetArray = [1, 2, 3];
+var sourceArray = [4, 5];
+
+var newTarget = Hoek.merge(target, source);     // results in {a: 0, b: 2, c: 5}
+newTarget = Hoek.merge(target, source2);        // results in {a: null, b: 2, c: 5}
+newTarget = Hoek.merge(target, source2, false); // results in {a: 1, b: 2, c: 5}
+
+newTarget = Hoek.merge(targetArray, sourceArray)              // results in [1, 2, 3, 4, 5]
+newTarget = Hoek.merge(targetArray, sourceArray, true, false) // results in [4, 5]
+
+
+
+
+```
+
+### applyToDefaults(defaults, options)
+
+Apply options to a copy of the defaults
+
+```javascript
+
+var defaults = {host: "localhost", port: 8000};
+var options = {port: 8080};
+
+var config = Hoek.applyToDefaults(defaults, options); // results in {host: "localhost", port: 8080};
+
+
+```
+
+### unique(array, key)
+
+Remove duplicate items from Array
+
+```javascript
+
+var array = [1, 2, 2, 3, 3, 4, 5, 6];
+
+var newArray = Hoek.unique(array); // results in [1,2,3,4,5,6];
+
+array = [{id: 1}, {id: 1}, {id: 2}];
+
+newArray = Hoek.unique(array, "id") // results in [{id: 1}, {id: 2}]
+
+```
+
+### mapToObject(array, key)
+
+Convert an Array into an Object
+
+```javascript
+
+var array = [1,2,3];
+var newObject = Hoek.mapToObject(array); // results in [{"1": true}, {"2": true}, {"3": true}]
+
+array = [{id: 1}, {id: 2}];
+newObject = Hoek.mapToObject(array, "id") // results in [{"id": 1}, {"id": 2}]
+
+```
+### intersect(array1, array2)
+
+Find the common unique items in two arrays
+
+```javascript
+
+var array1 = [1, 2, 3];
+var array2 = [1, 4, 5];
+
+var newArray = Hoek.intersect(array1, array2) // results in [1]
+
+```
+
+### matchKeys(obj, keys) 
+
+Find which keys are present
+
+```javascript
+
+var obj = {a: 1, b: 2, c: 3};
+var keys = ["a", "e"];
+
+Hoek.matchKeys(obj, keys) // returns ["a"]
+
+```
+
+### flatten(array, target)
+
+Flatten an array
+
+```javascript
+
+var array = [1, 2, 3];
+var target = [4, 5]; 
+
+var flattenedArray = Hoek.flatten(array, target) // results in [4, 5, 1, 2, 3];
+
+```
+
+### removeKeys(object, keys)
+
+Remove keys
+
+```javascript
+
+var object = {a: 1, b: 2, c: 3, d: 4};
+
+var keys = ["a", "b"];
+
+Hoek.removeKeys(object, keys) // object is now {c: 3, d: 4}
+
+```
+
+### reach(obj, chain)
+
+Converts an object key chain string to reference
+
+```javascript
+
+var chain = 'a.b.c';
+var obj = {a : {b : { c : 1}}};
+
+Hoek.reach(obj, chain) // returns 1
+
+```
+
+### inheritAsync(self, obj, keys) 
+
+Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors
+
+```javascript
+
+var targetFunc = function () { };
+
+var proto = {
+                a: function () {
+                    return 'a!';
+                },
+                b: function () {
+                    return 'b!';
+                },
+                c: function () {
+                    throw new Error('c!');
+                }
+            };
+
+var keys = ['a', 'c'];
+
+Hoek.inheritAsync(targetFunc, proto, ['a', 'c']);
+
+var target = new targetFunc();
+
+target.a(function(err, result){console.log(result)}         // returns 'a!'       
+
+target.c(function(err, result){console.log(result)}         // returns undefined
+
+target.b(function(err, result){console.log(result)}         // gives error: Object [object Object] has no method 'b'
+
+```
+
+### rename(obj, from, to)
+
+Rename a key of an object
+
+```javascript
+
+var obj = {a : 1, b : 2};
+
+Hoek.rename(obj, "a", "c");     // obj is now {c : 1, b : 2}
+
+```
+
+
+# Timer
+
+A Timer object. Initializing a new timer object sets the ts to the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.
+
+```javascript
+
+
+example : 
+
+
+var timerObj = new Hoek.Timer();
+console.log("Time is now: " + timerObj.ts)
+console.log("Elapsed time from initialization: " + timerObj.elapsed() + 'milliseconds')
+
+```
+
+# Binary Encoding/Decoding
+
+### base64urlEncode(value)
+
+Encodes value in Base64 or URL encoding
+
+### base64urlDecode(value)
+
+Decodes data in Base64 or URL encoding.
+# Escaping Characters
+
+Hoek provides convenient methods for escaping html characters. The escaped characters are as followed:
+
+```javascript
+
+internals.htmlEscaped = {
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;',
+    '"': '&quot;',
+    "'": '&#x27;',
+    '`': '&#x60;'
+};
+
+```
+
+### escapeHtml(string)
+
+```javascript
+
+var string = '<html> hey </html>';
+var escapedString = Hoek.escapeHtml(string); // returns &lt;html&gt; hey &lt;/html&gt;
+
+```
+
+### escapeHeaderAttribute(attribute)
+
+Escape attribute value for use in HTTP header
+
+```javascript
+
+var a = Hoek.escapeHeaderAttribute('I said "go w\\o me"');  //returns I said \"go w\\o me\"
+
+
+```
+
+
+### escapeRegex(string)
+
+Escape string for Regex construction
+
+```javascript
+
+var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');  // returns 4\^f\$s\.4\*5\+\-_\?%\=#\!\:@\|~\\\/`"\(>\)\[<\]d\{\}s\,
+
+
+
+```
+
+# Errors
+
+### assert(message)
+
+```javascript
+
+var a = 1, b =2;
+
+Hoek.assert(a === b, 'a should equal b');  // ABORT: a should equal b
+
+```
+
+### abort(message)
+
+First checks if process.env.NODE_ENV === 'test', and if so, throws error message. Otherwise,
+displays most recent stack and then exits process.
+
+
+
+### displayStack(slice)
+
+Displays the trace stack
+
+```javascript
+
+var stack = Hoek.displayStack();
+console.log(stack) // returns something like:
+
+[ 'null (/Users/user/Desktop/hoek/test.js:4:18)',
+  'Module._compile (module.js:449:26)',
+  'Module._extensions..js (module.js:467:10)',
+  'Module.load (module.js:356:32)',
+  'Module._load (module.js:312:12)',
+  'Module.runMain (module.js:492:10)',
+  'startup.processNextTick.process._tickCallback (node.js:244:9)' ]
+
+```
+
+### callStack(slice)
+
+Returns a trace stack array.
+
+```javascript
+
+var stack = Hoek.callStack();
+console.log(stack)  // returns something like:
+
+[ [ '/Users/user/Desktop/hoek/test.js', 4, 18, null, false ],
+  [ 'module.js', 449, 26, 'Module._compile', false ],
+  [ 'module.js', 467, 10, 'Module._extensions..js', false ],
+  [ 'module.js', 356, 32, 'Module.load', false ],
+  [ 'module.js', 312, 12, 'Module._load', false ],
+  [ 'module.js', 492, 10, 'Module.runMain', false ],
+  [ 'node.js',
+    244,
+    9,
+    'startup.processNextTick.process._tickCallback',
+    false ] ]
+
+
+```
+
+### toss(condition)
+
+toss(condition /*, [message], callback */)
+
+Return an error as first argument of a callback
+
+
+# Load Files
+
+### loadPackage(dir)
+
+Load and parse package.json process root or given directory
+
+```javascript
+
+var pack = Hoek.loadPackage();  // pack.name === 'hoek'
+
+```
+
+### loadDirModules(path, excludeFiles, target) 
+
+Loads modules from a given path; option to exclude files (array).
+
+
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/index.js	(revision 517)
@@ -0,0 +1,1 @@
+module.exports = require('./lib');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js	(revision 517)
@@ -0,0 +1,132 @@
+// Declare internals
+
+var internals = {};
+
+
+exports.escapeJavaScript = function (input) {
+
+    if (!input) {
+        return '';
+    }
+
+    var escaped = '';
+
+    for (var i = 0, il = input.length; i < il; ++i) {
+
+        var charCode = input.charCodeAt(i);
+
+        if (internals.isSafe(charCode)) {
+            escaped += input[i];
+        }
+        else {
+            escaped += internals.escapeJavaScriptChar(charCode);
+        }
+    }
+
+    return escaped;
+};
+
+
+exports.escapeHtml = function (input) {
+
+    if (!input) {
+        return '';
+    }
+
+    var escaped = '';
+
+    for (var i = 0, il = input.length; i < il; ++i) {
+
+        var charCode = input.charCodeAt(i);
+
+        if (internals.isSafe(charCode)) {
+            escaped += input[i];
+        }
+        else {
+            escaped += internals.escapeHtmlChar(charCode);
+        }
+    }
+
+    return escaped;
+};
+
+
+internals.escapeJavaScriptChar = function (charCode) {
+
+    if (charCode >= 256) {
+        return '\\u' + internals.padLeft('' + charCode, 4);
+    }
+
+    var hexValue = new Buffer(String.fromCharCode(charCode), 'ascii').toString('hex');
+    return '\\x' + internals.padLeft(hexValue, 2);
+};
+
+
+internals.escapeHtmlChar = function (charCode) {
+
+    var namedEscape = internals.namedHtml[charCode];
+    if (typeof namedEscape !== 'undefined') {
+        return namedEscape;
+    }
+
+    if (charCode >= 256) {
+        return '&#' + charCode + ';';
+    }
+
+    var hexValue = new Buffer(String.fromCharCode(charCode), 'ascii').toString('hex');
+    return '&#x' + internals.padLeft(hexValue, 2) + ';';
+};
+
+
+internals.padLeft = function (str, len) {
+
+    while (str.length < len) {
+        str = '0' + str;
+    }
+
+    return str;
+};
+
+
+internals.isSafe = function (charCode) {
+
+    return (typeof internals.safeCharCodes[charCode] !== 'undefined');
+};
+
+
+internals.namedHtml = {
+    '38': '&amp;',
+    '60': '&lt;',
+    '62': '&gt;',
+    '34': '&quot;',
+    '160': '&nbsp;',
+    '162': '&cent;',
+    '163': '&pound;',
+    '164': '&curren;',
+    '169': '&copy;',
+    '174': '&reg;'
+};
+
+
+internals.safeCharCodes = (function () {
+
+    var safe = {};
+
+    for (var i = 32; i < 123; ++i) {
+
+        if ((i >= 97 && i <= 122) ||         // a-z
+            (i >= 65 && i <= 90) ||          // A-Z
+            (i >= 48 && i <= 57) ||          // 0-9
+            i === 32 ||                      // space
+            i === 46 ||                      // .
+            i === 44 ||                      // ,
+            i === 45 ||                      // -
+            i === 58 ||                      // :
+            i === 95) {                      // _
+
+            safe[i] = null;
+        }
+    }
+
+    return safe;
+}());
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js	(revision 517)
@@ -0,0 +1,585 @@
+// Load modules
+
+var Fs = require('fs');
+var Escape = require('./escape');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Clone object or array
+
+exports.clone = function (obj, seen) {
+
+    if (typeof obj !== 'object' ||
+        obj === null) {
+
+        return obj;
+    }
+
+    seen = seen || { orig: [], copy: [] };
+
+    var lookup = seen.orig.indexOf(obj);
+    if (lookup !== -1) {
+        return seen.copy[lookup];
+    }
+
+    var newObj = (obj instanceof Array) ? [] : {};
+
+    seen.orig.push(obj);
+    seen.copy.push(newObj);
+
+    for (var i in obj) {
+        if (obj.hasOwnProperty(i)) {
+            if (obj[i] instanceof Buffer) {
+                newObj[i] = new Buffer(obj[i]);
+            }
+            else if (obj[i] instanceof Date) {
+                newObj[i] = new Date(obj[i].getTime());
+            }
+            else if (obj[i] instanceof RegExp) {
+                var flags = '' + (obj[i].global ? 'g' : '') + (obj[i].ignoreCase ? 'i' : '') + (obj[i].multiline ? 'm' : '');
+                newObj[i] = new RegExp(obj[i].source, flags);
+            }
+            else {
+                newObj[i] = exports.clone(obj[i], seen);
+            }
+        }
+    }
+
+    return newObj;
+};
+
+
+// Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied
+
+exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {
+
+    exports.assert(target && typeof target == 'object', 'Invalid target value: must be an object');
+    exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
+
+    if (!source) {
+        return target;
+    }
+
+    if (source instanceof Array) {
+        exports.assert(target instanceof Array, 'Cannot merge array onto an object');
+        if (isMergeArrays === false) {                                                  // isMergeArrays defaults to true
+            target.length = 0;                                                          // Must not change target assignment
+        }
+
+        for (var i = 0, il = source.length; i < il; ++i) {
+            target.push(source[i]);
+        }
+
+        return target;
+    }
+
+    var keys = Object.keys(source);
+    for (var k = 0, kl = keys.length; k < kl; ++k) {
+        var key = keys[k];
+        var value = source[key];
+        if (value &&
+            typeof value === 'object') {
+
+            if (!target[key] ||
+                typeof target[key] !== 'object') {
+
+                target[key] = exports.clone(value);
+            }
+            else {
+                exports.merge(target[key], source[key], isNullOverride, isMergeArrays);
+            }
+        }
+        else {
+            if (value !== null && value !== undefined) {            // Explicit to preserve empty strings
+                target[key] = value;
+            }
+            else if (isNullOverride !== false) {                    // Defaults to true
+                target[key] = value;
+            }
+        }
+    }
+
+    return target;
+};
+
+
+// Apply options to a copy of the defaults
+
+exports.applyToDefaults = function (defaults, options) {
+
+    exports.assert(defaults && typeof defaults == 'object', 'Invalid defaults value: must be an object');
+    exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
+
+    if (!options) {                                                 // If no options, return null
+        return null;
+    }
+
+    var copy = exports.clone(defaults);
+
+    if (options === true) {                                         // If options is set to true, use defaults
+        return copy;
+    }
+
+    return exports.merge(copy, options, false, false);
+};
+
+
+// Remove duplicate items from array
+
+exports.unique = function (array, key) {
+
+    var index = {};
+    var result = [];
+
+    for (var i = 0, il = array.length; i < il; ++i) {
+        var id = (key ? array[i][key] : array[i]);
+        if (index[id] !== true) {
+
+            result.push(array[i]);
+            index[id] = true;
+        }
+    }
+
+    return result;
+};
+
+
+// Convert array into object
+
+exports.mapToObject = function (array, key) {
+
+    if (!array) {
+        return null;
+    }
+
+    var obj = {};
+    for (var i = 0, il = array.length; i < il; ++i) {
+        if (key) {
+            if (array[i][key]) {
+                obj[array[i][key]] = true;
+            }
+        }
+        else {
+            obj[array[i]] = true;
+        }
+    }
+
+    return obj;
+};
+
+
+// Find the common unique items in two arrays
+
+exports.intersect = function (array1, array2, justFirst) {
+
+    if (!array1 || !array2) {
+        return [];
+    }
+
+    var common = [];
+    var hash = (array1 instanceof Array ? exports.mapToObject(array1) : array1);
+    var found = {};
+    for (var i = 0, il = array2.length; i < il; ++i) {
+        if (hash[array2[i]] && !found[array2[i]]) {
+            if (justFirst) {
+                return array2[i];
+            }
+
+            common.push(array2[i]);
+            found[array2[i]] = true;
+        }
+    }
+
+    return (justFirst ? null : common);
+};
+
+
+// Find which keys are present
+
+exports.matchKeys = function (obj, keys) {
+
+    var matched = [];
+    for (var i = 0, il = keys.length; i < il; ++i) {
+        if (obj.hasOwnProperty(keys[i])) {
+            matched.push(keys[i]);
+        }
+    }
+    return matched;
+};
+
+
+// Flatten array
+
+exports.flatten = function (array, target) {
+
+    var result = target || [];
+
+    for (var i = 0, il = array.length; i < il; ++i) {
+        if (Array.isArray(array[i])) {
+            exports.flatten(array[i], result);
+        }
+        else {
+            result.push(array[i]);
+        }
+    }
+
+    return result;
+};
+
+
+// Remove keys
+
+exports.removeKeys = function (object, keys) {
+
+    for (var i = 0, il = keys.length; i < il; i++) {
+        delete object[keys[i]];
+    }
+};
+
+
+// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])
+
+exports.reach = function (obj, chain) {
+
+    var path = chain.split('.');
+    var ref = obj;
+    for (var i = 0, il = path.length; i < il; ++i) {
+        if (ref) {
+            ref = ref[path[i]];
+        }
+    }
+
+    return ref;
+};
+
+
+// Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors
+
+exports.inheritAsync = function (self, obj, keys) {
+
+    keys = keys || null;
+
+    for (var i in obj) {
+        if (obj.hasOwnProperty(i)) {
+            if (keys instanceof Array &&
+                keys.indexOf(i) < 0) {
+
+                continue;
+            }
+
+            self.prototype[i] = (function (fn) {
+
+                return function (next) {
+
+                    var result = null;
+                    try {
+                        result = fn();
+                    }
+                    catch (err) {
+                        return next(err);
+                    }
+
+                    return next(null, result);
+                };
+            })(obj[i]);
+        }
+    }
+};
+
+
+exports.formatStack = function (stack) {
+
+    var trace = [];
+    for (var i = 0, il = stack.length; i < il; ++i) {
+        var item = stack[i];
+        trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
+    }
+
+    return trace;
+};
+
+
+exports.formatTrace = function (trace) {
+
+    var display = [];
+
+    for (var i = 0, il = trace.length; i < il; ++i) {
+        var row = trace[i];
+        display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
+    }
+
+    return display;
+};
+
+
+exports.callStack = function (slice) {
+
+    // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+
+    var v8 = Error.prepareStackTrace;
+    Error.prepareStackTrace = function (err, stack) {
+
+        return stack;
+    };
+
+    var capture = {};
+    Error.captureStackTrace(capture, arguments.callee);
+    var stack = capture.stack;
+
+    Error.prepareStackTrace = v8;
+
+    var trace = exports.formatStack(stack);
+
+    if (slice) {
+        return trace.slice(slice);
+    }
+
+    return trace;
+};
+
+
+exports.displayStack = function (slice) {
+
+    var trace = exports.callStack(slice === undefined ? 1 : slice + 1);
+
+    return exports.formatTrace(trace);
+};
+
+
+exports.abortThrow = false;
+
+
+exports.abort = function (message, hideStack) {
+
+    if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
+        throw new Error(message || 'Unknown error');
+    }
+
+    var stack = '';
+    if (!hideStack) {
+        stack = exports.displayStack(1).join('\n\t');
+    }
+    console.log('ABORT: ' + message + '\n\t' + stack);
+    process.exit(1);
+};
+
+
+exports.assert = function (condition /*, msg1, msg2, msg3 */) {
+
+    if (condition) {
+        return;
+    }
+
+    var msgs = Array.prototype.slice.call(arguments, 1);
+    msgs = msgs.map(function (msg) {
+
+        return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : JSON.stringify(msg);
+    });
+    throw new Error(msgs.join(' ') || 'Unknown error');
+};
+
+
+exports.loadDirModules = function (path, excludeFiles, target) {      // target(filename, name, capName)
+
+    var exclude = {};
+    for (var i = 0, il = excludeFiles.length; i < il; ++i) {
+        exclude[excludeFiles[i] + '.js'] = true;
+    }
+
+    var files = Fs.readdirSync(path);
+    for (i = 0, il = files.length; i < il; ++i) {
+        var filename = files[i];
+        if (/\.js$/.test(filename) &&
+            !exclude[filename]) {
+
+            var name = filename.substr(0, filename.lastIndexOf('.'));
+            var capName = name.charAt(0).toUpperCase() + name.substr(1).toLowerCase();
+
+            if (typeof target !== 'function') {
+                target[capName] = require(path + '/' + name);
+            }
+            else {
+                target(path + '/' + name, name, capName);
+            }
+        }
+    }
+};
+
+
+exports.rename = function (obj, from, to) {
+
+    obj[to] = obj[from];
+    delete obj[from];
+};
+
+
+exports.Timer = function () {
+
+    this.reset();
+};
+
+
+exports.Timer.prototype.reset = function () {
+
+    this.ts = Date.now();
+};
+
+
+exports.Timer.prototype.elapsed = function () {
+
+    return Date.now() - this.ts;
+};
+
+
+// Load and parse package.json process root or given directory
+
+exports.loadPackage = function (dir) {
+
+    var result = {};
+    var filepath = (dir || process.env.PWD) + '/package.json';
+    if (Fs.existsSync(filepath)) {
+        try {
+            result = JSON.parse(Fs.readFileSync(filepath));
+        }
+        catch (e) { }
+    }
+
+    return result;
+};
+
+
+// Escape string for Regex construction
+
+exports.escapeRegex = function (string) {
+
+    // Escape ^$.*+-?=!:|\/()[]{},
+    return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
+};
+
+
+// Return an error as first argument of a callback
+
+exports.toss = function (condition /*, [message], next */) {
+
+    var message = (arguments.length === 3 ? arguments[1] : '');
+    var next = (arguments.length === 3 ? arguments[2] : arguments[1]);
+
+    var err = (message instanceof Error ? message : (message ? new Error(message) : (condition instanceof Error ? condition : new Error())));
+
+    if (condition instanceof Error ||
+        !condition) {
+
+        return next(err);
+    }
+};
+
+
+// Base64url (RFC 4648) encode
+
+exports.base64urlEncode = function (value) {
+
+    return (new Buffer(value, 'binary')).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
+};
+
+
+// Base64url (RFC 4648) decode
+
+exports.base64urlDecode = function (encoded) {
+
+    if (encoded &&
+        !encoded.match(/^[\w\-]*$/)) {
+
+        return new Error('Invalid character');
+    }
+
+    try {
+        return (new Buffer(encoded.replace(/-/g, '+').replace(/:/g, '/'), 'base64')).toString('binary');
+    }
+    catch (err) {
+        return err;
+    }
+};
+
+
+// Escape attribute value for use in HTTP header
+
+exports.escapeHeaderAttribute = function (attribute) {
+
+    // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
+
+    exports.assert(attribute.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/), 'Bad attribute value (' + attribute + ')');
+
+    return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');                             // Escape quotes and slash
+};
+
+
+exports.escapeHtml = function (string) {
+
+    return Escape.escapeHtml(string);
+};
+
+
+exports.escapeJavaScript = function (string) {
+
+    return Escape.escapeJavaScript(string);
+};
+
+
+/*
+var event = {
+    timestamp: now.getTime(),
+    tags: ['tag'],
+    data: { some: 'data' }
+};
+*/
+
+exports.consoleFunc = console.log;
+
+exports.printEvent = function (event) {
+
+    var pad = function (value) {
+
+        return (value < 10 ? '0' : '') + value;
+    };
+
+    var now = new Date(event.timestamp);
+    var timestring = (now.getYear() - 100).toString() +
+        pad(now.getMonth() + 1) +
+        pad(now.getDate()) +
+        '/' +
+        pad(now.getHours()) +
+        pad(now.getMinutes()) +
+        pad(now.getSeconds()) +
+        '.' +
+        now.getMilliseconds();
+
+    var data = event.data;
+    if (typeof event.data !== 'string') {
+        try {
+            data = JSON.stringify(event.data);
+        }
+        catch (e) {
+            data = 'JSON Error: ' + e.message;
+        }
+    }
+
+    var output = timestring + ', ' + event.tags[0] + ', ' + data;
+    exports.consoleFunc(output);
+};
+
+
+exports.nextTick = function (callback) {
+
+    return function () {
+
+        var args = arguments;
+        process.nextTick(function () {
+
+            callback.apply(null, args);
+        });
+    };
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/package.json	(revision 517)
@@ -0,0 +1,49 @@
+{
+  "name": "hoek",
+  "description": "General purpose node utilities",
+  "version": "0.9.1",
+  "author": {
+    "name": "Eran Hammer",
+    "email": "eran@hueniverse.com",
+    "url": "http://hueniverse.com"
+  },
+  "contributors": [
+    {
+      "name": "Van Nguyen",
+      "email": "the.gol.effect@gmail.com"
+    }
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/spumko/hoek"
+  },
+  "main": "index",
+  "keywords": [
+    "utilities"
+  ],
+  "engines": {
+    "node": ">=0.8.0"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "lab": "0.1.x",
+    "complexity-report": "0.x.x"
+  },
+  "scripts": {
+    "test": "make test-cov"
+  },
+  "licenses": [
+    {
+      "type": "BSD",
+      "url": "http://github.com/spumko/hoek/raw/master/LICENSE"
+    }
+  ],
+  "readme": "<a href=\"https://github.com/spumko\"><img src=\"https://raw.github.com/spumko/spumko/master/images/from.png\" align=\"right\" /></a>\r\n![hoek Logo](https://raw.github.com/spumko/hoek/master/images/hoek.png)\r\n\r\nGeneral purpose node utilities\r\n\r\n[![Build Status](https://secure.travis-ci.org/spumko/hoek.png)](http://travis-ci.org/spumko/hoek)\r\n\r\n# Table of Contents\r\n\r\n* [Introduction](#introduction \"Introduction\")\r\n* [Object](#object \"Object\")\r\n  * [clone](#cloneobj \"clone\")\r\n  * [merge](#mergetarget-source-isnulloverride-ismergearrays \"merge\")\r\n  * [applyToDefaults](#applytodefaultsdefaults-options \"applyToDefaults\")\r\n  * [unique](#uniquearray-key \"unique\")\r\n  * [mapToObject](#maptoobjectarray-key \"mapToObject\")\r\n  * [intersect](#intersectarray1-array2 \"intersect\")\r\n  * [matchKeys](#matchkeysobj-keys \"matchKeys\")\r\n  * [flatten](#flattenarray-target \"flatten\")\r\n  * [removeKeys](#removekeysobject-keys \"removeKeys\")\r\n  * [reach](#reachobj-chain \"reach\")\r\n  * [inheritAsync](#inheritasyncself-obj-keys \"inheritAsync\")\r\n  * [rename](#renameobj-from-to \"rename\")\r\n* [Timer](#timer \"Timer\")\r\n* [Binary Encoding/Decoding](#binary \"Binary Encoding/Decoding\")\r\n  * [base64urlEncode](#binary64urlEncodevalue \"binary64urlEncode\")\r\n  * [base64urlDecode](#binary64urlDecodevalue \"binary64urlDecode\")\r\n* [Escaping Characters](#escaped \"Escaping Characters\")\r\n  * [escapeHtml](#escapeHtmlstring \"escapeHtml\")\r\n  * [escapeHeaderAttribute](#escapeHeaderAttributeattribute \"escapeHeaderAttribute\")\r\n  * [escapeRegex](#escapeRegexstring \"escapeRegex\")\r\n* [Errors](#errors \"Errors\")\r\n  * [assert](#assertmessage \"assert\")\r\n  * [abort](#abortmessage \"abort\")\r\n  * [displayStack](#displayStackslice \"displayStack\")\r\n  * [callStack](#callStackslice \"callStack\")\r\n  * [toss](#tosscondition \"toss\")\r\n* [Load files](#load-files \"Load Files\")\r\n  * [loadPackage](#loadPackagedir \"loadpackage\")\r\n  * [loadDirModules](#loadDirModulespath-excludefiles-target \"loaddirmodules\")\r\n\r\n\r\n\r\n# Introduction\r\n\r\nThe *Hoek* general purpose node utilities library is used to aid in a variety of manners. It comes with useful methods for Arrays (clone, merge, applyToDefaults), Objects (removeKeys, copy), Asserting and more. \r\n\r\nFor example, to use Hoek to set configuration with default options:\r\n```javascript\r\nvar Hoek = require('hoek');\r\n\r\nvar default = {url : \"www.github.com\", port : \"8000\", debug : true}\r\n\r\nvar config = Hoek.applyToDefaults(default, {port : \"3000\", admin : true});\r\n\r\n// In this case, config would be { url: 'www.github.com', port: '3000', debug: true, admin: true }\r\n```\r\n\r\nUnder each of the sections (such as Array), there are subsections which correspond to Hoek methods. Each subsection will explain how to use the corresponding method. In each js excerpt below, the var Hoek = require('hoek') is omitted for brevity.\r\n\r\n## Object\r\n\r\nHoek provides several helpful methods for objects and arrays.\r\n\r\n### clone(obj)\r\n\r\nThis method is used to clone an object or an array. A *deep copy* is made (duplicates everything, including values that are objects). \r\n\r\n```javascript\r\n\r\nvar nestedObj = {\r\n        w: /^something$/ig,\r\n        x: {\r\n            a: [1, 2, 3],\r\n            b: 123456,\r\n            c: new Date()\r\n        },\r\n        y: 'y',\r\n        z: new Date()\r\n    };\r\n\r\nvar copy = Hoek.clone(nestedObj);\r\n\r\ncopy.x.b = 100;\r\n\r\nconsole.log(copy.y)        // results in 'y'\r\nconsole.log(nestedObj.x.b) // results in 123456\r\nconsole.log(copy.x.b)      // results in 100\r\n```\r\n\r\n### merge(target, source, isNullOverride, isMergeArrays)\r\nisNullOverride, isMergeArrays default to true\r\n\r\nMerge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied\r\n\r\n\r\n```javascript\r\n\r\nvar target = {a: 1, b : 2}\r\nvar source = {a: 0, c: 5}\r\nvar source2 = {a: null, c: 5}\r\n\r\nvar targetArray = [1, 2, 3];\r\nvar sourceArray = [4, 5];\r\n\r\nvar newTarget = Hoek.merge(target, source);     // results in {a: 0, b: 2, c: 5}\r\nnewTarget = Hoek.merge(target, source2);        // results in {a: null, b: 2, c: 5}\r\nnewTarget = Hoek.merge(target, source2, false); // results in {a: 1, b: 2, c: 5}\r\n\r\nnewTarget = Hoek.merge(targetArray, sourceArray)              // results in [1, 2, 3, 4, 5]\r\nnewTarget = Hoek.merge(targetArray, sourceArray, true, false) // results in [4, 5]\r\n\r\n\r\n\r\n\r\n```\r\n\r\n### applyToDefaults(defaults, options)\r\n\r\nApply options to a copy of the defaults\r\n\r\n```javascript\r\n\r\nvar defaults = {host: \"localhost\", port: 8000};\r\nvar options = {port: 8080};\r\n\r\nvar config = Hoek.applyToDefaults(defaults, options); // results in {host: \"localhost\", port: 8080};\r\n\r\n\r\n```\r\n\r\n### unique(array, key)\r\n\r\nRemove duplicate items from Array\r\n\r\n```javascript\r\n\r\nvar array = [1, 2, 2, 3, 3, 4, 5, 6];\r\n\r\nvar newArray = Hoek.unique(array); // results in [1,2,3,4,5,6];\r\n\r\narray = [{id: 1}, {id: 1}, {id: 2}];\r\n\r\nnewArray = Hoek.unique(array, \"id\") // results in [{id: 1}, {id: 2}]\r\n\r\n```\r\n\r\n### mapToObject(array, key)\r\n\r\nConvert an Array into an Object\r\n\r\n```javascript\r\n\r\nvar array = [1,2,3];\r\nvar newObject = Hoek.mapToObject(array); // results in [{\"1\": true}, {\"2\": true}, {\"3\": true}]\r\n\r\narray = [{id: 1}, {id: 2}];\r\nnewObject = Hoek.mapToObject(array, \"id\") // results in [{\"id\": 1}, {\"id\": 2}]\r\n\r\n```\r\n### intersect(array1, array2)\r\n\r\nFind the common unique items in two arrays\r\n\r\n```javascript\r\n\r\nvar array1 = [1, 2, 3];\r\nvar array2 = [1, 4, 5];\r\n\r\nvar newArray = Hoek.intersect(array1, array2) // results in [1]\r\n\r\n```\r\n\r\n### matchKeys(obj, keys) \r\n\r\nFind which keys are present\r\n\r\n```javascript\r\n\r\nvar obj = {a: 1, b: 2, c: 3};\r\nvar keys = [\"a\", \"e\"];\r\n\r\nHoek.matchKeys(obj, keys) // returns [\"a\"]\r\n\r\n```\r\n\r\n### flatten(array, target)\r\n\r\nFlatten an array\r\n\r\n```javascript\r\n\r\nvar array = [1, 2, 3];\r\nvar target = [4, 5]; \r\n\r\nvar flattenedArray = Hoek.flatten(array, target) // results in [4, 5, 1, 2, 3];\r\n\r\n```\r\n\r\n### removeKeys(object, keys)\r\n\r\nRemove keys\r\n\r\n```javascript\r\n\r\nvar object = {a: 1, b: 2, c: 3, d: 4};\r\n\r\nvar keys = [\"a\", \"b\"];\r\n\r\nHoek.removeKeys(object, keys) // object is now {c: 3, d: 4}\r\n\r\n```\r\n\r\n### reach(obj, chain)\r\n\r\nConverts an object key chain string to reference\r\n\r\n```javascript\r\n\r\nvar chain = 'a.b.c';\r\nvar obj = {a : {b : { c : 1}}};\r\n\r\nHoek.reach(obj, chain) // returns 1\r\n\r\n```\r\n\r\n### inheritAsync(self, obj, keys) \r\n\r\nInherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors\r\n\r\n```javascript\r\n\r\nvar targetFunc = function () { };\r\n\r\nvar proto = {\r\n                a: function () {\r\n                    return 'a!';\r\n                },\r\n                b: function () {\r\n                    return 'b!';\r\n                },\r\n                c: function () {\r\n                    throw new Error('c!');\r\n                }\r\n            };\r\n\r\nvar keys = ['a', 'c'];\r\n\r\nHoek.inheritAsync(targetFunc, proto, ['a', 'c']);\r\n\r\nvar target = new targetFunc();\r\n\r\ntarget.a(function(err, result){console.log(result)}         // returns 'a!'       \r\n\r\ntarget.c(function(err, result){console.log(result)}         // returns undefined\r\n\r\ntarget.b(function(err, result){console.log(result)}         // gives error: Object [object Object] has no method 'b'\r\n\r\n```\r\n\r\n### rename(obj, from, to)\r\n\r\nRename a key of an object\r\n\r\n```javascript\r\n\r\nvar obj = {a : 1, b : 2};\r\n\r\nHoek.rename(obj, \"a\", \"c\");     // obj is now {c : 1, b : 2}\r\n\r\n```\r\n\r\n\r\n# Timer\r\n\r\nA Timer object. Initializing a new timer object sets the ts to the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.\r\n\r\n```javascript\r\n\r\n\r\nexample : \r\n\r\n\r\nvar timerObj = new Hoek.Timer();\r\nconsole.log(\"Time is now: \" + timerObj.ts)\r\nconsole.log(\"Elapsed time from initialization: \" + timerObj.elapsed() + 'milliseconds')\r\n\r\n```\r\n\r\n# Binary Encoding/Decoding\r\n\r\n### base64urlEncode(value)\r\n\r\nEncodes value in Base64 or URL encoding\r\n\r\n### base64urlDecode(value)\r\n\r\nDecodes data in Base64 or URL encoding.\r\n# Escaping Characters\r\n\r\nHoek provides convenient methods for escaping html characters. The escaped characters are as followed:\r\n\r\n```javascript\r\n\r\ninternals.htmlEscaped = {\r\n    '&': '&amp;',\r\n    '<': '&lt;',\r\n    '>': '&gt;',\r\n    '\"': '&quot;',\r\n    \"'\": '&#x27;',\r\n    '`': '&#x60;'\r\n};\r\n\r\n```\r\n\r\n### escapeHtml(string)\r\n\r\n```javascript\r\n\r\nvar string = '<html> hey </html>';\r\nvar escapedString = Hoek.escapeHtml(string); // returns &lt;html&gt; hey &lt;/html&gt;\r\n\r\n```\r\n\r\n### escapeHeaderAttribute(attribute)\r\n\r\nEscape attribute value for use in HTTP header\r\n\r\n```javascript\r\n\r\nvar a = Hoek.escapeHeaderAttribute('I said \"go w\\\\o me\"');  //returns I said \\\"go w\\\\o me\\\"\r\n\r\n\r\n```\r\n\r\n\r\n### escapeRegex(string)\r\n\r\nEscape string for Regex construction\r\n\r\n```javascript\r\n\r\nvar a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\\\/`\"(>)[<]d{}s,');  // returns 4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`\"\\(>\\)\\[<\\]d\\{\\}s\\,\r\n\r\n\r\n\r\n```\r\n\r\n# Errors\r\n\r\n### assert(message)\r\n\r\n```javascript\r\n\r\nvar a = 1, b =2;\r\n\r\nHoek.assert(a === b, 'a should equal b');  // ABORT: a should equal b\r\n\r\n```\r\n\r\n### abort(message)\r\n\r\nFirst checks if process.env.NODE_ENV === 'test', and if so, throws error message. Otherwise,\r\ndisplays most recent stack and then exits process.\r\n\r\n\r\n\r\n### displayStack(slice)\r\n\r\nDisplays the trace stack\r\n\r\n```javascript\r\n\r\nvar stack = Hoek.displayStack();\r\nconsole.log(stack) // returns something like:\r\n\r\n[ 'null (/Users/user/Desktop/hoek/test.js:4:18)',\r\n  'Module._compile (module.js:449:26)',\r\n  'Module._extensions..js (module.js:467:10)',\r\n  'Module.load (module.js:356:32)',\r\n  'Module._load (module.js:312:12)',\r\n  'Module.runMain (module.js:492:10)',\r\n  'startup.processNextTick.process._tickCallback (node.js:244:9)' ]\r\n\r\n```\r\n\r\n### callStack(slice)\r\n\r\nReturns a trace stack array.\r\n\r\n```javascript\r\n\r\nvar stack = Hoek.callStack();\r\nconsole.log(stack)  // returns something like:\r\n\r\n[ [ '/Users/user/Desktop/hoek/test.js', 4, 18, null, false ],\r\n  [ 'module.js', 449, 26, 'Module._compile', false ],\r\n  [ 'module.js', 467, 10, 'Module._extensions..js', false ],\r\n  [ 'module.js', 356, 32, 'Module.load', false ],\r\n  [ 'module.js', 312, 12, 'Module._load', false ],\r\n  [ 'module.js', 492, 10, 'Module.runMain', false ],\r\n  [ 'node.js',\r\n    244,\r\n    9,\r\n    'startup.processNextTick.process._tickCallback',\r\n    false ] ]\r\n\r\n\r\n```\r\n\r\n### toss(condition)\r\n\r\ntoss(condition /*, [message], callback */)\r\n\r\nReturn an error as first argument of a callback\r\n\r\n\r\n# Load Files\r\n\r\n### loadPackage(dir)\r\n\r\nLoad and parse package.json process root or given directory\r\n\r\n```javascript\r\n\r\nvar pack = Hoek.loadPackage();  // pack.name === 'hoek'\r\n\r\n```\r\n\r\n### loadDirModules(path, excludeFiles, target) \r\n\r\nLoads modules from a given path; option to exclude files (array).\r\n\r\n\r\n\r\n\r\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/spumko/hoek/issues"
+  },
+  "homepage": "https://github.com/spumko/hoek",
+  "_id": "hoek@0.9.1",
+  "_from": "hoek@0.9.x"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/escaper.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/escaper.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/escaper.js	(revision 517)
@@ -0,0 +1,86 @@
+// Load modules
+
+var Lab = require('lab');
+var Hoek = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hoek', function () {
+
+    describe('#escapeJavaScript', function () {
+
+        it('encodes / characters', function (done) {
+
+            var encoded = Hoek.escapeJavaScript('<script>alert(1)</script>');
+            expect(encoded).to.equal('\\x3cscript\\x3ealert\\x281\\x29\\x3c\\x2fscript\\x3e');
+            done();
+        });
+
+        it('encodes \' characters', function (done) {
+
+            var encoded = Hoek.escapeJavaScript('something(\'param\')');
+            expect(encoded).to.equal('something\\x28\\x27param\\x27\\x29');
+            done();
+        });
+
+        it('encodes large unicode characters with the correct padding', function (done) {
+
+            var encoded = Hoek.escapeJavaScript(String.fromCharCode(500) + String.fromCharCode(1000));
+            expect(encoded).to.equal('\\u0500\\u1000');
+            done();
+        });
+
+        it('doesn\'t throw an exception when passed null', function (done) {
+
+            var encoded = Hoek.escapeJavaScript(null);
+            expect(encoded).to.equal('');
+            done();
+        });
+    });
+
+    describe('#escapeHtml', function () {
+
+        it('encodes / characters', function (done) {
+
+            var encoded = Hoek.escapeHtml('<script>alert(1)</script>');
+            expect(encoded).to.equal('&lt;script&gt;alert&#x28;1&#x29;&lt;&#x2f;script&gt;');
+            done();
+        });
+
+        it('encodes < and > as named characters', function (done) {
+
+            var encoded = Hoek.escapeHtml('<script><>');
+            expect(encoded).to.equal('&lt;script&gt;&lt;&gt;');
+            done();
+        });
+
+        it('encodes large unicode characters', function (done) {
+
+            var encoded = Hoek.escapeHtml(String.fromCharCode(500) + String.fromCharCode(1000));
+            expect(encoded).to.equal('&#500;&#1000;');
+            done();
+        });
+
+        it('doesn\'t throw an exception when passed null', function (done) {
+
+            var encoded = Hoek.escapeHtml(null);
+            expect(encoded).to.equal('');
+            done();
+        });
+    });
+});
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/index.js	(revision 517)
@@ -0,0 +1,1078 @@
+// Load modules
+
+var Lab = require('lab');
+var Hoek = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hoek', function () {
+
+    var nestedObj = {
+        v: [7,8,9],
+        w: /^something$/igm,
+        x: {
+            a: [1, 2, 3],
+            b: 123456,
+            c: new Date(),
+            d: /hi/igm,
+            e: /hello/
+        },
+        y: 'y',
+        z: new Date()
+    };
+
+    var dupsArray = [nestedObj, { z: 'z' }, nestedObj];
+    var reducedDupsArray = [nestedObj, { z: 'z' }];
+
+    describe('#clone', function () {
+
+        it('should clone a nested object', function (done) {
+
+            var a = nestedObj;
+            var b = Hoek.clone(a);
+
+            expect(a).to.deep.equal(b);
+            expect(a.z.getTime()).to.equal(b.z.getTime());
+            done();
+        });
+
+        it('should clone a null object', function (done) {
+
+            var b = Hoek.clone(null);
+
+            expect(b).to.equal(null);
+            done();
+        });
+
+        it('should not convert undefined properties to null', function (done) {
+
+            var obj = { something: undefined };
+            var b = Hoek.clone(obj);
+
+            expect(typeof b.something).to.equal('undefined');
+            done();
+        });
+
+        it('should not throw on circular reference', function (done) {
+
+            var a = {};
+            a.x = a;
+
+            var test = (function () {
+
+                var b = Hoek.clone(a);
+            });
+
+            expect(test).to.not.throw();
+            done();
+        });
+
+        it('should properly clone circular reference', function (done) {
+
+            var x = {
+                'z': new Date()
+            };
+            x.y = x;
+
+            var b = Hoek.clone(x);
+            expect(Object.keys(b.y)).to.deep.equal(Object.keys(x))
+            expect(b.z).to.not.equal(x.z);
+            expect(b.y).to.not.equal(x.y);
+            expect(b.y.z).to.not.equal(x.y.z);
+            expect(b.y).to.equal(b);
+            expect(b.y.y.y.y).to.equal(b);
+            done();
+        });
+
+        it('should properly clone deeply nested object', function (done) {
+
+            var a = {
+                x: {
+                    y: {
+                        a: [1, 2, 3],
+                        b: 123456,
+                        c: new Date(),
+                        d: /hi/igm,
+                        e: /hello/
+                    },
+                }
+            };
+
+            var b = Hoek.clone(a);
+
+            expect(a).to.deep.equal(b);
+            expect(a.x.y.c.getTime()).to.equal(b.x.y.c.getTime());
+            done();
+        });
+
+        it('should properly clone arrays', function (done) {
+
+            var a = [1,2,3];
+
+            var b = Hoek.clone(a);
+
+            expect(a).to.deep.equal(b);
+            done();
+        });
+
+        it('should perform actual copy for shallow keys (no pass by reference)', function (done) {
+
+            var x = Hoek.clone(nestedObj);
+            var y = Hoek.clone(nestedObj);
+
+            // Date
+            expect(x.z).to.not.equal(nestedObj.z);
+            expect(x.z).to.not.equal(y.z);
+
+            // Regex
+            expect(x.w).to.not.equal(nestedObj.w);
+            expect(x.w).to.not.equal(y.w);
+
+            // Array
+            expect(x.v).to.not.equal(nestedObj.v);
+            expect(x.v).to.not.equal(y.v);
+
+            // Immutable(s)
+            x.y = 5;
+            expect(x.y).to.not.equal(nestedObj.y);
+            expect(x.y).to.not.equal(y.y);
+
+            done();
+        });
+
+        it('should perform actual copy for deep keys (no pass by reference)', function (done) {
+
+            var x = Hoek.clone(nestedObj);
+            var y = Hoek.clone(nestedObj);
+
+            expect(x.x.c).to.not.equal(nestedObj.x.c);
+            expect(x.x.c).to.not.equal(y.x.c);
+
+            expect(x.x.c.getTime()).to.equal(nestedObj.x.c.getTime());
+            expect(x.x.c.getTime()).to.equal(y.x.c.getTime());
+            done();
+        });
+
+        it('copies functions with properties', function (done) {
+
+            var a = {
+                x: function () { return 1; },
+                y: {}
+            };
+            a.x.z = 'string in function';
+            a.x.v = function () { return 2; };
+            a.y.u = a.x;
+
+            var b = Hoek.clone(a);
+            expect(b.x()).to.equal(1);
+            expect(b.x.v()).to.equal(2);
+            expect(b.y.u).to.equal(b.x);
+            expect(b.x.z).to.equal('string in function');
+            done();
+        });
+
+        it('should copy a buffer', function(done){
+            var tls = {
+                key: new Buffer([1,2,3,4,5]),
+                cert: new Buffer([1,2,3,4,5,6,10])
+            }
+
+            copiedTls = Hoek.clone(tls);
+            expect(Buffer.isBuffer(copiedTls.key)).to.equal(true);
+            expect(JSON.stringify(copiedTls.key)).to.equal(JSON.stringify(tls.key))
+            expect(Buffer.isBuffer(copiedTls.cert)).to.equal(true);
+            expect(JSON.stringify(copiedTls.cert)).to.equal(JSON.stringify(tls.cert))
+            done();
+        });
+    });
+
+    describe('#merge', function () {
+
+        it('does not throw if source is null', function (done) {
+
+            var a = {};
+            var b = null;
+            var c = null;
+
+            expect(function () {
+
+                c = Hoek.merge(a, b);
+            }).to.not.throw();
+
+            expect(c).to.equal(a);
+            done();
+        });
+
+        it('does not throw if source is undefined', function (done) {
+
+            var a = {};
+            var b = undefined;
+            var c = null;
+
+            expect(function () {
+
+                c = Hoek.merge(a, b);
+            }).to.not.throw();
+
+            expect(c).to.equal(a);
+            done();
+        });
+
+        it('throws if source is not an object', function (done) {
+
+            expect(function () {
+
+                var a = {};
+                var b = 0;
+
+                Hoek.merge(a, b);
+            }).to.throw('Invalid source value: must be null, undefined, or an object');
+            done();
+        });
+
+        it('throws if target is not an object', function (done) {
+
+            expect(function () {
+
+                var a = 0;
+                var b = {};
+
+                Hoek.merge(a, b);
+            }).to.throw('Invalid target value: must be an object');
+            done();
+        });
+
+        it('throws if target is not an array and source is', function (done) {
+
+            expect(function () {
+
+                var a = {};
+                var b = [1, 2];
+
+                Hoek.merge(a, b);
+            }).to.throw('Cannot merge array onto an object');
+            done();
+        });
+
+        it('returns the same object when merging arrays', function (done) {
+
+            var a = [];
+            var b = [1, 2];
+
+            expect(Hoek.merge(a, b)).to.equal(a);
+            done();
+        });
+
+        it('should combine an empty object with a non-empty object', function (done) {
+
+            var a = {};
+            var b = nestedObj;
+
+            var c = Hoek.merge(a, b);
+            expect(a).to.deep.equal(b);
+            expect(c).to.deep.equal(b);
+            done();
+        });
+
+        it('should override values in target', function (done) {
+
+            var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
+            var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
+
+            var c = Hoek.merge(a, b);
+            expect(c.x).to.equal(null);
+            expect(c.y).to.equal(2);
+            expect(c.z).to.equal(4);
+            expect(c.v).to.equal(0);
+            expect(c.m).to.equal('123');
+            expect(c.t).to.deep.equal({ u: 6 });
+            done();
+        });
+
+        it('should override values in target (flip)', function (done) {
+
+            var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
+            var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
+
+            var d = Hoek.merge(b, a);
+            expect(d.x).to.equal(1);
+            expect(d.y).to.equal(2);
+            expect(d.z).to.equal(3);
+            expect(d.v).to.equal(5);
+            expect(d.m).to.equal('abc');
+            expect(d.t).to.deep.equal('test');
+            done();
+        });
+    });
+
+    describe('#applyToDefaults', function () {
+
+        var defaults = {
+            a: 1,
+            b: 2,
+            c: {
+                d: 3,
+                e: [5, 6]
+            },
+            f: 6,
+            g: 'test'
+        };
+
+        it('should return null if options is false', function (done) {
+
+            var result = Hoek.applyToDefaults(defaults, false);
+            expect(result).to.equal(null);
+            done();
+        });
+
+        it('should return a copy of defaults if options is true', function (done) {
+
+            var result = Hoek.applyToDefaults(defaults, true);
+            expect(result).to.deep.equal(result);
+            done();
+        });
+
+        it('should apply object to defaults', function (done) {
+
+            var obj = {
+                a: null,
+                c: {
+                    e: [4]
+                },
+                f: 0,
+                g: {
+                    h: 5
+                }
+            };
+
+            var result = Hoek.applyToDefaults(defaults, obj);
+            expect(result.c.e).to.deep.equal([4]);
+            expect(result.a).to.equal(1);
+            expect(result.b).to.equal(2);
+            expect(result.f).to.equal(0);
+            expect(result.g).to.deep.equal({ h: 5 });
+            done();
+        });
+    });
+
+    describe('#unique', function () {
+
+        it('should ensure uniqueness within array of objects based on subkey', function (done) {
+
+            var a = Hoek.unique(dupsArray, 'x');
+            expect(a).to.deep.equal(reducedDupsArray);
+            done();
+        });
+
+        it('removes duplicated without key', function (done) {
+
+            expect(Hoek.unique([1, 2, 3, 4, 2, 1, 5])).to.deep.equal([1, 2, 3, 4, 5]);
+            done();
+        });
+    });
+
+    describe('#mapToObject', function () {
+
+        it('should return null on null array', function (done) {
+
+            var a = Hoek.mapToObject(null);
+            expect(a).to.equal(null);
+            done();
+        });
+
+        it('should convert basic array to existential object', function (done) {
+
+            var keys = [1, 2, 3, 4];
+            var a = Hoek.mapToObject(keys);
+            for (var i in keys) {
+                expect(a[keys[i]]).to.equal(true);
+            }
+            done();
+        });
+
+        it('should convert array of objects to existential object', function (done) {
+
+            var keys = [{ x: 1 }, { x: 2 }, { x: 3 }];
+            var subkey = 'x';
+            var a = Hoek.mapToObject(keys, subkey);
+            for (var i in keys) {
+                expect(a[keys[i][subkey]]).to.equal(true);
+            }
+            done();
+        });
+    });
+
+    describe('#intersect', function () {
+
+        it('should return the common objects of two arrays', function (done) {
+
+            var array1 = [1, 2, 3, 4, 4, 5, 5];
+            var array2 = [5, 4, 5, 6, 7];
+            var common = Hoek.intersect(array1, array2);
+            expect(common.length).to.equal(2);
+            done();
+        });
+
+        it('should return just the first common object of two arrays', function (done) {
+
+            var array1 = [1, 2, 3, 4, 4, 5, 5];
+            var array2 = [5, 4, 5, 6, 7];
+            var common = Hoek.intersect(array1, array2, true);
+            expect(common).to.equal(5);
+            done();
+        });
+
+        it('should return an empty array if either input is null', function (done) {
+
+            expect(Hoek.intersect([1], null).length).to.equal(0);
+            expect(Hoek.intersect(null, [1]).length).to.equal(0);
+            done();
+        });
+
+        it('should return the common objects of object and array', function (done) {
+
+            var array1 = [1, 2, 3, 4, 4, 5, 5];
+            var array2 = [5, 4, 5, 6, 7];
+            var common = Hoek.intersect(Hoek.mapToObject(array1), array2);
+            expect(common.length).to.equal(2);
+            done();
+        });
+    });
+
+    describe('#matchKeys', function () {
+
+        it('should match the existing object keys', function (done) {
+
+            var obj = {
+                a: 1,
+                b: 2,
+                c: 3,
+                d: null
+            };
+
+            expect(Hoek.matchKeys(obj, ['b', 'c', 'd', 'e'])).to.deep.equal(['b', 'c', 'd']);
+            done();
+        });
+    });
+
+    describe('#flatten', function () {
+
+        it('should return a flat array', function (done) {
+
+            var result = Hoek.flatten([1, 2, [3, 4, [5, 6], [7], 8], [9], [10, [11, 12]], 13]);
+            expect(result.length).to.equal(13);
+            expect(result).to.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
+            done();
+        });
+    });
+
+    describe('#removeKeys', function () {
+
+        var objWithHiddenKeys = {
+            location: {
+                name: 'San Bruno'
+            },
+            company: {
+                name: '@WalmartLabs'
+            }
+        };
+
+        it('should delete params with definition\'s hide set to true', function (done) {
+
+            var a = Hoek.removeKeys(objWithHiddenKeys, ['location']);
+            expect(objWithHiddenKeys.location).to.not.exist;
+            expect(objWithHiddenKeys.company).to.exist;
+            done();
+        });
+    });
+
+    describe('#reach', function () {
+
+        var obj = {
+            a: {
+                b: {
+                    c: {
+                        d: 1,
+                        e: 2
+                    },
+                    f: 'hello'
+                },
+                g: {
+                    h: 3
+                }
+            },
+            i: function () { }
+        };
+
+        it('returns a valid member', function (done) {
+
+            expect(Hoek.reach(obj, 'a.b.c.d')).to.equal(1);
+            done();
+        });
+
+        it('returns null on null object', function (done) {
+
+            expect(Hoek.reach(null, 'a.b.c.d')).to.not.exist;
+            done();
+        });
+
+        it('returns null on missing member', function (done) {
+
+            expect(Hoek.reach(obj, 'a.b.c.d.x')).to.not.exist;
+            done();
+        });
+
+        it('returns null on invalid member', function (done) {
+
+            expect(Hoek.reach(obj, 'a.b.c.d-.x')).to.not.exist;
+            done();
+        });
+
+        it('returns function member', function (done) {
+
+            expect(typeof Hoek.reach(obj, 'i')).to.equal('function');
+            done();
+        });
+    });
+
+    describe('#inheritAsync', function () {
+
+        it('should inherit selected methods and wrap in async call', function (done) {
+
+            var proto = {
+                a: function () {
+                    return 'a!';
+                },
+                b: function () {
+                    return 'b!';
+                },
+                c: function () {
+                    throw new Error('c!');
+                }
+            };
+
+            var targetFunc = function () { };
+            targetFunc.prototype.c = function () {
+
+                return 'oops';
+            };
+
+            Hoek.inheritAsync(targetFunc, proto, ['a', 'c']);
+            var target = new targetFunc();
+
+            expect(typeof target.a).to.equal('function');
+            expect(typeof target.c).to.equal('function');
+            expect(target.b).to.not.exist;
+
+            target.a(function (err, result) {
+
+                expect(err).to.not.exist;
+                expect(result).to.equal('a!');
+
+                target.c(function (err, result) {
+
+                    expect(result).to.not.exist;
+                    expect(err.message).to.equal('c!');
+                    done();
+                });
+            });
+        });
+    });
+
+    describe('#callStack', function () {
+
+        it('should return the full call stack', function (done) {
+
+            var stack = Hoek.callStack();
+            expect(stack[0][0]).to.contain('index.js');
+            expect(stack[0][2]).to.equal(30);
+            done();
+        });
+    });
+
+    describe('#displayStack ', function () {
+
+        it('should return the full call stack for display', function (done) {
+
+            var stack = Hoek.displayStack();
+            expect(stack[0]).to.contain('test/index.js:');
+            done();
+        });
+
+        it('should include constructor functions correctly', function (done) {
+
+            var Something = function (next) {
+
+                next();
+            };
+
+            var something = new Something(function () {
+
+                var stack = Hoek.displayStack();
+                expect(stack[1]).to.contain('new Something');
+                done();
+            });
+        });
+    });
+
+    describe('#abort', function () {
+
+        it('should exit process when not in test mode', function (done) {
+
+            var env = process.env.NODE_ENV;
+            var write = process.stdout.write;
+            var exit = process.exit;
+
+            process.env.NODE_ENV = 'nottatest';
+            process.stdout.write = function () { };
+            process.exit = function (state) {
+
+                process.exit = exit;
+                process.env.NODE_ENV = env;
+                process.stdout.write = write;
+
+                expect(state).to.equal(1);
+                done();
+            };
+
+            Hoek.abort('Boom');
+        });
+
+        it('should throw when not in test mode and abortThrow is true', function (done) {
+
+            var env = process.env.NODE_ENV;
+            process.env.NODE_ENV = 'nottatest';
+            Hoek.abortThrow = true;
+
+            var fn = function () {
+
+                Hoek.abort('my error message');
+            };
+
+            expect(fn).to.throw('my error message');
+            Hoek.abortThrow = false;
+            process.env.NODE_ENV = env;
+
+            done();
+        });
+
+
+        it('should respect hideStack argument', function (done) {
+
+            var env = process.env.NODE_ENV;
+            var write = process.stdout.write;
+            var exit = process.exit;
+            var output = '';
+
+            process.exit = function () { };
+            process.env.NODE_ENV = '';
+            process.stdout.write = function (message) {
+
+                output = message;
+            };
+
+            Hoek.abort('my error message', true);
+
+            process.env.NODE_ENV = env;
+            process.stdout.write = write;
+            process.exit = exit;
+
+            expect(output).to.equal('ABORT: my error message\n\t\n');
+
+            done();
+        });
+
+        it('should default to showing stack', function (done) {
+
+            var env = process.env.NODE_ENV;
+            var write = process.stdout.write;
+            var exit = process.exit;
+            var output = '';
+
+            process.exit = function () { };
+            process.env.NODE_ENV = '';
+            process.stdout.write = function (message) {
+
+                output = message;
+            };
+
+            Hoek.abort('my error message');
+
+            process.env.NODE_ENV = env;
+            process.stdout.write = write;
+            process.exit = exit;
+
+            expect(output).to.contain('index.js');
+
+            done();
+        });
+    });
+
+    describe('#assert', function () {
+
+        it('should throw an Error when using assert in a test', function (done) {
+
+            var fn = function () {
+
+                Hoek.assert(false, 'my error message');
+            };
+
+            expect(fn).to.throw('my error message');
+            done();
+        });
+
+        it('should throw an Error when using assert in a test with no message', function (done) {
+
+            var fn = function () {
+
+                Hoek.assert(false);
+            };
+
+            expect(fn).to.throw('Unknown error');
+            done();
+        });
+
+        it('should throw an Error when using assert in a test with multipart message', function (done) {
+
+            var fn = function () {
+
+                Hoek.assert(false, 'This', 'is', 'my message');
+            };
+
+            expect(fn).to.throw('This is my message');
+            done();
+        });
+
+        it('should throw an Error when using assert in a test with object message', function (done) {
+
+            var fn = function () {
+
+                Hoek.assert(false, 'This', 'is', { spinal: 'tap' });
+            };
+
+            expect(fn).to.throw('This is {"spinal":"tap"}');
+            done();
+        });
+
+        it('should throw an Error when using assert in a test with error object message', function (done) {
+
+            var fn = function () {
+
+                Hoek.assert(false, new Error('This is spinal tap'));
+            };
+
+            expect(fn).to.throw('This is spinal tap');
+            done();
+        });
+    });
+
+    describe('#loadDirModules', function () {
+
+        it('should load modules from directory', function (done) {
+
+            var target = {};
+            Hoek.loadDirModules(__dirname + '/modules', ['test2'], target);
+            expect(target.Test1.x).to.equal(1);
+            expect(target.Test2).to.not.exist;
+            expect(target.Test3.z).to.equal(3);
+            done();
+        });
+
+        it('should list modules from directory into function', function (done) {
+
+            var target = {};
+            Hoek.loadDirModules(__dirname + '/modules', ['test2'], function (path, name, capName) {
+
+                target[name] = capName;
+            });
+
+            expect(target.test1).to.equal('Test1');
+            expect(target.test2).to.not.exist;
+            expect(target.test3).to.equal('Test3');
+            done();
+        });
+    });
+
+    describe('#rename', function () {
+
+        it('should rename object key', function (done) {
+
+            var a = { b: 'c' };
+            Hoek.rename(a, 'b', 'x');
+            expect(a.b).to.not.exist;
+            expect(a.x).to.equal('c');
+            done();
+        });
+    });
+
+    describe('Timer', function () {
+
+        it('should return time elapsed', function (done) {
+
+            var timer = new Hoek.Timer();
+            setTimeout(function () {
+
+                expect(timer.elapsed()).to.be.above(9);
+                done();
+            }, 12);
+        });
+    });
+
+    describe('#loadPackage', function () {
+
+        it('should', function (done) {
+
+            var pack = Hoek.loadPackage();
+            expect(pack.name).to.equal('hoek');
+            done();
+        });
+    });
+
+    describe('#escapeRegex', function () {
+
+        it('should escape all special regular expression characters', function (done) {
+
+            var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');
+            expect(a).to.equal('4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`"\\(>\\)\\[<\\]d\\{\\}s\\,');
+            done();
+        });
+    });
+
+    describe('#toss', function () {
+
+        it('should call callback with new error', function (done) {
+
+            var callback = function (err) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('bug');
+                done();
+            };
+
+            Hoek.toss(true, 'feature', callback);
+            Hoek.toss(false, 'bug', callback);
+        });
+
+        it('should call callback with new error and no message', function (done) {
+
+            Hoek.toss(false, function (err) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('');
+                done();
+            });
+        });
+
+        it('should call callback with error condition', function (done) {
+
+            Hoek.toss(new Error('boom'), function (err) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('boom');
+                done();
+            });
+        });
+
+        it('should call callback with new error using message with error condition', function (done) {
+
+            Hoek.toss(new Error('ka'), 'boom', function (err) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('boom');
+                done();
+            });
+        });
+
+        it('should call callback with new error using passed error with error condition', function (done) {
+
+            Hoek.toss(new Error('ka'), new Error('boom'), function (err) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('boom');
+                done();
+            });
+        });
+    });
+
+    describe('Base64Url', function () {
+
+        var base64str = 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w';
+        var str = unescape('%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29*+%2C-./0123456789%3A%3B%3C%3D%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF');
+
+        describe('#base64urlEncode', function () {
+
+            it('should base64 URL-safe a string', function (done) {
+
+                expect(Hoek.base64urlEncode(str)).to.equal(base64str);
+                done();
+            });
+        });
+
+        describe('#base64urlDecode', function () {
+
+            it('should un-base64 URL-safe a string', function (done) {
+
+                expect(Hoek.base64urlDecode(base64str)).to.equal(str);
+                done();
+            });
+
+            it('should return error on undefined input', function (done) {
+
+                expect(Hoek.base64urlDecode().message).to.exist;
+                done();
+            });
+
+            it('should return error on invalid input', function (done) {
+
+                expect(Hoek.base64urlDecode('*').message).to.exist;
+                done();
+            });
+        });
+    });
+
+    describe('#escapeHeaderAttribute', function () {
+
+        it('should not alter ascii values', function (done) {
+
+            var a = Hoek.escapeHeaderAttribute('My Value');
+            expect(a).to.equal('My Value');
+            done();
+        });
+
+        it('should escape all special HTTP header attribute characters', function (done) {
+
+            var a = Hoek.escapeHeaderAttribute('I said go!!!#"' + String.fromCharCode(92));
+            expect(a).to.equal('I said go!!!#\\"\\\\');
+            done();
+        });
+
+        it('should throw on large unicode characters', function (done) {
+
+            var fn = function () {
+
+                Hoek.escapeHeaderAttribute('this is a test' + String.fromCharCode(500) + String.fromCharCode(300));
+            };
+
+            expect(fn).to.throw(Error);
+            done();
+        });
+
+        it('should throw on CRLF to prevent response splitting', function (done) {
+
+            var fn = function () {
+
+                Hoek.escapeHeaderAttribute('this is a test\r\n');
+            };
+
+            expect(fn).to.throw(Error);
+            done();
+        });
+    });
+
+    describe('#escapeHtml', function () {
+
+        it('should escape all special HTML characters', function (done) {
+
+            var a = Hoek.escapeHtml('&<>"\'`');
+            expect(a).to.equal('&amp;&lt;&gt;&quot;&#x27;&#x60;');
+            done();
+        });
+
+        it('should return empty string on falsy input', function (done) {
+
+            var a = Hoek.escapeHtml('');
+            expect(a).to.equal('');
+            done();
+        });
+
+        it('should return unchanged string on no reserved input', function (done) {
+
+            var a = Hoek.escapeHtml('abc');
+            expect(a).to.equal('abc');
+            done();
+        });
+    });
+
+    describe('#printEvent', function () {
+
+        it('outputs event as string', function (done) {
+
+            var event = {
+                timestamp: (new Date(2013, 1, 1, 6, 30, 45, 123)).getTime(),
+                tags: ['a', 'b', 'c'],
+                data: { some: 'data' }
+            };
+
+            Hoek.consoleFunc = function (string) {
+
+                Hoek.consoleFunc = console.log;
+                expect(string).to.equal('130201/063045.123, a, {"some":"data"}');
+                done();
+            };
+
+            Hoek.printEvent(event);
+        });
+
+        it('outputs JSON error', function (done) {
+
+            var event = {
+                timestamp: (new Date(2013, 1, 1, 6, 30, 45, 123)).getTime(),
+                tags: ['a', 'b', 'c'],
+                data: { some: 'data' }
+            };
+
+            event.data.a = event.data;
+
+            Hoek.consoleFunc = function (string) {
+
+                Hoek.consoleFunc = console.log;
+                expect(string).to.equal('130201/063045.123, a, JSON Error: Converting circular structure to JSON');
+                done();
+            };
+
+            Hoek.printEvent(event);
+        });
+    });
+
+    describe('#nextTick', function () {
+
+        it('calls the provided callback on nextTick', function (done) {
+
+            var a = 0;
+
+            var inc = function (step, next) {
+
+                a += step;
+                next();
+            };
+
+            var ticked = Hoek.nextTick(inc);
+
+            ticked(5, function () {
+
+                expect(a).to.equal(6);
+                done();
+            });
+
+            expect(a).to.equal(0);
+            inc(1, function () {
+
+                expect(a).to.equal(1);
+            });
+        });
+    });
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test1.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test1.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test1.js	(revision 517)
@@ -0,0 +1,1 @@
+exports.x = 1;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test2.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test2.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test2.js	(revision 517)
@@ -0,0 +1,1 @@
+exports.y = 2;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test3.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test3.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test3.js	(revision 517)
@@ -0,0 +1,1 @@
+exports.z = 3;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/.npmignore	(revision 517)
@@ -0,0 +1,18 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/.travis.yml
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/.travis.yml	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/.travis.yml	(revision 517)
@@ -0,0 +1,5 @@
+language: node_js
+
+node_js:
+  - 0.10
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/LICENSE	(revision 517)
@@ -0,0 +1,24 @@
+Copyright (c) 2012-2013, Eran Hammer.
+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 name of Eran Hammer 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 ERAN HAMMER 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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/Makefile
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/Makefile	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/Makefile	(revision 517)
@@ -0,0 +1,11 @@
+test:
+	@./node_modules/.bin/lab
+test-cov: 
+	@./node_modules/.bin/lab -r threshold -t 100
+test-cov-html:
+	@./node_modules/.bin/lab -r html -o coverage.html
+complexity:
+	@./node_modules/.bin/cr -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/README.md	(revision 517)
@@ -0,0 +1,68 @@
+# sntp
+
+An SNTP v4 client (RFC4330) for node. Simpy connects to the NTP or SNTP server requested and returns the server time
+along with the roundtrip duration and clock offset. To adjust the local time to the NTP time, add the returned `t` offset
+to the local time.
+
+[![Build Status](https://secure.travis-ci.org/hueniverse/sntp.png)](http://travis-ci.org/hueniverse/sntp)
+
+# Usage
+
+```javascript
+var Sntp = require('sntp');
+
+// All options are optional
+
+var options = {
+    host: 'nist1-sj.ustiming.org',  // Defaults to pool.ntp.org
+    port: 123,                      // Defaults to 123 (NTP)
+    resolveReference: true,         // Default to false (not resolving)
+    timeout: 1000                   // Defaults to zero (no timeout)
+};
+
+// Request server time
+
+Sntp.time(options, function (err, time) {
+
+    if (err) {
+        console.log('Failed: ' + err.message);
+        process.exit(1);
+    }
+
+    console.log('Local clock is off by: ' + time.t + ' milliseconds');
+    process.exit(0);
+});
+```
+
+If an application needs to maintain continuous time synchronization, the module provides a stateful method for
+querying the current offset only when the last one is too old (defaults to daily).
+
+```javascript
+// Request offset once
+
+Sntp.offset(function (err, offset) {
+
+    console.log(offset);                    // New (served fresh)
+
+    // Request offset again
+
+    Sntp.offset(function (err, offset) {
+
+        console.log(offset);                // Identical (served from cache)
+    });
+});
+```
+
+To set a background offset refresh, start the interval and use the provided now() method. If for any reason the
+client fails to obtain an up-to-date offset, the current system clock is used.
+
+```javascript
+var before = Sntp.now();                    // System time without offset
+
+Sntp.start(function () {
+
+    var now = Sntp.now();                   // With offset
+    Sntp.stop();
+});
+```
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/examples/offset.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/examples/offset.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/examples/offset.js	(revision 517)
@@ -0,0 +1,16 @@
+var Sntp = require('../lib');
+
+// Request offset once
+
+Sntp.offset(function (err, offset) {
+
+    console.log(offset);                    // New (served fresh)
+
+    // Request offset again
+
+    Sntp.offset(function (err, offset) {
+
+        console.log(offset);                // Identical (served from cache)
+    });
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/examples/time.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/examples/time.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/examples/time.js	(revision 517)
@@ -0,0 +1,25 @@
+var Sntp = require('../lib');
+
+// All options are optional
+
+var options = {
+    host: 'nist1-sj.ustiming.org',  // Defaults to pool.ntp.org
+    port: 123,                      // Defaults to 123 (NTP)
+    resolveReference: true,         // Default to false (not resolving)
+    timeout: 1000                   // Defaults to zero (no timeout)
+};
+
+// Request server time
+
+Sntp.time(options, function (err, time) {
+
+    if (err) {
+        console.log('Failed: ' + err.message);
+        process.exit(1);
+    }
+
+    console.log(time);
+    console.log('Local clock is off by: ' + time.t + ' milliseconds');
+    process.exit(0);
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/index.js	(revision 517)
@@ -0,0 +1,1 @@
+module.exports = require('./lib');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js	(revision 517)
@@ -0,0 +1,409 @@
+// Load modules
+
+var Dgram = require('dgram');
+var Dns = require('dns');
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports.time = function (options, callback) {
+
+    if (arguments.length !== 2) {
+        callback = arguments[0];
+        options = {};
+    }
+
+    var settings = Hoek.clone(options);
+    settings.host = settings.host || 'pool.ntp.org';
+    settings.port = settings.port || 123;
+    settings.resolveReference = settings.resolveReference || false;
+
+    // Declare variables used by callback
+
+    var timeoutId = 0;
+    var sent = 0;
+
+    // Ensure callback is only called once
+
+    var isFinished = false;
+    var finish = function (err, result) {
+
+        if (timeoutId) {
+            clearTimeout(timeoutId);
+            timeoutId = 0;
+        }
+
+        if (!isFinished) {
+            isFinished = true;
+            socket.removeAllListeners();
+            socket.close();
+            return callback(err, result);
+        }
+    };
+
+    // Create UDP socket
+
+    var socket = Dgram.createSocket('udp4');
+
+    socket.once('error', function (err) {
+
+        return finish(err);
+    });
+
+    // Listen to incoming messages
+
+    socket.on('message', function (buffer, rinfo) {
+
+        var received = Date.now();
+
+        var message = new internals.NtpMessage(buffer);
+        if (!message.isValid) {
+            return finish(new Error('Invalid server response'), message);
+        }
+
+        if (message.originateTimestamp !== sent) {
+            return finish(new Error('Wrong originate timestamp'), message);
+        }
+
+        // Timestamp Name          ID   When Generated
+        // ------------------------------------------------------------
+        // Originate Timestamp     T1   time request sent by client
+        // Receive Timestamp       T2   time request received by server
+        // Transmit Timestamp      T3   time reply sent by server
+        // Destination Timestamp   T4   time reply received by client
+        //
+        // The roundtrip delay d and system clock offset t are defined as:
+        //
+        // d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2
+
+        var T1 = message.originateTimestamp;
+        var T2 = message.receiveTimestamp;
+        var T3 = message.transmitTimestamp;
+        var T4 = received;
+
+        message.d = (T4 - T1) - (T3 - T2);
+        message.t = ((T2 - T1) + (T3 - T4)) / 2;
+        message.receivedLocally = received;
+
+        if (!settings.resolveReference ||
+            message.stratum !== 'secondary') {
+
+            return finish(null, message);
+        }
+
+        // Resolve reference IP address
+
+        Dns.reverse(message.referenceId, function (err, domains) {
+
+            if (!err) {
+                message.referenceHost = domains[0];
+            }
+
+            return finish(null, message);
+        });
+    });
+
+    // Set timeout
+
+    if (settings.timeout) {
+        timeoutId = setTimeout(function () {
+
+            timeoutId = 0;
+            return finish(new Error('Timeout'));
+        }, settings.timeout);
+    }
+
+    // Construct NTP message
+
+    var message = new Buffer(48);
+    for (var i = 0; i < 48; i++) {                      // Zero message
+        message[i] = 0;
+    }
+
+    message[0] = (0 << 6) + (4 << 3) + (3 << 0)         // Set version number to 4 and Mode to 3 (client)
+    sent = Date.now();
+    internals.fromMsecs(sent, message, 40);               // Set transmit timestamp (returns as originate)
+
+    // Send NTP request
+
+    socket.send(message, 0, message.length, settings.port, settings.host, function (err, bytes) {
+
+        if (err ||
+            bytes !== 48) {
+
+            return finish(err || new Error('Could not send entire message'));
+        }
+    });
+};
+
+
+internals.NtpMessage = function (buffer) {
+
+    this.isValid = false;
+
+    // Validate
+
+    if (buffer.length !== 48) {
+        return;
+    }
+
+    // Leap indicator
+
+    var li = (buffer[0] >> 6);
+    switch (li) {
+        case 0: this.leapIndicator = 'no-warning'; break;
+        case 1: this.leapIndicator = 'last-minute-61'; break;
+        case 2: this.leapIndicator = 'last-minute-59'; break;
+        case 3: this.leapIndicator = 'alarm'; break;
+    }
+
+    // Version
+
+    var vn = ((buffer[0] & 0x38) >> 3);
+    this.version = vn;
+
+    // Mode
+
+    var mode = (buffer[0] & 0x7);
+    switch (mode) {
+        case 1: this.mode = 'symmetric-active'; break;
+        case 2: this.mode = 'symmetric-passive'; break;
+        case 3: this.mode = 'client'; break;
+        case 4: this.mode = 'server'; break;
+        case 5: this.mode = 'broadcast'; break;
+        case 0:
+        case 6:
+        case 7: this.mode = 'reserved'; break;
+    }
+
+    // Stratum
+
+    var stratum = buffer[1];
+    if (stratum === 0) {
+        this.stratum = 'death';
+    }
+    else if (stratum === 1) {
+        this.stratum = 'primary';
+    }
+    else if (stratum <= 15) {
+        this.stratum = 'secondary';
+    }
+    else {
+        this.stratum = 'reserved';
+    }
+
+    // Poll interval (msec)
+
+    this.pollInterval = Math.round(Math.pow(2, buffer[2])) * 1000;
+
+    // Precision (msecs)
+
+    this.precision = Math.pow(2, buffer[3]) * 1000;
+
+    // Root delay (msecs)
+
+    var rootDelay = 256 * (256 * (256 * buffer[4] + buffer[5]) + buffer[6]) + buffer[7];
+    this.rootDelay = 1000 * (rootDelay / 0x10000);
+
+    // Root dispersion (msecs)
+
+    this.rootDispersion = ((buffer[8] << 8) + buffer[9] + ((buffer[10] << 8) + buffer[11]) / Math.pow(2, 16)) * 1000;
+
+    // Reference identifier
+
+    this.referenceId = '';
+    switch (this.stratum) {
+        case 'death':
+        case 'primary':
+            this.referenceId = String.fromCharCode(buffer[12]) + String.fromCharCode(buffer[13]) + String.fromCharCode(buffer[14]) + String.fromCharCode(buffer[15]);
+            break;
+        case 'secondary':
+            this.referenceId = '' + buffer[12] + '.' + buffer[13] + '.' + buffer[14] + '.' + buffer[15];
+            break;
+    }
+
+    // Reference timestamp
+
+    this.referenceTimestamp = internals.toMsecs(buffer, 16);
+
+    // Originate timestamp
+
+    this.originateTimestamp = internals.toMsecs(buffer, 24);
+
+    // Receive timestamp
+
+    this.receiveTimestamp = internals.toMsecs(buffer, 32);
+
+    // Transmit timestamp
+
+    this.transmitTimestamp = internals.toMsecs(buffer, 40);
+
+    // Validate
+
+    if (this.version === 4 &&
+        this.stratum !== 'reserved' &&
+        this.mode === 'server' &&
+        this.originateTimestamp &&
+        this.receiveTimestamp &&
+        this.transmitTimestamp) {
+
+        this.isValid = true;
+    }
+
+    return this;
+};
+
+
+internals.toMsecs = function (buffer, offset) {
+
+    var seconds = 0;
+    var fraction = 0;
+
+    for (var i = 0; i < 4; ++i) {
+        seconds = (seconds * 256) + buffer[offset + i];
+    }
+
+    for (i = 4; i < 8; ++i) {
+        fraction = (fraction * 256) + buffer[offset + i];
+    }
+
+    return ((seconds - 2208988800 + (fraction / Math.pow(2, 32))) * 1000);
+};
+
+
+internals.fromMsecs = function (ts, buffer, offset) {
+
+    var seconds = Math.floor(ts / 1000) + 2208988800;
+    var fraction = Math.round((ts % 1000) / 1000 * Math.pow(2, 32));
+
+    buffer[offset + 0] = (seconds & 0xFF000000) >> 24;
+    buffer[offset + 1] = (seconds & 0x00FF0000) >> 16;
+    buffer[offset + 2] = (seconds & 0x0000FF00) >> 8;
+    buffer[offset + 3] = (seconds & 0x000000FF);
+
+    buffer[offset + 4] = (fraction & 0xFF000000) >> 24;
+    buffer[offset + 5] = (fraction & 0x00FF0000) >> 16;
+    buffer[offset + 6] = (fraction & 0x0000FF00) >> 8;
+    buffer[offset + 7] = (fraction & 0x000000FF);
+};
+
+
+// Offset singleton
+
+internals.last = {
+    offset: 0,
+    expires: 0,
+    host: '',
+    port: 0
+};
+
+
+exports.offset = function (options, callback) {
+
+    if (arguments.length !== 2) {
+        callback = arguments[0];
+        options = {};
+    }
+
+    var now = Date.now();
+    var clockSyncRefresh = options.clockSyncRefresh || 24 * 60 * 60 * 1000;                    // Daily
+
+    if (internals.last.offset &&
+        internals.last.host === options.host &&
+        internals.last.port === options.port &&
+        now < internals.last.expires) {
+
+        process.nextTick(function () {
+                
+            callback(null, internals.last.offset);
+        });
+
+        return;
+    }
+
+    exports.time(options, function (err, time) {
+
+        if (err) {
+            return callback(err, 0);
+        }
+
+        internals.last = {
+            offset: Math.round(time.t),
+            expires: now + clockSyncRefresh,
+            host: options.host,
+            port: options.port
+        };
+
+        return callback(null, internals.last.offset);
+    });
+};
+
+
+// Now singleton
+
+internals.now = {
+    intervalId: 0
+};
+
+
+exports.start = function (options, callback) {
+
+    if (arguments.length !== 2) {
+        callback = arguments[0];
+        options = {};
+    }
+
+    if (internals.now.intervalId) {
+        process.nextTick(function () {
+            
+            callback();
+        });
+        
+        return;
+    }
+
+    exports.offset(options, function (err, offset) {
+
+        internals.now.intervalId = setInterval(function () {
+
+            exports.offset(options, function () { });
+        }, options.clockSyncRefresh || 24 * 60 * 60 * 1000);                                // Daily
+
+        return callback();
+    });
+};
+
+
+exports.stop = function () {
+
+    if (!internals.now.intervalId) {
+        return;
+    }
+
+    clearInterval(internals.now.intervalId);
+    internals.now.intervalId = 0;
+};
+
+
+exports.isLive = function () {
+
+    return !!internals.now.intervalId;
+};
+
+
+exports.now = function () {
+
+    var now = Date.now();
+    if (!exports.isLive() ||
+        now >= internals.last.expires) {
+
+        return now;
+    }
+
+    return now + internals.last.offset;
+};
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/package.json	(revision 517)
@@ -0,0 +1,48 @@
+{
+  "name": "sntp",
+  "description": "SNTP Client",
+  "version": "0.2.4",
+  "author": {
+    "name": "Eran Hammer",
+    "email": "eran@hueniverse.com",
+    "url": "http://hueniverse.com"
+  },
+  "contributors": [],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hueniverse/sntp"
+  },
+  "main": "index",
+  "keywords": [
+    "sntp",
+    "ntp",
+    "time"
+  ],
+  "engines": {
+    "node": ">=0.8.0"
+  },
+  "dependencies": {
+    "hoek": "0.9.x"
+  },
+  "devDependencies": {
+    "lab": "0.1.x",
+    "complexity-report": "0.x.x"
+  },
+  "scripts": {
+    "test": "make test-cov"
+  },
+  "licenses": [
+    {
+      "type": "BSD",
+      "url": "http://github.com/hueniverse/sntp/raw/master/LICENSE"
+    }
+  ],
+  "readme": "# sntp\n\nAn SNTP v4 client (RFC4330) for node. Simpy connects to the NTP or SNTP server requested and returns the server time\nalong with the roundtrip duration and clock offset. To adjust the local time to the NTP time, add the returned `t` offset\nto the local time.\n\n[![Build Status](https://secure.travis-ci.org/hueniverse/sntp.png)](http://travis-ci.org/hueniverse/sntp)\n\n# Usage\n\n```javascript\nvar Sntp = require('sntp');\n\n// All options are optional\n\nvar options = {\n    host: 'nist1-sj.ustiming.org',  // Defaults to pool.ntp.org\n    port: 123,                      // Defaults to 123 (NTP)\n    resolveReference: true,         // Default to false (not resolving)\n    timeout: 1000                   // Defaults to zero (no timeout)\n};\n\n// Request server time\n\nSntp.time(options, function (err, time) {\n\n    if (err) {\n        console.log('Failed: ' + err.message);\n        process.exit(1);\n    }\n\n    console.log('Local clock is off by: ' + time.t + ' milliseconds');\n    process.exit(0);\n});\n```\n\nIf an application needs to maintain continuous time synchronization, the module provides a stateful method for\nquerying the current offset only when the last one is too old (defaults to daily).\n\n```javascript\n// Request offset once\n\nSntp.offset(function (err, offset) {\n\n    console.log(offset);                    // New (served fresh)\n\n    // Request offset again\n\n    Sntp.offset(function (err, offset) {\n\n        console.log(offset);                // Identical (served from cache)\n    });\n});\n```\n\nTo set a background offset refresh, start the interval and use the provided now() method. If for any reason the\nclient fails to obtain an up-to-date offset, the current system clock is used.\n\n```javascript\nvar before = Sntp.now();                    // System time without offset\n\nSntp.start(function () {\n\n    var now = Sntp.now();                   // With offset\n    Sntp.stop();\n});\n```\n\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/hueniverse/sntp/issues"
+  },
+  "homepage": "https://github.com/hueniverse/sntp",
+  "_id": "sntp@0.2.4",
+  "_from": "sntp@0.2.x"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/test/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/test/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/node_modules/sntp/test/index.js	(revision 517)
@@ -0,0 +1,359 @@
+// Load modules
+
+var Dgram = require('dgram');
+var Lab = require('lab');
+var Sntp = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('SNTP', function () {
+
+    describe('#time', function () {
+
+        it('returns consistent result over multiple tries', function (done) {
+
+            Sntp.time(function (err, time) {
+
+                expect(err).to.not.exist;
+                expect(time).to.exist;
+                var t1 = time.t;
+
+                Sntp.time(function (err, time) {
+
+                    expect(err).to.not.exist;
+                    expect(time).to.exist;
+                    var t2 = time.t;
+                    expect(Math.abs(t1 - t2)).is.below(200);
+                    done();
+                });
+            });
+        });
+
+        it('resolves reference IP', function (done) {
+
+            Sntp.time({ host: 'ntp.exnet.com', resolveReference: true }, function (err, time) {
+
+                expect(err).to.not.exist;
+                expect(time).to.exist;
+                expect(time.referenceHost).to.exist;
+                done();
+            });
+        });
+
+        it('times out on no response', function (done) {
+
+            Sntp.time({ port: 124, timeout: 100 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time).to.not.exist;
+                expect(err.message).to.equal('Timeout');
+                done();
+            });
+        });
+
+        it('errors on error event', function (done) {
+
+            var orig = Dgram.createSocket;
+            Dgram.createSocket = function (type) {
+
+                Dgram.createSocket = orig;
+                var socket = Dgram.createSocket(type);
+                process.nextTick(function () { socket.emit('error', new Error('Fake')) });
+                return socket;
+            };
+
+            Sntp.time(function (err, time) {
+
+                expect(err).to.exist;
+                expect(time).to.not.exist;
+                expect(err.message).to.equal('Fake');
+                done();
+            });
+        });
+
+        it('times out on invalid host', function (done) {
+
+            Sntp.time({ host: 'error', timeout: 10000 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time).to.not.exist;
+                expect(err.message).to.equal('getaddrinfo ENOTFOUND');
+                done();
+            });
+        });
+
+        it('fails on bad response buffer size', function (done) {
+
+            var server = Dgram.createSocket('udp4');
+            server.on('message', function (message, remote) {
+                var message = new Buffer(10);
+                server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) {
+
+                    server.close();
+                });
+            });
+
+            server.bind(49123);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Invalid server response');
+                done();
+            });
+        });
+
+        var messup = function (bytes) {
+
+            var server = Dgram.createSocket('udp4');
+            server.on('message', function (message, remote) {
+
+                var message = new Buffer([
+                    0x24, 0x01, 0x00, 0xe3,
+                    0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00,
+                    0x41, 0x43, 0x54, 0x53,
+                    0xd4, 0xa8, 0x2d, 0xc7,
+                    0x1c, 0x5d, 0x49, 0x1b,
+                    0xd4, 0xa8, 0x2d, 0xe6,
+                    0x67, 0xef, 0x9d, 0xb2,
+                    0xd4, 0xa8, 0x2d, 0xe6,
+                    0x71, 0xed, 0xb5, 0xfb,
+                    0xd4, 0xa8, 0x2d, 0xe6,
+                    0x71, 0xee, 0x6c, 0xc5
+                ]);
+
+                for (var i = 0, il = bytes.length; i < il; ++i) {
+                    message[bytes[i][0]] = bytes[i][1];
+                }
+
+                server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) {
+
+                    server.close();
+                });
+            });
+
+            server.bind(49123);
+        };
+
+        it('fails on bad version', function (done) {
+
+            messup([[0, (0 << 6) + (3 << 3) + (4 << 0)]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time.version).to.equal(3);
+                expect(err.message).to.equal('Invalid server response');
+                done();
+            });
+        });
+
+        it('fails on bad originate timestamp and alarm li', function (done) {
+
+            messup([[0, (3 << 6) + (4 << 3) + (4 << 0)]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Wrong originate timestamp');
+                expect(time.leapIndicator).to.equal('alarm');
+                done();
+            });
+        });
+
+        it('returns time with death stratum and last61 li', function (done) {
+
+            messup([[0, (1 << 6) + (4 << 3) + (4 << 0)], [1, 0]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(time.stratum).to.equal('death');
+                expect(time.leapIndicator).to.equal('last-minute-61');
+                done();
+            });
+        });
+
+        it('returns time with reserved stratum and last59 li', function (done) {
+
+            messup([[0, (2 << 6) + (4 << 3) + (4 << 0)], [1, 0x1f]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(time.stratum).to.equal('reserved');
+                expect(time.leapIndicator).to.equal('last-minute-59');
+                done();
+            });
+        });
+
+        it('fails on bad mode (symmetric-active)', function (done) {
+
+            messup([[0, (0 << 6) + (4 << 3) + (1 << 0)]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time.mode).to.equal('symmetric-active');
+                done();
+            });
+        });
+
+        it('fails on bad mode (symmetric-passive)', function (done) {
+
+            messup([[0, (0 << 6) + (4 << 3) + (2 << 0)]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time.mode).to.equal('symmetric-passive');
+                done();
+            });
+        });
+
+        it('fails on bad mode (client)', function (done) {
+
+            messup([[0, (0 << 6) + (4 << 3) + (3 << 0)]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time.mode).to.equal('client');
+                done();
+            });
+        });
+
+        it('fails on bad mode (broadcast)', function (done) {
+
+            messup([[0, (0 << 6) + (4 << 3) + (5 << 0)]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time.mode).to.equal('broadcast');
+                done();
+            });
+        });
+
+        it('fails on bad mode (reserved)', function (done) {
+
+            messup([[0, (0 << 6) + (4 << 3) + (6 << 0)]]);
+
+            Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
+
+                expect(err).to.exist;
+                expect(time.mode).to.equal('reserved');
+                done();
+            });
+        });
+    });
+
+    describe('#offset', function () {
+
+        it('gets the current offset', function (done) {
+
+            Sntp.offset(function (err, offset) {
+
+                expect(err).to.not.exist;
+                expect(offset).to.not.equal(0);
+                done();
+            });
+        });
+
+        it('gets the current offset from cache', function (done) {
+
+            Sntp.offset(function (err, offset) {
+
+                expect(err).to.not.exist;
+                expect(offset).to.not.equal(0);
+                var offset1 = offset;
+                Sntp.offset({}, function (err, offset) {
+
+                    expect(err).to.not.exist;
+                    expect(offset).to.equal(offset1);
+                    done();
+                });
+            });
+        });
+
+        it('fails getting the current offset on invalid server', function (done) {
+
+            Sntp.offset({ host: 'error' }, function (err, offset) {
+
+                expect(err).to.exist;
+                expect(offset).to.equal(0);
+                done();
+            });
+        });
+    });
+
+    describe('#now', function () {
+
+        it('starts auto-sync, gets now, then stops', function (done) {
+
+            Sntp.stop();
+
+            var before = Sntp.now();
+            expect(before).to.equal(Date.now());
+
+            Sntp.start(function () {
+
+                var now = Sntp.now();
+                expect(now).to.not.equal(Date.now());
+                Sntp.stop();
+
+                done();
+            });
+        });
+
+        it('starts twice', function (done) {
+
+            Sntp.start(function () {
+
+                Sntp.start(function () {
+
+                    var now = Sntp.now();
+                    expect(now).to.not.equal(Date.now());
+                    Sntp.stop();
+
+                    done();
+                });
+            });
+        });
+
+        it('starts auto-sync, gets now, waits, gets again after timeout', function (done) {
+
+            Sntp.stop();
+
+            var before = Sntp.now();
+            expect(before).to.equal(Date.now());
+
+            Sntp.start({ clockSyncRefresh: 100 }, function () {
+
+                var now = Sntp.now();
+                expect(now).to.not.equal(Date.now());
+                expect(now).to.equal(Sntp.now());
+
+                setTimeout(function () {
+
+                    expect(Sntp.now()).to.not.equal(now);
+                    Sntp.stop();
+                    done();
+                }, 110);
+            });
+        });
+    });
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/package.json	(revision 517)
@@ -0,0 +1,53 @@
+{
+  "name": "hawk",
+  "description": "HTTP Hawk Authentication Scheme",
+  "version": "1.0.0",
+  "author": {
+    "name": "Eran Hammer",
+    "email": "eran@hueniverse.com",
+    "url": "http://hueniverse.com"
+  },
+  "contributors": [],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hueniverse/hawk"
+  },
+  "main": "index",
+  "keywords": [
+    "http",
+    "authentication",
+    "scheme",
+    "hawk"
+  ],
+  "engines": {
+    "node": ">=0.8.0"
+  },
+  "dependencies": {
+    "hoek": "0.9.x",
+    "boom": "0.4.x",
+    "cryptiles": "0.2.x",
+    "sntp": "0.2.x"
+  },
+  "devDependencies": {
+    "lab": "0.1.x",
+    "complexity-report": "0.x.x",
+    "localStorage": "1.0.x"
+  },
+  "scripts": {
+    "test": "make test-cov"
+  },
+  "licenses": [
+    {
+      "type": "BSD",
+      "url": "http://github.com/hueniverse/hawk/raw/master/LICENSE"
+    }
+  ],
+  "readme": "![hawk Logo](https://raw.github.com/hueniverse/hawk/master/images/hawk.png)\n\n<img align=\"right\" src=\"https://raw.github.com/hueniverse/hawk/master/images/logo.png\" /> **Hawk** is an HTTP authentication scheme using a message authentication code (MAC) algorithm to provide partial\nHTTP request cryptographic verification. For more complex use cases such as access delegation, see [Oz](https://github.com/hueniverse/oz).\n\nCurrent version: **1.0**\n\n[![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk)\n\n# Table of Content\n\n- [**Introduction**](#introduction)\n  - [Replay Protection](#replay-protection)\n  - [Usage Example](#usage-example)\n  - [Protocol Example](#protocol-example)\n    - [Payload Validation](#payload-validation)\n    - [Response Payload Validation](#response-payload-validation)\n  - [Browser Support and Considerations](#browser-support-and-considerations)\n<p></p>\n- [**Single URI Authorization**](#single-uri-authorization)\n  - [Usage Example](#bewit-usage-example)\n<p></p>\n- [**Security Considerations**](#security-considerations)\n  - [MAC Keys Transmission](#mac-keys-transmission)\n  - [Confidentiality of Requests](#confidentiality-of-requests)\n  - [Spoofing by Counterfeit Servers](#spoofing-by-counterfeit-servers)\n  - [Plaintext Storage of Credentials](#plaintext-storage-of-credentials)\n  - [Entropy of Keys](#entropy-of-keys)\n  - [Coverage Limitations](#coverage-limitations)\n  - [Future Time Manipulation](#future-time-manipulation)\n  - [Client Clock Poisoning](#client-clock-poisoning)\n  - [Bewit Limitations](#bewit-limitations)\n  - [Host Header Forgery](#host-header-forgery)\n<p></p>\n- [**Frequently Asked Questions**](#frequently-asked-questions)\n<p></p>\n- [**Acknowledgements**](#acknowledgements)\n\n# Introduction\n\n**Hawk** is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with\npartial cryptographic verification of the request and response, covering the HTTP method, request URI, host,\nand optionally the request payload.\n\nSimilar to the HTTP [Digest access authentication schemes](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** uses a set of\nclient credentials which include an identifier (e.g. username) and key (e.g. password). Likewise, just as with the Digest scheme,\nthe key is never included in authenticated requests. Instead, it is used to calculate a request MAC value which is\nincluded in its place.\n\nHowever, **Hawk** has several differences from Digest. In particular, while both use a nonce to limit the possibility of\nreplay attacks, in **Hawk** the client generates the nonce and uses it in combination with a timestamp, leading to less\n\"chattiness\" (interaction with the server).\n\nAlso unlike Digest, this scheme is not intended to protect the key itself (the password in Digest) because\nthe client and server must both have access to the key material in the clear.\n\nThe primary design goals of this scheme are to:\n* simplify and improve HTTP authentication for services that are unwilling or unable to deploy TLS for all resources,\n* secure credentials against leakage (e.g., when the client uses some form of dynamic configuration to determine where\n  to send an authenticated request), and\n* avoid the exposure of credentials sent to a malicious server over an unauthenticated secure channel due to client\n  failure to validate the server's identity as part of its TLS handshake.\n\nIn addition, **Hawk** supports a method for granting third-parties temporary access to individual resources using\na query parameter called _bewit_ (in falconry, a leather strap used to attach a tracking device to the leg of a hawk).\n\nThe **Hawk** scheme requires the establishment of a shared symmetric key between the client and the server,\nwhich is beyond the scope of this module. Typically, the shared credentials are established via an initial\nTLS-protected phase or derived from some other shared confidential information available to both the client\nand the server.\n\n\n## Replay Protection\n\nWithout replay protection, an attacker can use a compromised (but otherwise valid and authenticated) request more \nthan once, gaining access to a protected resource. To mitigate this, clients include both a nonce and a timestamp when \nmaking requests. This gives the server enough information to prevent replay attacks.\n\nThe nonce is generated by the client, and is a string unique across all requests with the same timestamp and\nkey identifier combination. \n\nThe timestamp enables the server to restrict the validity period of the credentials where requests occuring afterwards\nare rejected. It also removes the need for the server to retain an unbounded number of nonce values for future checks.\nBy default, **Hawk** uses a time window of 1 minute to allow for time skew between the client and server (which in\npractice translates to a maximum of 2 minutes as the skew can be positive or negative).\n\nUsing a timestamp requires the client's clock to be in sync with the server's clock. **Hawk** requires both the client\nclock and the server clock to use NTP to ensure synchronization. However, given the limitations of some client types\n(e.g. browsers) to deploy NTP, the server provides the client with its current time (in seconds precision) in response\nto a bad timestamp.\n\nThere is no expectation that the client will adjust its system clock to match the server (in fact, this would be a\npotential attack vector). Instead, the client only uses the server's time to calculate an offset used only\nfor communications with that particular server. The protocol rewards clients with synchronized clocks by reducing\nthe number of round trips required to authenticate the first request.\n\n\n## Usage Example\n\nServer code:\n\n```javascript\nvar Http = require('http');\nvar Hawk = require('hawk');\n\n\n// Credentials lookup function\n\nvar credentialsFunc = function (id, callback) {\n\n    var credentials = {\n        key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\n        algorithm: 'sha256',\n        user: 'Steve'\n    };\n\n    return callback(null, credentials);\n};\n\n// Create HTTP server\n\nvar handler = function (req, res) {\n\n    // Authenticate incoming request\n\n    Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {\n\n        // Prepare response\n\n        var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');\n        var headers = { 'Content-Type': 'text/plain' };\n\n        // Generate Server-Authorization response header\n\n        var header = Hawk.server.header(credentials, artifacts, { payload: payload, contentType: headers['Content-Type'] });\n        headers['Server-Authorization'] = header;\n\n        // Send the response back\n\n        res.writeHead(!err ? 200 : 401, headers);\n        res.end(payload);\n    });\n};\n\n// Start server\n\nHttp.createServer(handler).listen(8000, 'example.com');\n```\n\nClient code:\n\n```javascript\nvar Request = require('request');\nvar Hawk = require('hawk');\n\n\n// Client credentials\n\nvar credentials = {\n    id: 'dh37fgj492je',\n    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\n    algorithm: 'sha256'\n}\n\n// Request options\n\nvar requestOptions = {\n    uri: 'http://example.com:8000/resource/1?b=1&a=2',\n    method: 'GET',\n    headers: {}\n};\n\n// Generate Authorization request header\n\nvar header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });\nrequestOptions.headers.Authorization = header.field;\n\n// Send authenticated request\n\nRequest(requestOptions, function (error, response, body) {\n\n    // Authenticate the server's response\n\n    var isValid = Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });\n\n    // Output results\n\n    console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));\n});\n```\n\n**Hawk** utilized the [**SNTP**](https://github.com/hueniverse/sntp) module for time sync management. By default, the local\nmachine time is used. To automatically retrieve and synchronice the clock within the application, use the SNTP 'start()' method.\n\n```javascript\nHawk.sntp.start();\n```\n\n\n## Protocol Example\n\nThe client attempts to access a protected resource without authentication, sending the following HTTP request to\nthe resource server:\n\n```\nGET /resource/1?b=1&a=2 HTTP/1.1\nHost: example.com:8000\n```\n\nThe resource server returns an authentication challenge.\n\n```\nHTTP/1.1 401 Unauthorized\nWWW-Authenticate: Hawk\n```\n\nThe client has previously obtained a set of **Hawk** credentials for accessing resources on the \"http://example.com/\"\nserver. The **Hawk** credentials issued to the client include the following attributes:\n\n* Key identifier: dh37fgj492je\n* Key: werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn\n* Algorithm: sha256\n\nThe client generates the authentication header by calculating a timestamp (e.g. the number of seconds since January 1,\n1970 00:00:00 GMT), generating a nonce, and constructing the normalized request string (each value followed by a newline\ncharacter):\n\n```\nhawk.1.header\n1353832234\nj4h3g2\nGET\n/resource/1?b=1&a=2\nexample.com\n8000\n\nsome-app-ext-data\n\n```\n\nThe request MAC is calculated using HMAC with the specified hash algorithm \"sha256\" and the key over the normalized request string.\nThe result is base64-encoded to produce the request MAC:\n\n```\n6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\n```\n\nThe client includes the **Hawk** key identifier, timestamp, nonce, application specific data, and request MAC with the request using\nthe HTTP `Authorization` request header field:\n\n```\nGET /resource/1?b=1&a=2 HTTP/1.1\nHost: example.com:8000\nAuthorization: Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", ext=\"some-app-ext-data\", mac=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\"\n```\n\nThe server validates the request by calculating the request MAC again based on the request received and verifies the validity\nand scope of the **Hawk** credentials. If valid, the server responds with the requested resource.\n\n\n### Payload Validation\n\n**Hawk** provides optional payload validation. When generating the authentication header, the client calculates a payload hash\nusing the specified hash algorithm. The hash is calculated over the concatenated value of (each followed by a newline character):\n* `hawk.1.payload`\n* the content-type in lowercase, without any parameters (e.g. `application/json`)\n* the request payload prior to any content encoding (the exact representation requirements should be specified by the server for payloads other than simple single-part ascii to ensure interoperability)\n\nFor example:\n\n* Payload: `Thank you for flying Hawk`\n* Content Type: `text/plain`\n* Hash (sha256): `Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=`\n\nResults in the following input to the payload hash function (newline terminated values):\n\n```\nhawk.1.payload\ntext/plain\nThank you for flying Hawk\n\n```\n\nWhich produces the following hash value:\n\n```\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\n```\n\nThe client constructs the normalized request string (newline terminated values):\n\n```\nhawk.1.header\n1353832234\nj4h3g2\nPOST\n/resource/1?a=1&b=2\nexample.com\n8000\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\nsome-app-ext-data\n\n```\n\nThen calculates the request MAC and includes the **Hawk** key identifier, timestamp, nonce, payload hash, application specific data,\nand request MAC, with the request using the HTTP `Authorization` request header field:\n\n```\nPOST /resource/1?a=1&b=2 HTTP/1.1\nHost: example.com:8000\nAuthorization: Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", hash=\"Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\", ext=\"some-app-ext-data\", mac=\"aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw=\"\n```\n\nIt is up to the server if and when it validates the payload for any given request, based solely on it's security policy\nand the nature of the data included.\n\nIf the payload is available at the time of authentication, the server uses the hash value provided by the client to construct\nthe normalized string and validates the MAC. If the MAC is valid, the server calculates the payload hash and compares the value\nwith the provided payload hash in the header. In many cases, checking the MAC first is faster than calculating the payload hash.\n\nHowever, if the payload is not available at authentication time (e.g. too large to fit in memory, streamed elsewhere, or processed\nat a different stage in the application), the server may choose to defer payload validation for later by retaining the hash value\nprovided by the client after validating the MAC.\n\nIt is important to note that MAC validation does not mean the hash value provided by the client is valid, only that the value\nincluded in the header was not modified. Without calculating the payload hash on the server and comparing it to the value provided\nby the client, the payload may be modified by an attacker.\n\n\n## Response Payload Validation\n\n**Hawk** provides partial response payload validation. The server includes the `Server-Authorization` response header which enables the\nclient to authenticate the response and ensure it is talking to the right server. **Hawk** defines the HTTP `Server-Authorization` header\nas a response header using the exact same syntax as the `Authorization` request header field.\n\nThe header is contructed using the same process as the client's request header. The server uses the same credentials and other\nartifacts provided by the client to constructs the normalized request string. The `ext` and `hash` values are replaced with\nnew values based on the server response. The rest as identical to those used by the client.\n\nThe result MAC digest is included with the optional `hash` and `ext` values:\n\n```\nServer-Authorization: Hawk mac=\"XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=\", hash=\"f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=\", ext=\"response-specific\"\n```\n\n\n## Browser Support and Considerations\n\nA browser script is provided for including using a `<script>` tag in [lib/browser.js](/lib/browser.js).\n\n**Hawk** relies on the _Server-Authorization_ and _WWW-Authenticate_ headers in its response to communicate with the client.\nTherefore, in case of CORS requests, it is important to consider sending _Access-Control-Expose-Headers_ with the value\n_\"WWW-Authenticate, Server-Authorization\"_ on each response from your server. As explained in the\n[specifications](http://www.w3.org/TR/cors/#access-control-expose-headers-response-header), it will indicate that these headers\ncan safely be accessed by the client (using getResponseHeader() on the XmlHttpRequest object). Otherwise you will be met with a\n[\"simple response header\"](http://www.w3.org/TR/cors/#simple-response-header) which excludes these fields and would prevent the\nHawk client from authenticating the requests.You can read more about the why and how in this\n[article](http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server)\n\n\n# Single URI Authorization\n\nThere are cases in which limited and short-term access to a protected resource is granted to a third party which does not\nhave access to the shared credentials. For example, displaying a protected image on a web page accessed by anyone. **Hawk**\nprovides limited support for such URIs in the form of a _bewit_ - a URI query parameter appended to the request URI which contains\nthe necessary credentials to authenticate the request.\n\nBecause of the significant security risks involved in issuing such access, bewit usage is purposely limited only to GET requests\nand for a finite period of time. Both the client and server can issue bewit credentials, however, the server should not use the same\ncredentials as the client to maintain clear traceability as to who issued which credentials.\n\nIn order to simplify implementation, bewit credentials do not support single-use policy and can be replayed multiple times within\nthe granted access timeframe. \n\n\n## Bewit Usage Example\n\nServer code:\n\n```javascript\nvar Http = require('http');\nvar Hawk = require('hawk');\n\n\n// Credentials lookup function\n\nvar credentialsFunc = function (id, callback) {\n\n    var credentials = {\n        key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\n        algorithm: 'sha256'\n    };\n\n    return callback(null, credentials);\n};\n\n// Create HTTP server\n\nvar handler = function (req, res) {\n\n    Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {\n\n        res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });\n        res.end(!err ? 'Access granted' : 'Shoosh!');\n    });\n};\n\nHttp.createServer(handler).listen(8000, 'example.com');\n```\n\nBewit code generation:\n\n```javascript\nvar Request = require('request');\nvar Hawk = require('hawk');\n\n\n// Client credentials\n\nvar credentials = {\n    id: 'dh37fgj492je',\n    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\n    algorithm: 'sha256'\n}\n\n// Generate bewit\n\nvar duration = 60 * 5;      // 5 Minutes\nvar bewit = Hawk.uri.getBewit('http://example.com:8080/resource/1?b=1&a=2', { credentials: credentials, ttlSec: duration, ext: 'some-app-data' });\nvar uri = 'http://example.com:8000/resource/1?b=1&a=2' + '&bewit=' + bewit;\n```\n\n\n# Security Considerations\n\nThe greatest sources of security risks are usually found not in **Hawk** but in the policies and procedures surrounding its use.\nImplementers are strongly encouraged to assess how this module addresses their security requirements. This section includes\nan incomplete list of security considerations that must be reviewed and understood before deploying **Hawk** on the server.\nMany of the protections provided in **Hawk** depends on whether and how they are used.\n\n### MAC Keys Transmission\n\n**Hawk** does not provide any mechanism for obtaining or transmitting the set of shared credentials required. Any mechanism used\nto obtain **Hawk** credentials must ensure that these transmissions are protected using transport-layer mechanisms such as TLS.\n\n### Confidentiality of Requests\n\nWhile **Hawk** provides a mechanism for verifying the integrity of HTTP requests, it provides no guarantee of request\nconfidentiality. Unless other precautions are taken, eavesdroppers will have full access to the request content. Servers should\ncarefully consider the types of data likely to be sent as part of such requests, and employ transport-layer security mechanisms\nto protect sensitive resources.\n\n### Spoofing by Counterfeit Servers\n\n**Hawk** provides limited verification of the server authenticity. When receiving a response back from the server, the server\nmay choose to include a response `Server-Authorization` header which the client can use to verify the response. However, it is up to\nthe server to determine when such measure is included, to up to the client to enforce that policy.\n\nA hostile party could take advantage of this by intercepting the client's requests and returning misleading or otherwise\nincorrect responses. Service providers should consider such attacks when developing services using this protocol, and should\nrequire transport-layer security for any requests where the authenticity of the resource server or of server responses is an issue.\n\n### Plaintext Storage of Credentials\n\nThe **Hawk** key functions the same way passwords do in traditional authentication systems. In order to compute the request MAC,\nthe server must have access to the key in plaintext form. This is in contrast, for example, to modern operating systems, which\nstore only a one-way hash of user credentials.\n\nIf an attacker were to gain access to these keys - or worse, to the server's database of all such keys - he or she would be able\nto perform any action on behalf of any resource owner. Accordingly, it is critical that servers protect these keys from unauthorized\naccess.\n\n### Entropy of Keys\n\nUnless a transport-layer security protocol is used, eavesdroppers will have full access to authenticated requests and request\nMAC values, and will thus be able to mount offline brute-force attacks to recover the key used. Servers should be careful to\nassign keys which are long enough, and random enough, to resist such attacks for at least the length of time that the **Hawk**\ncredentials are valid.\n\nFor example, if the credentials are valid for two weeks, servers should ensure that it is not possible to mount a brute force\nattack that recovers the key in less than two weeks. Of course, servers are urged to err on the side of caution, and use the\nlongest key reasonable.\n\nIt is equally important that the pseudo-random number generator (PRNG) used to generate these keys be of sufficiently high\nquality. Many PRNG implementations generate number sequences that may appear to be random, but which nevertheless exhibit\npatterns or other weaknesses which make cryptanalysis or brute force attacks easier. Implementers should be careful to use\ncryptographically secure PRNGs to avoid these problems.\n\n### Coverage Limitations\n\nThe request MAC only covers the HTTP `Host` header and optionally the `Content-Type` header. It does not cover any other headers\nwhich can often affect how the request body is interpreted by the server. If the server behavior is influenced by the presence\nor value of such headers, an attacker can manipulate the request headers without being detected. Implementers should use the\n`ext` feature to pass application-specific information via the `Authorization` header which is protected by the request MAC.\n\nThe response authentication, when performed, only covers the response payload, content-type, and the request information \nprovided by the client in it's request (method, resource, timestamp, nonce, etc.). It does not cover the HTTP status code or\nany other response header field (e.g. Location) which can affect the client's behaviour.\n\n### Future Time Manipulation\n\nThe protocol relies on a clock sync between the client and server. To accomplish this, the server informs the client of its\ncurrent time when an invalid timestamp is received.\n\nIf an attacker is able to manipulate this information and cause the client to use an incorrect time, it would be able to cause\nthe client to generate authenticated requests using time in the future. Such requests will fail when sent by the client, and will\nnot likely leave a trace on the server (given the common implementation of nonce, if at all enforced). The attacker will then\nbe able to replay the request at the correct time without detection.\n\nThe client must only use the time information provided by the server if:\n* it was delivered over a TLS connection and the server identity has been verified, or\n* the `tsm` MAC digest calculated using the same client credentials over the timestamp has been verified.\n\n### Client Clock Poisoning\n\nWhen receiving a request with a bad timestamp, the server provides the client with its current time. The client must never use\nthe time received from the server to adjust its own clock, and must only use it to calculate an offset for communicating with\nthat particular server.\n\n### Bewit Limitations\n\nSpecial care must be taken when issuing bewit credentials to third parties. Bewit credentials are valid until expiration and cannot\nbe revoked or limited without using other means. Whatever resource they grant access to will be completely exposed to anyone with\naccess to the bewit credentials which act as bearer credentials for that particular resource. While bewit usage is limited to GET\nrequests only and therefore cannot be used to perform transactions or change server state, it can still be used to expose private\nand sensitive information.\n\n### Host Header Forgery\n\nHawk validates the incoming request MAC against the incoming HTTP Host header. However, unless the optional `host` and `port`\noptions are used with `server.authenticate()`, a malicous client can mint new host names pointing to the server's IP address and\nuse that to craft an attack by sending a valid request that's meant for another hostname than the one used by the server. Server\nimplementors must manually verify that the host header received matches their expectation (or use the options mentioned above).\n\n# Frequently Asked Questions\n\n### Where is the protocol specification?\n\nIf you are looking for some prose explaining how all this works, **this is it**. **Hawk** is being developed as an open source\nproject instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification. Not sure about\nsomething? Open an issue!\n\n### Is it done?\n\nAt if version 0.10.0, **Hawk** is feature-complete. However, until this module reaches version 1.0.0 it is considered experimental\nand is likely to change. This also means your feedback and contribution are very welcome. Feel free to open issues with questions\nand suggestions.\n\n### Where can I find **Hawk** implementations in other languages?\n\n**Hawk**'s only reference implementation is provided in JavaScript as a node.js module. However, others are actively porting it to other\nplatforms. There is already a [PHP](https://github.com/alexbilbie/PHP-Hawk),\n[.NET](https://github.com/pcibraro/hawknet), and [JAVA](https://github.com/wealdtech/hawk) libraries available. The full list\nis maintained [here](https://github.com/hueniverse/hawk/issues?labels=port). Please add an issue if you are working on another\nport. A cross-platform test-suite is in the works.\n\n### Why isn't the algorithm part of the challenge or dynamically negotiated?\n\nThe algorithm used is closely related to the key issued as different algorithms require different key sizes (and other\nrequirements). While some keys can be used for multiple algorithm, the protocol is designed to closely bind the key and algorithm\ntogether as part of the issued credentials.\n\n### Why is Host and Content-Type the only headers covered by the request MAC?\n\nIt is really hard to include other headers. Headers can be changed by proxies and other intermediaries and there is no\nwell-established way to normalize them. Many platforms change the case of header field names and values. The only\nstraight-forward solution is to include the headers in some blob (say, base64 encoded JSON) and include that with the request,\nan approach taken by JWT and other such formats. However, that design violates the HTTP header boundaries, repeats information,\nand introduces other security issues because firewalls will not be aware of these \"hidden\" headers. In addition, any information\nrepeated must be compared to the duplicated information in the header and therefore only moves the problem elsewhere.\n\n### Why not just use HTTP Digest?\n\nDigest requires pre-negotiation to establish a nonce. This means you can't just make a request - you must first send\na protocol handshake to the server. This pattern has become unacceptable for most web services, especially mobile\nwhere extra round-trip are costly.\n\n### Why bother with all this nonce and timestamp business?\n\n**Hawk** is an attempt to find a reasonable, practical compromise between security and usability. OAuth 1.0 got timestamp\nand nonces halfway right but failed when it came to scalability and consistent developer experience. **Hawk** addresses\nit by requiring the client to sync its clock, but provides it with tools to accomplish it.\n\nIn general, replay protection is a matter of application-specific threat model. It is less of an issue on a TLS-protected\nsystem where the clients are implemented using best practices and are under the control of the server. Instead of dropping\nreplay protection, **Hawk** offers a required time window and an optional nonce verification. Together, it provides developers\nwith the ability to decide how to enforce their security policy without impacting the client's implementation.\n\n### What are `app` and `dlg` in the authorization header and normalized mac string?\n\nThe original motivation for **Hawk** was to replace the OAuth 1.0 use cases. This included both a simple client-server mode which\nthis module is specifically designed for, and a delegated access mode which is being developed separately in\n[Oz](https://github.com/hueniverse/oz). In addition to the **Hawk** use cases, Oz requires another attribute: the application id `app`.\nThis provides binding between the credentials and the application in a way that prevents an attacker from tricking an application\nto use credentials issued to someone else. It also has an optional 'delegated-by' attribute `dlg` which is the application id of the\napplication the credentials were directly issued to. The goal of these two additions is to allow Oz to utilize **Hawk** directly,\nbut with the additional security of delegated credentials.\n\n### What is the purpose of the static strings used in each normalized MAC input?\n\nWhen calculating a hash or MAC, a static prefix (tag) is added. The prefix is used to prevent MAC values from being\nused or reused for a purpose other than what they were created for (i.e. prevents switching MAC values between a request,\nresponse, and a bewit use cases). It also protects against expliots created after a potential change in how the protocol\ncreates the normalized string. For example, if a future version would switch the order of nonce and timestamp, it\ncan create an exploit opportunity for cases where the nonce is similar in format to a timestamp.\n\n### Does **Hawk** have anything to do with OAuth?\n\nShort answer: no.\n\n**Hawk** was originally proposed as the OAuth MAC Token specification. However, the OAuth working group in its consistent\nincompetence failed to produce a final, usable solution to address one of the most popular use cases of OAuth 1.0 - using it\nto authenticate simple client-server transactions (i.e. two-legged). As you can guess, the OAuth working group is still hard\nat work to produce more garbage.\n\n**Hawk** provides a simple HTTP authentication scheme for making client-server requests. It does not address the OAuth use case\nof delegating access to a third party. If you are looking for an OAuth alternative, check out [Oz](https://github.com/hueniverse/oz).\n\n\n# Acknowledgements\n\n**Hawk** is a derivative work of the [HTTP MAC Authentication Scheme](http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05) proposal\nco-authored by Ben Adida, Adam Barth, and Eran Hammer, which in turn was based on the OAuth 1.0 community specification.\n\nSpecial thanks to Ben Laurie for his always insightful feedback and advice.\n\nThe **Hawk** logo was created by [Chris Carrasco](http://chriscarrasco.com).\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/hueniverse/hawk/issues"
+  },
+  "homepage": "https://github.com/hueniverse/hawk",
+  "_id": "hawk@1.0.0",
+  "_from": "hawk@~1.0.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/browser.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/browser.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/browser.js	(revision 517)
@@ -0,0 +1,771 @@
+// Load modules
+
+var Lab = require('lab');
+var Hoek = require('hoek');
+var Hawk = require('../lib');
+var Browser = require('../lib/browser');
+var LocalStorage = require('localStorage');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Browser', function () {
+
+    var credentialsFunc = function (id, callback) {
+
+        var credentials = {
+            id: id,
+            key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+            algorithm: (id === '1' ? 'sha1' : 'sha256'),
+            user: 'steve'
+        };
+
+        return callback(null, credentials);
+    };
+
+    it('should generate a header then successfully parse it (configuration)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+            expect(req.authorization).to.exist;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (node request)', function (done) {
+
+        var req = {
+            method: 'POST',
+            url: '/resource/4?filter=a',
+            headers: {
+                host: 'example.com:8080',
+                'content-type': 'text/plain;x=y'
+            }
+        };
+
+        var payload = 'some not so random text';
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+            req.headers.authorization = reqHeader.field;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+                expect(res.headers['server-authorization']).to.exist;
+
+                expect(Browser.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(true);
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (no server header options)', function (done) {
+
+        var req = {
+            method: 'POST',
+            url: '/resource/4?filter=a',
+            headers: {
+                host: 'example.com:8080',
+                'content-type': 'text/plain;x=y'
+            }
+        };
+
+        var payload = 'some not so random text';
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+            req.headers.authorization = reqHeader.field;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+                expect(res.headers['server-authorization']).to.exist;
+
+                expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (no server header)', function (done) {
+
+        var req = {
+            method: 'POST',
+            url: '/resource/4?filter=a',
+            headers: {
+                host: 'example.com:8080',
+                'content-type': 'text/plain;x=y'
+            }
+        };
+
+        var payload = 'some not so random text';
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+            req.headers.authorization = reqHeader.field;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
+                done();
+            });
+        });
+    });
+
+    it('should generate a header with stale ts and successfully authenticate on second call', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            Browser.utils.setNtpOffset(60 * 60 * 1000);
+            var header = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' });
+            req.authorization = header.field;
+            expect(req.authorization).to.exist;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Stale timestamp');
+
+                var res = {
+                    headers: {
+                        'www-authenticate': err.response.headers['WWW-Authenticate']
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                expect(Browser.utils.getNtpOffset()).to.equal(60 * 60 * 1000);
+                expect(Browser.client.authenticate(res, credentials, header.artifacts)).to.equal(true);
+                expect(Browser.utils.getNtpOffset()).to.equal(0);
+
+                req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+                expect(req.authorization).to.exist;
+
+                Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    expect(artifacts.ext).to.equal('some-app-data');
+                    done();
+                });
+            });
+        });
+    });
+
+    it('should generate a header with stale ts and successfully authenticate on second call (manual localStorage)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+            Browser.utils.setStorage(LocalStorage)
+
+            Browser.utils.setNtpOffset(60 * 60 * 1000);
+            var header = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' });
+            req.authorization = header.field;
+            expect(req.authorization).to.exist;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Stale timestamp');
+
+                var res = {
+                    headers: {
+                        'www-authenticate': err.response.headers['WWW-Authenticate']
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                expect(parseInt(LocalStorage.getItem('hawk_ntp_offset'))).to.equal(60 * 60 * 1000);
+                expect(Browser.utils.getNtpOffset()).to.equal(60 * 60 * 1000);
+                expect(Browser.client.authenticate(res, credentials, header.artifacts)).to.equal(true);
+                expect(Browser.utils.getNtpOffset()).to.equal(0);
+                expect(parseInt(LocalStorage.getItem('hawk_ntp_offset'))).to.equal(0);
+
+                req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+                expect(req.authorization).to.exist;
+
+                Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    expect(artifacts.ext).to.equal('some-app-data');
+                    done();
+                });
+            });
+        });
+    });
+
+    it('should generate a header then fails to parse it (missing server header hash)', function (done) {
+
+        var req = {
+            method: 'POST',
+            url: '/resource/4?filter=a',
+            headers: {
+                host: 'example.com:8080',
+                'content-type': 'text/plain;x=y'
+            }
+        };
+
+        var payload = 'some not so random text';
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+            req.headers.authorization = reqHeader.field;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+                expect(res.headers['server-authorization']).to.exist;
+
+                expect(Browser.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(false);
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (with hash)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it then validate payload', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload('hola!', credentials, artifacts)).to.be.true;
+                expect(Hawk.server.authenticatePayload('hello!', credentials, artifacts)).to.be.false;
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (app)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(artifacts.app).to.equal('asd23ased');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (app, dlg)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased', dlg: '23434szr3q4d' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(artifacts.app).to.equal('asd23ased');
+                expect(artifacts.dlg).to.equal('23434szr3q4d');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then fail authentication due to bad hash', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, { payload: 'byebye!' }, function (err, credentials, artifacts) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Bad payload hash');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header for one resource then fail to authenticate another', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+            req.url = '/something/else';
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.exist;
+                expect(credentials).to.exist;
+                done();
+            });
+        });
+    });
+
+    describe('client', function () {
+
+        describe('#header', function () {
+
+            it('should return a valid authorization header (sha1)', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'sha1'
+                };
+
+                var header = Browser.client.header('http://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about' }).field;
+                expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="bsvY3IfUllw6V5rvk4tStEvpBhE=", ext="Bazinga!", mac="qbf1ZPG/r/e06F4ht+T77LXi5vw="');
+                done();
+            });
+
+            it('should return a valid authorization header (sha256)', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'sha256'
+                };
+
+                var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+                expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ext="Bazinga!", mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="');
+                done();
+            });
+
+            it('should return a valid authorization header (no ext)', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'sha256'
+                };
+
+                var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+                expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+                done();
+            });
+
+            it('should return an empty authorization header on missing options', function (done) {
+
+                var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST').field;
+                expect(header).to.equal('');
+                done();
+            });
+
+            it('should return an empty authorization header on invalid credentials', function (done) {
+
+                var credentials = {
+                    key: '2983d45yun89q',
+                    algorithm: 'sha256'
+                };
+
+                var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 }).field;
+                expect(header).to.equal('');
+                done();
+            });
+
+            it('should return an empty authorization header on invalid algorithm', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'hmac-sha-0'
+                };
+
+                var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, payload: 'something, anything!', ext: 'Bazinga!', timestamp: 1353809207 }).field;
+                expect(header).to.equal('');
+                done();
+            });
+        });
+
+        describe('#authenticate', function () {
+
+            it('should return false on invalid header', function (done) {
+
+                var res = {
+                    headers: {
+                        'server-authorization': 'Hawk mac="abc", bad="xyz"'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                expect(Browser.client.authenticate(res, {})).to.equal(false);
+                done();
+            });
+
+            it('should return false on invalid mac', function (done) {
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain',
+                        'server-authorization': 'Hawk mac="_IJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                var artifacts = {
+                    method: 'POST',
+                    host: 'example.com',
+                    port: '8080',
+                    resource: '/resource/4?filter=a',
+                    ts: '1362336900',
+                    nonce: 'eb5S_L',
+                    hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+                    ext: 'some-app-data',
+                    app: undefined,
+                    dlg: undefined,
+                    mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+                    id: '123456'
+                };
+
+                var credentials = {
+                    id: '123456',
+                    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                    algorithm: 'sha256',
+                    user: 'steve'
+                };
+
+                expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(false);
+                done();
+            });
+
+            it('should return true on ignoring hash', function (done) {
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain',
+                        'server-authorization': 'Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                var artifacts = {
+                    method: 'POST',
+                    host: 'example.com',
+                    port: '8080',
+                    resource: '/resource/4?filter=a',
+                    ts: '1362336900',
+                    nonce: 'eb5S_L',
+                    hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+                    ext: 'some-app-data',
+                    app: undefined,
+                    dlg: undefined,
+                    mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+                    id: '123456'
+                };
+
+                var credentials = {
+                    id: '123456',
+                    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                    algorithm: 'sha256',
+                    user: 'steve'
+                };
+
+                expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
+                done();
+            });
+
+            it('should fail on invalid WWW-Authenticate header format', function (done) {
+
+                var res = {
+                    headers: {
+                        'www-authenticate': 'Hawk ts="1362346425875", tsm="PhwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", x="Stale timestamp"'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                expect(Browser.client.authenticate(res, {})).to.equal(false);
+                done();
+            });
+
+            it('should fail on invalid WWW-Authenticate header format', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                    algorithm: 'sha256',
+                    user: 'steve'
+                };
+
+                var res = {
+                    headers: {
+                        'www-authenticate': 'Hawk ts="1362346425875", tsm="hwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", error="Stale timestamp"'
+                    },
+                    getResponseHeader: function (header) {
+
+                        return res.headers[header.toLowerCase()];
+                    }
+                };
+
+                expect(Browser.client.authenticate(res, credentials)).to.equal(false);
+                done();
+            });
+        });
+
+        describe('#message', function () {
+            it('should generate an authorization then successfully parse it', function (done) {
+
+                credentialsFunc('123456', function (err, credentials) {
+
+                    var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: credentials });
+                    expect(auth).to.exist;
+
+                    Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+                        expect(err).to.not.exist;
+                        expect(credentials.user).to.equal('steve');
+                        done();
+                    });
+                });
+            });
+
+            it('should fail on missing host', function (done) {
+
+                credentialsFunc('123456', function (err, credentials) {
+
+                    var auth = Browser.client.message(null, 8080, 'some message', { credentials: credentials });
+                    expect(auth).to.not.exist;
+                    done();
+                });
+            });
+
+            it('should fail on missing credentials', function (done) {
+
+                var auth = Browser.client.message('example.com', 8080, 'some message', {});
+                expect(auth).to.not.exist;
+                done();
+            });
+
+            it('should fail on invalid algorithm', function (done) {
+
+                credentialsFunc('123456', function (err, credentials) {
+
+                    var creds = Hoek.clone(credentials);
+                    creds.algorithm = 'blah';
+                    var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: creds });
+                    expect(auth).to.not.exist;
+                    done();
+                });
+            });
+        });
+    });
+
+    describe('#parseAuthorizationHeader', function (done) {
+
+        it('returns null on missing header', function (done) {
+
+            expect(Browser.utils.parseAuthorizationHeader()).to.equal(null);
+            done();
+        });
+
+        it('returns null on bad header syntax (structure)', function (done) {
+
+            expect(Browser.utils.parseAuthorizationHeader('Hawk')).to.equal(null);
+            done();
+        });
+
+        it('returns null on bad header syntax (parts)', function (done) {
+
+            expect(Browser.utils.parseAuthorizationHeader(' ')).to.equal(null);
+            done();
+        });
+
+        it('returns null on bad scheme name', function (done) {
+
+            expect(Browser.utils.parseAuthorizationHeader('Basic asdasd')).to.equal(null);
+            done();
+        });
+
+        it('returns null on bad attribute value', function (done) {
+
+            expect(Browser.utils.parseAuthorizationHeader('Hawk test="\t"', ['test'])).to.equal(null);
+            done();
+        });
+
+        it('returns null on duplicated attribute', function (done) {
+
+            expect(Browser.utils.parseAuthorizationHeader('Hawk test="a", test="b"', ['test'])).to.equal(null);
+            done();
+        });
+    });
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/client.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/client.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/client.js	(revision 517)
@@ -0,0 +1,206 @@
+// Load modules
+
+var Url = require('url');
+var Lab = require('lab');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    describe('client', function () {
+
+        describe('#header', function () {
+
+            it('should return a valid authorization header (sha1)', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'sha1'
+                };
+
+                var header = Hawk.client.header('http://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about' }).field;
+                expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="bsvY3IfUllw6V5rvk4tStEvpBhE=", ext="Bazinga!", mac="qbf1ZPG/r/e06F4ht+T77LXi5vw="');
+                done();
+            });
+
+            it('should return a valid authorization header (sha256)', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'sha256'
+                };
+
+                var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+                expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ext="Bazinga!", mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="');
+                done();
+            });
+
+            it('should return a valid authorization header (no ext)', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'sha256'
+                };
+
+                var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+                expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+                done();
+            });
+
+            it('should return an empty authorization header on missing options', function (done) {
+
+                var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST').field;
+                expect(header).to.equal('');
+                done();
+            });
+
+            it('should return an empty authorization header on invalid credentials', function (done) {
+
+                var credentials = {
+                    key: '2983d45yun89q',
+                    algorithm: 'sha256'
+                };
+
+                var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 }).field;
+                expect(header).to.equal('');
+                done();
+            });
+
+            it('should return an empty authorization header on invalid algorithm', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: '2983d45yun89q',
+                    algorithm: 'hmac-sha-0'
+                };
+
+                var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, payload: 'something, anything!', ext: 'Bazinga!', timestamp: 1353809207 }).field;
+                expect(header).to.equal('');
+                done();
+            });
+        });
+
+        describe('#authenticate', function () {
+
+            it('should return false on invalid header', function (done) {
+
+                var res = {
+                    headers: {
+                        'server-authorization': 'Hawk mac="abc", bad="xyz"'
+                    }
+                };
+
+                expect(Hawk.client.authenticate(res, {})).to.equal(false);
+                done();
+            });
+
+            it('should return false on invalid mac', function (done) {
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain',
+                        'server-authorization': 'Hawk mac="_IJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+                    }
+                };
+
+                var artifacts = {
+                    method: 'POST',
+                    host: 'example.com',
+                    port: '8080',
+                    resource: '/resource/4?filter=a',
+                    ts: '1362336900',
+                    nonce: 'eb5S_L',
+                    hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+                    ext: 'some-app-data',
+                    app: undefined,
+                    dlg: undefined,
+                    mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+                    id: '123456'
+                };
+
+                var credentials = {
+                    id: '123456',
+                    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                    algorithm: 'sha256',
+                    user: 'steve'
+                };
+
+                expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(false);
+                done();
+            });
+
+            it('should return true on ignoring hash', function (done) {
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain',
+                        'server-authorization': 'Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+                    }
+                };
+
+                var artifacts = {
+                    method: 'POST',
+                    host: 'example.com',
+                    port: '8080',
+                    resource: '/resource/4?filter=a',
+                    ts: '1362336900',
+                    nonce: 'eb5S_L',
+                    hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+                    ext: 'some-app-data',
+                    app: undefined,
+                    dlg: undefined,
+                    mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+                    id: '123456'
+                };
+
+                var credentials = {
+                    id: '123456',
+                    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                    algorithm: 'sha256',
+                    user: 'steve'
+                };
+
+                expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(true);
+                done();
+            });
+
+            it('should fail on invalid WWW-Authenticate header format', function (done) {
+
+                var header = 'Hawk ts="1362346425875", tsm="PhwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", x="Stale timestamp"';
+                expect(Hawk.client.authenticate({ headers: { 'www-authenticate': header } }, {})).to.equal(false);
+                done();
+            });
+
+            it('should fail on invalid WWW-Authenticate header format', function (done) {
+
+                var credentials = {
+                    id: '123456',
+                    key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                    algorithm: 'sha256',
+                    user: 'steve'
+                };
+
+                var header = 'Hawk ts="1362346425875", tsm="hwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", error="Stale timestamp"';
+                expect(Hawk.client.authenticate({ headers: { 'www-authenticate': header } }, credentials)).to.equal(false);
+                done();
+            });
+        });
+    });
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/crypto.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/crypto.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/crypto.js	(revision 517)
@@ -0,0 +1,86 @@
+// Load modules
+
+var Lab = require('lab');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    describe('Crypto', function () {
+
+        describe('#generateNormalizedString', function () {
+
+            it('should return a valid normalized string', function (done) {
+
+                expect(Hawk.crypto.generateNormalizedString('header', {
+                    credentials: {
+                        key: 'dasdfasdf',
+                        algorithm: 'sha256'
+                    },
+                    ts: 1357747017,
+                    nonce: 'k3k4j5',
+                    method: 'GET',
+                    resource: '/resource/something',
+                    host: 'example.com',
+                    port: 8080
+                })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\n\n\n');
+
+                done();
+            });
+
+            it('should return a valid normalized string (ext)', function (done) {
+
+                expect(Hawk.crypto.generateNormalizedString('header', {
+                    credentials: {
+                        key: 'dasdfasdf',
+                        algorithm: 'sha256'
+                    },
+                    ts: 1357747017,
+                    nonce: 'k3k4j5',
+                    method: 'GET',
+                    resource: '/resource/something',
+                    host: 'example.com',
+                    port: 8080,
+                    ext: 'this is some app data'
+                })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\n\nthis is some app data\n');
+
+                done();
+            });
+
+            it('should return a valid normalized string (payload + ext)', function (done) {
+
+                expect(Hawk.crypto.generateNormalizedString('header', {
+                    credentials: {
+                        key: 'dasdfasdf',
+                        algorithm: 'sha256'
+                    },
+                    ts: 1357747017,
+                    nonce: 'k3k4j5',
+                    method: 'GET',
+                    resource: '/resource/something',
+                    host: 'example.com',
+                    port: 8080,
+                    hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=',
+                    ext: 'this is some app data'
+                })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\nU4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=\nthis is some app data\n');
+
+                done();
+            });
+        });
+    });
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/index.js	(revision 517)
@@ -0,0 +1,316 @@
+// Load modules
+
+var Url = require('url');
+var Lab = require('lab');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    var credentialsFunc = function (id, callback) {
+
+        var credentials = {
+            id: id,
+            key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+            algorithm: (id === '1' ? 'sha1' : 'sha256'),
+            user: 'steve'
+        };
+
+        return callback(null, credentials);
+    };
+
+    it('should generate a header then successfully parse it (configuration)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Hawk.client.header(Url.parse('http://example.com:8080/resource/4?filter=a'), req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+            expect(req.authorization).to.exist;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (node request)', function (done) {
+
+        var req = {
+            method: 'POST',
+            url: '/resource/4?filter=a',
+            headers: {
+                host: 'example.com:8080',
+                'content-type': 'text/plain;x=y'
+            }
+        };
+
+        var payload = 'some not so random text';
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+            req.headers.authorization = reqHeader.field;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain'
+                    }
+                };
+
+                res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+                expect(res.headers['server-authorization']).to.exist;
+
+                expect(Hawk.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(true);
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (no server header options)', function (done) {
+
+        var req = {
+            method: 'POST',
+            url: '/resource/4?filter=a',
+            headers: {
+                host: 'example.com:8080',
+                'content-type': 'text/plain;x=y'
+            }
+        };
+
+        var payload = 'some not so random text';
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+            req.headers.authorization = reqHeader.field;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain'
+                    }
+                };
+
+                res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+                expect(res.headers['server-authorization']).to.exist;
+
+                expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(true);
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then fails to parse it (missing server header hash)', function (done) {
+
+        var req = {
+            method: 'POST',
+            url: '/resource/4?filter=a',
+            headers: {
+                host: 'example.com:8080',
+                'content-type': 'text/plain;x=y'
+            }
+        };
+
+        var payload = 'some not so random text';
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+            req.headers.authorization = reqHeader.field;
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+                var res = {
+                    headers: {
+                        'content-type': 'text/plain'
+                    }
+                };
+
+                res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+                expect(res.headers['server-authorization']).to.exist;
+
+                expect(Hawk.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(false);
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (with hash)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it then validate payload', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(Hawk.server.authenticatePayload('hola!', credentials, artifacts)).to.be.true;
+                expect(Hawk.server.authenticatePayload('hello!', credentials, artifacts)).to.be.false;
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (app)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(artifacts.app).to.equal('asd23ased');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then successfully parse it (app, dlg)', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased', dlg: '23434szr3q4d' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(artifacts.ext).to.equal('some-app-data');
+                expect(artifacts.app).to.equal('asd23ased');
+                expect(artifacts.dlg).to.equal('23434szr3q4d');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header then fail authentication due to bad hash', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+            Hawk.server.authenticate(req, credentialsFunc, { payload: 'byebye!' }, function (err, credentials, artifacts) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Bad payload hash');
+                done();
+            });
+        });
+    });
+
+    it('should generate a header for one resource then fail to authenticate another', function (done) {
+
+        var req = {
+            method: 'GET',
+            url: '/resource/4?filter=a',
+            host: 'example.com',
+            port: 8080
+        };
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+            req.url = '/something/else';
+
+            Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                expect(err).to.exist;
+                expect(credentials).to.exist;
+                done();
+            });
+        });
+    });
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/message.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/message.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/message.js	(revision 517)
@@ -0,0 +1,246 @@
+// Load modules
+
+var Url = require('url');
+var Lab = require('lab');
+var Hoek = require('hoek');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    var credentialsFunc = function (id, callback) {
+
+        var credentials = {
+            id: id,
+            key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+            algorithm: (id === '1' ? 'sha1' : 'sha256'),
+            user: 'steve'
+        };
+
+        return callback(null, credentials);
+    };
+
+    it('should generate an authorization then successfully parse it', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on mismatching host', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            Hawk.server.authenticateMessage('example1.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Bad mac');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on stale timestamp', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, { localtimeOffsetMsec: 100000 }, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Stale timestamp');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on invalid authorization', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+            delete auth.id;
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Invalid authorization');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on bad hash', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message1', auth, credentialsFunc, {}, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Bad message hash');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on nonce error', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, { nonceFunc: function (nonce, ts, callback) { callback (new Error('kaboom')); } }, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Invalid nonce');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on credentials error', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            var errFunc = function (id, callback) {
+
+                callback(new Error('kablooey'));
+            };
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('kablooey');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on missing credentials', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            var errFunc = function (id, callback) {
+
+                callback();
+            };
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Unknown credentials');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on invalid credentials', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            var errFunc = function (id, callback) {
+
+                callback(null, {});
+            };
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Invalid credentials');
+                done();
+            });
+        });
+    });
+
+    it('should fail authorization on invalid credentials algorithm', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+            expect(auth).to.exist;
+
+            var errFunc = function (id, callback) {
+
+                callback(null, { key: '123', algorithm: '456' });
+            };
+
+            Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Unknown algorithm');
+                done();
+            });
+        });
+    });
+
+    it('should fail on missing host', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var auth = Hawk.client.message(null, 8080, 'some message', { credentials: credentials });
+            expect(auth).to.not.exist;
+            done();
+        });
+    });
+
+    it('should fail on missing credentials', function (done) {
+
+        var auth = Hawk.client.message('example.com', 8080, 'some message', {});
+        expect(auth).to.not.exist;
+        done();
+    });
+
+    it('should fail on invalid algorithm', function (done) {
+
+        credentialsFunc('123456', function (err, credentials) {
+
+            var creds = Hoek.clone(credentials);
+            creds.algorithm = 'blah';
+            var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: creds });
+            expect(auth).to.not.exist;
+            done();
+        });
+    });
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/readme.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/readme.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/readme.js	(revision 517)
@@ -0,0 +1,98 @@
+// Load modules
+
+var Lab = require('lab');
+var Hoek = require('hoek');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    describe('README', function () {
+
+        describe('core', function () {
+
+            var credentials = {
+                id: 'dh37fgj492je',
+                key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                algorithm: 'sha256'
+            };
+
+            var options = {
+                credentials: credentials,
+                timestamp: 1353832234,
+                nonce: 'j4h3g2',
+                ext: 'some-app-ext-data'
+            };
+
+            it('should generate a header protocol example', function (done) {
+
+                var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', options).field;
+
+                expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="');
+                done();
+            });
+
+            it('should generate a normalized string protocol example', function (done) {
+
+                var normalized = Hawk.crypto.generateNormalizedString('header', {
+                    credentials: credentials,
+                    ts: options.timestamp,
+                    nonce: options.nonce,
+                    method: 'GET',
+                    resource: '/resource?a=1&b=2',
+                    host: 'example.com',
+                    port: 8000,
+                    ext: options.ext
+                });
+
+                expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nGET\n/resource?a=1&b=2\nexample.com\n8000\n\nsome-app-ext-data\n');
+                done();
+            });
+
+            var payloadOptions = Hoek.clone(options);
+            payloadOptions.payload = 'Thank you for flying Hawk';
+            payloadOptions.contentType = 'text/plain';
+
+            it('should generate a header protocol example (with payload)', function (done) {
+
+                var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'POST', payloadOptions).field;
+
+                expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="');
+                done();
+            });
+
+            it('should generate a normalized string protocol example (with payload)', function (done) {
+
+                var normalized = Hawk.crypto.generateNormalizedString('header', {
+                    credentials: credentials,
+                    ts: options.timestamp,
+                    nonce: options.nonce,
+                    method: 'POST',
+                    resource: '/resource?a=1&b=2',
+                    host: 'example.com',
+                    port: 8000,
+                    hash: Hawk.crypto.calculatePayloadHash(payloadOptions.payload, credentials.algorithm, payloadOptions.contentType),
+                    ext: options.ext
+                });
+
+                expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nPOST\n/resource?a=1&b=2\nexample.com\n8000\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\nsome-app-ext-data\n');
+                done();
+            });
+        });
+    });
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/server.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/server.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/server.js	(revision 517)
@@ -0,0 +1,686 @@
+// Load modules
+
+var Url = require('url');
+var Lab = require('lab');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    describe('server', function () {
+
+        var credentialsFunc = function (id, callback) {
+
+            var credentials = {
+                id: id,
+                key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                algorithm: (id === '1' ? 'sha1' : 'sha256'),
+                user: 'steve'
+            };
+
+            return callback(null, credentials);
+        };
+
+        describe('#authenticate', function () {
+
+            it('should parse a valid authentication header (sha1)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    done();
+                });
+            });
+
+            it('should parse a valid authentication header (sha256)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/1?b=1&a=2',
+                    host: 'example.com',
+                    port: 8000,
+                    authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    done();
+                });
+            });
+
+            it('should parse a valid authentication header (host override)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: 'example1.com:8080',
+                        authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"'
+                    }
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { host: 'example.com', localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    done();
+                });
+            });
+
+            it('should parse a valid authentication header (host port override)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: 'example1.com:80',
+                        authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"'
+                    }
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { host: 'example.com', port: 8080, localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    done();
+                });
+            });
+
+            it('should parse a valid authentication header (POST with payload)', function (done) {
+
+                var req = {
+                    method: 'POST',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123456", ts="1357926341", nonce="1AwuJD", hash="qAiXIVv+yjDATneWxZP2YCTa9aHRgQdnH9b3Wc+o3dg=", ext="some-app-data", mac="UeYcj5UoTVaAWXNvJfLVia7kU3VabxCqrccXP8sUGC4="'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1357926341000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    done();
+                });
+            });
+
+            it('should fail on missing hash', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/1?b=1&a=2',
+                    host: 'example.com',
+                    port: 8000,
+                    authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { payload: 'body', localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Missing required payload hash');
+                    done();
+                });
+            });
+
+            it('should fail on a stale timestamp', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123456", ts="1362337299", nonce="UzmxSs", ext="some-app-data", mac="wnNUxchvvryMH2RxckTdZ/gY3ijzvccx4keVvELC61w="'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Stale timestamp');
+                    var header = err.response.headers['WWW-Authenticate'];
+                    var ts = header.match(/^Hawk ts\=\"(\d+)\"\, tsm\=\"([^\"]+)\"\, error=\"Stale timestamp\"$/);
+                    var now = Hawk.utils.now();
+                    expect(parseInt(ts[1], 10) * 1000).to.be.within(now - 1000, now + 1000);
+
+                    var res = {
+                        headers: {
+                            'www-authenticate': header
+                        }
+                    };
+
+                    expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(true);
+                    done();
+                });
+            });
+
+            it('should fail on a replay', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="bXx7a7p1h9QYQNZ8x7QhvDQym8ACgab4m3lVSFn4DBw=", ext="hello"'
+                };
+
+                var memoryCache = {};
+                var options = {
+                    localtimeOffsetMsec: 1353788437000 - Hawk.utils.now(),
+                    nonceFunc: function (nonce, ts, callback) {
+
+                        if (memoryCache[nonce]) {
+                            return callback(new Error());
+                        }
+
+                        memoryCache[nonce] = true;
+                        return callback();
+                    }
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, options, function (err, credentials, artifacts) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+
+                    Hawk.server.authenticate(req, credentialsFunc, options, function (err, credentials, artifacts) {
+
+                        expect(err).to.exist;
+                        expect(err.response.payload.message).to.equal('Invalid nonce');
+                        done();
+                    });
+                });
+            });
+
+            it('should fail on an invalid authentication header: wrong scheme', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Basic asdasdasdasd'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.not.exist;
+                    done();
+                });
+            });
+
+            it('should fail on an invalid authentication header: no scheme', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: '!@#'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Invalid header syntax');
+                    done();
+                });
+            });
+
+            it('should fail on an missing authorization header', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.isMissing).to.equal(true);
+                    done();
+                });
+            });
+
+            it('should fail on an missing host header', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                    }
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Invalid Host header');
+                    done();
+                });
+            });
+
+            it('should fail on an missing authorization attribute (id)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Missing attributes');
+                    done();
+                });
+            });
+
+            it('should fail on an missing authorization attribute (ts)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Missing attributes');
+                    done();
+                });
+            });
+
+            it('should fail on an missing authorization attribute (nonce)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Missing attributes');
+                    done();
+                });
+            });
+
+            it('should fail on an missing authorization attribute (mac)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Missing attributes');
+                    done();
+                });
+            });
+
+            it('should fail on an unknown authorization attribute', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", x="3", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Unknown attribute: x');
+                    done();
+                });
+            });
+
+            it('should fail on an bad authorization header format', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123\\", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Bad header format');
+                    done();
+                });
+            });
+
+            it('should fail on an bad authorization attribute value', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="\t", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Bad attribute value: id');
+                    done();
+                });
+            });
+
+            it('should fail on an empty authorization attribute value', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Bad attribute value: id');
+                    done();
+                });
+            });
+
+            it('should fail on duplicated authorization attribute key', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", id="456", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Duplicate attribute: id');
+                    done();
+                });
+            });
+
+            it('should fail on an invalid authorization header format', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk'
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Invalid header syntax');
+                    done();
+                });
+            });
+
+            it('should fail on an bad host header (missing host)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: ':8080',
+                        authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                    }
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Invalid Host header');
+                    done();
+                });
+            });
+
+            it('should fail on an bad host header (pad port)', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: 'example.com:something',
+                        authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                    }
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Invalid Host header');
+                    done();
+                });
+            });
+
+            it('should fail on credentialsFunc error', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                var credentialsFunc = function (id, callback) {
+
+                    return callback(new Error('Unknown user'));
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.message).to.equal('Unknown user');
+                    done();
+                });
+            });
+
+            it('should fail on missing credentials', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                var credentialsFunc = function (id, callback) {
+
+                    return callback(null, null);
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Unknown credentials');
+                    done();
+                });
+            });
+
+            it('should fail on invalid credentials', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                var credentialsFunc = function (id, callback) {
+
+                    var credentials = {
+                        key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                        user: 'steve'
+                    };
+
+                    return callback(null, credentials);
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.message).to.equal('Invalid credentials');
+                    expect(err.response.payload.message).to.equal('An internal server error occurred');
+                    done();
+                });
+            });
+
+            it('should fail on unknown credentials algorithm', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                var credentialsFunc = function (id, callback) {
+
+                    var credentials = {
+                        key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                        algorithm: 'hmac-sha-0',
+                        user: 'steve'
+                    };
+
+                    return callback(null, credentials);
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.message).to.equal('Unknown algorithm');
+                    expect(err.response.payload.message).to.equal('An internal server error occurred');
+                    done();
+                });
+            });
+
+            it('should fail on unknown bad mac', function (done) {
+
+                var req = {
+                    method: 'GET',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080,
+                    authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcU4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+                };
+
+                var credentialsFunc = function (id, callback) {
+
+                    var credentials = {
+                        key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                        algorithm: 'sha256',
+                        user: 'steve'
+                    };
+
+                    return callback(null, credentials);
+                };
+
+                Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Bad mac');
+                    done();
+                });
+            });
+        });
+
+        describe('#header', function () {
+
+            it('should return an empty authorization header on missing options', function (done) {
+
+                var header = Hawk.server.header();
+                expect(header).to.equal('');
+                done();
+            });
+
+            it('should return an empty authorization header on missing credentials', function (done) {
+
+                var header = Hawk.server.header(null, {});
+                expect(header).to.equal('');
+                done();
+            });
+
+            it('should return an empty authorization header on invalid credentials', function (done) {
+
+                var credentials = {
+                    key: '2983d45yun89q'
+                };
+
+                var header = Hawk.server.header(credentials);
+                expect(header).to.equal('');
+                done();
+            });
+
+            it('should return an empty authorization header on invalid algorithm', function (done) {
+
+                var artifacts = {
+                    id: '123456'
+                };
+
+                var credentials = {
+                    key: '2983d45yun89q',
+                    algorithm: 'hmac-sha-0'
+                };
+
+                var header = Hawk.server.header(credentials, artifacts);
+                expect(header).to.equal('');
+                done();
+            });
+        });
+    });
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/uri.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/uri.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/uri.js	(revision 517)
@@ -0,0 +1,456 @@
+// Load modules
+
+var Http = require('http');
+var Lab = require('lab');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    describe('Uri', function () {
+
+        var credentialsFunc = function (id, callback) {
+
+            var credentials = {
+                id: id,
+                key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+                algorithm: 'sha256',
+                user: 'steve'
+            };
+
+            return callback(null, credentials);
+        };
+
+        it('should generate a bewit then successfully authenticate it', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?a=1&b=2',
+                host: 'example.com',
+                port: 80
+            };
+
+            credentialsFunc('123456', function (err, credentials) {
+
+                var bewit = Hawk.uri.getBewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100, ext: 'some-app-data' });
+                req.url += '&bewit=' + bewit;
+
+                Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    expect(attributes.ext).to.equal('some-app-data');
+                    done();
+                });
+            });
+        });
+
+        it('should generate a bewit then successfully authenticate it (no ext)', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?a=1&b=2',
+                host: 'example.com',
+                port: 80
+            };
+
+            credentialsFunc('123456', function (err, credentials) {
+
+                var bewit = Hawk.uri.getBewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100 });
+                req.url += '&bewit=' + bewit;
+
+                Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                    expect(err).to.not.exist;
+                    expect(credentials.user).to.equal('steve');
+                    done();
+                });
+            });
+        });
+
+        it('should successfully authenticate a request (last param)', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?a=1&b=2&bewit=MTIzNDU2XDQ1MTE0ODQ2MjFcMzFjMmNkbUJFd1NJRVZDOVkva1NFb2c3d3YrdEVNWjZ3RXNmOGNHU2FXQT1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(attributes.ext).to.equal('some-app-data');
+                done();
+            });
+        });
+
+        it('should successfully authenticate a request (first param)', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2MjFcMzFjMmNkbUJFd1NJRVZDOVkva1NFb2c3d3YrdEVNWjZ3RXNmOGNHU2FXQT1cc29tZS1hcHAtZGF0YQ&a=1&b=2',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(attributes.ext).to.equal('some-app-data');
+                done();
+            });
+        });
+
+        it('should successfully authenticate a request (only param)', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2NDFcZm1CdkNWT3MvcElOTUUxSTIwbWhrejQ3UnBwTmo4Y1VrSHpQd3Q5OXJ1cz1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.not.exist;
+                expect(credentials.user).to.equal('steve');
+                expect(attributes.ext).to.equal('some-app-data');
+                done();
+            });
+        });
+
+        it('should fail on multiple authentication', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2NDFcZm1CdkNWT3MvcElOTUUxSTIwbWhrejQ3UnBwTmo4Y1VrSHpQd3Q5OXJ1cz1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080,
+                authorization: 'Basic asdasdasdasd'
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Multiple authentications');
+                done();
+            });
+        });
+
+        it('should fail on method other than GET', function (done) {
+
+            credentialsFunc('123456', function (err, credentials) {
+
+                var req = {
+                    method: 'POST',
+                    url: '/resource/4?filter=a',
+                    host: 'example.com',
+                    port: 8080
+                };
+
+                var exp = Math.floor(Hawk.utils.now() / 1000) + 60;
+                var ext = 'some-app-data';
+                var mac = Hawk.crypto.calculateMac('bewit', credentials, {
+                    timestamp: exp,
+                    nonce: '',
+                    method: req.method,
+                    resource: req.url,
+                    host: req.host,
+                    port: req.port,
+                    ext: ext
+                });
+
+                var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + ext;
+
+                req.url += '&bewit=' + Hawk.utils.base64urlEncode(bewit);
+
+                Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                    expect(err).to.exist;
+                    expect(err.response.payload.message).to.equal('Invalid method');
+                    done();
+                });
+            });
+        });
+
+        it('should fail on invalid host header', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+                headers: {
+                    host: 'example.com:something'
+                }
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Invalid Host header');
+                done();
+            });
+        });
+
+        it('should fail on empty bewit', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Empty bewit');
+                expect(err.isMissing).to.not.exist;
+                done();
+            });
+        });
+
+        it('should fail on invalid bewit', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=*',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Invalid bewit encoding');
+                expect(err.isMissing).to.not.exist;
+                done();
+            });
+        });
+
+        it('should fail on missing bewit', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.not.exist;
+                expect(err.isMissing).to.equal(true);
+                done();
+            });
+        });
+
+        it('should fail on invalid bewit structure', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=abc',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Invalid bewit structure');
+                done();
+            });
+        });
+
+        it('should fail on empty bewit attribute', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=YVxcY1xk',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Missing bewit attributes');
+                done();
+            });
+        });
+
+        it('should fail on expired access', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?a=1&b=2&bewit=MTIzNDU2XDEzNTY0MTg1ODNcWk1wZlMwWU5KNHV0WHpOMmRucTRydEk3NXNXTjFjeWVITTcrL0tNZFdVQT1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Access expired');
+                done();
+            });
+        });
+
+        it('should fail on credentials function error', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, function (id, callback) { callback(Hawk.error.badRequest('Boom')); }, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Boom');
+                done();
+            });
+        });
+
+        it('should fail on null credentials function response', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, function (id, callback) { callback(null, null); }, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Unknown credentials');
+                done();
+            });
+        });
+
+        it('should fail on invalid credentials function response', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, function (id, callback) { callback(null, {}); }, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Invalid credentials');
+                done();
+            });
+        });
+
+        it('should fail on invalid credentials function response (unknown algorithm)', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, function (id, callback) { callback(null, { key: 'xxx', algorithm: 'xxx' }); }, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.message).to.equal('Unknown algorithm');
+                done();
+            });
+        });
+
+        it('should fail on expired access', function (done) {
+
+            var req = {
+                method: 'GET',
+                url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+                host: 'example.com',
+                port: 8080
+            };
+
+            Hawk.uri.authenticate(req, function (id, callback) { callback(null, { key: 'xxx', algorithm: 'sha256' }); }, {}, function (err, credentials, attributes) {
+
+                expect(err).to.exist;
+                expect(err.response.payload.message).to.equal('Bad mac');
+                done();
+            });
+        });
+    });
+
+    describe('#getBewit', function () {
+
+        it('should return a valid bewit value', function (done) {
+
+            var credentials = {
+                id: '123456',
+                key: '2983d45yun89q',
+                algorithm: 'sha256'
+            };
+
+            var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+            expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdca3NjeHdOUjJ0SnBQMVQxekRMTlBiQjVVaUtJVTl0T1NKWFRVZEc3WDloOD1ceGFuZHlhbmR6');
+            done();
+        });
+
+        it('should return an empty bewit on invalid credentials', function (done) {
+
+            var credentials = {
+                key: '2983d45yun89q',
+                algorithm: 'sha256'
+            };
+
+            var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 3000, ext: 'xandyandz' });
+            expect(bewit).to.equal('');
+            done();
+        });
+
+        it('should return an empty bewit on invalid algorithm', function (done) {
+
+            var credentials = {
+                id: '123456',
+                key: '2983d45yun89q',
+                algorithm: 'hmac-sha-0'
+            };
+
+            var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, ext: 'xandyandz' });
+            expect(bewit).to.equal('');
+            done();
+        });
+
+        it('should return an empty bewit on missing options', function (done) {
+
+            var credentials = {
+                id: '123456',
+                key: '2983d45yun89q',
+                algorithm: 'hmac-sha-0'
+            };
+
+            var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow');
+            expect(bewit).to.equal('');
+            done();
+        });
+    });
+});
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/utils.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/utils.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/hawk/test/utils.js	(revision 517)
@@ -0,0 +1,120 @@
+// Load modules
+
+var Lab = require('lab');
+var Hawk = require('../lib');
+var Package = require('../package.json');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hawk', function () {
+
+    describe('Utils', function () {
+
+        describe('#parseHost', function () {
+
+            it('returns port 80 for non tls node request', function (done) {
+
+                var req = {
+                    method: 'POST',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: 'example.com',
+                        'content-type': 'text/plain;x=y'
+                    }
+                };
+
+                expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(80);
+                done();
+            });
+
+            it('returns port 443 for non tls node request', function (done) {
+
+                var req = {
+                    method: 'POST',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: 'example.com',
+                        'content-type': 'text/plain;x=y'
+                    },
+                    connection: {
+                        encrypted: true
+                    }
+                };
+
+                expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(443);
+                done();
+            });
+
+            it('returns port 443 for non tls node request (IPv6)', function (done) {
+
+                var req = {
+                    method: 'POST',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: '[123:123:123]',
+                        'content-type': 'text/plain;x=y'
+                    },
+                    connection: {
+                        encrypted: true
+                    }
+                };
+
+                expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(443);
+                done();
+            });
+
+            it('parses IPv6 headers', function (done) {
+
+                var req = {
+                    method: 'POST',
+                    url: '/resource/4?filter=a',
+                    headers: {
+                        host: '[123:123:123]:8000',
+                        'content-type': 'text/plain;x=y'
+                    },
+                    connection: {
+                        encrypted: true
+                    }
+                };
+
+                var host = Hawk.utils.parseHost(req, 'Host');
+                expect(host.port).to.equal('8000');
+                expect(host.name).to.equal('[123:123:123]');
+                done();
+            });
+        });
+
+        describe('#version', function () {
+
+            it('returns the correct package version number', function (done) {
+
+                expect(Hawk.utils.version()).to.equal(Package.version);
+                done();
+            });
+        });
+
+        describe('#unauthorized', function () {
+
+            it('returns a hawk 401', function (done) {
+
+                expect(Hawk.utils.unauthorized('kaboom').response.headers['WWW-Authenticate']).to.equal('Hawk error="kaboom"');
+                done();
+            });
+        });
+    });
+});
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/.dir-locals.el
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/.dir-locals.el	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/.dir-locals.el	(revision 517)
@@ -0,0 +1,6 @@
+((nil . ((indent-tabs-mode . nil)
+         (tab-width . 8)
+         (fill-column . 80)))
+ (js-mode . ((js-indent-level . 2)
+             (indent-tabs-mode . nil)
+             )))
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/.npmignore	(revision 517)
@@ -0,0 +1,7 @@
+.gitmodules
+deps
+docs
+Makefile
+node_modules
+test
+tools
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/LICENSE	(revision 517)
@@ -0,0 +1,18 @@
+Copyright Joyent, Inc. All rights reserved.
+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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/README.md	(revision 517)
@@ -0,0 +1,75 @@
+# node-http-signature
+
+node-http-signature is a node.js library that has client and server components
+for Joyent's [HTTP Signature Scheme](http_signing.md).
+
+## Usage
+
+Note the example below signs a request with the same key/cert used to start an
+HTTP server. This is almost certainly not what you actaully want, but is just
+used to illustrate the API calls; you will need to provide your own key
+management in addition to this library.
+
+### Client
+
+    var fs = require('fs');
+    var https = require('https');
+    var httpSignature = require('http-signature');
+
+    var key = fs.readFileSync('./key.pem', 'ascii');
+
+    var options = {
+      host: 'localhost',
+      port: 8443,
+      path: '/',
+      method: 'GET',
+      headers: {}
+    };
+
+    // Adds a 'Date' header in, signs it, and adds the
+    // 'Authorization' header in.
+    var req = https.request(options, function(res) {
+      console.log(res.statusCode);
+    });
+
+
+    httpSignature.sign(req, {
+      key: key,
+      keyId: './cert.pem'
+    });
+
+    req.end();
+
+### Server
+
+    var fs = require('fs');
+    var https = require('https');
+    var httpSignature = require('http-signature');
+
+    var options = {
+      key: fs.readFileSync('./key.pem'),
+      cert: fs.readFileSync('./cert.pem')
+    };
+
+    https.createServer(options, function (req, res) {
+      var rc = 200;
+      var parsed = httpSignature.parseRequest(req);
+      var pub = fs.readFileSync(parsed.keyId, 'ascii');
+      if (!httpSignature.verifySignature(parsed, pub))
+        rc = 401;
+
+      res.writeHead(rc);
+      res.end();
+    }).listen(8443);
+
+## Installation
+
+    npm install http-signature
+
+## License
+
+MIT.
+
+## Bugs
+
+See <https://github.com/joyent/node-http-signature/issues>.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/http_signing.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/http_signing.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/http_signing.md	(revision 517)
@@ -0,0 +1,296 @@
+# Abstract
+
+This document describes a way to add origin authentication, message integrity,
+and replay resistance to HTTP REST requests.  It is intended to be used over
+the HTTPS protocol.
+
+# Copyright Notice
+
+Copyright (c) 2011 Joyent, Inc. and the persons identified as document authors.
+All rights reserved.
+
+Code Components extracted from this document must include MIT License text.
+
+# Introduction
+
+This protocol is intended to provide a standard way for clients to sign HTTP
+requests.  RFC2617 (HTTP Authentication) defines Basic and Digest authentication
+mechanisms, and RFC5246 (TLS 1.2) defines client-auth, both of which are widely
+employed on the Internet today.  However, it is common place that the burdens of
+PKI prevent web service operators from deploying that methodoloy, and so many
+fall back to Basic authentication, which has poor security characteristics.
+
+Additionally, OAuth provides a fully-specified alternative for authorization
+of web service requests, but is not (always) ideal for machine to machine
+communication, as the key acquisition steps (generally) imply a fixed
+infrastructure that may not make sense to a service provider (e.g., symmetric
+keys).
+
+Several web service providers have invented their own schemes for signing
+HTTP requests, but to date, none have been placed in the public domain as a
+standard.  This document serves that purpose.  There are no techniques in this
+proposal that are novel beyond previous art, however, this aims to be a simple
+mechanism for signing these requests.
+
+# Signature Authentication Scheme
+
+The "signature" authentication scheme is based on the model that the client must
+authenticate itself with a digital signature produced by either a private
+asymmetric key (e.g., RSA) or a shared symmetric key (e.g., HMAC).  The scheme
+is parameterized enough such that it is not bound to any particular key type or
+signing algorithm.  However, it does explicitly assume that clients can send an
+HTTP `Date` header.
+
+## Authorization Header
+
+The client is expected to send an Authorization header (as defined in RFC 2617)
+with the following parameterization:
+
+    credentials := "Signature" params
+    params := 1#(keyId | algorithm | [headers] | [ext] | signature)
+    digitalSignature := plain-string
+
+    keyId := "keyId" "=" <"> plain-string <">
+    algorithm := "algorithm" "=" <"> plain-string <">
+    headers := "headers" "=" <"> 1#headers-value <">
+    ext := "ext" "=" <"> plain-string <">
+    signature := "signature" "=" <"> plain-string <">
+
+    headers-value := plain-string
+    plain-string   = 1*( %x20-21 / %x23-5B / %x5D-7E )
+
+### Signature Parameters
+
+#### keyId
+
+REQUIRED.  The `keyId` field is an opaque string that the server can use to look
+up the component they need to validate the signature.  It could be an SSH key
+fingerprint, an LDAP DN, etc.  Management of keys and assignment of `keyId` is
+out of scope for this document.
+
+#### algorithm
+
+REQUIRED. The `algorithm` parameter is used if the client and server agree on a
+non-standard digital signature algorithm.  The full list of supported signature
+mechanisms is listed below.
+
+#### headers
+
+OPTIONAL.  The `headers` parameter is used to specify the list of HTTP headers
+used to sign the request.  If specified, it should be a quoted list of HTTP
+header names, separated by a single space character.  By default, only one
+HTTP header is signed, which is the `Date` header.  Note that the list MUST be
+specified in the order the values are concatenated together during signing. To
+include the HTTP request line in the signature calculation, use the special
+`request-line` value.  While this is overloading the definition of `headers` in
+HTTP linguism, the request-line is defined in RFC 2616, and as the outlier from
+headers in useful signature calculation, it is deemed simpler to simply use
+`request-line` than to add a separate parameter for it.
+
+#### extensions
+
+OPTIONAL.  The `extensions` parameter is used to include additional information
+which is covered by the request.  The content and format of the string is out of
+scope for this document, and expected to be specified by implementors.
+
+#### signature
+
+REQUIRED.  The `signature` parameter is a `Base64` encoded digital signature
+generated by the client. The client uses the `algorithm` and `headers` request
+parameters to form a canonicalized `signing string`.  This `signing string` is
+then signed with the key associated with `keyId` and the algorithm
+corresponding to `algorithm`.  The `signature` parameter is then set to the
+`Base64` encoding of the signature.
+
+### Signing String Composition
+
+In order to generate the string that is signed with a key, the client MUST take
+the values of each HTTP header specified by `headers` in the order they appear.
+
+1. If the header name is not `request-line` then append the lowercased header
+   name followed with an ASCII colon `:` and an ASCII space ` `.
+2. If the header name is `request-line` then appened the HTTP request line,
+   otherwise append the header value.
+3. If value is not the last value then append an ASCII newline `\n`. The string
+   MUST NOT include a trailing ASCII newline.
+
+# Example Requests
+
+All requests refer to the following request (body ommitted):
+
+    POST /foo HTTP/1.1
+    Host: example.org
+    Date: Tue, 07 Jun 2011 20:51:35 GMT
+    Content-Type: application/json
+    Content-MD5: h0auK8hnYJKmHTLhKtMTkQ==
+    Content-Length: 123
+
+The "rsa-key-1" keyId refers to a private key known to the client and a public
+key known to the server. The "hmac-key-1" keyId refers to key known to the
+client and server.
+
+## Default parameterization
+
+The authorization header and signature would be generated as:
+
+    Authorization: Signature keyId="rsa-key-1",algorithm="rsa-sha256",signature="Base64(RSA-SHA256(signing string))"
+
+The client would compose the signing string as:
+
+    date: Tue, 07 Jun 2011 20:51:35 GMT
+
+## Header List
+
+The authorization header and signature would be generated as:
+
+    Authorization: Signature keyId="rsa-key-1",algorithm="rsa-sha256",headers="request-line date content-type content-md5",signature="Base64(RSA-SHA256(signing string))"
+
+The client would compose the signing string as (`+ "\n"` inserted for
+readability):
+
+    POST /foo HTTP/1.1 + "\n"
+    date: Tue, 07 Jun 2011 20:51:35 GMT + "\n"
+    content-type: application/json + "\n"
+    content-md5: h0auK8hnYJKmHTLhKtMTkQ==
+
+## Algorithm
+
+The authorization header and signature would be generated as:
+
+    Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))"
+
+The client would compose the signing string as:
+
+    date: Tue, 07 Jun 2011 20:51:35 GMT
+
+# Signing Algorithms
+
+Currently supported algorithm names are:
+
+* rsa-sha1
+* rsa-sha256
+* rsa-sha512
+* dsa-sha1
+* hmac-sha1
+* hmac-sha256
+* hmac-sha512
+
+# Security Considerations
+
+## Default Parameters
+
+Note the default parameterization of the `Signature` scheme is only safe if all
+requests are carried over a secure transport (i.e., TLS).  Sending the default
+scheme over a non-secure transport will leave the request vulnerable to
+spoofing, tampering, replay/repudiaton, and integrity violations (if using the
+STRIDE threat-modeling methodology).
+
+## Insecure Transports
+
+If sending the request over plain HTTP, service providers SHOULD require clients
+to sign ALL HTTP headers, and the `request-line`.  Additionally, service
+providers SHOULD require `Content-MD5` calculations to be performed to ensure
+against any tampering from clients.
+
+## Nonces
+
+Nonces are out of scope for this document simply because many service providers
+fail to implement them correctly, or do not adopt security specfiications
+because of the infrastructure complexity.  Given the `header` parameterization,
+a service provider is fully enabled to add nonce semantics into this scheme by
+using something like an `x-request-nonce` header, and ensuring it is signed
+with the `Date` header.
+
+## Clock Skew
+
+As the default scheme is to sign the `Date` header, service providers SHOULD
+protect against logged replay attacks by enforcing a clock skew.  The server
+SHOULD be synchronized with NTP, and the recommendation in this specification
+is to allow 300s of clock skew (in either direction).
+
+## Required Headers to Sign
+
+It is out of scope for this document to dictate what headers a service provider
+will want to enforce, but service providers SHOULD at minimum include the
+`Date` header.
+
+# References
+
+## Normative References
+
+* [RFC2616] Hypertext Transfer Protocol -- HTTP/1.1
+* [RFC2617] HTTP Authentication: Basic and Digest Access Authentication
+* [RFC5246] The Transport Layer Security (TLS) Protocol Version 1.2
+
+## Informative References
+
+    Name: Mark Cavage (editor)
+    Company: Joyent, Inc.
+    Email: mark.cavage@joyent.com
+    URI: http://www.joyent.com
+
+# Appendix A - Test Values
+
+The following test data uses the RSA (2048b) keys, which we will refer
+to as `keyId=Test` in the following samples:
+
+   -----BEGIN PUBLIC KEY-----
+   MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
+   6rPJj+CvfSC8+q28hxA161QFNUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6
+   Z4UMR7EOcpfdUE9Hf3m/hs+FUR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJw
+   oYi+1hqp1fIekaxsyQIDAQAB
+   -----END PUBLIC KEY-----
+
+    -----BEGIN RSA PRIVATE KEY-----
+    MIICXgIBAAKBgQDCFENGw33yGihy92pDjZQhl0C36rPJj+CvfSC8+q28hxA161QF
+    NUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6Z4UMR7EOcpfdUE9Hf3m/hs+F
+    UR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJwoYi+1hqp1fIekaxsyQIDAQAB
+    AoGBAJR8ZkCUvx5kzv+utdl7T5MnordT1TvoXXJGXK7ZZ+UuvMNUCdN2QPc4sBiA
+    QWvLw1cSKt5DsKZ8UETpYPy8pPYnnDEz2dDYiaew9+xEpubyeW2oH4Zx71wqBtOK
+    kqwrXa/pzdpiucRRjk6vE6YY7EBBs/g7uanVpGibOVAEsqH1AkEA7DkjVH28WDUg
+    f1nqvfn2Kj6CT7nIcE3jGJsZZ7zlZmBmHFDONMLUrXR/Zm3pR5m0tCmBqa5RK95u
+    412jt1dPIwJBANJT3v8pnkth48bQo/fKel6uEYyboRtA5/uHuHkZ6FQF7OUkGogc
+    mSJluOdc5t6hI1VsLn0QZEjQZMEOWr+wKSMCQQCC4kXJEsHAve77oP6HtG/IiEn7
+    kpyUXRNvFsDE0czpJJBvL/aRFUJxuRK91jhjC68sA7NsKMGg5OXb5I5Jj36xAkEA
+    gIT7aFOYBFwGgQAQkWNKLvySgKbAZRTeLBacpHMuQdl1DfdntvAyqpAZ0lY0RKmW
+    G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
+    7U1yQXnTAEFYM560yJlzUpOb1V4cScGd365tiSMvxLOvTA==
+    -----END RSA PRIVATE KEY-----
+
+And all examples use this request:
+
+    POST /foo?param=value&pet=dog HTTP/1.1
+    Host: example.com
+    Date: Thu, 05 Jan 2012 21:31:40 GMT
+    Content-Type: application/json
+    Content-MD5: Sd/dVLAcvNLSq16eXua5uQ==
+    Content-Length: 18
+
+    {"hello": "world"}
+
+### Default
+
+The string to sign would be:
+
+    date: Thu, 05 Jan 2012 21:31:40 GMT
+
+The Authorization header would be:
+
+    Authorization: Signature keyId="Test",algorithm="rsa-sha256",signature="JldXnt8W9t643M2Sce10gqCh/+E7QIYLiI+bSjnFBGCti7s+mPPvOjVb72sbd1FjeOUwPTDpKbrQQORrm+xBYfAwCxF3LBSSzORvyJ5nRFCFxfJ3nlQD6Kdxhw8wrVZX5nSem4A/W3C8qH5uhFTRwF4ruRjh+ENHWuovPgO/HGQ="
+
+### All Headers
+
+Parameterized to include all headers, the string to sign would be (`+ "\n"`
+inserted for readability):
+
+    POST /foo?param=value&pet=dog HTTP/1.1 + "\n"
+    host: example.com + "\n"
+    date: Thu, 05 Jan 2012 21:31:40 GMT + "\n"
+    content-type: application/json + "\n"
+    content-md5: Sd/dVLAcvNLSq16eXua5uQ== + "\n"
+    content-length: 18
+
+The Authorization header would be:
+
+    Authorization: Signature keyId="Test",algorithm="rsa-sha256",headers="request-line host date content-type content-md5 content-length",signature="Gm7W/r+e90REDpWytALMrft4MqZxCmslOTOvwJX17ViEBA5E65QqvWI0vIH3l/vSsGiaMVmuUgzYsJLYMLcm5dGrv1+a+0fCoUdVKPZWHyImQEqpLkopVwqEH67LVECFBqFTAKlQgBn676zrfXQbb+b/VebAsNUtvQMe6cTjnDY="
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/index.js	(revision 517)
@@ -0,0 +1,25 @@
+// Copyright 2011 Joyent, Inc.  All rights reserved.
+
+var parser = require('./parser');
+var signer = require('./signer');
+var verify = require('./verify');
+var util = require('./util');
+
+
+
+///--- API
+
+module.exports = {
+
+  parse: parser.parseRequest,
+  parseRequest: parser.parseRequest,
+
+  sign: signer.signRequest,
+  signRequest: signer.signRequest,
+
+  sshKeyToPEM: util.sshKeyToPEM,
+  sshKeyFingerprint: util.fingerprint,
+
+  verify: verify.verifySignature,
+  verifySignature: verify.verifySignature
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/parser.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/parser.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/parser.js	(revision 517)
@@ -0,0 +1,304 @@
+// Copyright 2012 Joyent, Inc.  All rights reserved.
+
+var assert = require('assert-plus');
+var util = require('util');
+
+
+
+///--- Globals
+
+var Algorithms = {
+  'rsa-sha1': true,
+  'rsa-sha256': true,
+  'rsa-sha512': true,
+  'dsa-sha1': true,
+  'hmac-sha1': true,
+  'hmac-sha256': true,
+  'hmac-sha512': true
+};
+
+var State = {
+  New: 0,
+  Params: 1
+};
+
+var ParamsState = {
+  Name: 0,
+  Quote: 1,
+  Value: 2,
+  Comma: 3
+};
+
+
+
+///--- Specific Errors
+
+function HttpSignatureError(message, caller) {
+  if (Error.captureStackTrace)
+    Error.captureStackTrace(this, caller || HttpSignatureError);
+
+  this.message = message;
+  this.name = caller.name;
+}
+util.inherits(HttpSignatureError, Error);
+
+function ExpiredRequestError(message) {
+  HttpSignatureError.call(this, message, ExpiredRequestError);
+}
+util.inherits(ExpiredRequestError, HttpSignatureError);
+
+
+function InvalidHeaderError(message) {
+  HttpSignatureError.call(this, message, InvalidHeaderError);
+}
+util.inherits(InvalidHeaderError, HttpSignatureError);
+
+
+function InvalidParamsError(message) {
+  HttpSignatureError.call(this, message, InvalidParamsError);
+}
+util.inherits(InvalidParamsError, HttpSignatureError);
+
+
+function MissingHeaderError(message) {
+  HttpSignatureError.call(this, message, MissingHeaderError);
+}
+util.inherits(MissingHeaderError, HttpSignatureError);
+
+
+
+///--- Exported API
+
+module.exports = {
+
+  /**
+   * Parses the 'Authorization' header out of an http.ServerRequest object.
+   *
+   * Note that this API will fully validate the Authorization header, and throw
+   * on any error.  It will not however check the signature, or the keyId format
+   * as those are specific to your environment.  You can use the options object
+   * to pass in extra constraints.
+   *
+   * As a response object you can expect this:
+   *
+   *     {
+   *       "scheme": "Signature",
+   *       "params": {
+   *         "keyId": "foo",
+   *         "algorithm": "rsa-sha256",
+   *         "headers": [
+   *           "date" or "x-date",
+   *           "content-md5"
+   *         ],
+   *         "signature": "base64"
+   *       },
+   *       "signingString": "ready to be passed to crypto.verify()"
+   *     }
+   *
+   * @param {Object} request an http.ServerRequest.
+   * @param {Object} options an optional options object with:
+   *                   - clockSkew: allowed clock skew in seconds (default 300).
+   *                   - headers: required header names (def: date or x-date)
+   *                   - algorithms: algorithms to support (default: all).
+   * @return {Object} parsed out object (see above).
+   * @throws {TypeError} on invalid input.
+   * @throws {InvalidHeaderError} on an invalid Authorization header error.
+   * @throws {InvalidParamsError} if the params in the scheme are invalid.
+   * @throws {MissingHeaderError} if the params indicate a header not present,
+   *                              either in the request headers from the params,
+   *                              or not in the params from a required header
+   *                              in options.
+   * @throws {ExpiredRequestError} if the value of date or x-date exceeds skew.
+   */
+  parseRequest: function parseRequest(request, options) {
+    assert.object(request, 'request');
+    assert.object(request.headers, 'request.headers');
+    if (options === undefined) {
+      options = {};
+    }
+    if (options.headers === undefined) {
+      options.headers = [request.headers['x-date'] ? 'x-date' : 'date'];
+    }
+    assert.object(options, 'options');
+    assert.arrayOfString(options.headers, 'options.headers');
+    assert.optionalNumber(options.clockSkew, 'options.clockSkew');
+
+    if (!request.headers.authorization)
+      throw new MissingHeaderError('no authorization header present in ' +
+                                   'the request');
+
+    options.clockSkew = options.clockSkew || 300;
+
+
+    var i = 0;
+    var state = State.New;
+    var substate = ParamsState.Name;
+    var tmpName = '';
+    var tmpValue = '';
+
+    var parsed = {
+      scheme: '',
+      params: {},
+      signingString: '',
+
+      get algorithm() {
+        return this.params.algorithm.toUpperCase();
+      },
+
+      get keyId() {
+        return this.params.keyId;
+      }
+
+    };
+
+    var authz = request.headers.authorization;
+    for (i = 0; i < authz.length; i++) {
+      var c = authz.charAt(i);
+
+      switch (Number(state)) {
+
+      case State.New:
+        if (c !== ' ') parsed.scheme += c;
+        else state = State.Params;
+        break;
+
+      case State.Params:
+        switch (Number(substate)) {
+
+        case ParamsState.Name:
+          var code = c.charCodeAt(0);
+          // restricted name of A-Z / a-z
+          if ((code >= 0x41 && code <= 0x5a) || // A-Z
+              (code >= 0x61 && code <= 0x7a)) { // a-z
+            tmpName += c;
+          } else if (c === '=') {
+            if (tmpName.length === 0)
+              throw new InvalidHeaderError('bad param format');
+            substate = ParamsState.Quote;
+          } else {
+            throw new InvalidHeaderError('bad param format');
+          }
+          break;
+
+        case ParamsState.Quote:
+          if (c === '"') {
+            tmpValue = '';
+            substate = ParamsState.Value;
+          } else {
+            throw new InvalidHeaderError('bad param format');
+          }
+          break;
+
+        case ParamsState.Value:
+          if (c === '"') {
+            parsed.params[tmpName] = tmpValue;
+            substate = ParamsState.Comma;
+          } else {
+            tmpValue += c;
+          }
+          break;
+
+        case ParamsState.Comma:
+          if (c === ',') {
+            tmpName = '';
+            substate = ParamsState.Name;
+          } else {
+            throw new InvalidHeaderError('bad param format');
+          }
+          break;
+
+        default:
+          throw new Error('Invalid substate');
+        }
+        break;
+
+      default:
+        throw new Error('Invalid substate');
+      }
+
+    }
+
+    if (!parsed.params.headers || parsed.params.headers === '') {
+      if (request.headers['x-date']) {
+        parsed.params.headers = ['x-date'];
+      } else {
+        parsed.params.headers = ['date'];
+      }
+    } else {
+      parsed.params.headers = parsed.params.headers.split(' ');
+    }
+
+    // Minimally validate the parsed object
+    if (!parsed.scheme || parsed.scheme !== 'Signature')
+      throw new InvalidHeaderError('scheme was not "Signature"');
+
+    if (!parsed.params.keyId)
+      throw new InvalidHeaderError('keyId was not specified');
+
+    if (!parsed.params.algorithm)
+      throw new InvalidHeaderError('algorithm was not specified');
+
+    if (!parsed.params.signature)
+      throw new InvalidHeaderError('signature was not specified');
+
+    // Check the algorithm against the official list
+    parsed.params.algorithm = parsed.params.algorithm.toLowerCase();
+    if (!Algorithms[parsed.params.algorithm])
+      throw new InvalidParamsError(parsed.params.algorithm +
+                                   ' is not supported');
+
+    // Build the signingString
+    for (i = 0; i < parsed.params.headers.length; i++) {
+      var h = parsed.params.headers[i].toLowerCase();
+      parsed.params.headers[i] = h;
+
+      if (h !== 'request-line') {
+        var value = request.headers[h];
+        if (!value)
+          throw new MissingHeaderError(h + ' was not in the request');
+        parsed.signingString += h + ': ' + value;
+      } else {
+        parsed.signingString +=
+          request.method + ' ' + request.url + ' HTTP/' + request.httpVersion;
+      }
+
+      if ((i + 1) < parsed.params.headers.length)
+        parsed.signingString += '\n';
+    }
+
+    // Check against the constraints
+    var date;
+    if (request.headers.date || request.headers['x-date']) {
+        if (request.headers['x-date']) {
+          date = new Date(request.headers['x-date']);
+        } else {
+          date = new Date(request.headers.date);
+        }
+      var now = new Date();
+      var skew = Math.abs(now.getTime() - date.getTime());
+
+      if (skew > options.clockSkew * 1000) {
+        throw new ExpiredRequestError('clock skew of ' +
+                                      (skew / 1000) +
+                                      's was greater than ' +
+                                      options.clockSkew + 's');
+      }
+    }
+
+    options.headers.forEach(function (hdr) {
+      // Remember that we already checked any headers in the params
+      // were in the request, so if this passes we're good.
+      if (parsed.params.headers.indexOf(hdr) < 0)
+        throw new MissingHeaderError(hdr + ' was not a signed header');
+    });
+
+    if (options.algorithms) {
+      if (options.algorithms.indexOf(parsed.params.algorithm) === -1)
+        throw new InvalidParamsError(parsed.params.algorithm +
+                                     ' is not a supported algorithm');
+    }
+
+    return parsed;
+  }
+
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/signer.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/signer.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/signer.js	(revision 517)
@@ -0,0 +1,179 @@
+// Copyright 2012 Joyent, Inc.  All rights reserved.
+
+var assert = require('assert-plus');
+var crypto = require('crypto');
+var http = require('http');
+
+var sprintf = require('util').format;
+
+
+
+///--- Globals
+
+var Algorithms = {
+  'rsa-sha1': true,
+  'rsa-sha256': true,
+  'rsa-sha512': true,
+  'dsa-sha1': true,
+  'hmac-sha1': true,
+  'hmac-sha256': true,
+  'hmac-sha512': true
+};
+
+var Authorization =
+  'Signature keyId="%s",algorithm="%s",headers="%s",signature="%s"';
+
+
+
+///--- Specific Errors
+
+function MissingHeaderError(message) {
+    this.name = 'MissingHeaderError';
+    this.message = message;
+    this.stack = (new Error()).stack;
+}
+MissingHeaderError.prototype = new Error();
+
+
+function InvalidAlgorithmError(message) {
+    this.name = 'InvalidAlgorithmError';
+    this.message = message;
+    this.stack = (new Error()).stack;
+}
+InvalidAlgorithmError.prototype = new Error();
+
+
+
+///--- Internal Functions
+
+function _pad(val) {
+  if (parseInt(val, 10) < 10) {
+    val = '0' + val;
+  }
+  return val;
+}
+
+
+function _rfc1123() {
+  var date = new Date();
+
+  var months = ['Jan',
+                'Feb',
+                'Mar',
+                'Apr',
+                'May',
+                'Jun',
+                'Jul',
+                'Aug',
+                'Sep',
+                'Oct',
+                'Nov',
+                'Dec'];
+  var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+  return days[date.getUTCDay()] + ', ' +
+    _pad(date.getUTCDate()) + ' ' +
+    months[date.getUTCMonth()] + ' ' +
+    date.getUTCFullYear() + ' ' +
+    _pad(date.getUTCHours()) + ':' +
+    _pad(date.getUTCMinutes()) + ':' +
+    _pad(date.getUTCSeconds()) +
+    ' GMT';
+}
+
+
+
+///--- Exported API
+
+module.exports = {
+
+  /**
+   * Adds an 'Authorization' header to an http.ClientRequest object.
+   *
+   * Note that this API will add a Date header if it's not already set. Any
+   * other headers in the options.headers array MUST be present, or this
+   * will throw.
+   *
+   * You shouldn't need to check the return type; it's just there if you want
+   * to be pedantic.
+   *
+   * @param {Object} request an instance of http.ClientRequest.
+   * @param {Object} options signing parameters object:
+   *                   - {String} keyId required.
+   *                   - {String} key required (either a PEM or HMAC key).
+   *                   - {Array} headers optional; defaults to ['date'].
+   *                   - {String} algorithm optional; defaults to 'rsa-sha256'.
+   *                   - {String} httpVersion optional; defaults to '1.1'.
+   * @return {Boolean} true if Authorization (and optionally Date) were added.
+   * @throws {TypeError} on bad parameter types (input).
+   * @throws {InvalidAlgorithmError} if algorithm was bad.
+   * @throws {MissingHeaderError} if a header to be signed was specified but
+   *                              was not present.
+   */
+  signRequest: function signRequest(request, options) {
+    assert.object(request, 'request');
+    assert.object(options, 'options');
+    assert.optionalString(options.algorithm, 'options.algorithm');
+    assert.string(options.keyId, 'options.keyId');
+    assert.optionalArrayOfString(options.headers, 'options.headers');
+    assert.optionalString(options.httpVersion, 'options.httpVersion');
+
+    if (!request.getHeader('Date'))
+      request.setHeader('Date', _rfc1123());
+    if (!options.headers)
+      options.headers = ['date'];
+    if (!options.algorithm)
+      options.algorithm = 'rsa-sha256';
+    if (!options.httpVersion)
+      options.httpVersion = '1.1';
+
+    options.algorithm = options.algorithm.toLowerCase();
+
+    if (!Algorithms[options.algorithm])
+      throw new InvalidAlgorithmError(options.algorithm + ' is not supported');
+
+    var i;
+    var stringToSign = '';
+    for (i = 0; i < options.headers.length; i++) {
+      if (typeof (options.headers[i]) !== 'string')
+        throw new TypeError('options.headers must be an array of Strings');
+
+      var h = options.headers[i].toLowerCase();
+
+      if (h !== 'request-line') {
+        var value = request.getHeader(h);
+        if (!value) {
+          throw new MissingHeaderError(h + ' was not in the request');
+        }
+        stringToSign += h + ': ' + value;
+      } else {
+        value =
+        stringToSign +=
+          request.method + ' ' + request.path + ' HTTP/' + options.httpVersion;
+      }
+
+      if ((i + 1) < options.headers.length)
+        stringToSign += '\n';
+    }
+
+    var alg = options.algorithm.match(/(hmac|rsa)-(\w+)/);
+    var signature;
+    if (alg[1] === 'hmac') {
+      var hmac = crypto.createHmac(alg[2].toUpperCase(), options.key);
+      hmac.update(stringToSign);
+      signature = hmac.digest('base64');
+    } else {
+      var signer = crypto.createSign(options.algorithm.toUpperCase());
+      signer.update(stringToSign);
+      signature = signer.sign(options.key, 'base64');
+    }
+
+    request.setHeader('Authorization', sprintf(Authorization,
+                                               options.keyId,
+                                               options.algorithm,
+                                               options.headers.join(' '),
+                                               signature));
+
+    return true;
+  }
+
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/util.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/util.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/util.js	(revision 517)
@@ -0,0 +1,249 @@
+// Copyright 2012 Joyent, Inc.  All rights reserved.
+
+var assert = require('assert-plus');
+var crypto = require('crypto');
+
+var asn1 = require('asn1');
+var ctype = require('ctype');
+
+
+
+///--- Helpers
+
+function readNext(buffer, offset) {
+  var len = ctype.ruint32(buffer, 'big', offset);
+  offset += 4;
+
+  var newOffset = offset + len;
+
+  return {
+    data: buffer.slice(offset, newOffset),
+    offset: newOffset
+  };
+}
+
+
+function writeInt(writer, buffer) {
+  writer.writeByte(0x02); // ASN1.Integer
+  writer.writeLength(buffer.length);
+
+  for (var i = 0; i < buffer.length; i++)
+    writer.writeByte(buffer[i]);
+
+  return writer;
+}
+
+
+function rsaToPEM(key) {
+  var buffer;
+  var der;
+  var exponent;
+  var i;
+  var modulus;
+  var newKey = '';
+  var offset = 0;
+  var type;
+  var tmp;
+
+  try {
+    buffer = new Buffer(key.split(' ')[1], 'base64');
+
+    tmp = readNext(buffer, offset);
+    type = tmp.data.toString();
+    offset = tmp.offset;
+
+    if (type !== 'ssh-rsa')
+      throw new Error('Invalid ssh key type: ' + type);
+
+    tmp = readNext(buffer, offset);
+    exponent = tmp.data;
+    offset = tmp.offset;
+
+    tmp = readNext(buffer, offset);
+    modulus = tmp.data;
+  } catch (e) {
+    throw new Error('Invalid ssh key: ' + key);
+  }
+
+  // DER is a subset of BER
+  der = new asn1.BerWriter();
+
+  der.startSequence();
+
+  der.startSequence();
+  der.writeOID('1.2.840.113549.1.1.1');
+  der.writeNull();
+  der.endSequence();
+
+  der.startSequence(0x03); // bit string
+  der.writeByte(0x00);
+
+  // Actual key
+  der.startSequence();
+  writeInt(der, modulus);
+  writeInt(der, exponent);
+  der.endSequence();
+
+  // bit string
+  der.endSequence();
+
+  der.endSequence();
+
+  tmp = der.buffer.toString('base64');
+  for (i = 0; i < tmp.length; i++) {
+    if ((i % 64) === 0)
+      newKey += '\n';
+    newKey += tmp.charAt(i);
+  }
+
+  if (!/\\n$/.test(newKey))
+    newKey += '\n';
+
+  return '-----BEGIN PUBLIC KEY-----' + newKey + '-----END PUBLIC KEY-----\n';
+}
+
+
+function dsaToPEM(key) {
+  var buffer;
+  var offset = 0;
+  var tmp;
+  var der;
+  var newKey = '';
+
+  var type;
+  var p;
+  var q;
+  var g;
+  var y;
+
+  try {
+    buffer = new Buffer(key.split(' ')[1], 'base64');
+
+    tmp = readNext(buffer, offset);
+    type = tmp.data.toString();
+    offset = tmp.offset;
+
+    /* JSSTYLED */
+    if (!/^ssh-ds[as].*/.test(type))
+      throw new Error('Invalid ssh key type: ' + type);
+
+    tmp = readNext(buffer, offset);
+    p = tmp.data;
+    offset = tmp.offset;
+
+    tmp = readNext(buffer, offset);
+    q = tmp.data;
+    offset = tmp.offset;
+
+    tmp = readNext(buffer, offset);
+    g = tmp.data;
+    offset = tmp.offset;
+
+    tmp = readNext(buffer, offset);
+    y = tmp.data;
+  } catch (e) {
+    console.log(e.stack);
+    throw new Error('Invalid ssh key: ' + key);
+  }
+
+  // DER is a subset of BER
+  der = new asn1.BerWriter();
+
+  der.startSequence();
+
+  der.startSequence();
+  der.writeOID('1.2.840.10040.4.1');
+
+  der.startSequence();
+  writeInt(der, p);
+  writeInt(der, q);
+  writeInt(der, g);
+  der.endSequence();
+
+  der.endSequence();
+
+  der.startSequence(0x03); // bit string
+  der.writeByte(0x00);
+  writeInt(der, y);
+  der.endSequence();
+
+  der.endSequence();
+
+  tmp = der.buffer.toString('base64');
+  for (var i = 0; i < tmp.length; i++) {
+    if ((i % 64) === 0)
+      newKey += '\n';
+    newKey += tmp.charAt(i);
+  }
+
+  if (!/\\n$/.test(newKey))
+    newKey += '\n';
+
+  return '-----BEGIN PUBLIC KEY-----' + newKey + '-----END PUBLIC KEY-----\n';
+}
+
+
+///--- API
+
+module.exports = {
+
+  /**
+   * Converts an OpenSSH public key (rsa only) to a PKCS#8 PEM file.
+   *
+   * The intent of this module is to interoperate with OpenSSL only,
+   * specifically the node crypto module's `verify` method.
+   *
+   * @param {String} key an OpenSSH public key.
+   * @return {String} PEM encoded form of the RSA public key.
+   * @throws {TypeError} on bad input.
+   * @throws {Error} on invalid ssh key formatted data.
+   */
+  sshKeyToPEM: function sshKeyToPEM(key) {
+    assert.string(key, 'ssh_key');
+
+    /* JSSTYLED */
+    if (/^ssh-rsa.*/.test(key))
+      return rsaToPEM(key);
+
+    /* JSSTYLED */
+    if (/^ssh-ds[as].*/.test(key))
+      return dsaToPEM(key);
+
+    throw new Error('Only RSA and DSA public keys are allowed');
+  },
+
+
+  /**
+   * Generates an OpenSSH fingerprint from an ssh public key.
+   *
+   * @param {String} key an OpenSSH public key.
+   * @return {String} key fingerprint.
+   * @throws {TypeError} on bad input.
+   * @throws {Error} if what you passed doesn't look like an ssh public key.
+   */
+  fingerprint: function fingerprint(key) {
+    assert.string(key, 'ssh_key');
+
+    var pieces = key.split(' ');
+    if (!pieces || !pieces.length || pieces.length < 2)
+      throw new Error('invalid ssh key');
+
+    var data = new Buffer(pieces[1], 'base64');
+
+    var hash = crypto.createHash('md5');
+    hash.update(data);
+    var digest = hash.digest('hex');
+
+    var fp = '';
+    for (var i = 0; i < digest.length; i++) {
+      if (i && i % 2 === 0)
+        fp += ':';
+
+      fp += digest[i];
+    }
+
+    return fp;
+  }
+
+
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/verify.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/verify.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/lib/verify.js	(revision 517)
@@ -0,0 +1,42 @@
+// Copyright 2011 Joyent, Inc.  All rights reserved.
+
+var assert = require('assert-plus');
+var crypto = require('crypto');
+
+
+
+///--- Exported API
+
+module.exports = {
+
+  /**
+   * Simply wraps up the node crypto operations for you, and returns
+   * true or false.  You are expected to pass in an object that was
+   * returned from `parse()`.
+   *
+   * @param {Object} parsedSignature the object you got from `parse`.
+   * @param {String} key either an RSA private key PEM or HMAC secret.
+   * @return {Boolean} true if valid, false otherwise.
+   * @throws {TypeError} if you pass in bad arguments.
+   */
+  verifySignature: function verifySignature(parsedSignature, key) {
+    assert.object(parsedSignature, 'parsedSignature');
+    assert.string(key, 'key');
+
+    var alg = parsedSignature.algorithm.match(/(HMAC|RSA|DSA)-(\w+)/);
+    if (!alg || alg.length !== 3)
+      throw new TypeError('parsedSignature: unsupported algorithm ' +
+                          parsedSignature.algorithm);
+
+    if (alg[1] === 'HMAC') {
+      var hmac = crypto.createHmac(alg[2].toUpperCase(), key);
+      hmac.update(parsedSignature.signingString);
+      return (hmac.digest('base64') === parsedSignature.params.signature);
+    } else {
+      var verify = crypto.createVerify(alg[0]);
+      verify.update(parsedSignature.signingString);
+      return verify.verify(key, parsedSignature.params.signature, 'base64');
+    }
+  }
+
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/.npmignore	(revision 517)
@@ -0,0 +1,2 @@
+node_modules
+*.log
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/LICENSE	(revision 517)
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Mark Cavage, All rights reserved.
+
+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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/README.md	(revision 517)
@@ -0,0 +1,50 @@
+node-asn1 is a library for encoding and decoding ASN.1 datatypes in pure JS.
+Currently BER encoding is supported; at some point I'll likely have to do DER.
+
+## Usage
+
+Mostly, if you're *actually* needing to read and write ASN.1, you probably don't
+need this readme to explain what and why.  If you have no idea what ASN.1 is,
+see this: ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc
+
+The source is pretty much self-explanatory, and has read/write methods for the
+common types out there.
+
+### Decoding
+
+The following reads an ASN.1 sequence with a boolean.
+
+    var Ber = require('asn1').Ber;
+
+    var reader = new Ber.Reader(new Buffer([0x30, 0x03, 0x01, 0x01, 0xff]));
+
+    reader.readSequence();
+    console.log('Sequence len: ' + reader.length);
+    if (reader.peek() === Ber.Boolean)
+      console.log(reader.readBoolean());
+
+### Encoding
+
+The following generates the same payload as above.
+
+    var Ber = require('asn1').Ber;
+
+    var writer = new Ber.Writer();
+
+    writer.startSequence();
+    writer.writeBoolean(true);
+    writer.endSequence();
+
+    console.log(writer.buffer);
+
+## Installation
+
+    npm install asn1
+
+## License
+
+MIT.
+
+## Bugs
+
+See <https://github.com/mcavage/node-asn1/issues>.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/errors.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/errors.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/errors.js	(revision 517)
@@ -0,0 +1,13 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+
+module.exports = {
+
+  newInvalidAsn1Error: function(msg) {
+    var e = new Error();
+    e.name = 'InvalidAsn1Error';
+    e.message = msg || '';
+    return e;
+  }
+
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/index.js	(revision 517)
@@ -0,0 +1,27 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+var errors = require('./errors');
+var types = require('./types');
+
+var Reader = require('./reader');
+var Writer = require('./writer');
+
+
+///--- Exports
+
+module.exports = {
+
+  Reader: Reader,
+
+  Writer: Writer
+
+};
+
+for (var t in types) {
+  if (types.hasOwnProperty(t))
+    module.exports[t] = types[t];
+}
+for (var e in errors) {
+  if (errors.hasOwnProperty(e))
+    module.exports[e] = errors[e];
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/reader.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/reader.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/reader.js	(revision 517)
@@ -0,0 +1,267 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+var assert = require('assert');
+
+var ASN1 = require('./types');
+var errors = require('./errors');
+
+
+///--- Globals
+
+var newInvalidAsn1Error = errors.newInvalidAsn1Error;
+
+
+
+///--- API
+
+function Reader(data) {
+  if (!data || !Buffer.isBuffer(data))
+    throw new TypeError('data must be a node Buffer');
+
+  this._buf = data;
+  this._size = data.length;
+
+  // These hold the "current" state
+  this._len = 0;
+  this._offset = 0;
+
+  var self = this;
+  this.__defineGetter__('length', function() { return self._len; });
+  this.__defineGetter__('offset', function() { return self._offset; });
+  this.__defineGetter__('remain', function() {
+    return self._size - self._offset;
+  });
+  this.__defineGetter__('buffer', function() {
+    return self._buf.slice(self._offset);
+  });
+}
+
+
+/**
+ * Reads a single byte and advances offset; you can pass in `true` to make this
+ * a "peek" operation (i.e., get the byte, but don't advance the offset).
+ *
+ * @param {Boolean} peek true means don't move offset.
+ * @return {Number} the next byte, null if not enough data.
+ */
+Reader.prototype.readByte = function(peek) {
+  if (this._size - this._offset < 1)
+    return null;
+
+  var b = this._buf[this._offset] & 0xff;
+
+  if (!peek)
+    this._offset += 1;
+
+  return b;
+};
+
+
+Reader.prototype.peek = function() {
+  return this.readByte(true);
+};
+
+
+/**
+ * Reads a (potentially) variable length off the BER buffer.  This call is
+ * not really meant to be called directly, as callers have to manipulate
+ * the internal buffer afterwards.
+ *
+ * As a result of this call, you can call `Reader.length`, until the
+ * next thing called that does a readLength.
+ *
+ * @return {Number} the amount of offset to advance the buffer.
+ * @throws {InvalidAsn1Error} on bad ASN.1
+ */
+Reader.prototype.readLength = function(offset) {
+  if (offset === undefined)
+    offset = this._offset;
+
+  if (offset >= this._size)
+    return null;
+
+  var lenB = this._buf[offset++] & 0xff;
+  if (lenB === null)
+    return null;
+
+  if ((lenB & 0x80) == 0x80) {
+    lenB &= 0x7f;
+
+    if (lenB == 0)
+      throw newInvalidAsn1Error('Indefinite length not supported');
+
+    if (lenB > 4)
+      throw newInvalidAsn1Error('encoding too long');
+
+    if (this._size - offset < lenB)
+      return null;
+
+    this._len = 0;
+    for (var i = 0; i < lenB; i++)
+      this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
+
+  } else {
+    // Wasn't a variable length
+    this._len = lenB;
+  }
+
+  return offset;
+};
+
+
+/**
+ * Parses the next sequence in this BER buffer.
+ *
+ * To get the length of the sequence, call `Reader.length`.
+ *
+ * @return {Number} the sequence's tag.
+ */
+Reader.prototype.readSequence = function(tag) {
+  var seq = this.peek();
+  if (seq === null)
+    return null;
+  if (tag !== undefined && tag !== seq)
+    throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
+                              ': got 0x' + seq.toString(16));
+
+  var o = this.readLength(this._offset + 1); // stored in `length`
+  if (o === null)
+    return null;
+
+  this._offset = o;
+  return seq;
+};
+
+
+Reader.prototype.readInt = function() {
+  return this._readTag(ASN1.Integer);
+};
+
+
+Reader.prototype.readBoolean = function() {
+  return (this._readTag(ASN1.Boolean) === 0 ? false : true);
+};
+
+
+Reader.prototype.readEnumeration = function() {
+  return this._readTag(ASN1.Enumeration);
+};
+
+
+Reader.prototype.readString = function(tag, retbuf) {
+  if (!tag)
+    tag = ASN1.OctetString;
+
+  var b = this.peek();
+  if (b === null)
+    return null;
+
+  if (b !== tag)
+    throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
+                              ': got 0x' + b.toString(16));
+
+  var o = this.readLength(this._offset + 1); // stored in `length`
+
+  if (o === null)
+    return null;
+
+  if (this.length > this._size - o)
+    return null;
+
+  this._offset = o;
+
+  if (this.length === 0)
+    return '';
+
+  var str = this._buf.slice(this._offset, this._offset + this.length);
+  this._offset += this.length;
+
+  return retbuf ? str : str.toString('utf8');
+};
+
+Reader.prototype.readOID = function(tag) {
+  if (!tag)
+    tag = ASN1.OID;
+
+  var b = this.peek();
+  if (b === null)
+    return null;
+
+  if (b !== tag)
+    throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
+                              ': got 0x' + b.toString(16));
+
+  var o = this.readLength(this._offset + 1); // stored in `length`
+  if (o === null)
+    return null;
+
+  if (this.length > this._size - o)
+    return null;
+
+  this._offset = o;
+
+  var values = [];
+  var value = 0;
+
+  for (var i = 0; i < this.length; i++) {
+    var byte = this._buf[this._offset++] & 0xff;
+
+    value <<= 7;
+    value += byte & 0x7f;
+    if ((byte & 0x80) == 0) {
+      values.push(value);
+      value = 0;
+    }
+  }
+
+  value = values.shift();
+  values.unshift(value % 40);
+  values.unshift((value / 40) >> 0);
+
+  return values.join('.');
+};
+
+
+Reader.prototype._readTag = function(tag) {
+  assert.ok(tag !== undefined);
+
+  var b = this.peek();
+
+  if (b === null)
+    return null;
+
+  if (b !== tag)
+    throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
+                              ': got 0x' + b.toString(16));
+
+  var o = this.readLength(this._offset + 1); // stored in `length`
+  if (o === null)
+    return null;
+
+  if (this.length > 4)
+    throw newInvalidAsn1Error('Integer too long: ' + this.length);
+
+  if (this.length > this._size - o)
+    return null;
+  this._offset = o;
+
+  var fb = this._buf[this._offset++];
+  var value = 0;
+
+  value = fb & 0x7F;
+  for (var i = 1; i < this.length; i++) {
+    value <<= 8;
+    value |= (this._buf[this._offset++] & 0xff);
+  }
+
+  if ((fb & 0x80) == 0x80)
+    value = -value;
+
+  return value;
+};
+
+
+
+///--- Exported API
+
+module.exports = Reader;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/types.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/types.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/types.js	(revision 517)
@@ -0,0 +1,36 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+
+module.exports = {
+  EOC: 0,
+  Boolean: 1,
+  Integer: 2,
+  BitString: 3,
+  OctetString: 4,
+  Null: 5,
+  OID: 6,
+  ObjectDescriptor: 7,
+  External: 8,
+  Real: 9, // float
+  Enumeration: 10,
+  PDV: 11,
+  Utf8String: 12,
+  RelativeOID: 13,
+  Sequence: 16,
+  Set: 17,
+  NumericString: 18,
+  PrintableString: 19,
+  T61String: 20,
+  VideotexString: 21,
+  IA5String: 22,
+  UTCTime: 23,
+  GeneralizedTime: 24,
+  GraphicString: 25,
+  VisibleString: 26,
+  GeneralString: 28,
+  UniversalString: 29,
+  CharacterString: 30,
+  BMPString: 31,
+  Constructor: 32,
+  Context: 128
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/writer.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/writer.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/ber/writer.js	(revision 517)
@@ -0,0 +1,317 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+var assert = require('assert');
+var ASN1 = require('./types');
+var errors = require('./errors');
+
+
+///--- Globals
+
+var newInvalidAsn1Error = errors.newInvalidAsn1Error;
+
+var DEFAULT_OPTS = {
+  size: 1024,
+  growthFactor: 8
+};
+
+
+///--- Helpers
+
+function merge(from, to) {
+  assert.ok(from);
+  assert.equal(typeof(from), 'object');
+  assert.ok(to);
+  assert.equal(typeof(to), 'object');
+
+  var keys = Object.getOwnPropertyNames(from);
+  keys.forEach(function(key) {
+    if (to[key])
+      return;
+
+    var value = Object.getOwnPropertyDescriptor(from, key);
+    Object.defineProperty(to, key, value);
+  });
+
+  return to;
+}
+
+
+
+///--- API
+
+function Writer(options) {
+  options = merge(DEFAULT_OPTS, options || {});
+
+  this._buf = new Buffer(options.size || 1024);
+  this._size = this._buf.length;
+  this._offset = 0;
+  this._options = options;
+
+  // A list of offsets in the buffer where we need to insert
+  // sequence tag/len pairs.
+  this._seq = [];
+
+  var self = this;
+  this.__defineGetter__('buffer', function() {
+    if (self._seq.length)
+      throw new InvalidAsn1Error(self._seq.length + ' unended sequence(s)');
+
+    return self._buf.slice(0, self._offset);
+  });
+}
+
+
+Writer.prototype.writeByte = function(b) {
+  if (typeof(b) !== 'number')
+    throw new TypeError('argument must be a Number');
+
+  this._ensure(1);
+  this._buf[this._offset++] = b;
+};
+
+
+Writer.prototype.writeInt = function(i, tag) {
+  if (typeof(i) !== 'number')
+    throw new TypeError('argument must be a Number');
+  if (typeof(tag) !== 'number')
+    tag = ASN1.Integer;
+
+  var sz = 4;
+
+  while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000)) &&
+         (sz > 1)) {
+    sz--;
+    i <<= 8;
+  }
+
+  if (sz > 4)
+    throw new InvalidAsn1Error('BER ints cannot be > 0xffffffff');
+
+  this._ensure(2 + sz);
+  this._buf[this._offset++] = tag;
+  this._buf[this._offset++] = sz;
+
+  while (sz-- > 0) {
+    this._buf[this._offset++] = ((i & 0xff000000) >> 24);
+    i <<= 8;
+  }
+
+};
+
+
+Writer.prototype.writeNull = function() {
+  this.writeByte(ASN1.Null);
+  this.writeByte(0x00);
+};
+
+
+Writer.prototype.writeEnumeration = function(i, tag) {
+  if (typeof(i) !== 'number')
+    throw new TypeError('argument must be a Number');
+  if (typeof(tag) !== 'number')
+    tag = ASN1.Enumeration;
+
+  return this.writeInt(i, tag);
+};
+
+
+Writer.prototype.writeBoolean = function(b, tag) {
+  if (typeof(b) !== 'boolean')
+    throw new TypeError('argument must be a Boolean');
+  if (typeof(tag) !== 'number')
+    tag = ASN1.Boolean;
+
+  this._ensure(3);
+  this._buf[this._offset++] = tag;
+  this._buf[this._offset++] = 0x01;
+  this._buf[this._offset++] = b ? 0xff : 0x00;
+};
+
+
+Writer.prototype.writeString = function(s, tag) {
+  if (typeof(s) !== 'string')
+    throw new TypeError('argument must be a string (was: ' + typeof(s) + ')');
+  if (typeof(tag) !== 'number')
+    tag = ASN1.OctetString;
+
+  var len = Buffer.byteLength(s);
+  this.writeByte(tag);
+  this.writeLength(len);
+  if (len) {
+    this._ensure(len);
+    this._buf.write(s, this._offset);
+    this._offset += len;
+  }
+};
+
+
+Writer.prototype.writeBuffer = function(buf, tag) {
+  if (typeof(tag) !== 'number')
+    throw new TypeError('tag must be a number');
+  if (!Buffer.isBuffer(buf))
+    throw new TypeError('argument must be a buffer');
+
+  this.writeByte(tag);
+  this.writeLength(buf.length);
+  this._ensure(buf.length);
+  buf.copy(this._buf, this._offset, 0, buf.length);
+  this._offset += buf.length;
+};
+
+
+Writer.prototype.writeStringArray = function(strings) {
+  if ((!strings instanceof Array))
+    throw new TypeError('argument must be an Array[String]');
+
+  var self = this;
+  strings.forEach(function(s) {
+    self.writeString(s);
+  });
+};
+
+// This is really to solve DER cases, but whatever for now
+Writer.prototype.writeOID = function(s, tag) {
+  if (typeof(s) !== 'string')
+    throw new TypeError('argument must be a string');
+  if (typeof(tag) !== 'number')
+    tag = ASN1.OID;
+
+  if (!/^([0-9]+\.){3,}[0-9]+$/.test(s))
+    throw new Error('argument is not a valid OID string');
+
+  function encodeOctet(bytes, octet) {
+    if (octet < 128) {
+        bytes.push(octet);
+    } else if (octet < 16384) {
+        bytes.push((octet >>> 7) | 0x80);
+        bytes.push(octet & 0x7F);
+    } else if (octet < 2097152) {
+      bytes.push((octet >>> 14) | 0x80);
+      bytes.push(((octet >>> 7) | 0x80) & 0xFF);
+      bytes.push(octet & 0x7F);
+    } else if (octet < 268435456) {
+      bytes.push((octet >>> 21) | 0x80);
+      bytes.push(((octet >>> 14) | 0x80) & 0xFF);
+      bytes.push(((octet >>> 7) | 0x80) & 0xFF);
+      bytes.push(octet & 0x7F);
+    } else {
+      bytes.push(((octet >>> 28) | 0x80) & 0xFF);
+      bytes.push(((octet >>> 21) | 0x80) & 0xFF);
+      bytes.push(((octet >>> 14) | 0x80) & 0xFF);
+      bytes.push(((octet >>> 7) | 0x80) & 0xFF);
+      bytes.push(octet & 0x7F);
+    }
+  }
+
+  var tmp = s.split('.');
+  var bytes = [];
+  bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10));
+  tmp.slice(2).forEach(function(b) {
+    encodeOctet(bytes, parseInt(b, 10));
+  });
+
+  var self = this;
+  this._ensure(2 + bytes.length);
+  this.writeByte(tag);
+  this.writeLength(bytes.length);
+  bytes.forEach(function(b) {
+    self.writeByte(b);
+  });
+};
+
+
+Writer.prototype.writeLength = function(len) {
+  if (typeof(len) !== 'number')
+    throw new TypeError('argument must be a Number');
+
+  this._ensure(4);
+
+  if (len <= 0x7f) {
+    this._buf[this._offset++] = len;
+  } else if (len <= 0xff) {
+    this._buf[this._offset++] = 0x81;
+    this._buf[this._offset++] = len;
+  } else if (len <= 0xffff) {
+    this._buf[this._offset++] = 0x82;
+    this._buf[this._offset++] = len >> 8;
+    this._buf[this._offset++] = len;
+  } else if (len <= 0xffffff) {
+    this._shift(start, len, 1);
+    this._buf[this._offset++] = 0x83;
+    this._buf[this._offset++] = len >> 16;
+    this._buf[this._offset++] = len >> 8;
+    this._buf[this._offset++] = len;
+  } else {
+    throw new InvalidAsn1ERror('Length too long (> 4 bytes)');
+  }
+};
+
+Writer.prototype.startSequence = function(tag) {
+  if (typeof(tag) !== 'number')
+    tag = ASN1.Sequence | ASN1.Constructor;
+
+  this.writeByte(tag);
+  this._seq.push(this._offset);
+  this._ensure(3);
+  this._offset += 3;
+};
+
+
+Writer.prototype.endSequence = function() {
+  var seq = this._seq.pop();
+  var start = seq + 3;
+  var len = this._offset - start;
+
+  if (len <= 0x7f) {
+    this._shift(start, len, -2);
+    this._buf[seq] = len;
+  } else if (len <= 0xff) {
+    this._shift(start, len, -1);
+    this._buf[seq] = 0x81;
+    this._buf[seq + 1] = len;
+  } else if (len <= 0xffff) {
+    this._buf[seq] = 0x82;
+    this._buf[seq + 1] = len >> 8;
+    this._buf[seq + 2] = len;
+  } else if (len <= 0xffffff) {
+    this._shift(start, len, 1);
+    this._buf[seq] = 0x83;
+    this._buf[seq + 1] = len >> 16;
+    this._buf[seq + 2] = len >> 8;
+    this._buf[seq + 3] = len;
+  } else {
+    throw new InvalidAsn1Error('Sequence too long');
+  }
+};
+
+
+Writer.prototype._shift = function(start, len, shift) {
+  assert.ok(start !== undefined);
+  assert.ok(len !== undefined);
+  assert.ok(shift);
+
+  this._buf.copy(this._buf, start + shift, start, start + len);
+  this._offset += shift;
+};
+
+Writer.prototype._ensure = function(len) {
+  assert.ok(len);
+
+  if (this._size - this._offset < len) {
+    var sz = this._size * this._options.growthFactor;
+    if (sz - this._offset < len)
+      sz += len;
+
+    var buf = new Buffer(sz);
+
+    this._buf.copy(buf, 0, 0, this._offset);
+    this._buf = buf;
+    this._size = sz;
+  }
+};
+
+
+
+///--- Exported API
+
+module.exports = Writer;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/lib/index.js	(revision 517)
@@ -0,0 +1,20 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+// If you have no idea what ASN.1 or BER is, see this:
+// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc
+
+var Ber = require('./ber/index');
+
+
+
+///--- Exported API
+
+module.exports = {
+
+  Ber: Ber,
+
+  BerReader: Ber.Reader,
+
+  BerWriter: Ber.Writer
+
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/package.json	(revision 517)
@@ -0,0 +1,43 @@
+{
+  "author": {
+    "name": "Mark Cavage",
+    "email": "mcavage@gmail.com"
+  },
+  "contributors": [
+    {
+      "name": "David Gwynne",
+      "email": "loki@animata.net"
+    },
+    {
+      "name": "Yunong Xiao",
+      "email": "yunong@joyent.com"
+    }
+  ],
+  "name": "asn1",
+  "description": "Contains parsers and serializers for ASN.1 (currently BER only)",
+  "version": "0.1.11",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/mcavage/node-asn1.git"
+  },
+  "main": "lib/index.js",
+  "engines": {
+    "node": ">=0.4.9"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "tap": "0.1.4"
+  },
+  "scripts": {
+    "pretest": "which gjslint; if [[ \"$?\" = 0 ]] ; then  gjslint --nojsdoc -r lib -r tst; else echo \"Missing gjslint. Skipping lint\"; fi",
+    "test": "tap ./tst"
+  },
+  "readme": "node-asn1 is a library for encoding and decoding ASN.1 datatypes in pure JS.\nCurrently BER encoding is supported; at some point I'll likely have to do DER.\n\n## Usage\n\nMostly, if you're *actually* needing to read and write ASN.1, you probably don't\nneed this readme to explain what and why.  If you have no idea what ASN.1 is,\nsee this: ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc\n\nThe source is pretty much self-explanatory, and has read/write methods for the\ncommon types out there.\n\n### Decoding\n\nThe following reads an ASN.1 sequence with a boolean.\n\n    var Ber = require('asn1').Ber;\n\n    var reader = new Ber.Reader(new Buffer([0x30, 0x03, 0x01, 0x01, 0xff]));\n\n    reader.readSequence();\n    console.log('Sequence len: ' + reader.length);\n    if (reader.peek() === Ber.Boolean)\n      console.log(reader.readBoolean());\n\n### Encoding\n\nThe following generates the same payload as above.\n\n    var Ber = require('asn1').Ber;\n\n    var writer = new Ber.Writer();\n\n    writer.startSequence();\n    writer.writeBoolean(true);\n    writer.endSequence();\n\n    console.log(writer.buffer);\n\n## Installation\n\n    npm install asn1\n\n## License\n\nMIT.\n\n## Bugs\n\nSee <https://github.com/mcavage/node-asn1/issues>.\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/mcavage/node-asn1/issues"
+  },
+  "homepage": "https://github.com/mcavage/node-asn1",
+  "_id": "asn1@0.1.11",
+  "_from": "asn1@0.1.11"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/tst/ber/reader.test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/tst/ber/reader.test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/tst/ber/reader.test.js	(revision 517)
@@ -0,0 +1,172 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+var test = require('tap').test;
+
+
+
+///--- Globals
+
+var BerReader;
+
+
+
+///--- Tests
+
+test('load library', function(t) {
+  BerReader = require('../../lib/index').BerReader;
+  t.ok(BerReader);
+  try {
+    new BerReader();
+    t.fail('Should have thrown');
+  } catch (e) {
+    t.ok(e instanceof TypeError, 'Should have been a type error');
+  }
+  t.end();
+});
+
+
+test('read byte', function(t) {
+  var reader = new BerReader(new Buffer([0xde]));
+  t.ok(reader);
+  t.equal(reader.readByte(), 0xde, 'wrong value');
+  t.end();
+});
+
+
+test('read 1 byte int', function(t) {
+  var reader = new BerReader(new Buffer([0x02, 0x01, 0x03]));
+  t.ok(reader);
+  t.equal(reader.readInt(), 0x03, 'wrong value');
+  t.equal(reader.length, 0x01, 'wrong length');
+  t.end();
+});
+
+
+test('read 2 byte int', function(t) {
+  var reader = new BerReader(new Buffer([0x02, 0x02, 0x7e, 0xde]));
+  t.ok(reader);
+  t.equal(reader.readInt(), 0x7ede, 'wrong value');
+  t.equal(reader.length, 0x02, 'wrong length');
+  t.end();
+});
+
+
+test('read 3 byte int', function(t) {
+  var reader = new BerReader(new Buffer([0x02, 0x03, 0x7e, 0xde, 0x03]));
+  t.ok(reader);
+  t.equal(reader.readInt(), 0x7ede03, 'wrong value');
+  t.equal(reader.length, 0x03, 'wrong length');
+  t.end();
+});
+
+
+test('read 4 byte int', function(t) {
+  var reader = new BerReader(new Buffer([0x02, 0x04, 0x7e, 0xde, 0x03, 0x01]));
+  t.ok(reader);
+  t.equal(reader.readInt(), 0x7ede0301, 'wrong value');
+  t.equal(reader.length, 0x04, 'wrong length');
+  t.end();
+});
+
+
+test('read boolean true', function(t) {
+  var reader = new BerReader(new Buffer([0x01, 0x01, 0xff]));
+  t.ok(reader);
+  t.equal(reader.readBoolean(), true, 'wrong value');
+  t.equal(reader.length, 0x01, 'wrong length');
+  t.end();
+});
+
+
+test('read boolean false', function(t) {
+  var reader = new BerReader(new Buffer([0x01, 0x01, 0x00]));
+  t.ok(reader);
+  t.equal(reader.readBoolean(), false, 'wrong value');
+  t.equal(reader.length, 0x01, 'wrong length');
+  t.end();
+});
+
+
+test('read enumeration', function(t) {
+  var reader = new BerReader(new Buffer([0x0a, 0x01, 0x20]));
+  t.ok(reader);
+  t.equal(reader.readEnumeration(), 0x20, 'wrong value');
+  t.equal(reader.length, 0x01, 'wrong length');
+  t.end();
+});
+
+
+test('read string', function(t) {
+  var dn = 'cn=foo,ou=unit,o=test';
+  var buf = new Buffer(dn.length + 2);
+  buf[0] = 0x04;
+  buf[1] = Buffer.byteLength(dn);
+  buf.write(dn, 2);
+  var reader = new BerReader(buf);
+  t.ok(reader);
+  t.equal(reader.readString(), dn, 'wrong value');
+  t.equal(reader.length, dn.length, 'wrong length');
+  t.end();
+});
+
+
+test('read sequence', function(t) {
+  var reader = new BerReader(new Buffer([0x30, 0x03, 0x01, 0x01, 0xff]));
+  t.ok(reader);
+  t.equal(reader.readSequence(), 0x30, 'wrong value');
+  t.equal(reader.length, 0x03, 'wrong length');
+  t.equal(reader.readBoolean(), true, 'wrong value');
+  t.equal(reader.length, 0x01, 'wrong length');
+  t.end();
+});
+
+
+test('anonymous LDAPv3 bind', function(t) {
+  var BIND = new Buffer(14);
+  BIND[0] = 0x30;  // Sequence
+  BIND[1] = 12;    // len
+  BIND[2] = 0x02;  // ASN.1 Integer
+  BIND[3] = 1;     // len
+  BIND[4] = 0x04;  // msgid (make up 4)
+  BIND[5] = 0x60;  // Bind Request
+  BIND[6] = 7;     // len
+  BIND[7] = 0x02;  // ASN.1 Integer
+  BIND[8] = 1;     // len
+  BIND[9] = 0x03;  // v3
+  BIND[10] = 0x04; // String (bind dn)
+  BIND[11] = 0;    // len
+  BIND[12] = 0x80; // ContextSpecific (choice)
+  BIND[13] = 0;    // simple bind
+
+  // Start testing ^^
+  var ber = new BerReader(BIND);
+  t.equal(ber.readSequence(), 48, 'Not an ASN.1 Sequence');
+  t.equal(ber.length, 12, 'Message length should be 12');
+  t.equal(ber.readInt(), 4, 'Message id should have been 4');
+  t.equal(ber.readSequence(), 96, 'Bind Request should have been 96');
+  t.equal(ber.length, 7, 'Bind length should have been 7');
+  t.equal(ber.readInt(), 3, 'LDAP version should have been 3');
+  t.equal(ber.readString(), '', 'Bind DN should have been empty');
+  t.equal(ber.length, 0, 'string length should have been 0');
+  t.equal(ber.readByte(), 0x80, 'Should have been ContextSpecific (choice)');
+  t.equal(ber.readByte(), 0, 'Should have been simple bind');
+  t.equal(null, ber.readByte(), 'Should be out of data');
+  t.end();
+});
+
+
+test('long string', function(t) {
+  var buf = new Buffer(256);
+  var o;
+  var s =
+    '2;649;CN=Red Hat CS 71GA Demo,O=Red Hat CS 71GA Demo,C=US;' +
+    'CN=RHCS Agent - admin01,UID=admin01,O=redhat,C=US [1] This is ' +
+    'Teena Vradmin\'s description.';
+  buf[0] = 0x04;
+  buf[1] = 0x81;
+  buf[2] = 0x94;
+  buf.write(s, 3);
+  var ber = new BerReader(buf.slice(0, 3 + s.length));
+  t.equal(ber.readString(), s);
+  t.end();
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/tst/ber/writer.test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/tst/ber/writer.test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/asn1/tst/ber/writer.test.js	(revision 517)
@@ -0,0 +1,296 @@
+// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
+
+var test = require('tap').test;
+var sys = require('sys');
+
+///--- Globals
+
+var BerWriter;
+
+var BerReader;
+
+
+///--- Tests
+
+test('load library', function(t) {
+  BerWriter = require('../../lib/index').BerWriter;
+  t.ok(BerWriter);
+  t.ok(new BerWriter());
+  t.end();
+});
+
+
+test('write byte', function(t) {
+  var writer = new BerWriter();
+
+  writer.writeByte(0xC2);
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 1, 'Wrong length');
+  t.equal(ber[0], 0xC2, 'value wrong');
+
+  t.end();
+});
+
+
+test('write 1 byte int', function(t) {
+  var writer = new BerWriter();
+
+  writer.writeInt(0x7f);
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 3, 'Wrong length for an int: ' + ber.length);
+  t.equal(ber[0], 0x02, 'ASN.1 tag wrong (2) -> ' + ber[0]);
+  t.equal(ber[1], 0x01, 'length wrong(1) -> ' + ber[1]);
+  t.equal(ber[2], 0x7f, 'value wrong(3) -> ' + ber[2]);
+
+  t.end();
+});
+
+
+test('write 2 byte int', function(t) {
+  var writer = new BerWriter();
+
+  writer.writeInt(0x7ffe);
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 4, 'Wrong length for an int');
+  t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
+  t.equal(ber[1], 0x02, 'length wrong');
+  t.equal(ber[2], 0x7f, 'value wrong (byte 1)');
+  t.equal(ber[3], 0xfe, 'value wrong (byte 2)');
+
+  t.end();
+});
+
+
+test('write 3 byte int', function(t) {
+  var writer = new BerWriter();
+
+  writer.writeInt(0x7ffffe);
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 5, 'Wrong length for an int');
+  t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
+  t.equal(ber[1], 0x03, 'length wrong');
+  t.equal(ber[2], 0x7f, 'value wrong (byte 1)');
+  t.equal(ber[3], 0xff, 'value wrong (byte 2)');
+  t.equal(ber[4], 0xfe, 'value wrong (byte 3)');
+
+  t.end();
+});
+
+
+test('write 4 byte int', function(t) {
+  var writer = new BerWriter();
+
+  writer.writeInt(0x7ffffffe);
+  var ber = writer.buffer;
+
+  t.ok(ber);
+
+  t.equal(ber.length, 6, 'Wrong length for an int');
+  t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
+  t.equal(ber[1], 0x04, 'length wrong');
+  t.equal(ber[2], 0x7f, 'value wrong (byte 1)');
+  t.equal(ber[3], 0xff, 'value wrong (byte 2)');
+  t.equal(ber[4], 0xff, 'value wrong (byte 3)');
+  t.equal(ber[5], 0xfe, 'value wrong (byte 4)');
+
+  t.end();
+});
+
+
+test('write boolean', function(t) {
+  var writer = new BerWriter();
+
+  writer.writeBoolean(true);
+  writer.writeBoolean(false);
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 6, 'Wrong length');
+  t.equal(ber[0], 0x01, 'tag wrong');
+  t.equal(ber[1], 0x01, 'length wrong');
+  t.equal(ber[2], 0xff, 'value wrong');
+  t.equal(ber[3], 0x01, 'tag wrong');
+  t.equal(ber[4], 0x01, 'length wrong');
+  t.equal(ber[5], 0x00, 'value wrong');
+
+  t.end();
+});
+
+
+test('write string', function(t) {
+  var writer = new BerWriter();
+  writer.writeString('hello world');
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 13, 'wrong length');
+  t.equal(ber[0], 0x04, 'wrong tag');
+  t.equal(ber[1], 11, 'wrong length');
+  t.equal(ber.slice(2).toString('utf8'), 'hello world', 'wrong value');
+
+  t.end();
+});
+
+test('write buffer', function(t) {
+  var writer = new BerWriter();
+  // write some stuff to start with
+  writer.writeString('hello world');
+  var ber = writer.buffer;
+  var buf = new Buffer([0x04, 0x0b, 0x30, 0x09, 0x02, 0x01, 0x0f, 0x01, 0x01,
+     0xff, 0x01, 0x01, 0xff]);
+  writer.writeBuffer(buf.slice(2, buf.length), 0x04);
+  ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 26, 'wrong length');
+  t.equal(ber[0], 0x04, 'wrong tag');
+  t.equal(ber[1], 11, 'wrong length');
+  t.equal(ber.slice(2, 13).toString('utf8'), 'hello world', 'wrong value');
+  t.equal(ber[13], buf[0], 'wrong tag');
+  t.equal(ber[14], buf[1], 'wrong length');
+  for (var i = 13, j = 0; i < ber.length && j < buf.length; i++, j++) {
+    t.equal(ber[i], buf[j], 'buffer contents not identical');
+  }
+  t.end();
+});
+
+test('write string array', function(t) {
+  var writer = new BerWriter();
+  writer.writeStringArray(['hello world', 'fubar!']);
+  var ber = writer.buffer;
+
+  t.ok(ber);
+
+  t.equal(ber.length, 21, 'wrong length');
+  t.equal(ber[0], 0x04, 'wrong tag');
+  t.equal(ber[1], 11, 'wrong length');
+  t.equal(ber.slice(2, 13).toString('utf8'), 'hello world', 'wrong value');
+
+  t.equal(ber[13], 0x04, 'wrong tag');
+  t.equal(ber[14], 6, 'wrong length');
+  t.equal(ber.slice(15).toString('utf8'), 'fubar!', 'wrong value');
+
+  t.end();
+});
+
+
+test('resize internal buffer', function(t) {
+  var writer = new BerWriter({size: 2});
+  writer.writeString('hello world');
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 13, 'wrong length');
+  t.equal(ber[0], 0x04, 'wrong tag');
+  t.equal(ber[1], 11, 'wrong length');
+  t.equal(ber.slice(2).toString('utf8'), 'hello world', 'wrong value');
+
+  t.end();
+});
+
+
+test('sequence', function(t) {
+  var writer = new BerWriter({size: 25});
+  writer.startSequence();
+  writer.writeString('hello world');
+  writer.endSequence();
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  console.log(ber);
+  t.equal(ber.length, 15, 'wrong length');
+  t.equal(ber[0], 0x30, 'wrong tag');
+  t.equal(ber[1], 13, 'wrong length');
+  t.equal(ber[2], 0x04, 'wrong tag');
+  t.equal(ber[3], 11, 'wrong length');
+  t.equal(ber.slice(4).toString('utf8'), 'hello world', 'wrong value');
+
+  t.end();
+});
+
+
+test('nested sequence', function(t) {
+  var writer = new BerWriter({size: 25});
+  writer.startSequence();
+  writer.writeString('hello world');
+  writer.startSequence();
+  writer.writeString('hello world');
+  writer.endSequence();
+  writer.endSequence();
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 30, 'wrong length');
+  t.equal(ber[0], 0x30, 'wrong tag');
+  t.equal(ber[1], 28, 'wrong length');
+  t.equal(ber[2], 0x04, 'wrong tag');
+  t.equal(ber[3], 11, 'wrong length');
+  t.equal(ber.slice(4, 15).toString('utf8'), 'hello world', 'wrong value');
+  t.equal(ber[15], 0x30, 'wrong tag');
+  t.equal(ber[16], 13, 'wrong length');
+  t.equal(ber[17], 0x04, 'wrong tag');
+  t.equal(ber[18], 11, 'wrong length');
+  t.equal(ber.slice(19, 30).toString('utf8'), 'hello world', 'wrong value');
+
+  t.end();
+});
+
+
+test('LDAP bind message', function(t) {
+  var dn = 'cn=foo,ou=unit,o=test';
+  var writer = new BerWriter();
+  writer.startSequence();
+  writer.writeInt(3);             // msgid = 3
+  writer.startSequence(0x60);     // ldap bind
+  writer.writeInt(3);             // ldap v3
+  writer.writeString(dn);
+  writer.writeByte(0x80);
+  writer.writeByte(0x00);
+  writer.endSequence();
+  writer.endSequence();
+  var ber = writer.buffer;
+
+  t.ok(ber);
+  t.equal(ber.length, 35, 'wrong length (buffer)');
+  t.equal(ber[0], 0x30, 'wrong tag');
+  t.equal(ber[1], 33, 'wrong length');
+  t.equal(ber[2], 0x02, 'wrong tag');
+  t.equal(ber[3], 1, 'wrong length');
+  t.equal(ber[4], 0x03, 'wrong value');
+  t.equal(ber[5], 0x60, 'wrong tag');
+  t.equal(ber[6], 28, 'wrong length');
+  t.equal(ber[7], 0x02, 'wrong tag');
+  t.equal(ber[8], 1, 'wrong length');
+  t.equal(ber[9], 0x03, 'wrong value');
+  t.equal(ber[10], 0x04, 'wrong tag');
+  t.equal(ber[11], dn.length, 'wrong length');
+  t.equal(ber.slice(12, 33).toString('utf8'), dn, 'wrong value');
+  t.equal(ber[33], 0x80, 'wrong tag');
+  t.equal(ber[34], 0x00, 'wrong len');
+
+  t.end();
+});
+
+
+test('Write OID', function(t) {
+  var oid = '1.2.840.113549.1.1.1';
+  var writer = new BerWriter();
+  writer.writeOID(oid);
+
+  var ber = writer.buffer;
+  t.ok(ber);
+  console.log(require('util').inspect(ber));
+  console.log(require('util').inspect(new Buffer([0x06, 0x09, 0x2a, 0x86,
+                                                  0x48, 0x86, 0xf7, 0x0d,
+                                                  0x01, 0x01, 0x01])));
+
+  t.end();
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/README.md	(revision 517)
@@ -0,0 +1,126 @@
+# node-assert-plus
+
+This library is a super small wrapper over node's assert module that has two
+things: (1) the ability to disable assertions with the environment variable
+NODE_NDEBUG, and (2) some API wrappers for argument testing.  Like
+`assert.string(myArg, 'myArg')`.  As a simple example, most of my code looks
+like this:
+
+    var assert = require('assert-plus');
+
+    function fooAccount(options, callback) {
+	    assert.object(options, 'options');
+		assert.number(options.id, 'options.id);
+		assert.bool(options.isManager, 'options.isManager');
+		assert.string(options.name, 'options.name');
+		assert.arrayOfString(options.email, 'options.email');
+		assert.func(callback, 'callback');
+
+        // Do stuff
+		callback(null, {});
+    }
+
+# API
+
+All methods that *aren't* part of node's core assert API are simply assumed to
+take an argument, and then a string 'name' that's not a message; `AssertionError`
+will be thrown if the assertion fails with a message like:
+
+    AssertionError: foo (string) is required
+	at test (/home/mark/work/foo/foo.js:3:9)
+	at Object.<anonymous> (/home/mark/work/foo/foo.js:15:1)
+	at Module._compile (module.js:446:26)
+	at Object..js (module.js:464:10)
+	at Module.load (module.js:353:31)
+	at Function._load (module.js:311:12)
+	at Array.0 (module.js:484:10)
+	at EventEmitter._tickCallback (node.js:190:38)
+
+from:
+
+    function test(foo) {
+	    assert.string(foo, 'foo');
+    }
+
+There you go.  You can check that arrays are of a homogenous type with `Arrayof$Type`:
+
+    function test(foo) {
+	    assert.arrayOfString(foo, 'foo');
+    }
+
+You can assert IFF an argument is not `undefined` (i.e., an optional arg):
+
+    assert.optionalString(foo, 'foo');
+
+Lastly, you can opt-out of assertion checking altogether by setting the
+environment variable `NODE_NDEBUG=1`.  This is pseudo-useful if you have
+lots of assertions, and don't want to pay `typeof ()` taxes to v8 in
+production.
+
+The complete list of APIs is:
+
+* assert.bool
+* assert.buffer
+* assert.func
+* assert.number
+* assert.object
+* assert.string
+* assert.arrayOfBool
+* assert.arrayOfFunc
+* assert.arrayOfNumber
+* assert.arrayOfObject
+* assert.arrayOfString
+* assert.optionalBool
+* assert.optionalBuffer
+* assert.optionalFunc
+* assert.optionalNumber
+* assert.optionalObject
+* assert.optionalString
+* assert.optionalArrayOfBool
+* assert.optionalArrayOfFunc
+* assert.optionalArrayOfNumber
+* assert.optionalArrayOfObject
+* assert.optionalArrayOfString
+* assert.AssertionError
+* assert.fail
+* assert.ok
+* assert.equal
+* assert.notEqual
+* assert.deepEqual
+* assert.notDeepEqual
+* assert.strictEqual
+* assert.notStrictEqual
+* assert.throws
+* assert.doesNotThrow
+* assert.ifError
+
+# Installation
+
+    npm install assert-plus
+
+## License
+
+The MIT License (MIT)
+Copyright (c) 2012 Mark Cavage
+
+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.
+
+## Bugs
+
+See <https://github.com/mcavage/node-assert-plus/issues>.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js	(revision 517)
@@ -0,0 +1,196 @@
+// Copyright (c) 2012, Mark Cavage. All rights reserved.
+
+var assert = require('assert');
+var Stream = require('stream').Stream;
+var util = require('util');
+
+
+
+///--- Globals
+
+var NDEBUG = process.env.NODE_NDEBUG || false;
+
+
+
+///--- Messages
+
+var ARRAY_TYPE_REQUIRED = '%s ([%s]) required';
+var TYPE_REQUIRED = '%s (%s) is required';
+
+
+
+///--- Internal
+
+function capitalize(str) {
+        return (str.charAt(0).toUpperCase() + str.slice(1));
+}
+
+function uncapitalize(str) {
+        return (str.charAt(0).toLowerCase() + str.slice(1));
+}
+
+function _() {
+        return (util.format.apply(util, arguments));
+}
+
+
+function _assert(arg, type, name, stackFunc) {
+        if (!NDEBUG) {
+                name = name || type;
+                stackFunc = stackFunc || _assert.caller;
+                var t = typeof (arg);
+
+                if (t !== type) {
+                        throw new assert.AssertionError({
+                                message: _(TYPE_REQUIRED, name, type),
+                                actual: t,
+                                expected: type,
+                                operator: '===',
+                                stackStartFunction: stackFunc
+                        });
+                }
+        }
+}
+
+
+
+///--- API
+
+function array(arr, type, name) {
+        if (!NDEBUG) {
+                name = name || type;
+
+                if (!Array.isArray(arr)) {
+                        throw new assert.AssertionError({
+                                message: _(ARRAY_TYPE_REQUIRED, name, type),
+                                actual: typeof (arr),
+                                expected: 'array',
+                                operator: 'Array.isArray',
+                                stackStartFunction: array.caller
+                        });
+                }
+
+                for (var i = 0; i < arr.length; i++) {
+                        _assert(arr[i], type, name, array);
+                }
+        }
+}
+
+
+function bool(arg, name) {
+        _assert(arg, 'boolean', name, bool);
+}
+
+
+function buffer(arg, name) {
+        if (!Buffer.isBuffer(arg)) {
+                throw new assert.AssertionError({
+                        message: _(TYPE_REQUIRED, name, type),
+                        actual: typeof (arg),
+                        expected: 'buffer',
+                        operator: 'Buffer.isBuffer',
+                        stackStartFunction: buffer
+                });
+        }
+}
+
+
+function func(arg, name) {
+        _assert(arg, 'function', name);
+}
+
+
+function number(arg, name) {
+        _assert(arg, 'number', name);
+}
+
+
+function object(arg, name) {
+        _assert(arg, 'object', name);
+}
+
+
+function stream(arg, name) {
+        if (!(arg instanceof Stream)) {
+                throw new assert.AssertionError({
+                        message: _(TYPE_REQUIRED, name, type),
+                        actual: typeof (arg),
+                        expected: 'Stream',
+                        operator: 'instanceof',
+                        stackStartFunction: buffer
+                });
+        }
+}
+
+
+function string(arg, name) {
+        _assert(arg, 'string', name);
+}
+
+
+
+///--- Exports
+
+module.exports = {
+        bool: bool,
+        buffer: buffer,
+        func: func,
+        number: number,
+        object: object,
+        stream: stream,
+        string: string
+};
+
+
+Object.keys(module.exports).forEach(function (k) {
+        if (k === 'buffer')
+                return;
+
+        var name = 'arrayOf' + capitalize(k);
+
+        if (k === 'bool')
+                k = 'boolean';
+        if (k === 'func')
+                k = 'function';
+        module.exports[name] = function (arg, name) {
+                array(arg, k, name);
+        };
+});
+
+Object.keys(module.exports).forEach(function (k) {
+        var _name = 'optional' + capitalize(k);
+        var s = uncapitalize(k.replace('arrayOf', ''));
+        if (s === 'bool')
+                s = 'boolean';
+        if (s === 'func')
+                s = 'function';
+
+        if (k.indexOf('arrayOf') !== -1) {
+          module.exports[_name] = function (arg, name) {
+                  if (!NDEBUG && arg !== undefined) {
+                          array(arg, s, name);
+                  }
+          };
+        } else {
+          module.exports[_name] = function (arg, name) {
+                  if (!NDEBUG && arg !== undefined) {
+                          _assert(arg, s, name);
+                  }
+          };
+        }
+});
+
+
+// Reexport built-in assertions
+Object.keys(assert).forEach(function (k) {
+        if (k === 'AssertionError') {
+                module.exports[k] = assert[k];
+                return;
+        }
+
+        module.exports[k] = function () {
+                if (!NDEBUG) {
+                        assert[k].apply(assert[k], arguments);
+                }
+        };
+});
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/assert-plus/package.json	(revision 517)
@@ -0,0 +1,20 @@
+{
+  "author": {
+    "name": "Mark Cavage",
+    "email": "mcavage@gmail.com"
+  },
+  "name": "assert-plus",
+  "description": "Extra assertions on top of node's assert module",
+  "version": "0.1.2",
+  "main": "./assert.js",
+  "dependencies": {},
+  "devDependencies": {},
+  "optionalDependencies": {},
+  "engines": {
+    "node": ">=0.6"
+  },
+  "readme": "# node-assert-plus\n\nThis library is a super small wrapper over node's assert module that has two\nthings: (1) the ability to disable assertions with the environment variable\nNODE_NDEBUG, and (2) some API wrappers for argument testing.  Like\n`assert.string(myArg, 'myArg')`.  As a simple example, most of my code looks\nlike this:\n\n    var assert = require('assert-plus');\n\n    function fooAccount(options, callback) {\n\t    assert.object(options, 'options');\n\t\tassert.number(options.id, 'options.id);\n\t\tassert.bool(options.isManager, 'options.isManager');\n\t\tassert.string(options.name, 'options.name');\n\t\tassert.arrayOfString(options.email, 'options.email');\n\t\tassert.func(callback, 'callback');\n\n        // Do stuff\n\t\tcallback(null, {});\n    }\n\n# API\n\nAll methods that *aren't* part of node's core assert API are simply assumed to\ntake an argument, and then a string 'name' that's not a message; `AssertionError`\nwill be thrown if the assertion fails with a message like:\n\n    AssertionError: foo (string) is required\n\tat test (/home/mark/work/foo/foo.js:3:9)\n\tat Object.<anonymous> (/home/mark/work/foo/foo.js:15:1)\n\tat Module._compile (module.js:446:26)\n\tat Object..js (module.js:464:10)\n\tat Module.load (module.js:353:31)\n\tat Function._load (module.js:311:12)\n\tat Array.0 (module.js:484:10)\n\tat EventEmitter._tickCallback (node.js:190:38)\n\nfrom:\n\n    function test(foo) {\n\t    assert.string(foo, 'foo');\n    }\n\nThere you go.  You can check that arrays are of a homogenous type with `Arrayof$Type`:\n\n    function test(foo) {\n\t    assert.arrayOfString(foo, 'foo');\n    }\n\nYou can assert IFF an argument is not `undefined` (i.e., an optional arg):\n\n    assert.optionalString(foo, 'foo');\n\nLastly, you can opt-out of assertion checking altogether by setting the\nenvironment variable `NODE_NDEBUG=1`.  This is pseudo-useful if you have\nlots of assertions, and don't want to pay `typeof ()` taxes to v8 in\nproduction.\n\nThe complete list of APIs is:\n\n* assert.bool\n* assert.buffer\n* assert.func\n* assert.number\n* assert.object\n* assert.string\n* assert.arrayOfBool\n* assert.arrayOfFunc\n* assert.arrayOfNumber\n* assert.arrayOfObject\n* assert.arrayOfString\n* assert.optionalBool\n* assert.optionalBuffer\n* assert.optionalFunc\n* assert.optionalNumber\n* assert.optionalObject\n* assert.optionalString\n* assert.optionalArrayOfBool\n* assert.optionalArrayOfFunc\n* assert.optionalArrayOfNumber\n* assert.optionalArrayOfObject\n* assert.optionalArrayOfString\n* assert.AssertionError\n* assert.fail\n* assert.ok\n* assert.equal\n* assert.notEqual\n* assert.deepEqual\n* assert.notDeepEqual\n* assert.strictEqual\n* assert.notStrictEqual\n* assert.throws\n* assert.doesNotThrow\n* assert.ifError\n\n# Installation\n\n    npm install assert-plus\n\n## License\n\nThe MIT License (MIT)\nCopyright (c) 2012 Mark Cavage\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n## Bugs\n\nSee <https://github.com/mcavage/node-assert-plus/issues>.\n",
+  "readmeFilename": "README.md",
+  "_id": "assert-plus@0.1.2",
+  "_from": "assert-plus@0.1.2"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/CHANGELOG
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/CHANGELOG	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/CHANGELOG	(revision 517)
@@ -0,0 +1,71 @@
+This contains tickets fixed in each version release in reverse chronological
+order. There is one ticket per line. Each commits message has the tickets fixed
+in it. The commit message also has the corresponding github issue. i.e. CTYPE-42
+would be issue 42. Each issue can be found at:
+https://github.com/rmustacc/node-ctype/issues/%d.
+
+CTYPE v0.5.2
+CTYPE-46 Release 0.5.2
+CTYPE-45 error in setEndian logic
+
+v0.5.1
+CTYPE-44 Release 0.5.1
+Contributed by Terin Stock:
+CTYPE-41 CTypeParser.writeStruct should return its offset
+Contributed by Terin Stock:
+CTYPE-42 int64_t returns wrong size
+
+v0.5.0
+CTYPE-40 Release 0.5.0
+CTYPE-39 want > 0.6 engine support
+
+v0.4.0
+CTYPE-37 Release v0.4.0
+CTYPE-6 want additional entry point for write
+CTYPE-20 Add 64-bit int support into core parser
+CTYPE-31 Fix bounds errors node/2129
+CTYPE-33 Update copyright holders
+CTYPE-34 ctf.js confuses sign bit.
+CTYPE-35 Make the README more useful for getting started
+CTYPE-36 want manual page on ctio functions
+
+v0.3.1
+CTYPE-29 Release 0.3.1
+CTYPE-28 Want v0.6 npm support
+
+v0.3.0
+CTYPE-27 Release v0.3.0
+CTYPE-26 Want alternate default char behavior
+
+v0.2.1
+CTYPE-25 Release v0.2.1
+CTYPE-24 Writing structs is busted
+
+v0.2.0:
+CTYPE-23 Release v0.2.0
+CTYPE-21 Add support for CTF JSON data
+CTYPE-22 Add Javascriptlint profile
+CTYPE-15 Pull in ctio updates from node/master
+
+v0.1.0:
+CTYPE-18 Bump version to v0.1.0
+CTYPE-17 Fix nested structures
+CTYPE-16 Remove extraneous logging
+CTYPE-14 toAbs64 and toApprox64 are not exported
+
+v0.0.3:
+CTYPE-12 Bump version to v0.0.3
+CTYPE-11 fix typo in wuint64
+CTYPE-10 Integrate jsstyle
+
+v0.0.2:
+CTYPE-8 dump npm version to v0.0.2
+CTYPE-9 want changelog
+CTYPE-7 fix typo in detypes.
+
+v0.0.1:
+CTYPE-5 Missing from NPM registry
+CTYPE-4 int16_t calls wrong read function
+CTYPE-3 API example types are missing quotes as strings
+CTYPE-2 doc missing 64-bit functions
+CTYPE-1 Need license
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/LICENSE	(revision 517)
@@ -0,0 +1,24 @@
+The following license applies to all files unless the file is specified below.
+Each file specified below has its license information embedded in it:
+
+tools/jsstyle
+
+Copyright 2011, Robert Mustacchi. All rights reserved.
+Copyright 2011, Joyent, Inc. All rights reserved.
+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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/README
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/README	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/README	(revision 517)
@@ -0,0 +1,82 @@
+Node-CType is a way to read and write binary data in structured and easy to use
+format. Its name comes from the C header file.
+
+To get started, simply clone the repository or use npm to install it. Once it is
+there, simply require it.
+
+git clone git://github.com/rmustacc/node-ctype
+npm install ctype
+var mod_ctype = require('ctype')
+
+
+There are two APIs that you can use, depending on what abstraction you'd like.
+The low level API let's you read and write individual integers and floats from
+buffers. The higher level API let's you read and write structures of these. To
+illustrate this, let's looks look at how we would read and write a binary
+encoded x,y point.
+
+In C we would define this structure as follows:
+
+typedef struct point {
+	uint16_t	p_x;
+	uint16_t	p_y;
+} point_t;
+
+To read a binary encoded point from a Buffer, we first need to create a CType
+parser (where we specify the endian and other options) and add the typedef.
+
+var parser = new mod_ctype.Parser({ endian: 'big' });
+parser.typedef('point_t', [
+	{ x: { type: 'uint16_t' } },
+	{ y: { type: 'uint16_t' } }
+]);
+
+From here, given a buffer buf and an offset into it, we can read a point.
+
+var out = parser.readData([ { point: { type: 'point_t' } } ], buffer, 0);
+console.log(out);
+{ point: { x: 23, y: 42 } }
+
+Another way to get the same information would be to use the low level methods.
+Note that these require you to manually deal with the offset. Here's how we'd
+get the same values of x and y from the buffer.
+
+var x = mod_ctype.ruint16(buf, 'big', 0);
+var y = mod_ctype.ruint16(buf, 'big', 2);
+console.log(x + ', ' + y);
+23, 42
+
+The true power of this API comes from the ability to define and nest typedefs,
+just as you would in C. By default, the following types are defined by default.
+Note that they return a Number, unless indicated otherwise.
+
+    * int8_t
+    * int16_t
+    * int32_t
+    * int64_t (returns an array where val[0] << 32 + val[1] would be the value)
+    * uint8_t
+    * uint16_t
+    * uint32_t
+    * uint64_t (returns an array where val[0] << 32 + val[1] would be the value)
+    * float
+    * double
+    * char (either returns a buffer with that character or a uint8_t)
+    * char[] (returns an object with the buffer and the number of characters read which is either the total amount requested or until the first 0)
+
+
+ctf2json integration:
+
+Node-CType supports consuming the output of ctf2json. Once you read in a JSON file,
+all you have to do to add all the definitions it contains is:
+
+var data, parser;
+data = JSON.parse(parsedJSONData);
+parser = mod_ctype.parseCTF(data, { endian: 'big' });
+
+For more documentation, see the file README.old. Full documentation is in the
+process of being rewritten as a series of manual pages which will be available
+in the repository and online for viewing.
+
+To read the ctio manual page simple run, from the root of the workspace:
+
+man -Mman -s 3ctype ctio
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/README.old
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/README.old	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/README.old	(revision 517)
@@ -0,0 +1,298 @@
+This library provides a way to read and write binary data.
+
+Node CType is a way to read and write binary data in structured and easy to use
+formats. It's name comes from the header file, though it does not share as much
+with it as it perhaps should.
+
+There are two levels of the API. One is the raw API which everything is built on
+top of, while the other provides a much nicer abstraction and is built entirely
+by using the lower level API. The hope is that the low level API is both clear
+and useful. The low level API gets it's names from stdint.h (a rather
+appropriate source). The lower level API is presented at the end of this
+document.
+
+Standard CType API
+
+The CType interface is presented as a parser object that controls the
+endianness combined with a series of methods to change that value, parse and
+write out buffers, and a way to provide typedefs.  Standard Types
+
+The CType parser supports the following basic types which return Numbers except
+as indicated:
+
+    * int8_t
+    * int16_t
+    * int32_t
+    * int64_t (returns an array where val[0] << 32 + val[1] would be the value)
+    * uint8_t
+    * uint16_t
+    * uint32_t
+    * uint64_t (returns an array where val[0] << 32 + val[1] would be the value)
+    * float
+    * double
+    * char (returns a buffer with just that single character)
+    * char[] (returns an object with the buffer and the number of characters read which is either the total amount requested or until the first 0)
+
+Specifying Structs
+
+The CType parser also supports the notion of structs. A struct is an array of
+JSON objects that defines an order of keys which have types and values. One
+would build a struct to represent a point (x,y) as follows:
+
+[
+    { x: { type: 'int16_t' }},
+    { y: { type: 'int16_t' }}
+]
+
+When this is passed into the read routine, it would read the first two bytes
+(as defined by int16_t) to determine the Number to use for X, and then it would
+read the next two bytes to determine the value of Y. When read this could
+return something like:
+
+{
+    x: 42,
+    y: -23
+}
+
+When someone wants to write values, we use the same format as above, but with
+additional value field:
+
+[
+    { x: { type: 'int16_t', value: 42 }},
+    { y: { type: 'int16_t', value: -23 }}
+]
+
+Now, the structure above may be optionally annotated with offsets. This tells
+us to rather than read continuously we should read the given value at the
+specified offset. If an offset is provided, it is is effectively the equivalent
+of lseek(offset, SEEK_SET). Thus, subsequent values will be read from that
+offset and incremented by the appropriate value. As an example:
+
+[
+    { x: { type: 'int16_t' }},
+    { y: { type: 'int16_t', offset: 20 }},
+    { z: { type: 'int16_t' }}
+]
+
+We would read x from the first starting offset given to us, for the sake of
+example, let's assume that's 0. After reading x, the next offset to read from
+would be 2; however, y specifies an offset, thus we jump directly to that
+offset and read y from byte 20. We would then read z from byte 22.
+
+The same offsets may be used when writing values.
+
+Typedef
+
+The basic set of types while covers the basics, is somewhat limiting. To make
+this richer, there is functionality to typedef something like in C. One can use
+typedef to add a new name to an existing type or to define a name to refer to a
+struct. Thus the following are all examples of a typedef:
+
+typedef('size_t', 'uint32_t');
+typedef('ssize_t', 'int32_t');
+typedef('point_t', [
+    { x: { type: 'int16_t' }},
+    { y: { type: 'int16_t' }}
+]);
+
+Once something has been typedef'd it can be used in any of the definitions
+previously shown.
+
+One cannot remove a typedef once created, this is analogous to C.
+
+The set of defined types can be printed with lstypes. The format of this output
+is subject to change, but likely will look something like:
+
+> lstypes();
+{
+    size_t: 'uint32_t',
+    ssize_t: 'int32_t',
+    point_t: [
+        { x: { type: 'int16_t' }},
+        { y: { type: 'int16_t' }}
+    ]
+}
+
+Specifying arrays
+
+Arrays can be specified by appending []s to a type. Arrays must have the size
+specified. The size must be specified and it can be done in one of two ways:
+
+    * An explicit non-zero integer size
+    * A name of a previously declared variable in the struct whose value is a
+      number.
+
+Note, that when using the name of a variable, it should be the string name for
+the key. This is only valid inside structs and the value must be declared
+before the value with the array. The following are examples:
+
+[
+    { ip_addr4: { type: 'uint8_t[4]' }},
+    { len: { type: 'uint32_t' }},
+    { data: { type: 'uint8_t[len]' }}
+]
+
+Arrays are permitted in typedefs; however, they must have a declared integer
+size. The following are examples of valid and invalid arrays:
+
+typedef('path', 'char[1024]'); /* Good */
+typedef('path', 'char[len]');  /* Bad! */
+
+64 bit values:
+
+Unfortunately Javascript represents values with a double, so you lose precision
+and the ability to represent Integers roughly beyond 2^53. To alleviate this, I
+propose the following for returning 64 bit integers when read:
+
+value[2]: Each entry is a 32 bit number which can be reconstructed to the
+original by the following formula:
+
+value[0] << 32 + value[1] (Note this will not work in Javascript)
+
+CTF JSON data:
+
+node-ctype can also handle JSON data that mathces the format described in the
+documentation of the tool ctf2json. Given the JSON data which specifies type
+information, it will transform that into a parser that understands all of the
+types defined inside of it. This is useful for more complicated structures that
+have a lot of typedefs.
+
+Interface overview
+
+The following is the header-file like interface to the parser object:
+
+/*
+ * Create a new instance of the parser. Each parser has its own store of
+ * typedefs and endianness. Conf is an object with the following values:
+ *
+ *      endian          Either 'big' or 'little' do determine the endianness we
+ *                      want to read from or write to.
+ *
+ */
+function CTypeParser(conf);
+
+/*
+ * Parses the CTF JSON data and creates a parser that understands all of those
+ * types.
+ *
+ *	data		Parsed JSON data that maches that CTF JSON
+ *			specification.
+ *
+ *	conf		The configuration object to create a new CTypeParser
+ *			from.
+ */
+CTypeParser parseCTF(data, conf);
+
+/*
+ * This is what we were born to do. We read the data from a buffer and return it
+ * in an object whose keys match the values from the object.
+ *
+ *      def             The array definition of the data to read in
+ *
+ *      buffer          The buffer to read data from
+ *
+ *      offset          The offset to start writing to
+ *
+ * Returns an object where each key corresponds to an entry in def and the value
+ * is the read value.
+ */
+Object CTypeParser.readData(<Type Definition>, buffer, offset);
+
+/*
+ * This is the second half of what we were born to do, write out the data
+ * itself.
+ *
+ *      def             The array definition of the data to write out with
+ *                      values
+ *
+ *      buffer          The buffer to write to
+ *
+ *      offset          The offset in the buffer to write to
+ */
+void CTypeParser.writeData(<Type Definition>, buffer, offset);
+
+/*
+ * A user has requested to add a type, let us honor their request. Yet, if their
+ * request doth spurn us, send them unto the Hells which Dante describes.
+ *
+ *      name            The string for the type definition we're adding
+ *
+ *      value           Either a string that is a type/array name or an object
+ *                      that describes a struct.
+ */
+void CTypeParser.prototype.typedef(name, value);
+
+Object CTypeParser.prototype.lstypes();
+
+/*
+ * Get the endian value for the current parser
+ */
+String CTypeParser.prototype.getEndian();
+
+/*
+ * Sets the current endian value for the Parser. If the value is not valid,
+ * throws an Error.
+ *
+ *      endian          Either 'big' or 'little' do determine the endianness we
+ *                      want to read from or write to.
+ *
+ */
+void CTypeParser.protoype.setEndian(String);
+
+/*
+ * Attempts to convert an array of two integers returned from rsint64 / ruint64
+ * into an absolute 64 bit number. If however the value would exceed 2^52 this
+ * will instead throw an error. The mantissa in a double is a 52 bit number and
+ * rather than potentially give you a value that is an approximation this will
+ * error. If you would rather an approximation, please see toApprox64.
+ *
+ *	val		An array of two 32-bit integers
+ */
+Number function toAbs64(val)
+
+/*
+ * Will return the 64 bit value as returned in an array from rsint64 / ruint64
+ * to a value as close as it can. Note that Javascript stores all numbers as a
+ * double and the mantissa only has 52 bits. Thus this version may approximate
+ * the value.
+ *
+ *	val		An array of two 32-bit integers
+ */
+Number function toApprox64(val)
+
+Low Level API
+
+The following function are provided at the low level:
+
+Read unsigned integers from a buffer:
+Number ruint8(buffer, endian, offset);
+Number ruint16(buffer, endian, offset);
+Number ruint32(buffer, endian, offset);
+Number[] ruint64(buffer, endian, offset);
+
+Read signed integers from a buffer:
+Number rsint8(buffer, endian, offset);
+Number rsint16(buffer, endian, offset);
+Number rsint32(buffer, endian, offset);
+Number[] rsint64(buffer, endian, offset);
+
+Read floating point numbers from a buffer:
+Number rfloat(buffer, endian, offset);   /* IEEE-754 Single precision */
+Number rdouble(buffer, endian, offset);  /* IEEE-754 Double precision */
+
+Write unsigned integers to a buffer:
+void wuint8(Number, endian, buffer, offset);
+void wuint16(Number, endian, buffer, offset);
+void wuint32(Number, endian, buffer, offset);
+void wuint64(Number[], endian, buffer, offset);
+
+Write signed integers from a buffer:
+void wsint8(Number, endian, buffer, offset);
+void wsint16(Number, endian, buffer, offset);
+void wsint32(Number, endian, buffer, offset);
+void wsint64(Number[], endian, buffer offset);
+
+Write floating point numbers from a buffer:
+void wfloat(Number, buffer, endian, offset);   /* IEEE-754 Single precision */
+void wdouble(Number, buffer, endian, offset);  /* IEEE-754 Double precision */
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctf.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctf.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctf.js	(revision 517)
@@ -0,0 +1,245 @@
+/*
+ * ctf.js
+ *
+ * Understand and parse all of the different JSON formats of CTF data and
+ * translate that into a series of node-ctype friendly pieces. The reason for
+ * the abstraction is to handle different changes in the file format.
+ *
+ * We have to be careful here that we don't end up using a name that is already
+ * a built in type.
+ */
+var mod_assert = require('assert');
+var ASSERT = mod_assert.ok;
+
+var ctf_versions = [ '1.0' ];
+var ctf_entries = [ 'integer', 'float', 'typedef', 'struct' ];
+var ctf_deftypes = [ 'int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t',
+    'uint32_t', 'float', 'double' ];
+
+function ctfParseInteger(entry, ctype)
+{
+	var name, sign, len, type;
+
+	name = entry['name'];
+	if (!('signed' in entry['integer']))
+		throw (new Error('Malformed CTF JSON: integer missing ' +
+		    'signed value'));
+
+
+	if (!('length' in entry['integer']))
+		throw (new Error('Malformed CTF JSON: integer missing ' +
+		    'length value'));
+
+	sign = entry['integer']['signed'];
+	len = entry['integer']['length'];
+	type = null;
+
+	if (sign && len == 1)
+		type = 'int8_t';
+	else if (len == 1)
+		type = 'uint8_t';
+	else if (sign && len == 2)
+		type = 'int16_t';
+	else if (len == 2)
+		type = 'uint16_t';
+	else if (sign && len == 4)
+		type = 'int32_t';
+	else if (len == 4)
+		type = 'uint32_t';
+	else if (sign && len == 8)
+		type = 'int64_t';
+	else if (len == 8)
+		type = 'uint64_t';
+
+	if (type === null)
+		throw (new Error('Malformed CTF JSON: integer has ' +
+		    'unsupported length and sign - ' + len + '/' + sign));
+
+	/*
+	 * This means that this is the same as one of our built in types. If
+	 * that's the case defining it would be an error. So instead of trying
+	 * to typedef it, we'll return here.
+	 */
+	if (name == type)
+		return;
+
+	if (name == 'char') {
+		ASSERT(type == 'int8_t');
+		return;
+	}
+
+	ctype.typedef(name, type);
+}
+
+function ctfParseFloat(entry, ctype)
+{
+	var name, len;
+
+	name = entry['name'];
+	if (!('length' in entry['float']))
+		throw (new Error('Malformed CTF JSON: float missing ' +
+		    'length value'));
+
+	len = entry['float']['length'];
+	if (len != 4 && len != 8)
+		throw (new Error('Malformed CTF JSON: float has invalid ' +
+		    'length value'));
+
+	if (len == 4) {
+		if (name == 'float')
+			return;
+		ctype.typedef(name, 'float');
+	} else if (len == 8) {
+		if (name == 'double')
+			return;
+		ctype.typedef(name, 'double');
+	}
+}
+
+function ctfParseTypedef(entry, ctype)
+{
+	var name, type, ii;
+
+	name = entry['name'];
+	if (typeof (entry['typedef']) != 'string')
+		throw (new Error('Malformed CTF JSON: typedef value in not ' +
+		    'a string'));
+
+	type = entry['typedef'];
+
+	/*
+	 * We need to ensure that we're not looking at type that's one of our
+	 * built in types. Traditionally in C a uint32_t would be a typedef to
+	 * some kind of integer. However, those size types are built ins.
+	 */
+	for (ii = 0; ii < ctf_deftypes.length; ii++) {
+		if (name == ctf_deftypes[ii])
+			return;
+	}
+
+	ctype.typedef(name, type);
+}
+
+function ctfParseStruct(entry, ctype)
+{
+	var name, type, ii, val, index, member, push;
+
+	member = [];
+	if (!Array.isArray(entry['struct']))
+		throw (new Error('Malformed CTF JSON: struct value is not ' +
+		    'an array'));
+
+	for (ii = 0; ii < entry['struct'].length; ii++) {
+		val = entry['struct'][ii];
+		if (!('name' in val))
+			throw (new Error('Malformed CTF JSON: struct member ' +
+			    'missing name'));
+
+		if (!('type' in val))
+			throw (new Error('Malformed CTF JSON: struct member ' +
+			    'missing type'));
+
+		if (typeof (val['name']) != 'string')
+			throw (new Error('Malformed CTF JSON: struct member ' +
+			    'name isn\'t a string'));
+
+		if (typeof (val['type']) != 'string')
+			throw (new Error('Malformed CTF JSON: struct member ' +
+			    'type isn\'t a string'));
+
+		/*
+		 * CTF version 2 specifies array names as <type> [<num>] where
+		 * as node-ctype does this as <type>[<num>].
+		 */
+		name = val['name'];
+		type = val['type'];
+		index = type.indexOf(' [');
+		if (index != -1) {
+			type = type.substring(0, index) +
+			    type.substring(index + 1, type.length);
+		}
+		push = {};
+		push[name] = { 'type': type };
+		member.push(push);
+	}
+
+	name = entry['name'];
+	ctype.typedef(name, member);
+}
+
+function ctfParseEntry(entry, ctype)
+{
+	var ii, found;
+
+	if (!('name' in entry))
+		throw (new Error('Malformed CTF JSON: entry missing "name" ' +
+		    'section'));
+
+	for (ii = 0; ii < ctf_entries.length; ii++) {
+		if (ctf_entries[ii] in entry)
+			found++;
+	}
+
+	if (found === 0)
+		throw (new Error('Malformed CTF JSON: found no entries'));
+
+	if (found >= 2)
+		throw (new Error('Malformed CTF JSON: found more than one ' +
+		    'entry'));
+
+	if ('integer' in entry) {
+		ctfParseInteger(entry, ctype);
+		return;
+	}
+
+	if ('float' in entry) {
+		ctfParseFloat(entry, ctype);
+		return;
+	}
+
+	if ('typedef' in entry) {
+		ctfParseTypedef(entry, ctype);
+		return;
+	}
+
+	if ('struct' in entry) {
+		ctfParseStruct(entry, ctype);
+		return;
+	}
+
+	ASSERT(false, 'shouldn\'t reach here');
+}
+
+function ctfParseJson(json, ctype)
+{
+	var version, ii;
+
+	ASSERT(json);
+	ASSERT(ctype);
+	if (!('metadata' in json))
+		throw (new Error('Invalid CTF JSON: missing metadata section'));
+
+	if (!('ctf2json_version' in json['metadata']))
+		throw (new Error('Invalid CTF JSON: missing ctf2json_version'));
+
+	version = json['metadata']['ctf2json_version'];
+	for (ii = 0; ii < ctf_versions.length; ii++) {
+		if (ctf_versions[ii] == version)
+			break;
+	}
+
+	if (ii == ctf_versions.length)
+		throw (new Error('Unsuported ctf2json_version: ' + version));
+
+	if (!('data' in json))
+		throw (new Error('Invalid CTF JSON: missing data section'));
+
+	if (!Array.isArray(json['data']))
+		throw (new Error('Malformed CTF JSON: data section is not ' +
+		    'an array'));
+
+	for (ii = 0; ii < json['data'].length; ii++)
+		ctfParseEntry(json['data'][ii], ctype);
+}
+
+exports.ctfParseJson = ctfParseJson;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctio.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctio.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctio.js	(revision 517)
@@ -0,0 +1,1485 @@
+/*
+ * rm - Feb 2011
+ * ctio.js:
+ *
+ * A simple way to read and write simple ctypes. Of course, as you'll find the
+ * code isn't as simple as it might appear. The following types are currently
+ * supported in big and little endian formats:
+ *
+ * 	uint8_t			int8_t
+ * 	uint16_t		int16_t
+ * 	uint32_t		int32_t
+ *	float (single precision IEEE 754)
+ *	double (double precision IEEE 754)
+ *
+ * This is designed to work in Node and v8. It may in fact work in other
+ * Javascript interpreters (that'd be pretty neat), but it hasn't been tested.
+ * If you find that it does in fact work, that's pretty cool. Try and pass word
+ * back to the original author.
+ *
+ * Note to the reader: If you're tabstop isn't set to 8, parts of this may look
+ * weird.
+ */
+
+/*
+ * Numbers in Javascript have a secret: all numbers must be represented with an
+ * IEEE-754 double. The double has a mantissa with a length of 52 bits with an
+ * implicit one. Thus the range of integers that can be represented is limited
+ * to the size of the mantissa, this makes reading and writing 64-bit integers
+ * difficult, but far from impossible.
+ *
+ * Another side effect of this representation is what happens when you use the
+ * bitwise operators, i.e. shift left, shift right, and, or, etc. In Javascript,
+ * each operand and the result is cast to a signed 32-bit number. However, in
+ * the case of >>> the values are cast to an unsigned number.
+ */
+
+/*
+ * A reminder on endian related issues:
+ *
+ * Big Endian: MSB -> First byte
+ * Little Endian: MSB->Last byte
+ */
+var mod_assert = require('assert');
+
+/*
+ * An 8 bit unsigned integer involves doing no significant work.
+ */
+function ruint8(buffer, endian, offset)
+{
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	return (buffer[offset]);
+}
+
+/*
+ * For 16 bit unsigned numbers we can do all the casting that we want to do.
+ */
+function rgint16(buffer, endian, offset)
+{
+	var val = 0;
+
+	if (endian == 'big') {
+		val = buffer[offset] << 8;
+		val |=  buffer[offset+1];
+	} else {
+		val = buffer[offset];
+		val |= buffer[offset+1] << 8;
+	}
+
+	return (val);
+
+}
+
+function ruint16(buffer, endian, offset)
+{
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 1 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	return (rgint16(buffer, endian, offset));
+}
+
+/*
+ * Because most bitshifting is done using signed numbers, if we would go into
+ * the realm where we use that 32nd bit, we'll end up going into the negative
+ * range. i.e.:
+ * > 200 << 24
+ * -939524096
+ *
+ * Not the value you'd expect. To work around this, we end up having to do some
+ * abuse of the JavaScript standard. in this case, we know that a >>> shift is
+ * defined to cast our value to an *unsigned* 32-bit number. Because of that, we
+ * use that instead to save us some additional math, though it does feel a
+ * little weird and it isn't obvious as to why you woul dwant to do this at
+ * first.
+ */
+function rgint32(buffer, endian, offset)
+{
+	var val = 0;
+
+	if (endian == 'big') {
+		val = buffer[offset+1] << 16;
+		val |= buffer[offset+2] << 8;
+		val |= buffer[offset+3];
+		val = val + (buffer[offset] << 24 >>> 0);
+	} else {
+		val = buffer[offset+2] << 16;
+		val |= buffer[offset+1] << 8;
+		val |= buffer[offset];
+		val = val + (buffer[offset + 3] << 24 >>> 0);
+	}
+
+	return (val);
+}
+
+function ruint32(buffer, endian, offset)
+{
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 3 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	return (rgint32(buffer, endian, offset));
+}
+
+/*
+ * Reads a 64-bit unsigned number. The astue observer will note that this
+ * doesn't quite work. Javascript has chosen to only have numbers that can be
+ * represented by a double. A double only has 52 bits of mantissa with an
+ * implicit 1, thus we have up to 53 bits to represent an integer. However, 2^53
+ * doesn't quite give us what we want. Isn't 53 bits enough for anyone? What
+ * could you have possibly wanted to represent that was larger than that? Oh,
+ * maybe a size? You mean we bypassed the 4 GB limit on file sizes, when did
+ * that happen?
+ *
+ * To get around this egregious language issue, we're going to instead construct
+ * an array of two 32 bit unsigned integers. Where arr[0] << 32 + arr[1] would
+ * give the actual number. However, note that the above code probably won't
+ * produce the desired results because of the way Javascript numbers are
+ * doubles.
+ */
+function rgint64(buffer, endian, offset)
+{
+	var val = new Array(2);
+
+	if (endian == 'big') {
+		val[0] = ruint32(buffer, endian, offset);
+		val[1] = ruint32(buffer, endian, offset+4);
+	} else {
+		val[0] = ruint32(buffer, endian, offset+4);
+		val[1] = ruint32(buffer, endian, offset);
+	}
+
+	return (val);
+}
+
+function ruint64(buffer, endian, offset)
+{
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 7 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	return (rgint64(buffer, endian, offset));
+}
+
+
+/*
+ * Signed integer types, yay team! A reminder on how two's complement actually
+ * works. The first bit is the signed bit, i.e. tells us whether or not the
+ * number should be positive or negative. If the two's complement value is
+ * positive, then we're done, as it's equivalent to the unsigned representation.
+ *
+ * Now if the number is positive, you're pretty much done, you can just leverage
+ * the unsigned translations and return those. Unfortunately, negative numbers
+ * aren't quite that straightforward.
+ *
+ * At first glance, one might be inclined to use the traditional formula to
+ * translate binary numbers between the positive and negative values in two's
+ * complement. (Though it doesn't quite work for the most negative value)
+ * Mainly:
+ *  - invert all the bits
+ *  - add one to the result
+ *
+ * Of course, this doesn't quite work in Javascript. Take for example the value
+ * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of
+ * course, Javascript will do the following:
+ *
+ * > ~0xff80
+ * -65409
+ *
+ * Whoh there, Javascript, that's not quite right. But wait, according to
+ * Javascript that's perfectly correct. When Javascript ends up seeing the
+ * constant 0xff80, it has no notion that it is actually a signed number. It
+ * assumes that we've input the unsigned value 0xff80. Thus, when it does the
+ * binary negation, it casts it into a signed value, (positive 0xff80). Then
+ * when you perform binary negation on that, it turns it into a negative number.
+ *
+ * Instead, we're going to have to use the following general formula, that works
+ * in a rather Javascript friendly way. I'm glad we don't support this kind of
+ * weird numbering scheme in the kernel.
+ *
+ * (BIT-MAX - (unsigned)val + 1) * -1
+ *
+ * The astute observer, may think that this doesn't make sense for 8-bit numbers
+ * (really it isn't necessary for them). However, when you get 16-bit numbers,
+ * you do. Let's go back to our prior example and see how this will look:
+ *
+ * (0xffff - 0xff80 + 1) * -1
+ * (0x007f + 1) * -1
+ * (0x0080) * -1
+ *
+ * Doing it this way ends up allowing us to treat it appropriately in
+ * Javascript. Sigh, that's really quite ugly for what should just be a few bit
+ * shifts, ~ and &.
+ */
+
+/*
+ * Endianness doesn't matter for 8-bit signed values. We could in fact optimize
+ * this case because the more traditional methods work, but for consistency,
+ * we'll keep doing this the same way.
+ */
+function rsint8(buffer, endian, offset)
+{
+	var neg;
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	neg = buffer[offset] & 0x80;
+	if (!neg)
+		return (buffer[offset]);
+
+	return ((0xff - buffer[offset] + 1) * -1);
+}
+
+/*
+ * The 16-bit version requires a bit more effort. In this case, we can leverage
+ * our unsigned code to generate the value we want to return.
+ */
+function rsint16(buffer, endian, offset)
+{
+	var neg, val;
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 1 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = rgint16(buffer, endian, offset);
+	neg = val & 0x8000;
+	if (!neg)
+		return (val);
+
+	return ((0xffff - val + 1) * -1);
+}
+
+/*
+ * We really shouldn't leverage our 32-bit code here and instead utilize the
+ * fact that we know that since these are signed numbers, we can do all the
+ * shifting and binary anding to generate the 32-bit number. But, for
+ * consistency we'll do the same. If we want to do otherwise, we should instead
+ * make the 32 bit unsigned code do the optimization. But as long as there
+ * aren't floats secretly under the hood for that, we /should/ be okay.
+ */
+function rsint32(buffer, endian, offset)
+{
+	var neg, val;
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 3 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = rgint32(buffer, endian, offset);
+	neg = val & 0x80000000;
+	if (!neg)
+		return (val);
+
+	return ((0xffffffff - val + 1) * -1);
+}
+
+/*
+ * The signed version of this code suffers from all of the same problems of the
+ * other 64 bit version.
+ */
+function rsint64(buffer, endian, offset)
+{
+	var neg, val;
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 3 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = rgint64(buffer, endian, offset);
+	neg = val[0] & 0x80000000;
+
+	if (!neg)
+		return (val);
+
+	val[0] = (0xffffffff - val[0]) * -1;
+	val[1] = (0xffffffff - val[1] + 1) * -1;
+
+	/*
+	 * If we had the key 0x8000000000000000, that would leave the lower 32
+	 * bits as 0xffffffff, however, since we're goint to add one, that would
+	 * actually leave the lower 32-bits as 0x100000000, which would break
+	 * our ability to write back a value that we received. To work around
+	 * this, if we actually get that value, we're going to bump the upper
+	 * portion by 1 and set this to zero.
+	 */
+	mod_assert.ok(val[1] <= 0x100000000);
+	if (val[1] == -0x100000000) {
+		val[1] = 0;
+		val[0]--;
+	}
+
+	return (val);
+}
+
+/*
+ * We now move onto IEEE 754: The traditional form for floating point numbers
+ * and what is secretly hiding at the heart of everything in this. I really hope
+ * that someone is actually using this, as otherwise, this effort is probably
+ * going to be more wasted.
+ *
+ * One might be tempted to use parseFloat here, but that wouldn't work at all
+ * for several reasons. Mostly due to the way floats actually work, and
+ * parseFloat only actually works in base 10. I don't see base 10 anywhere near
+ * this file.
+ *
+ * In this case we'll implement the single and double precision versions. The
+ * quadruple precision, while probably useful, wouldn't really be accepted by
+ * Javascript, so let's not even waste our time.
+ *
+ * So let's review how this format looks like. A single precision value is 32
+ * bits and has three parts:
+ *   -  Sign bit
+ *   -  Exponent (Using bias notation)
+ *   -  Mantissa
+ *
+ * |s|eeeeeeee|mmmmmmmmmmmmmmmmmmmmmmmmm|
+ * 31| 30-23  |  22    	-       0       |
+ *
+ * The exponent is stored in a biased input. The bias in this case 127.
+ * Therefore, our exponent is equal to the 8-bit value - 127.
+ *
+ * By default, a number is normalized in IEEE, that means that the mantissa has
+ * an implicit one that we don't see. So really the value stored is 1.m.
+ * However, if the exponent is all zeros, then instead we have to shift
+ * everything to the right one and there is no more implicit one.
+ *
+ * Special values:
+ *  - Positive Infinity:
+ *	Sign:		0
+ *	Exponent: 	All 1s
+ *	Mantissa:	0
+ *  - Negative Infinity:
+ *	Sign:		1
+ *	Exponent: 	All 1s
+ *	Mantissa:	0
+ *  - NaN:
+ *	Sign:		*
+ *	Exponent: 	All 1s
+ *	Mantissa:	non-zero
+ *  - Zero:
+ *	Sign:		*
+ *	Exponent:	All 0s
+ *	Mantissa:	0
+ *
+ * In the case of zero, the sign bit determines whether we get a positive or
+ * negative zero. However, since Javascript cannot determine the difference
+ * between the two: i.e. -0 == 0, we just always return 0.
+ *
+ */
+function rfloat(buffer, endian, offset)
+{
+	var bytes = [];
+	var sign, exponent, mantissa, val;
+	var bias = 127;
+	var maxexp = 0xff;
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 3 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	/* Normalize the bytes to be in endian order */
+	if (endian == 'big') {
+		bytes[0] = buffer[offset];
+		bytes[1] = buffer[offset+1];
+		bytes[2] = buffer[offset+2];
+		bytes[3] = buffer[offset+3];
+	} else {
+		bytes[3] = buffer[offset];
+		bytes[2] = buffer[offset+1];
+		bytes[1] = buffer[offset+2];
+		bytes[0] = buffer[offset+3];
+	}
+
+	sign = bytes[0] & 0x80;
+	exponent = (bytes[0] & 0x7f) << 1;
+	exponent |= (bytes[1] & 0x80) >>> 7;
+	mantissa = (bytes[1] & 0x7f) << 16;
+	mantissa |= bytes[2] << 8;
+	mantissa |= bytes[3];
+
+	/* Check for special cases before we do general parsing */
+	if (!sign && exponent == maxexp && mantissa === 0)
+		return (Number.POSITIVE_INFINITY);
+
+	if (sign && exponent == maxexp && mantissa === 0)
+		return (Number.NEGATIVE_INFINITY);
+
+	if (exponent == maxexp && mantissa !== 0)
+		return (Number.NaN);
+
+	/*
+	 * Javascript really doesn't have support for positive or negative zero.
+	 * So we're not going to try and give it to you. That would be just
+	 * plain weird. Besides -0 == 0.
+	 */
+	if (exponent === 0 && mantissa === 0)
+		return (0);
+
+	/*
+	 * Now we can deal with the bias and the determine whether the mantissa
+	 * has the implicit one or not.
+	 */
+	exponent -= bias;
+	if (exponent == -bias) {
+		exponent++;
+		val = 0;
+	} else {
+		val = 1;
+	}
+
+	val = (val + mantissa * Math.pow(2, -23)) * Math.pow(2, exponent);
+
+	if (sign)
+		val *= -1;
+
+	return (val);
+}
+
+/*
+ * Doubles in IEEE 754 are like their brothers except for a few changes and
+ * increases in size:
+ *   - The exponent is now 11 bits
+ *   - The mantissa is now 52 bits
+ *   - The bias is now 1023
+ *
+ * |s|eeeeeeeeeee|mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm|
+ * 63| 62 - 52   | 	51		-			0     |
+ * 63| 62 - 52   |      51              -                       0     |
+ *
+ * While the size has increased a fair amount, we're going to end up keeping the
+ * same general formula for calculating the final value. As a reminder, this
+ * formula is:
+ *
+ * (-1)^s * (n + m) * 2^(e-b)
+ *
+ * Where:
+ *	s	is the sign bit
+ *	n	is (exponent > 0) ? 1 : 0 -- Determines whether we're normalized
+ *					     or not
+ *	m	is the mantissa
+ *	e	is the exponent specified
+ *	b	is the bias for the exponent
+ *
+ */
+function rdouble(buffer, endian, offset)
+{
+	var bytes = [];
+	var sign, exponent, mantissa, val, lowmant;
+	var bias = 1023;
+	var maxexp = 0x7ff;
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 7 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	/* Normalize the bytes to be in endian order */
+	if (endian == 'big') {
+		bytes[0] = buffer[offset];
+		bytes[1] = buffer[offset+1];
+		bytes[2] = buffer[offset+2];
+		bytes[3] = buffer[offset+3];
+		bytes[4] = buffer[offset+4];
+		bytes[5] = buffer[offset+5];
+		bytes[6] = buffer[offset+6];
+		bytes[7] = buffer[offset+7];
+	} else {
+		bytes[7] = buffer[offset];
+		bytes[6] = buffer[offset+1];
+		bytes[5] = buffer[offset+2];
+		bytes[4] = buffer[offset+3];
+		bytes[3] = buffer[offset+4];
+		bytes[2] = buffer[offset+5];
+		bytes[1] = buffer[offset+6];
+		bytes[0] = buffer[offset+7];
+	}
+
+	/*
+	 * We can construct the exponent and mantissa the same way as we did in
+	 * the case of a float, just increase the range of the exponent.
+	 */
+	sign = bytes[0] & 0x80;
+	exponent = (bytes[0] & 0x7f) << 4;
+	exponent |= (bytes[1] & 0xf0) >>> 4;
+
+	/*
+	 * This is going to be ugly but then again, we're dealing with IEEE 754.
+	 * This could probably be done as a node add on in a few lines of C++,
+	 * but oh we'll, we've made it this far so let's be native the rest of
+	 * the way...
+	 *
+	 * What we're going to do is break the mantissa into two parts, the
+	 * lower 24 bits and the upper 28 bits. We'll multiply the upper 28 bits
+	 * by the appropriate power and then add in the lower 24-bits. Not
+	 * really that great. It's pretty much a giant kludge to deal with
+	 * Javascript eccentricities around numbers.
+	 */
+	lowmant = bytes[7];
+	lowmant |= bytes[6] << 8;
+	lowmant |= bytes[5] << 16;
+	mantissa = bytes[4];
+	mantissa |= bytes[3] << 8;
+	mantissa |= bytes[2] << 16;
+	mantissa |= (bytes[1] & 0x0f) << 24;
+	mantissa *= Math.pow(2, 24); /* Equivalent to << 24, but JS compat */
+	mantissa += lowmant;
+
+	/* Check for special cases before we do general parsing */
+	if (!sign && exponent == maxexp && mantissa === 0)
+		return (Number.POSITIVE_INFINITY);
+
+	if (sign && exponent == maxexp && mantissa === 0)
+		return (Number.NEGATIVE_INFINITY);
+
+	if (exponent == maxexp && mantissa !== 0)
+		return (Number.NaN);
+
+	/*
+	 * Javascript really doesn't have support for positive or negative zero.
+	 * So we're not going to try and give it to you. That would be just
+	 * plain weird. Besides -0 == 0.
+	 */
+	if (exponent === 0 && mantissa === 0)
+		return (0);
+
+	/*
+	 * Now we can deal with the bias and the determine whether the mantissa
+	 * has the implicit one or not.
+	 */
+	exponent -= bias;
+	if (exponent == -bias) {
+		exponent++;
+		val = 0;
+	} else {
+		val = 1;
+	}
+
+	val = (val + mantissa * Math.pow(2, -52)) * Math.pow(2, exponent);
+
+	if (sign)
+		val *= -1;
+
+	return (val);
+}
+
+/*
+ * Now that we have gone through the pain of reading the individual types, we're
+ * probably going to want some way to write these back. None of this is going to
+ * be good. But since we have Javascript numbers this should certainly be more
+ * interesting. Though we can constrain this end a little bit more in what is
+ * valid. For now, let's go back to our friends the unsigned value.
+ */
+
+/*
+ * Unsigned numbers seem deceptively easy. Here are the general steps and rules
+ * that we are going to take:
+ *   -  If the number is negative, throw an Error
+ *   -  Truncate any floating point portion
+ *   -  Take the modulus of the number in our base
+ *   -  Write it out to the buffer in the endian format requested at the offset
+ */
+
+/*
+ * We have to make sure that the value is a valid integer. This means that it is
+ * non-negative. It has no fractional component and that it does not exceed the
+ * maximum allowed value.
+ *
+ *	value		The number to check for validity
+ *
+ *	max		The maximum value
+ */
+function prepuint(value, max)
+{
+	if (typeof (value) != 'number')
+		throw (new (Error('cannot write a non-number as a number')));
+
+	if (value < 0)
+		throw (new Error('specified a negative value for writing an ' +
+		    'unsigned value'));
+
+	if (value > max)
+		throw (new Error('value is larger than maximum value for ' +
+		    'type'));
+
+	if (Math.floor(value) !== value)
+		throw (new Error('value has a fractional component'));
+
+	return (value);
+}
+
+/*
+ * 8-bit version, classy. We can ignore endianness which is good.
+ */
+function wuint8(value, endian, buffer, offset)
+{
+	var val;
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = prepuint(value, 0xff);
+	buffer[offset] = val;
+}
+
+/*
+ * Pretty much the same as the 8-bit version, just this time we need to worry
+ * about endian related issues.
+ */
+function wgint16(val, endian, buffer, offset)
+{
+	if (endian == 'big') {
+		buffer[offset] = (val & 0xff00) >>> 8;
+		buffer[offset+1] = val & 0x00ff;
+	} else {
+		buffer[offset+1] = (val & 0xff00) >>> 8;
+		buffer[offset] = val & 0x00ff;
+	}
+}
+
+function wuint16(value, endian, buffer, offset)
+{
+	var val;
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 1 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = prepuint(value, 0xffff);
+	wgint16(val, endian, buffer, offset);
+}
+
+/*
+ * The 32-bit version is going to have to be a little different unfortunately.
+ * We can't quite bitshift to get the largest byte, because that would end up
+ * getting us caught by the signed values.
+ *
+ * And yes, we do want to subtract out the lower part by default. This means
+ * that when we do the division, it will be treated as a bit shift and we won't
+ * end up generating a floating point value. If we did generate a floating point
+ * value we'd have to truncate it intelligently, this saves us that problem and
+ * may even be somewhat faster under the hood.
+ */
+function wgint32(val, endian, buffer, offset)
+{
+	if (endian == 'big') {
+		buffer[offset] = (val - (val & 0x00ffffff)) / Math.pow(2, 24);
+		buffer[offset+1] = (val >>> 16) & 0xff;
+		buffer[offset+2] = (val >>> 8) & 0xff;
+		buffer[offset+3] = val & 0xff;
+	} else {
+		buffer[offset+3] = (val - (val & 0x00ffffff)) /
+		    Math.pow(2, 24);
+		buffer[offset+2] = (val >>> 16) & 0xff;
+		buffer[offset+1] = (val >>> 8) & 0xff;
+		buffer[offset] = val & 0xff;
+	}
+}
+
+function wuint32(value, endian, buffer, offset)
+{
+	var val;
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 3 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = prepuint(value, 0xffffffff);
+	wgint32(val, endian, buffer, offset);
+}
+
+/*
+ * Unlike the other versions, we expect the value to be in the form of two
+ * arrays where value[0] << 32 + value[1] would result in the value that we
+ * want.
+ */
+function wgint64(value, endian, buffer, offset)
+{
+	if (endian == 'big') {
+		wgint32(value[0], endian, buffer, offset);
+		wgint32(value[1], endian, buffer, offset+4);
+	} else {
+		wgint32(value[0], endian, buffer, offset+4);
+		wgint32(value[1], endian, buffer, offset);
+	}
+}
+
+function wuint64(value, endian, buffer, offset)
+{
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (!(value instanceof Array))
+		throw (new Error('value must be an array'));
+
+	if (value.length != 2)
+		throw (new Error('value must be an array of length 2'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 7 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	prepuint(value[0], 0xffffffff);
+	prepuint(value[1], 0xffffffff);
+	wgint64(value, endian, buffer, offset);
+}
+
+/*
+ * We now move onto our friends in the signed number category. Unlike unsigned
+ * numbers, we're going to have to worry a bit more about how we put values into
+ * arrays. Since we are only worrying about signed 32-bit values, we're in
+ * slightly better shape. Unfortunately, we really can't do our favorite binary
+ * & in this system. It really seems to do the wrong thing. For example:
+ *
+ * > -32 & 0xff
+ * 224
+ *
+ * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of
+ * this aren't treated as a signed number. Ultimately a bad thing.
+ *
+ * What we're going to want to do is basically create the unsigned equivalent of
+ * our representation and pass that off to the wuint* functions. To do that
+ * we're going to do the following:
+ *
+ *  - if the value is positive
+ *	we can pass it directly off to the equivalent wuint
+ *  - if the value is negative
+ *	we do the following computation:
+ *	mb + val + 1, where
+ *	mb	is the maximum unsigned value in that byte size
+ *	val	is the Javascript negative integer
+ *
+ *
+ * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If
+ * you do out the computations:
+ *
+ * 0xffff - 128 + 1
+ * 0xffff - 127
+ * 0xff80
+ *
+ * You can then encode this value as the signed version. This is really rather
+ * hacky, but it should work and get the job done which is our goal here.
+ *
+ * Thus the overall flow is:
+ *   -  Truncate the floating point part of the number
+ *   -  We don't have to take the modulus, because the unsigned versions will
+ *   	take care of that for us. And we don't have to worry about that
+ *   	potentially causing bad things to happen because of sign extension
+ *   -  Pass it off to the appropriate unsigned version, potentially modifying
+ *	the negative portions as necessary.
+ */
+
+/*
+ * A series of checks to make sure we actually have a signed 32-bit number
+ */
+function prepsint(value, max, min)
+{
+	if (typeof (value) != 'number')
+		throw (new (Error('cannot write a non-number as a number')));
+
+	if (value > max)
+		throw (new Error('value larger than maximum allowed value'));
+
+	if (value < min)
+		throw (new Error('value smaller than minimum allowed value'));
+
+	if (Math.floor(value) !== value)
+		throw (new Error('value has a fractional component'));
+
+	return (value);
+}
+
+/*
+ * The 8-bit version of the signed value. Overall, fairly straightforward.
+ */
+function wsint8(value, endian, buffer, offset)
+{
+	var val;
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = prepsint(value, 0x7f, -0x80);
+	if (val >= 0)
+		wuint8(val, endian, buffer, offset);
+	else
+		wuint8(0xff + val + 1, endian, buffer, offset);
+}
+
+/*
+ * The 16-bit version of the signed value. Also, fairly straightforward.
+ */
+function wsint16(value, endian, buffer, offset)
+{
+	var val;
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 1 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = prepsint(value, 0x7fff, -0x8000);
+	if (val >= 0)
+		wgint16(val, endian, buffer, offset);
+	else
+		wgint16(0xffff + val + 1, endian, buffer, offset);
+
+}
+
+/*
+ * We can do this relatively easily by leveraging the code used for 32-bit
+ * unsigned code.
+ */
+function wsint32(value, endian, buffer, offset)
+{
+	var val;
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 3 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	val = prepsint(value, 0x7fffffff, -0x80000000);
+	if (val >= 0)
+		wgint32(val, endian, buffer, offset);
+	else
+		wgint32(0xffffffff + val + 1, endian, buffer, offset);
+}
+
+/*
+ * The signed 64 bit integer should by in the same format as when received.
+ * Mainly it should ensure that the value is an array of two integers where
+ * value[0] << 32 + value[1] is the desired number. Furthermore, the two values
+ * need to be equal.
+ */
+function wsint64(value, endian, buffer, offset)
+{
+	var vzpos, vopos;
+	var vals = new Array(2);
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (!(value instanceof Array))
+		throw (new Error('value must be an array'));
+
+	if (value.length != 2)
+		throw (new Error('value must be an array of length 2'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+	if (offset + 7 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	/*
+	 * We need to make sure that we have the same sign on both values. The
+	 * hokiest way to to do this is to multiply the number by +inf. If we do
+	 * this, we'll get either +/-inf depending on the sign of the value.
+	 * Once we have this, we can compare it to +inf to see if the number is
+	 * positive or not.
+	 */
+	vzpos = (value[0] * Number.POSITIVE_INFINITY) ==
+	    Number.POSITIVE_INFINITY;
+	vopos = (value[1] * Number.POSITIVE_INFINITY) ==
+	    Number.POSITIVE_INFINITY;
+
+	/*
+	 * If either of these is zero, then we don't actually need this check.
+	 */
+	if (value[0] != 0 && value[1] != 0 && vzpos != vopos)
+		throw (new Error('Both entries in the array must have ' +
+		    'the same sign'));
+
+	/*
+	 * Doing verification for a signed 64-bit integer is actually a big
+	 * trickier than it appears. We can't quite use our standard techniques
+	 * because we need to compare both sets of values. The first value is
+	 * pretty straightforward. If the first value is beond the extremes than
+	 * we error out. However, the valid range of the second value varies
+	 * based on the first one. If the first value is negative, and *not* the
+	 * largest negative value, than it can be any integer within the range [
+	 * 0, 0xffffffff ]. If it is the largest negative number, it must be
+	 * zero.
+	 *
+	 * If the first number is positive, than it doesn't matter what the
+	 * value is. We just simply have to make sure we have a valid positive
+	 * integer.
+	 */
+	if (vzpos) {
+		prepuint(value[0], 0x7fffffff);
+		prepuint(value[1], 0xffffffff);
+	} else {
+		prepsint(value[0], 0, -0x80000000);
+		prepsint(value[1], 0, -0xffffffff);
+		if (value[0] == -0x80000000 && value[1] != 0)
+			throw (new Error('value smaller than minimum ' +
+			    'allowed value'));
+	}
+
+	/* Fix negative numbers */
+	if (value[0] < 0 || value[1] < 0) {
+		vals[0] = 0xffffffff - Math.abs(value[0]);
+		vals[1] = 0x100000000 - Math.abs(value[1]);
+		if (vals[1] == 0x100000000) {
+			vals[1] = 0;
+			vals[0]++;
+		}
+	} else {
+		vals[0] = value[0];
+		vals[1] = value[1];
+	}
+	wgint64(vals, endian, buffer, offset);
+}
+
+/*
+ * Now we are moving onto the weirder of these, the float and double. For this
+ * we're going to just have to do something that's pretty weird. First off, we
+ * have no way to get at the underlying float representation, at least not
+ * easily. But that doesn't mean we can't figure it out, we just have to use our
+ * heads.
+ *
+ * One might propose to use Number.toString(2). Of course, this is not really
+ * that good, because the ECMAScript 262 v3 Standard says the following Section
+ * 15.7.4.2-Number.prototype.toString (radix):
+ *
+ * If radix is an integer from 2 to 36, but not 10, the result is a string, the
+ * choice of which is implementation-dependent.
+ *
+ * Well that doesn't really help us one bit now does it? We could use the
+ * standard base 10 version of the string, but that's just going to create more
+ * errors as we end up trying to convert it back to a binary value. So, really
+ * this just means we have to be non-lazy and parse the structure intelligently.
+ *
+ * First off, we can do the basic checks: NaN, positive and negative infinity.
+ *
+ * Now that those are done we can work backwards to generate the mantissa and
+ * exponent.
+ *
+ * The first thing we need to do is determine the sign bit, easy to do, check
+ * whether the value is less than 0. And convert the number to its absolute
+ * value representation. Next, we need to determine if the value is less than
+ * one or greater than or equal to one and from there determine what power was
+ * used to get there. What follows is now specific to floats, though the general
+ * ideas behind this will hold for doubles as well, but the exact numbers
+ * involved will change.
+ *
+ * Once we have that power we can determine the exponent and the mantissa. Call
+ * the value that has the number of bits to reach the power ebits. In the
+ * general case they have the following values:
+ *
+ *	exponent	127 + ebits
+ *	mantissa	value * 2^(23 - ebits) & 0x7fffff
+ *
+ * In the case where the value of ebits is <= -127 we are now in the case where
+ * we no longer have normalized numbers. In this case the values take on the
+ * following values:
+ *
+ * 	exponent	0
+ *	mantissa	value * 2^149 & 0x7fffff
+ *
+ * Once we have the values for the sign, mantissa, and exponent. We reconstruct
+ * the four bytes as follows:
+ *
+ *	byte0		sign bit and seven most significant bits from the exp
+ *			sign << 7 | (exponent & 0xfe) >>> 1
+ *
+ *	byte1		lsb from the exponent and 7 top bits from the mantissa
+ *			(exponent & 0x01) << 7 | (mantissa & 0x7f0000) >>> 16
+ *
+ *	byte2		bits 8-15 (zero indexing) from mantissa
+ *			mantissa & 0xff00 >> 8
+ *
+ *	byte3		bits 0-7 from mantissa
+ *			mantissa & 0xff
+ *
+ * Once we have this we have to assign them into the buffer in proper endian
+ * order.
+ */
+
+/*
+ * Compute the log base 2 of the value. Now, someone who remembers basic
+ * properties of logarithms will point out that we could use the change of base
+ * formula for logs, and in fact that would be astute, because that's what we'll
+ * do for now. It feels cleaner, albeit it may be less efficient than just
+ * iterating and dividing by 2. We may want to come back and revisit that some
+ * day.
+ */
+function log2(value)
+{
+	return (Math.log(value) / Math.log(2));
+}
+
+/*
+ * Helper to determine the exponent of the number we're looking at.
+ */
+function intexp(value)
+{
+	return (Math.floor(log2(value)));
+}
+
+/*
+ * Helper to determine the exponent of the fractional part of the value.
+ */
+function fracexp(value)
+{
+	return (Math.floor(log2(value)));
+}
+
+function wfloat(value, endian, buffer, offset)
+{
+	var sign, exponent, mantissa, ebits;
+	var bytes = [];
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+
+	if (offset + 3 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	if (isNaN(value)) {
+		sign = 0;
+		exponent = 0xff;
+		mantissa = 23;
+	} else if (value == Number.POSITIVE_INFINITY) {
+		sign = 0;
+		exponent = 0xff;
+		mantissa = 0;
+	} else if (value == Number.NEGATIVE_INFINITY) {
+		sign = 1;
+		exponent = 0xff;
+		mantissa = 0;
+	} else {
+		/* Well we have some work to do */
+
+		/* Thankfully the sign bit is trivial */
+		if (value < 0) {
+			sign = 1;
+			value = Math.abs(value);
+		} else {
+			sign = 0;
+		}
+
+		/* Use the correct function to determine number of bits */
+		if (value < 1)
+			ebits = fracexp(value);
+		else
+			ebits = intexp(value);
+
+		/* Time to deal with the issues surrounding normalization */
+		if (ebits <= -127) {
+			exponent = 0;
+			mantissa = (value * Math.pow(2, 149)) & 0x7fffff;
+		} else {
+			exponent = 127 + ebits;
+			mantissa = value * Math.pow(2, 23 - ebits);
+			mantissa &= 0x7fffff;
+		}
+	}
+
+	bytes[0] = sign << 7 | (exponent & 0xfe) >>> 1;
+	bytes[1] = (exponent & 0x01) << 7 | (mantissa & 0x7f0000) >>> 16;
+	bytes[2] = (mantissa & 0x00ff00) >>> 8;
+	bytes[3] = mantissa & 0x0000ff;
+
+	if (endian == 'big') {
+		buffer[offset] = bytes[0];
+		buffer[offset+1] = bytes[1];
+		buffer[offset+2] = bytes[2];
+		buffer[offset+3] = bytes[3];
+	} else {
+		buffer[offset] = bytes[3];
+		buffer[offset+1] = bytes[2];
+		buffer[offset+2] = bytes[1];
+		buffer[offset+3] = bytes[0];
+	}
+}
+
+/*
+ * Now we move onto doubles. Doubles are similar to floats in pretty much all
+ * ways except that the processing isn't quite as straightforward because we
+ * can't always use shifting, i.e. we have > 32 bit values.
+ *
+ * We're going to proceed in an identical fashion to floats and utilize the same
+ * helper functions. All that really is changing are the specific values that we
+ * use to do the calculations. Thus, to review we have to do the following.
+ *
+ * First get the sign bit and convert the value to its absolute value
+ * representation. Next, we determine the number of bits that we used to get to
+ * the value, branching whether the value is greater than or less than 1. Once
+ * we have that value which we will again call ebits, we have to do the
+ * following in the general case:
+ *
+ *	exponent	1023 + ebits
+ *	mantissa	[value * 2^(52 - ebits)] % 2^52
+ *
+ * In the case where the value of ebits <= -1023 we no longer use normalized
+ * numbers, thus like with floats we have to do slightly different processing:
+ *
+ *	exponent	0
+ *	mantissa	[value * 2^1074] % 2^52
+ *
+ * Once we have determined the sign, exponent and mantissa we can construct the
+ * bytes as follows:
+ *
+ *	byte0		sign bit and seven most significant bits form the exp
+ *			sign << 7 | (exponent & 0x7f0) >>> 4
+ *
+ *	byte1		Remaining 4 bits from the exponent and the four most
+ *			significant bits from the mantissa 48-51
+ *			(exponent & 0x00f) << 4 | mantissa >>> 48
+ *
+ *	byte2		Bits 40-47 from the mantissa
+ *			(mantissa >>> 40) & 0xff
+ *
+ *	byte3		Bits 32-39 from the mantissa
+ *			(mantissa >>> 32) & 0xff
+ *
+ *	byte4		Bits 24-31 from the mantissa
+ *			(mantissa >>> 24) & 0xff
+ *
+ *	byte5		Bits 16-23 from the Mantissa
+ *			(mantissa >>> 16) & 0xff
+ *
+ *	byte6		Bits 8-15 from the mantissa
+ *			(mantissa >>> 8) & 0xff
+ *
+ *	byte7		Bits 0-7 from the mantissa
+ *			mantissa & 0xff
+ *
+ * Now we can't quite do the right shifting that we want in bytes 1 - 3, because
+ * we'll have extended too far and we'll lose those values when we try and do
+ * the shift. Instead we have to use an alternate approach. To try and stay out
+ * of floating point, what we'll do is say that mantissa -= bytes[4-7] and then
+ * divide by 2^32. Once we've done that we can use binary arithmetic. Oof,
+ * that's ugly, but it seems to avoid using floating point (just based on how v8
+ * seems to be optimizing for base 2 arithmetic).
+ */
+function wdouble(value, endian, buffer, offset)
+{
+	var sign, exponent, mantissa, ebits;
+	var bytes = [];
+
+	if (value === undefined)
+		throw (new Error('missing value'));
+
+	if (endian === undefined)
+		throw (new Error('missing endian'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset'));
+
+
+	if (offset + 7 >= buffer.length)
+		throw (new Error('Trying to read beyond buffer length'));
+
+	if (isNaN(value)) {
+		sign = 0;
+		exponent = 0x7ff;
+		mantissa = 23;
+	} else if (value == Number.POSITIVE_INFINITY) {
+		sign = 0;
+		exponent = 0x7ff;
+		mantissa = 0;
+	} else if (value == Number.NEGATIVE_INFINITY) {
+		sign = 1;
+		exponent = 0x7ff;
+		mantissa = 0;
+	} else {
+		/* Well we have some work to do */
+
+		/* Thankfully the sign bit is trivial */
+		if (value < 0) {
+			sign = 1;
+			value = Math.abs(value);
+		} else {
+			sign = 0;
+		}
+
+		/* Use the correct function to determine number of bits */
+		if (value < 1)
+			ebits = fracexp(value);
+		else
+			ebits = intexp(value);
+
+		/*
+		 * This is a total hack to determine a denormalized value.
+		 * Unfortunately, we sometimes do not get a proper value for
+		 * ebits, i.e. we lose the values that would get rounded off.
+		 *
+		 *
+		 * The astute observer may wonder why we would be
+		 * multiplying by two Math.pows rather than just summing
+		 * them. Well, that's to get around a small bug in the
+		 * way v8 seems to implement the function. On occasion
+		 * doing:
+		 *
+		 * foo * Math.pow(2, 1023 + 51)
+		 *
+		 * Causes us to overflow to infinity, where as doing:
+		 *
+		 * foo * Math.pow(2, 1023) * Math.pow(2, 51)
+		 *
+		 * Does not cause us to overflow. Go figure.
+		 *
+		 */
+		if (value <= 2.225073858507201e-308 || ebits <= -1023) {
+			exponent = 0;
+			mantissa = value * Math.pow(2, 1023) * Math.pow(2, 51);
+			mantissa %= Math.pow(2, 52);
+		} else {
+			/*
+			 * We might have gotten fucked by our floating point
+			 * logarithm magic. This is rather crappy, but that's
+			 * our luck. If we just had a log base 2 or access to
+			 * the stupid underlying representation this would have
+			 * been much easier and we wouldn't have such stupid
+			 * kludges or hacks.
+			 */
+			if (ebits > 1023)
+				ebits = 1023;
+			exponent = 1023 + ebits;
+			mantissa = value * Math.pow(2, -ebits);
+			mantissa *= Math.pow(2, 52);
+			mantissa %= Math.pow(2, 52);
+		}
+	}
+
+	/* Fill the bytes in backwards to deal with the size issues */
+	bytes[7] = mantissa & 0xff;
+	bytes[6] = (mantissa >>> 8) & 0xff;
+	bytes[5] = (mantissa >>> 16) & 0xff;
+	mantissa = (mantissa - (mantissa & 0xffffff)) / Math.pow(2, 24);
+	bytes[4] = mantissa & 0xff;
+	bytes[3] = (mantissa >>> 8) & 0xff;
+	bytes[2] = (mantissa >>> 16) & 0xff;
+	bytes[1] = (exponent & 0x00f) << 4 | mantissa >>> 24;
+	bytes[0] = (sign << 7) | (exponent & 0x7f0) >>> 4;
+
+	if (endian == 'big') {
+		buffer[offset] = bytes[0];
+		buffer[offset+1] = bytes[1];
+		buffer[offset+2] = bytes[2];
+		buffer[offset+3] = bytes[3];
+		buffer[offset+4] = bytes[4];
+		buffer[offset+5] = bytes[5];
+		buffer[offset+6] = bytes[6];
+		buffer[offset+7] = bytes[7];
+	} else {
+		buffer[offset+7] = bytes[0];
+		buffer[offset+6] = bytes[1];
+		buffer[offset+5] = bytes[2];
+		buffer[offset+4] = bytes[3];
+		buffer[offset+3] = bytes[4];
+		buffer[offset+2] = bytes[5];
+		buffer[offset+1] = bytes[6];
+		buffer[offset] = bytes[7];
+	}
+}
+
+/*
+ * Actually export our work above. One might argue that we shouldn't expose
+ * these interfaces and just force people to use the higher level abstractions
+ * around this work. However, unlike say other libraries we've come across, this
+ * interface has several properties: it makes sense, it's simple, and it's
+ * useful.
+ */
+exports.ruint8 = ruint8;
+exports.ruint16 = ruint16;
+exports.ruint32 = ruint32;
+exports.ruint64 = ruint64;
+exports.wuint8 = wuint8;
+exports.wuint16 = wuint16;
+exports.wuint32 = wuint32;
+exports.wuint64 = wuint64;
+
+exports.rsint8 = rsint8;
+exports.rsint16 = rsint16;
+exports.rsint32 = rsint32;
+exports.rsint64 = rsint64;
+exports.wsint8 = wsint8;
+exports.wsint16 = wsint16;
+exports.wsint32 = wsint32;
+exports.wsint64 = wsint64;
+
+exports.rfloat = rfloat;
+exports.rdouble = rdouble;
+exports.wfloat = wfloat;
+exports.wdouble = wdouble;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctype.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctype.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/ctype.js	(revision 517)
@@ -0,0 +1,944 @@
+/*
+ * rm - Feb 2011
+ * ctype.js
+ *
+ * This module provides a simple abstraction towards reading and writing
+ * different types of binary data. It is designed to use ctio.js and provide a
+ * richer and more expressive API on top of it.
+ *
+ * By default we support the following as built in basic types:
+ *	int8_t
+ *	int16_t
+ *	int32_t
+ *	uint8_t
+ *	uint16_t
+ *	uint32_t
+ *	uint64_t
+ *	float
+ *	double
+ *	char
+ *	char[]
+ *
+ * Each type is returned as a Number, with the exception of char and char[]
+ * which are returned as Node Buffers. A char is considered a uint8_t.
+ *
+ * Requests to read and write data are specified as an array of JSON objects.
+ * This is also the same way that one declares structs. Even if just a single
+ * value is requested, it must be done as a struct. The array order determines
+ * the order that we try and read values. Each entry has the following format
+ * with values marked with a * being optional.
+ *
+ * { key: { type: /type/, value*: /value/, offset*: /offset/ }
+ *
+ * If offset is defined, we lseek(offset, SEEK_SET) before reading the next
+ * value. Value is defined when we're writing out data, otherwise it's ignored.
+ *
+ */
+
+var mod_ctf = require('./ctf.js');
+var mod_ctio = require('./ctio.js');
+var mod_assert = require('assert');
+
+/*
+ * This is the set of basic types that we support.
+ *
+ *	read		The function to call to read in a value from a buffer
+ *
+ *	write		The function to call to write a value to a buffer
+ *
+ */
+var deftypes = {
+    'uint8_t':  { read: ctReadUint8, write: ctWriteUint8 },
+    'uint16_t': { read: ctReadUint16, write: ctWriteUint16 },
+    'uint32_t': { read: ctReadUint32, write: ctWriteUint32 },
+    'uint64_t': { read: ctReadUint64, write: ctWriteUint64 },
+    'int8_t': { read: ctReadSint8, write: ctWriteSint8 },
+    'int16_t': { read: ctReadSint16, write: ctWriteSint16 },
+    'int32_t': { read: ctReadSint32, write: ctWriteSint32 },
+    'int64_t': { read: ctReadSint64, write: ctWriteSint64 },
+    'float': { read: ctReadFloat, write: ctWriteFloat },
+    'double': { read: ctReadDouble, write: ctWriteDouble },
+    'char': { read: ctReadChar, write: ctWriteChar },
+    'char[]': { read: ctReadCharArray, write: ctWriteCharArray }
+};
+
+/*
+ * The following are wrappers around the CType IO low level API. They encode
+ * knowledge about the size and return something in the expected format.
+ */
+function ctReadUint8(endian, buffer, offset)
+{
+	var val = mod_ctio.ruint8(buffer, endian, offset);
+	return ({ value: val, size: 1 });
+}
+
+function ctReadUint16(endian, buffer, offset)
+{
+	var val = mod_ctio.ruint16(buffer, endian, offset);
+	return ({ value: val, size: 2 });
+}
+
+function ctReadUint32(endian, buffer, offset)
+{
+	var val = mod_ctio.ruint32(buffer, endian, offset);
+	return ({ value: val, size: 4 });
+}
+
+function ctReadUint64(endian, buffer, offset)
+{
+	var val = mod_ctio.ruint64(buffer, endian, offset);
+	return ({ value: val, size: 8 });
+}
+
+function ctReadSint8(endian, buffer, offset)
+{
+	var val = mod_ctio.rsint8(buffer, endian, offset);
+	return ({ value: val, size: 1 });
+}
+
+function ctReadSint16(endian, buffer, offset)
+{
+	var val = mod_ctio.rsint16(buffer, endian, offset);
+	return ({ value: val, size: 2 });
+}
+
+function ctReadSint32(endian, buffer, offset)
+{
+	var val = mod_ctio.rsint32(buffer, endian, offset);
+	return ({ value: val, size: 4 });
+}
+
+function ctReadSint64(endian, buffer, offset)
+{
+	var val = mod_ctio.rsint64(buffer, endian, offset);
+	return ({ value: val, size: 8 });
+}
+
+function ctReadFloat(endian, buffer, offset)
+{
+	var val = mod_ctio.rfloat(buffer, endian, offset);
+	return ({ value: val, size: 4 });
+}
+
+function ctReadDouble(endian, buffer, offset)
+{
+	var val = mod_ctio.rdouble(buffer, endian, offset);
+	return ({ value: val, size: 8 });
+}
+
+/*
+ * Reads a single character into a node buffer
+ */
+function ctReadChar(endian, buffer, offset)
+{
+	var res = new Buffer(1);
+	res[0] = mod_ctio.ruint8(buffer, endian, offset);
+	return ({ value: res, size: 1 });
+}
+
+function ctReadCharArray(length, endian, buffer, offset)
+{
+	var ii;
+	var res = new Buffer(length);
+
+	for (ii = 0; ii < length; ii++)
+		res[ii] = mod_ctio.ruint8(buffer, endian, offset + ii);
+
+	return ({ value: res, size: length });
+}
+
+function ctWriteUint8(value, endian, buffer, offset)
+{
+	mod_ctio.wuint8(value, endian, buffer, offset);
+	return (1);
+}
+
+function ctWriteUint16(value, endian, buffer, offset)
+{
+	mod_ctio.wuint16(value, endian, buffer, offset);
+	return (2);
+}
+
+function ctWriteUint32(value, endian, buffer, offset)
+{
+	mod_ctio.wuint32(value, endian, buffer, offset);
+	return (4);
+}
+
+function ctWriteUint64(value, endian, buffer, offset)
+{
+	mod_ctio.wuint64(value, endian, buffer, offset);
+	return (8);
+}
+
+function ctWriteSint8(value, endian, buffer, offset)
+{
+	mod_ctio.wsint8(value, endian, buffer, offset);
+	return (1);
+}
+
+function ctWriteSint16(value, endian, buffer, offset)
+{
+	mod_ctio.wsint16(value, endian, buffer, offset);
+	return (2);
+}
+
+function ctWriteSint32(value, endian, buffer, offset)
+{
+	mod_ctio.wsint32(value, endian, buffer, offset);
+	return (4);
+}
+
+function ctWriteSint64(value, endian, buffer, offset)
+{
+	mod_ctio.wsint64(value, endian, buffer, offset);
+	return (8);
+}
+
+function ctWriteFloat(value, endian, buffer, offset)
+{
+	mod_ctio.wfloat(value, endian, buffer, offset);
+	return (4);
+}
+
+function ctWriteDouble(value, endian, buffer, offset)
+{
+	mod_ctio.wdouble(value, endian, buffer, offset);
+	return (8);
+}
+
+/*
+ * Writes a single character into a node buffer
+ */
+function ctWriteChar(value, endian, buffer, offset)
+{
+	if (!(value instanceof Buffer))
+		throw (new Error('Input must be a buffer'));
+
+	mod_ctio.ruint8(value[0], endian, buffer, offset);
+	return (1);
+}
+
+/*
+ * We're going to write 0s into the buffer if the string is shorter than the
+ * length of the array.
+ */
+function ctWriteCharArray(value, length, endian, buffer, offset)
+{
+	var ii;
+
+	if (!(value instanceof Buffer))
+		throw (new Error('Input must be a buffer'));
+
+	if (value.length > length)
+		throw (new Error('value length greater than array length'));
+
+	for (ii = 0; ii < value.length && ii < length; ii++)
+		mod_ctio.wuint8(value[ii], endian, buffer, offset + ii);
+
+	for (; ii < length; ii++)
+		mod_ctio.wuint8(0, endian, offset + ii);
+
+
+	return (length);
+}
+
+/*
+ * Each parser has their own set of types. We want to make sure that they each
+ * get their own copy as they may need to modify it.
+ */
+function ctGetBasicTypes()
+{
+	var ret = {};
+	var key;
+	for (key in deftypes)
+		ret[key] = deftypes[key];
+
+	return (ret);
+}
+
+/*
+ * Given a string in the form of type[length] we want to split this into an
+ * object that extracts that information. We want to note that we could possibly
+ * have nested arrays so this should only check the furthest one. It may also be
+ * the case that we have no [] pieces, in which case we just return the current
+ * type.
+ */
+function ctParseType(str)
+{
+	var begInd, endInd;
+	var type, len;
+	if (typeof (str) != 'string')
+		throw (new Error('type must be a Javascript string'));
+
+	endInd = str.lastIndexOf(']');
+	if (endInd == -1) {
+		if (str.lastIndexOf('[') != -1)
+			throw (new Error('found invalid type with \'[\' but ' +
+			    'no corresponding \']\''));
+
+		return ({ type: str });
+	}
+
+	begInd = str.lastIndexOf('[');
+	if (begInd == -1)
+		throw (new Error('found invalid type with \']\' but ' +
+		    'no corresponding \'[\''));
+
+	if (begInd >= endInd)
+		throw (new Error('malformed type, \']\' appears before \'[\''));
+
+	type = str.substring(0, begInd);
+	len = str.substring(begInd + 1, endInd);
+
+	return ({ type: type, len: len });
+}
+
+/*
+ * Given a request validate that all of the fields for it are valid and make
+ * sense. This includes verifying the following notions:
+ *  - Each type requested is present in types
+ *  - Only allow a name for a field to be specified once
+ *  - If an array is specified, validate that the requested field exists and
+ *    comes before it.
+ *  - If fields is defined, check that each entry has the occurrence of field
+ */
+function ctCheckReq(def, types, fields)
+{
+	var ii, jj;
+	var req, keys, key;
+	var found = {};
+
+	if (!(def instanceof Array))
+		throw (new Error('definition is not an array'));
+
+	if (def.length === 0)
+		throw (new Error('definition must have at least one element'));
+
+	for (ii = 0; ii < def.length; ii++) {
+		req = def[ii];
+		if (!(req instanceof Object))
+			throw (new Error('definition must be an array of' +
+			    'objects'));
+
+		keys = Object.keys(req);
+		if (keys.length != 1)
+			throw (new Error('definition entry must only have ' +
+			    'one key'));
+
+		if (keys[0] in found)
+			throw (new Error('Specified name already ' +
+			    'specified: ' + keys[0]));
+
+		if (!('type' in req[keys[0]]))
+			throw (new Error('missing required type definition'));
+
+		key = ctParseType(req[keys[0]]['type']);
+
+		/*
+		 * We may have nested arrays, we need to check the validity of
+		 * the types until the len field is undefined in key. However,
+		 * each time len is defined we need to verify it is either an
+		 * integer or corresponds to an already seen key.
+		 */
+		while (key['len'] !== undefined) {
+			if (isNaN(parseInt(key['len'], 10))) {
+				if (!(key['len'] in found))
+					throw (new Error('Given an array ' +
+					    'length without a matching type'));
+
+			}
+
+			key = ctParseType(key['type']);
+		}
+
+		/* Now we can validate if the type is valid */
+		if (!(key['type'] in types))
+			throw (new Error('type not found or typdefed: ' +
+			    key['type']));
+
+		/* Check for any required fields */
+		if (fields !== undefined) {
+			for (jj = 0; jj < fields.length; jj++) {
+				if (!(fields[jj] in req[keys[0]]))
+					throw (new Error('Missing required ' +
+					    'field: ' + fields[jj]));
+			}
+		}
+
+		found[keys[0]] = true;
+	}
+}
+
+
+/*
+ * Create a new instance of the parser. Each parser has its own store of
+ * typedefs and endianness. Conf is an object with the following required
+ * values:
+ *
+ *	endian		Either 'big' or 'little' do determine the endianness we
+ *			want to read from or write to.
+ *
+ * And the following optional values:
+ *
+ * 	char-type	Valid options here are uint8 and int8. If uint8 is
+ * 			specified this changes the default behavior of a single
+ * 			char from being a buffer of a single character to being
+ * 			a uint8_t. If int8, it becomes an int8_t instead.
+ */
+function CTypeParser(conf)
+{
+	if (!conf) throw (new Error('missing required argument'));
+
+	if (!('endian' in conf))
+		throw (new Error('missing required endian value'));
+
+	if (conf['endian'] != 'big' && conf['endian'] != 'little')
+		throw (new Error('Invalid endian type'));
+
+	if ('char-type' in conf && (conf['char-type'] != 'uint8' &&
+	    conf['char-type'] != 'int8'))
+		throw (new Error('invalid option for char-type: ' +
+		    conf['char-type']));
+
+	this.endian = conf['endian'];
+	this.types = ctGetBasicTypes();
+
+	/*
+	 * There may be a more graceful way to do this, but this will have to
+	 * serve.
+	 */
+	if ('char-type' in conf && conf['char-type'] == 'uint8')
+		this.types['char'] = this.types['uint8_t'];
+
+	if ('char-type' in conf && conf['char-type'] == 'int8')
+		this.types['char'] = this.types['int8_t'];
+}
+
+/*
+ * Sets the current endian value for the Parser. If the value is not valid,
+ * throws an Error.
+ *
+ *	endian		Either 'big' or 'little' do determine the endianness we
+ *			want to read from or write to.
+ *
+ */
+CTypeParser.prototype.setEndian = function (endian)
+{
+	if (endian != 'big' && endian != 'little')
+		throw (new Error('invalid endian type, must be big or ' +
+		    'little'));
+
+	this.endian = endian;
+};
+
+/*
+ * Returns the current value of the endian value for the parser.
+ */
+CTypeParser.prototype.getEndian = function ()
+{
+	return (this.endian);
+};
+
+/*
+ * A user has requested to add a type, let us honor their request. Yet, if their
+ * request doth spurn us, send them unto the Hells which Dante describes.
+ *
+ * 	name		The string for the type definition we're adding
+ *
+ *	value		Either a string that is a type/array name or an object
+ *			that describes a struct.
+ */
+CTypeParser.prototype.typedef = function (name, value)
+{
+	var type;
+
+	if (name === undefined)
+		throw (new (Error('missing required typedef argument: name')));
+
+	if (value === undefined)
+		throw (new (Error('missing required typedef argument: value')));
+
+	if (typeof (name) != 'string')
+		throw (new (Error('the name of a type must be a string')));
+
+	type = ctParseType(name);
+
+	if (type['len'] !== undefined)
+		throw (new Error('Cannot have an array in the typedef name'));
+
+	if (name in this.types)
+		throw (new Error('typedef name already present: ' + name));
+
+	if (typeof (value) != 'string' && !(value instanceof Array))
+		throw (new Error('typedef value must either be a string or ' +
+		    'struct'));
+
+	if (typeof (value) == 'string') {
+		type = ctParseType(value);
+		if (type['len'] !== undefined) {
+			if (isNaN(parseInt(type['len'], 10)))
+				throw (new (Error('typedef value must use ' +
+				    'fixed size array when outside of a ' +
+				    'struct')));
+		}
+
+		this.types[name] = value;
+	} else {
+		/* We have a struct, validate it */
+		ctCheckReq(value, this.types);
+		this.types[name] = value;
+	}
+};
+
+/*
+ * Include all of the typedefs, but none of the built in types. This should be
+ * treated as read-only.
+ */
+CTypeParser.prototype.lstypes = function ()
+{
+	var key;
+	var ret = {};
+
+	for (key in this.types) {
+		if (key in deftypes)
+			continue;
+		ret[key] = this.types[key];
+	}
+
+	return (ret);
+};
+
+/*
+ * Given a type string that may have array types that aren't numbers, try and
+ * fill them in from the values object. The object should be of the format where
+ * indexing into it should return a number for that type.
+ *
+ *	str		The type string
+ *
+ *	values		An object that can be used to fulfill type information
+ */
+function ctResolveArray(str, values)
+{
+	var ret = '';
+	var type = ctParseType(str);
+
+	while (type['len'] !== undefined) {
+		if (isNaN(parseInt(type['len'], 10))) {
+			if (typeof (values[type['len']]) != 'number')
+				throw (new Error('cannot sawp in non-number ' +
+				    'for array value'));
+			ret = '[' + values[type['len']] + ']' + ret;
+		} else {
+			ret = '[' + type['len'] + ']' + ret;
+		}
+		type = ctParseType(type['type']);
+	}
+
+	ret = type['type'] + ret;
+
+	return (ret);
+}
+
+/*
+ * [private] Either the typedef resolves to another type string or to a struct.
+ * If it resolves to a struct, we just pass it off to read struct. If not, we
+ * can just pass it off to read entry.
+ */
+CTypeParser.prototype.resolveTypedef = function (type, dispatch, buffer,
+    offset, value)
+{
+	var pt;
+
+	mod_assert.ok(type in this.types);
+	if (typeof (this.types[type]) == 'string') {
+		pt = ctParseType(this.types[type]);
+		if (dispatch == 'read')
+			return (this.readEntry(pt, buffer, offset));
+		else if (dispatch == 'write')
+			return (this.writeEntry(value, pt, buffer, offset));
+		else
+			throw (new Error('invalid dispatch type to ' +
+			    'resolveTypedef'));
+	} else {
+		if (dispatch == 'read')
+			return (this.readStruct(this.types[type], buffer,
+			    offset));
+		else if (dispatch == 'write')
+			return (this.writeStruct(value, this.types[type],
+			    buffer, offset));
+		else
+			throw (new Error('invalid dispatch type to ' +
+			    'resolveTypedef'));
+	}
+
+};
+
+/*
+ * [private] Try and read in the specific entry.
+ */
+CTypeParser.prototype.readEntry = function (type, buffer, offset)
+{
+	var parse, len;
+
+	/*
+	 * Because we want to special case char[]s this is unfortunately
+	 * a bit uglier than it really should be. We want to special
+	 * case char[]s so that we return a node buffer, thus they are a
+	 * first class type where as all other arrays just call into a
+	 * generic array routine which calls their data-specific routine
+	 * the specified number of times.
+	 *
+	 * The valid dispatch options we have are:
+	 *  - Array and char => char[] handler
+	 *  - Generic array handler
+	 *  - Generic typedef handler
+	 *  - Basic type handler
+	 */
+	if (type['len'] !== undefined) {
+		len = parseInt(type['len'], 10);
+		if (isNaN(len))
+			throw (new Error('somehow got a non-numeric length'));
+
+		if (type['type'] == 'char')
+			parse = this.types['char[]']['read'](len,
+			    this.endian, buffer, offset);
+		else
+			parse = this.readArray(type['type'],
+			    len, buffer, offset);
+	} else {
+		if (type['type'] in deftypes)
+			parse = this.types[type['type']]['read'](this.endian,
+			    buffer, offset);
+		else
+			parse = this.resolveTypedef(type['type'], 'read',
+			    buffer, offset);
+	}
+
+	return (parse);
+};
+
+/*
+ * [private] Read an array of data
+ */
+CTypeParser.prototype.readArray = function (type, length, buffer, offset)
+{
+	var ii, ent, pt;
+	var baseOffset = offset;
+	var ret = new Array(length);
+	pt = ctParseType(type);
+
+	for (ii = 0; ii < length; ii++) {
+		ent = this.readEntry(pt, buffer, offset);
+		offset += ent['size'];
+		ret[ii] = ent['value'];
+	}
+
+	return ({ value: ret, size: offset - baseOffset });
+};
+
+/*
+ * [private] Read a single struct in.
+ */
+CTypeParser.prototype.readStruct = function (def, buffer, offset)
+{
+	var parse, ii, type, entry, key;
+	var baseOffset = offset;
+	var ret = {};
+
+	/* Walk it and handle doing what's necessary */
+	for (ii = 0; ii < def.length; ii++) {
+		key = Object.keys(def[ii])[0];
+		entry = def[ii][key];
+
+		/* Resolve all array values */
+		type = ctParseType(ctResolveArray(entry['type'], ret));
+
+		if ('offset' in entry)
+			offset = baseOffset + entry['offset'];
+
+		parse = this.readEntry(type, buffer, offset);
+
+		offset += parse['size'];
+		ret[key] = parse['value'];
+	}
+
+	return ({ value: ret, size: (offset-baseOffset)});
+};
+
+/*
+ * This is what we were born to do. We read the data from a buffer and return it
+ * in an object whose keys match the values from the object.
+ *
+ *	def		The array definition of the data to read in
+ *
+ *	buffer		The buffer to read data from
+ *
+ *	offset		The offset to start writing to
+ *
+ * Returns an object where each key corresponds to an entry in def and the value
+ * is the read value.
+ */
+CTypeParser.prototype.readData = function (def, buffer, offset)
+{
+	/* Sanity check for arguments */
+	if (def === undefined)
+		throw (new Error('missing definition for what we should be' +
+		    'parsing'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer for what we should be ' +
+		    'parsing'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset for what we should be ' +
+		    'parsing'));
+
+	/* Sanity check the object definition */
+	ctCheckReq(def, this.types);
+
+	return (this.readStruct(def, buffer, offset)['value']);
+};
+
+/*
+ * [private] Write out an array of data
+ */
+CTypeParser.prototype.writeArray = function (value, type, length, buffer,
+    offset)
+{
+	var ii, pt;
+	var baseOffset = offset;
+	if (!(value instanceof Array))
+		throw (new Error('asked to write an array, but value is not ' +
+		    'an array'));
+
+	if (value.length != length)
+		throw (new Error('asked to write array of length ' + length +
+		    ' but that does not match value length: ' + value.length));
+
+	pt = ctParseType(type);
+	for (ii = 0; ii < length; ii++)
+		offset += this.writeEntry(value[ii], pt, buffer, offset);
+
+	return (offset - baseOffset);
+};
+
+/*
+ * [private] Write the specific entry
+ */
+CTypeParser.prototype.writeEntry = function (value, type, buffer, offset)
+{
+	var len, ret;
+
+	if (type['len'] !== undefined) {
+		len = parseInt(type['len'], 10);
+		if (isNaN(len))
+			throw (new Error('somehow got a non-numeric length'));
+
+		if (type['type'] == 'char')
+			ret = this.types['char[]']['write'](value, len,
+			    this.endian, buffer, offset);
+		else
+			ret = this.writeArray(value, type['type'],
+			    len, buffer, offset);
+	} else {
+		if (type['type'] in deftypes)
+			ret = this.types[type['type']]['write'](value,
+			    this.endian, buffer, offset);
+		else
+			ret = this.resolveTypedef(type['type'], 'write',
+			    buffer, offset, value);
+	}
+
+	return (ret);
+};
+
+/*
+ * [private] Write a single struct out.
+ */
+CTypeParser.prototype.writeStruct = function (value, def, buffer, offset)
+{
+	var ii, entry, type, key;
+	var baseOffset = offset;
+	var vals = {};
+
+	for (ii = 0; ii < def.length; ii++) {
+		key = Object.keys(def[ii])[0];
+		entry = def[ii][key];
+
+		type = ctParseType(ctResolveArray(entry['type'], vals));
+
+		if ('offset' in entry)
+			offset = baseOffset + entry['offset'];
+
+		offset += this.writeEntry(value[ii], type, buffer, offset);
+		/* Now that we've written it out, we can use it for arrays */
+		vals[key] = value[ii];
+	}
+
+	return (offset);
+};
+
+/*
+ * Unfortunately, we're stuck with the sins of an initial poor design. Because
+ * of that, we are going to have to support the old way of writing data via
+ * writeData. There we insert the values that you want to write into the
+ * definition. A little baroque. Internally, we use the new model. So we need to
+ * just get those values out of there. But to maintain the principle of least
+ * surprise, we're not going to modify the input data.
+ */
+function getValues(def)
+{
+	var ii, out, key;
+	out = [];
+	for (ii = 0; ii < def.length; ii++) {
+		key = Object.keys(def[ii])[0];
+		mod_assert.ok('value' in def[ii][key]);
+		out.push(def[ii][key]['value']);
+	}
+
+	return (out);
+}
+
+/*
+ * This is the second half of what we were born to do, write out the data
+ * itself. Historically this function required you to put your values in the
+ * definition section. This was not the smartest thing to do and a bit of an
+ * oversight to be honest. As such, this function now takes a values argument.
+ * If values is non-null and non-undefined, it will be used to determine the
+ * values. This means that the old method is still supported, but is no longer
+ * acceptable.
+ *
+ *	def		The array definition of the data to write out with
+ *			values
+ *
+ *	buffer		The buffer to write to
+ *
+ *	offset		The offset in the buffer to write to
+ *
+ *	values		An array of values to write.
+ */
+CTypeParser.prototype.writeData = function (def, buffer, offset, values)
+{
+	var hv;
+
+	if (def === undefined)
+		throw (new Error('missing definition for what we should be' +
+		    'parsing'));
+
+	if (buffer === undefined)
+		throw (new Error('missing buffer for what we should be ' +
+		    'parsing'));
+
+	if (offset === undefined)
+		throw (new Error('missing offset for what we should be ' +
+		    'parsing'));
+
+	hv = (values != null && values != undefined);
+	if (hv) {
+		if (!Array.isArray(values))
+			throw (new Error('missing values for writing'));
+		ctCheckReq(def, this.types);
+	} else {
+		ctCheckReq(def, this.types, [ 'value' ]);
+	}
+
+	this.writeStruct(hv ? values : getValues(def), def, buffer, offset);
+};
+
+/*
+ * Functions to go to and from 64 bit numbers in a way that is compatible with
+ * Javascript limitations. There are two sets. One where the user is okay with
+ * an approximation and one where they are definitely not okay with an
+ * approximation.
+ */
+
+/*
+ * Attempts to convert an array of two integers returned from rsint64 / ruint64
+ * into an absolute 64 bit number. If however the value would exceed 2^52 this
+ * will instead throw an error. The mantissa in a double is a 52 bit number and
+ * rather than potentially give you a value that is an approximation this will
+ * error. If you would rather an approximation, please see toApprox64.
+ *
+ *	val		An array of two 32-bit integers
+ */
+function toAbs64(val)
+{
+	if (val === undefined)
+		throw (new Error('missing required arg: value'));
+
+	if (!Array.isArray(val))
+		throw (new Error('value must be an array'));
+
+	if (val.length != 2)
+		throw (new Error('value must be an array of length 2'));
+
+	/* We have 20 bits worth of precision in this range */
+	if (val[0] >= 0x100000)
+		throw (new Error('value would become approximated'));
+
+	return (val[0] * Math.pow(2, 32) + val[1]);
+}
+
+/*
+ * Will return the 64 bit value as returned in an array from rsint64 / ruint64
+ * to a value as close as it can. Note that Javascript stores all numbers as a
+ * double and the mantissa only has 52 bits. Thus this version may approximate
+ * the value.
+ *
+ *	val		An array of two 32-bit integers
+ */
+function toApprox64(val)
+{
+	if (val === undefined)
+		throw (new Error('missing required arg: value'));
+
+	if (!Array.isArray(val))
+		throw (new Error('value must be an array'));
+
+	if (val.length != 2)
+		throw (new Error('value must be an array of length 2'));
+
+	return (Math.pow(2, 32) * val[0] + val[1]);
+}
+
+function parseCTF(json, conf)
+{
+	var ctype = new CTypeParser(conf);
+	mod_ctf.ctfParseJson(json, ctype);
+
+	return (ctype);
+}
+
+/*
+ * Export the few things we actually want to. Currently this is just the CType
+ * Parser and ctio.
+ */
+exports.Parser = CTypeParser;
+exports.toAbs64 = toAbs64;
+exports.toApprox64 = toApprox64;
+
+exports.parseCTF = parseCTF;
+
+exports.ruint8 = mod_ctio.ruint8;
+exports.ruint16 = mod_ctio.ruint16;
+exports.ruint32 = mod_ctio.ruint32;
+exports.ruint64 = mod_ctio.ruint64;
+exports.wuint8 = mod_ctio.wuint8;
+exports.wuint16 = mod_ctio.wuint16;
+exports.wuint32 = mod_ctio.wuint32;
+exports.wuint64 = mod_ctio.wuint64;
+
+exports.rsint8 = mod_ctio.rsint8;
+exports.rsint16 = mod_ctio.rsint16;
+exports.rsint32 = mod_ctio.rsint32;
+exports.rsint64 = mod_ctio.rsint64;
+exports.wsint8 = mod_ctio.wsint8;
+exports.wsint16 = mod_ctio.wsint16;
+exports.wsint32 = mod_ctio.wsint32;
+exports.wsint64 = mod_ctio.wsint64;
+
+exports.rfloat = mod_ctio.rfloat;
+exports.rdouble = mod_ctio.rdouble;
+exports.wfloat = mod_ctio.wfloat;
+exports.wdouble = mod_ctio.wdouble;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/man/man3ctype/ctio.3ctype
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/man/man3ctype/ctio.3ctype	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/man/man3ctype/ctio.3ctype	(revision 517)
@@ -0,0 +1,241 @@
+'\" te
+.\" Copyright (c) 2011, Robert Mustacchi.  All Rights Reserved.
+.\" Copyright (c) 2011, Joyent, Inc.  All Rights Reserved.
+.\"
+.\" 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.
+.TH CTIO 3CTYPE "December 12, 2011"
+.SH NAME
+ctio, ruint8, ruint16, ruint32, ruint64, wuint8, wuint16, wuint32, wuint64,
+rsint8, rsint16, rsint32, rsint64, wsint8, wsint16, wsint32, wsint64, rfloat,
+rdouble, wfloat, wdouble \- integer and float operations
+.SH SYNOPSIS
+.LP
+.nf
+var mod_ctype = require('ctype');
+
+\fBNumber\fR \fBmod_ctype.ruint8\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber\fR \fBmod_ctype.ruint16\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber\fR \fBmod_ctype.ruint32\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber[2]\fR \fBmod_ctype.ruint64\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber\fR \fBmod_ctype.rsint8\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber\fR \fBmod_ctype.rsint16\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber\fR \fBmod_ctype.rsint32\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber[2]\fR \fBmod_ctype.rsint64\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber\fR \fBmod_ctype.rfloat\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBNumber\fR \fBmod_ctype.rdouble\fR(\fBBuffer\fR \fIbuf\fR, \fBString\fR \fIendian\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wuint8\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wuint16\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wuint32\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wuint64\fR(\fBNumber[2]\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wsint8\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wsint16\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wsint32\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wsint64\fR(\fBNumber[2]\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wfloat\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.LP
+.nf
+\fBvoid\fR \fBmod_ctype.wdouble\fR(\fBNumber\fR value, \fBString\fR \fIendian\fR, \fBBuffer\fR \fIbuf\fR, \fBNumber\fR \fIoffset\fR);
+.fi
+
+.SH DESCRIPTION
+.sp
+.LP
+The argument \fIbuf\fR refers to a valid buffer (from calling new Buffer()). The
+argument \fIendian\fR is either the string 'big' or 'little' and controls
+whether the data in the buffer is interpreted as big or little endian. The argument
+\fIoffset\fR indicates the starting index into the buffer to read or write. All
+functions ensure that starting at \fIoffset\fR does not overflow the end of the
+buffer. The argument \fIvalue\fR is a Number that is the valid type for the
+specific function. All functions that take \fIvalue\fR as an argument, verify
+that the passed value is valid.
+
+.SS "\fBruint8()\fR, \fBruint16()\fR, \fBruint32()\fR"
+.sp
+.LP
+The \fBruint8()\fR, \fBruint16()\fR, and \fBruint32()\fR functions read an 8,
+16, and 32-bit unsigned value from \fIbuf\fR and return it. The value read is
+influenced by the values of \fIoffset\fR and \fRendian\fI.
+
+
+.SS "\fBrsint8()\fR, \fBrsint16()\fR, \fBrsint32()\fR"
+.sp
+.LP
+The \fBruint8()\fR, \fBruint16()\fR, and \fBruint32()\fR functions work just as
+\fBruint8()\fR, \fBruint16()\fR, and \fBruint32()\fR, except they return signed
+integers.
+
+.SS "\fBruint64()\fR, \fBrsint64()\fR"
+.sp
+.LP
+The \fBruint64()\fR and \fBrsint64()\fR functions read unsigned and signed 64
+bit integers respectively from \fBbuf\fR. Due to the limitations of ECMAScript's
+\fBNumber\fR type, they cannot be stored as one value without a loss of
+precision. Instead of returning the values as a single \fBNumber\fR, the
+functions return an array of two numbers. The first entry always contains the
+upper 32-bits and the second value contains the lower 32-bits. The lossy
+transformation into a number would be \fIres[0]*Math.pow(2,32)+res[1]\fR.
+Note that, unless an entry is zero, both array entries are guaranteed to have
+the same sign.
+
+.SS "\fBwuint8()\fR, \fBwuint16()\fR, \fBwuint32()\fR"
+.sp
+.LP
+The functions \fBwuint8()\fR, \fBwuint16()\fR, and \fBwuint32()\fR modify the
+contents of \fBbuf\fR by writing an 8, 16, and 32-bit unsigned integer
+respectively to \fBbuf\fR. It is illegal to pass a number that is not an integer
+within the domain of the integer size, for example, for \fBwuint8()\fR the valid
+range is \fB[0, 255]\fR. The value will be written in either big or little
+endian format based upon the value of \fBendian\fR.
+
+
+.SS "\fBwsint8()\fR, \fBwsint16()\fR, \fBwsint32()\fR"
+.sp
+.LP
+The functions \fBwsint8()\fR, \fBwsint16()\fR, and \fBwsint32()\fR function
+identically to the functions \fBwuint8()\fR, \fBwuint16()\fR, and
+\fBwuint32()\fR except that they the valid domain for \fBvalue\fR is that of a
+signed number instead of an unsigned number. For example the \fBwsint8()\fR has
+a domain of \fB[-128, 127]\fR.
+
+.SS "\fBwuint64()\fR, \fBwsint64()\fR"
+.sp
+.LP
+The functions \fBwuint64()\fR and \fBswint64()\fR write out 64-bit unsigned and
+signed integers to \fBbuf\fR. The \fBvalue\fR argument must be in the same
+format as described in \fBruint64()\fR and \fBrsint64()\fR.
+
+.SS "\fBrfloat()\fR, \fBrdouble()\fR"
+.sp
+.LP
+The functions "\fBrfloat()\fR and \fBrdouble()\fR" work like the other read
+functions, except that they read a single precision and double precision
+IEEE-754 floating point value instead.
+
+.SS "\fBwfloat()\fR, \fBwdouble()\fR"
+.sp
+.LP
+The functions "\fBrfloat()\fR and \fBrdouble()\fR" work like the other write 
+functions, except that the domain for a float is that of a single precision 4
+byte value. The domain for a double is any \fBNumber\fR in ECMAScript, which is
+defined to be represented by a double.
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE	ATTRIBUTE VALUE
+_
+Interface Stability	Committed
+_
+MT-Level	See below.
+_
+Standard	Not standardized.
+.TE
+
+.sp
+.LP
+
+All functions are MT-safe in so far as there aren't shared memory MT concerns in
+most node programs. If one where to concoct such an environment, these functions
+wouldn't be MT-safe.
+
+.SH SEE ALSO
+.sp
+.LP
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/package.json	(revision 517)
@@ -0,0 +1,18 @@
+{
+  "name": "ctype",
+  "version": "0.5.2",
+  "description": "read and write binary structures and data types",
+  "homepage": "https://github.com/rmustacc/node-ctype",
+  "author": {
+    "name": "Robert Mustacchi",
+    "email": "rm@fingolfin.org"
+  },
+  "engines": {
+    "node": ">= 0.4"
+  },
+  "main": "ctype.js",
+  "readme": "Node-CType is a way to read and write binary data in structured and easy to use\nformat. Its name comes from the C header file.\n\nTo get started, simply clone the repository or use npm to install it. Once it is\nthere, simply require it.\n\ngit clone git://github.com/rmustacc/node-ctype\nnpm install ctype\nvar mod_ctype = require('ctype')\n\n\nThere are two APIs that you can use, depending on what abstraction you'd like.\nThe low level API let's you read and write individual integers and floats from\nbuffers. The higher level API let's you read and write structures of these. To\nillustrate this, let's looks look at how we would read and write a binary\nencoded x,y point.\n\nIn C we would define this structure as follows:\n\ntypedef struct point {\n\tuint16_t\tp_x;\n\tuint16_t\tp_y;\n} point_t;\n\nTo read a binary encoded point from a Buffer, we first need to create a CType\nparser (where we specify the endian and other options) and add the typedef.\n\nvar parser = new mod_ctype.Parser({ endian: 'big' });\nparser.typedef('point_t', [\n\t{ x: { type: 'uint16_t' } },\n\t{ y: { type: 'uint16_t' } }\n]);\n\nFrom here, given a buffer buf and an offset into it, we can read a point.\n\nvar out = parser.readData([ { point: { type: 'point_t' } } ], buffer, 0);\nconsole.log(out);\n{ point: { x: 23, y: 42 } }\n\nAnother way to get the same information would be to use the low level methods.\nNote that these require you to manually deal with the offset. Here's how we'd\nget the same values of x and y from the buffer.\n\nvar x = mod_ctype.ruint16(buf, 'big', 0);\nvar y = mod_ctype.ruint16(buf, 'big', 2);\nconsole.log(x + ', ' + y);\n23, 42\n\nThe true power of this API comes from the ability to define and nest typedefs,\njust as you would in C. By default, the following types are defined by default.\nNote that they return a Number, unless indicated otherwise.\n\n    * int8_t\n    * int16_t\n    * int32_t\n    * int64_t (returns an array where val[0] << 32 + val[1] would be the value)\n    * uint8_t\n    * uint16_t\n    * uint32_t\n    * uint64_t (returns an array where val[0] << 32 + val[1] would be the value)\n    * float\n    * double\n    * char (either returns a buffer with that character or a uint8_t)\n    * char[] (returns an object with the buffer and the number of characters read which is either the total amount requested or until the first 0)\n\n\nctf2json integration:\n\nNode-CType supports consuming the output of ctf2json. Once you read in a JSON file,\nall you have to do to add all the definitions it contains is:\n\nvar data, parser;\ndata = JSON.parse(parsedJSONData);\nparser = mod_ctype.parseCTF(data, { endian: 'big' });\n\nFor more documentation, see the file README.old. Full documentation is in the\nprocess of being rewritten as a series of manual pages which will be available\nin the repository and online for viewing.\n\nTo read the ctio manual page simple run, from the root of the workspace:\n\nman -Mman -s 3ctype ctio\n",
+  "readmeFilename": "README",
+  "_id": "ctype@0.5.2",
+  "_from": "ctype@0.5.2"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tools/jsl.conf
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tools/jsl.conf	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tools/jsl.conf	(revision 517)
@@ -0,0 +1,129 @@
+#
+# Configuration File for JavaScript Lint 0.3.0
+# Developed by Matthias Miller (http://www.JavaScriptLint.com)
+#
+# This configuration file can be used to lint a collection of scripts, or to enable
+# or disable warnings for scripts that are linted via the command line.
+#
+
+### Warnings
+# Enable or disable warnings based on requirements.
+# Use "+WarningName" to display or "-WarningName" to suppress.
+#
++no_return_value              # function {0} does not always return a value
++duplicate_formal             # duplicate formal argument {0}
++equal_as_assign              # test for equality (==) mistyped as assignment (=)?{0}
++var_hides_arg                # variable {0} hides argument
++redeclared_var               # redeclaration of {0} {1}
++anon_no_return_value         # anonymous function does not always return a value
++missing_semicolon            # missing semicolon
++meaningless_block            # meaningless block; curly braces have no impact
++comma_separated_stmts        # multiple statements separated by commas (use semicolons?)
++unreachable_code             # unreachable code
++missing_break                # missing break statement
++missing_break_for_last_case  # missing break statement for last case in switch
++comparison_type_conv         # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
+-inc_dec_within_stmt          # increment (++) and decrement (--) operators used as part of greater statement
++useless_void                 # use of the void type may be unnecessary (void is always undefined)
+-useless_quotes			# quotation marks are unnecessary
++multiple_plus_minus          # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
++use_of_label                 # use of label
+-block_without_braces         # block statement without curly braces
++leading_decimal_point        # leading decimal point may indicate a number or an object member
++trailing_decimal_point       # trailing decimal point may indicate a number or an object member
+-octal_number                 # leading zeros make an octal number
++nested_comment               # nested comment
++misplaced_regex              # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
++ambiguous_newline            # unexpected end of line; it is ambiguous whether these lines are part of the same statement
++empty_statement              # empty statement or extra semicolon
+-missing_option_explicit      # the "option explicit" control comment is missing
++partial_option_explicit      # the "option explicit" control comment, if used, must be in the first script tag
++dup_option_explicit          # duplicate "option explicit" control comment
++useless_assign               # useless assignment
++ambiguous_nested_stmt        # block statements containing block statements should use curly braces to resolve ambiguity
++ambiguous_else_stmt          # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
++missing_default_case         # missing default case in switch statement
++duplicate_case_in_switch     # duplicate case in switch statements
++default_not_at_end           # the default case is not at the end of the switch statement
++legacy_cc_not_understood     # couldn't understand control comment using /*@keyword@*/ syntax
++jsl_cc_not_understood        # couldn't understand control comment using /*jsl:keyword*/ syntax
++useless_comparison           # useless comparison; comparing identical expressions
++with_statement               # with statement hides undeclared variables; use temporary variable instead
++trailing_comma_in_array      # extra comma is not recommended in array initializers
++assign_to_function_call      # assignment to a function call
++parseint_missing_radix       # parseInt missing radix parameter
+-unreferenced_argument        # argument declared but never referenced: {name}
+
+### Output format
+# Customize the format of the error message.
+#    __FILE__ indicates current file path
+#    __FILENAME__ indicates current file name
+#    __LINE__ indicates current line
+#    __ERROR__ indicates error message
+#
+# Visual Studio syntax (default):
++output-format __FILE__(__LINE__): __ERROR__
+# Alternative syntax:
+#+output-format __FILE__:__LINE__: __ERROR__
+
+
+### Context
+# Show the in-line position of the error.
+# Use "+context" to display or "-context" to suppress.
+#
++context
+
+
+### Semicolons
+# By default, assignments of an anonymous function to a variable or
+# property (such as a function prototype) must be followed by a semicolon.
+#
+#+lambda_assign_requires_semicolon # deprecated setting
+
+
+### Control Comments
+# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
+# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
+# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
+# although legacy control comments are enabled by default for backward compatibility.
+#
++legacy_control_comments
+
+
+### JScript Function Extensions
+# JScript allows member functions to be defined like this:
+#     function MyObj() { /*constructor*/ }
+#     function MyObj.prototype.go() { /*member function*/ }
+#
+# It also allows events to be attached like this:
+#     function window::onload() { /*init page*/ }
+#
+# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
+#
+#-jscript_function_extensions # deprecated setting
+
+
+### Defining identifiers
+# By default, "option explicit" is enabled on a per-file basis.
+# To enable this for all files, use "+always_use_option_explicit"
+-always_use_option_explicit
+
+# Define certain identifiers of which the lint is not aware.
+# (Use this in conjunction with the "undeclared identifier" warning.)
+#
+# Common uses for webpages might be:
+#+define window
+#+define document
++define require
++define exports
++define console
++define Buffer
++define JSON
+
+### Files
+# Specify which files to lint
+# Use "+recurse" to enable recursion (disabled by default).
+# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
+# or "+process Folder\Path\*.htm".
+#
+#+process jsl-test.js
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tools/jsstyle
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tools/jsstyle	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tools/jsstyle	(revision 517)
@@ -0,0 +1,839 @@
+#!/usr/bin/env perl
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+#
+# jsstyle - check for some common stylistic errors.
+#
+#	jsstyle is a sort of "lint" for Javascript coding style.  This tool is
+#	derived from the cstyle tool, used to check for the style used in the
+#	Solaris kernel, sometimes known as "Bill Joy Normal Form".
+#
+#	There's a lot this can't check for, like proper indentation of code
+#	blocks.  There's also a lot more this could check for.
+#
+#	A note to the non perl literate:
+#
+#		perl regular expressions are pretty much like egrep
+#		regular expressions, with the following special symbols
+#
+#		\s	any space character
+#		\S	any non-space character
+#		\w	any "word" character [a-zA-Z0-9_]
+#		\W	any non-word character
+#		\d	a digit [0-9]
+#		\D	a non-digit
+#		\b	word boundary (between \w and \W)
+#		\B	non-word boundary
+#
+
+require 5.0;
+use IO::File;
+use Getopt::Std;
+use strict;
+
+my $usage =
+"usage: jsstyle [-chvC] [-o constructs] file ...
+	-c	check continuation indentation inside functions
+	-h	perform heuristic checks that are sometimes wrong
+	-v	verbose
+	-C	don't check anything in header block comments
+	-o constructs
+		allow a comma-seperated list of optional constructs:
+		    doxygen	allow doxygen-style block comments (/** /*!)
+		    splint	allow splint-style lint comments (/*@ ... @*/)
+";
+
+my %opts;
+
+if (!getopts("cho:vC", \%opts)) {
+	print $usage;
+	exit 2;
+}
+
+my $check_continuation = $opts{'c'};
+my $heuristic = $opts{'h'};
+my $verbose = $opts{'v'};
+my $ignore_hdr_comment = $opts{'C'};
+
+my $doxygen_comments = 0;
+my $splint_comments = 0;
+
+if (defined($opts{'o'})) {
+	for my $x (split /,/, $opts{'o'}) {
+		if ($x eq "doxygen") {
+			$doxygen_comments = 1;
+		} elsif ($x eq "splint") {
+			$splint_comments = 1;
+		} else {
+			print "jsstyle: unrecognized construct \"$x\"\n";
+			print $usage;
+			exit 2;
+		}
+	}
+}
+
+my ($filename, $line, $prev);		# shared globals
+
+my $fmt;
+my $hdr_comment_start;
+
+if ($verbose) {
+	$fmt = "%s: %d: %s\n%s\n";
+} else {
+	$fmt = "%s: %d: %s\n";
+}
+
+if ($doxygen_comments) {
+	# doxygen comments look like "/*!" or "/**"; allow them.
+	$hdr_comment_start = qr/^\s*\/\*[\!\*]?$/;
+} else {
+	$hdr_comment_start = qr/^\s*\/\*$/;
+}
+
+# Note, following must be in single quotes so that \s and \w work right.
+my $lint_re = qr/\/\*(?:
+	jsl:\w+?|ARGSUSED[0-9]*|NOTREACHED|LINTLIBRARY|VARARGS[0-9]*|
+	CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY|
+	FALLTHRU|FALLTHROUGH|LINTED.*?|PRINTFLIKE[0-9]*|
+	PROTOLIB[0-9]*|SCANFLIKE[0-9]*|JSSTYLED.*?
+    )\*\//x;
+
+my $splint_re = qr/\/\*@.*?@\*\//x;
+
+my $err_stat = 0;		# exit status
+
+if ($#ARGV >= 0) {
+	foreach my $arg (@ARGV) {
+		my $fh = new IO::File $arg, "r";
+		if (!defined($fh)) {
+			printf "%s: cannot open\n", $arg;
+		} else {
+			&jsstyle($arg, $fh);
+			close $fh;
+		}
+	}
+} else {
+	&jsstyle("<stdin>", *STDIN);
+}
+exit $err_stat;
+
+my $no_errs = 0;		# set for JSSTYLED-protected lines
+
+sub err($) {
+	my ($error) = @_;
+	unless ($no_errs) {
+		printf $fmt, $filename, $., $error, $line;
+		$err_stat = 1;
+	}
+}
+
+sub err_prefix($$) {
+	my ($prevline, $error) = @_;
+	my $out = $prevline."\n".$line;
+	unless ($no_errs) {
+		printf $fmt, $filename, $., $error, $out;
+		$err_stat = 1;
+	}
+}
+
+sub err_prev($) {
+	my ($error) = @_;
+	unless ($no_errs) {
+		printf $fmt, $filename, $. - 1, $error, $prev;
+		$err_stat = 1;
+	}
+}
+
+sub jsstyle($$) {
+
+my ($fn, $filehandle) = @_;
+$filename = $fn;			# share it globally
+
+my $in_cpp = 0;
+my $next_in_cpp = 0;
+
+my $in_comment = 0;
+my $in_header_comment = 0;
+my $comment_done = 0;
+my $in_function = 0;
+my $in_function_header = 0;
+my $in_declaration = 0;
+my $note_level = 0;
+my $nextok = 0;
+my $nocheck = 0;
+
+my $in_string = 0;
+
+my ($okmsg, $comment_prefix);
+
+$line = '';
+$prev = '';
+reset_indent();
+
+line: while (<$filehandle>) {
+	s/\r?\n$//;	# strip return and newline
+
+	# save the original line, then remove all text from within
+	# double or single quotes, we do not want to check such text.
+
+	$line = $_;
+
+	#
+	# C allows strings to be continued with a backslash at the end of
+	# the line.  We translate that into a quoted string on the previous
+	# line followed by an initial quote on the next line.
+	#
+	# (we assume that no-one will use backslash-continuation with character
+	# constants)
+	#
+	$_ = '"' . $_		if ($in_string && !$nocheck && !$in_comment);
+
+	#
+	# normal strings and characters
+	#
+	s/'([^\\']|\\.)*'/\'\'/g;
+	s/"([^\\"]|\\.)*"/\"\"/g;
+
+	#
+	# detect string continuation
+	#
+	if ($nocheck || $in_comment) {
+		$in_string = 0;
+	} else {
+		#
+		# Now that all full strings are replaced with "", we check
+		# for unfinished strings continuing onto the next line.
+		#
+		$in_string =
+		    (s/([^"](?:"")*)"([^\\"]|\\.)*\\$/$1""/ ||
+		    s/^("")*"([^\\"]|\\.)*\\$/""/);
+	}
+
+	#
+	# figure out if we are in a cpp directive
+	#
+	$in_cpp = $next_in_cpp || /^\s*#/;	# continued or started
+	$next_in_cpp = $in_cpp && /\\$/;	# only if continued
+
+	# strip off trailing backslashes, which appear in long macros
+	s/\s*\\$//;
+
+	# an /* END JSSTYLED */ comment ends a no-check block.
+	if ($nocheck) {
+		if (/\/\* *END *JSSTYLED *\*\//) {
+			$nocheck = 0;
+		} else {
+			reset_indent();
+			next line;
+		}
+	}
+
+	# a /*JSSTYLED*/ comment indicates that the next line is ok.
+	if ($nextok) {
+		if ($okmsg) {
+			err($okmsg);
+		}
+		$nextok = 0;
+		$okmsg = 0;
+		if (/\/\* *JSSTYLED.*\*\//) {
+			/^.*\/\* *JSSTYLED *(.*) *\*\/.*$/;
+			$okmsg = $1;
+			$nextok = 1;
+		}
+		$no_errs = 1;
+	} elsif ($no_errs) {
+		$no_errs = 0;
+	}
+
+	# check length of line.
+	# first, a quick check to see if there is any chance of being too long.
+	if (($line =~ tr/\t/\t/) * 7 + length($line) > 80) {
+		# yes, there is a chance.
+		# replace tabs with spaces and check again.
+		my $eline = $line;
+		1 while $eline =~
+		    s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
+		if (length($eline) > 80) {
+			err("line > 80 characters");
+		}
+	}
+
+	# ignore NOTE(...) annotations (assumes NOTE is on lines by itself).
+	if ($note_level || /\b_?NOTE\s*\(/) { # if in NOTE or this is NOTE
+		s/[^()]//g;			  # eliminate all non-parens
+		$note_level += s/\(//g - length;  # update paren nest level
+		next;
+	}
+
+	# a /* BEGIN JSSTYLED */ comment starts a no-check block.
+	if (/\/\* *BEGIN *JSSTYLED *\*\//) {
+		$nocheck = 1;
+	}
+
+	# a /*JSSTYLED*/ comment indicates that the next line is ok.
+	if (/\/\* *JSSTYLED.*\*\//) {
+		/^.*\/\* *JSSTYLED *(.*) *\*\/.*$/;
+		$okmsg = $1;
+		$nextok = 1;
+	}
+	if (/\/\/ *JSSTYLED/) {
+		/^.*\/\/ *JSSTYLED *(.*)$/;
+		$okmsg = $1;
+		$nextok = 1;
+	}
+
+	# universal checks; apply to everything
+	if (/\t +\t/) {
+		err("spaces between tabs");
+	}
+	if (/ \t+ /) {
+		err("tabs between spaces");
+	}
+	if (/\s$/) {
+		err("space or tab at end of line");
+	}
+	if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) {
+		err("comment preceded by non-blank");
+	}
+
+	# is this the beginning or ending of a function?
+	# (not if "struct foo\n{\n")
+	if (/^{$/ && $prev =~ /\)\s*(const\s*)?(\/\*.*\*\/\s*)?\\?$/) {
+		$in_function = 1;
+		$in_declaration = 1;
+		$in_function_header = 0;
+		$prev = $line;
+		next line;
+	}
+	if (/^}\s*(\/\*.*\*\/\s*)*$/) {
+		if ($prev =~ /^\s*return\s*;/) {
+			err_prev("unneeded return at end of function");
+		}
+		$in_function = 0;
+		reset_indent();		# we don't check between functions
+		$prev = $line;
+		next line;
+	}
+	if (/^\w*\($/) {
+		$in_function_header = 1;
+	}
+
+	# a blank line terminates the declarations within a function.
+	# XXX - but still a problem in sub-blocks.
+	if ($in_declaration && /^$/) {
+		$in_declaration = 0;
+	}
+
+	if ($comment_done) {
+		$in_comment = 0;
+		$in_header_comment = 0;
+		$comment_done = 0;
+	}
+	# does this looks like the start of a block comment?
+	if (/$hdr_comment_start/) {
+		if (!/^\t*\/\*/) {
+			err("block comment not indented by tabs");
+		}
+		$in_comment = 1;
+		/^(\s*)\//;
+		$comment_prefix = $1;
+		if ($comment_prefix eq "") {
+			$in_header_comment = 1;
+		}
+		$prev = $line;
+		next line;
+	}
+	# are we still in the block comment?
+	if ($in_comment) {
+		if (/^$comment_prefix \*\/$/) {
+			$comment_done = 1;
+		} elsif (/\*\//) {
+			$comment_done = 1;
+			err("improper block comment close")
+			    unless ($ignore_hdr_comment && $in_header_comment);
+		} elsif (!/^$comment_prefix \*[ \t]/ &&
+		    !/^$comment_prefix \*$/) {
+			err("improper block comment")
+			    unless ($ignore_hdr_comment && $in_header_comment);
+		}
+	}
+
+	if ($in_header_comment && $ignore_hdr_comment) {
+		$prev = $line;
+		next line;
+	}
+
+	# check for errors that might occur in comments and in code.
+
+	# allow spaces to be used to draw pictures in header comments.
+	#if (/[^ ]     / && !/".*     .*"/ && !$in_header_comment) {
+	#	err("spaces instead of tabs");
+	#}
+	#if (/^ / && !/^ \*[ \t\/]/ && !/^ \*$/ &&
+	#    (!/^    \w/ || $in_function != 0)) {
+	#	err("indent by spaces instead of tabs");
+	#}
+	if (/^ {2,}/ && !/^    [^ ]/) {
+		err("indent by spaces instead of tabs");
+	}
+	if (/^\t+ [^ \t\*]/ || /^\t+  \S/ || /^\t+   \S/) {
+		err("continuation line not indented by 4 spaces");
+	}
+
+	if (/^\s*\/\*./ && !/^\s*\/\*.*\*\// && !/$hdr_comment_start/) {
+		err("improper first line of block comment");
+	}
+
+	if ($in_comment) {	# still in comment, don't do further checks
+		$prev = $line;
+		next line;
+	}
+
+	if ((/[^(]\/\*\S/ || /^\/\*\S/) &&
+	    !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
+		err("missing blank after open comment");
+	}
+	if (/\S\*\/[^)]|\S\*\/$/ &&
+	    !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
+		err("missing blank before close comment");
+	}
+	if (/\/\/\S/) {		# C++ comments
+		err("missing blank after start comment");
+	}
+	# check for unterminated single line comments, but allow them when
+	# they are used to comment out the argument list of a function
+	# declaration.
+	if (/\S.*\/\*/ && !/\S.*\/\*.*\*\// && !/\(\/\*/) {
+		err("unterminated single line comment");
+	}
+
+	if (/^(#else|#endif|#include)(.*)$/) {
+		$prev = $line;
+		next line;
+	}
+
+	#
+	# delete any comments and check everything else.  Note that
+	# ".*?" is a non-greedy match, so that we don't get confused by
+	# multiple comments on the same line.
+	#
+	s/\/\*.*?\*\///g;
+	s/\/\/.*$//;		# C++ comments
+
+	# delete any trailing whitespace; we have already checked for that.
+	s/\s*$//;
+
+	# following checks do not apply to text in comments.
+	if (/"/) {
+		err("literal string using double-quote instead of single");
+	}
+
+	if (/[^=!<>\s][!<>=]=/ || /[^<>!=][!<>=]==?[^\s,=]/ ||
+	    (/[^->]>[^,=>\s]/ && !/[^->]>$/) ||
+	    (/[^<]<[^,=<\s]/ && !/[^<]<$/) ||
+	    /[^<\s]<[^<]/ || /[^->\s]>[^>]/) {
+		err("missing space around relational operator");
+	}
+	if (/\S>>=/ || /\S<<=/ || />>=\S/ || /<<=\S/ || /\S[-+*\/&|^%]=/ ||
+	    (/[^-+*\/&|^%!<>=\s]=[^=]/ && !/[^-+*\/&|^%!<>=\s]=$/) ||
+	    (/[^!<>=]=[^=\s]/ && !/[^!<>=]=$/)) {
+		# XXX - should only check this for C++ code
+		# XXX - there are probably other forms that should be allowed
+		if (!/\soperator=/) {
+			err("missing space around assignment operator");
+		}
+	}
+	if (/[,;]\S/ && !/\bfor \(;;\)/) {
+		err("comma or semicolon followed by non-blank");
+	}
+	# allow "for" statements to have empty "while" clauses
+	if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) {
+		err("comma or semicolon preceded by blank");
+	}
+	if (/^\s*(&&|\|\|)/) {
+		err("improper boolean continuation");
+	}
+	if (/\S   *(&&|\|\|)/ || /(&&|\|\|)   *\S/) {
+		err("more than one space around boolean operator");
+	}
+	if (/\b(delete|typeof|instanceOf|throw|with|catch|new|function|in|for|if|while|switch|return|case)\(/) {
+		err("missing space between keyword and paren");
+	}
+	if (/(\b(catch|for|if|with|while|switch|return)\b.*){2,}/) {
+		# multiple "case" and "sizeof" allowed
+		err("more than one keyword on line");
+	}
+	if (/\b(delete|typeof|instanceOf|with|throw|catch|new|function|in|for|if|while|switch|return|case)\s\s+\(/ &&
+	    !/^#if\s+\(/) {
+		err("extra space between keyword and paren");
+	}
+	# try to detect "func (x)" but not "if (x)" or
+	# "#define foo (x)" or "int (*func)();"
+	if (/\w\s\(/) {
+		my $s = $_;
+		# strip off all keywords on the line
+		s/\b(delete|typeof|instanceOf|throw|with|catch|new|function|in|for|if|while|switch|return|case)\s\(/XXX(/g;
+		s/#elif\s\(/XXX(/g;
+		s/^#define\s+\w+\s+\(/XXX(/;
+		# do not match things like "void (*f)();"
+		# or "typedef void (func_t)();"
+		s/\w\s\(+\*/XXX(*/g;
+		s/\b(void)\s+\(+/XXX(/og;
+		if (/\w\s\(/) {
+			err("extra space between function name and left paren");
+		}
+		$_ = $s;
+	}
+
+	if (/^\s*return\W[^;]*;/ && !/^\s*return\s*\(.*\);/) {
+		err("unparenthesized return expression");
+	}
+	if (/\btypeof\b/ && !/\btypeof\s*\(.*\)/) {
+		err("unparenthesized typeof expression");
+	}
+	if (/\(\s/) {
+		err("whitespace after left paren");
+	}
+	# allow "for" statements to have empty "continue" clauses
+	if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) {
+		err("whitespace before right paren");
+	}
+	if (/^\s*\(void\)[^ ]/) {
+		err("missing space after (void) cast");
+	}
+	if (/\S{/ && !/({|\(){/) {
+		err("missing space before left brace");
+	}
+	if ($in_function && /^\s+{/ &&
+	    ($prev =~ /\)\s*$/ || $prev =~ /\bstruct\s+\w+$/)) {
+		err("left brace starting a line");
+	}
+	if (/}(else|while)/) {
+		err("missing space after right brace");
+	}
+	if (/}\s\s+(else|while)/) {
+		err("extra space after right brace");
+	}
+	if (/^\s+#/) {
+		err("preprocessor statement not in column 1");
+	}
+	if (/^#\s/) {
+		err("blank after preprocessor #");
+	}
+
+	#
+	# We completely ignore, for purposes of indentation:
+	#  * lines outside of functions
+	#  * preprocessor lines
+	#
+	if ($check_continuation && $in_function && !$in_cpp) {
+		process_indent($_);
+	}
+
+	if ($heuristic) {
+		# cannot check this everywhere due to "struct {\n...\n} foo;"
+		if ($in_function && !$in_declaration &&
+		    /}./ && !/}\s+=/ && !/{.*}[;,]$/ && !/}(\s|)*$/ &&
+		    !/} (else|while)/ && !/}}/) {
+			err("possible bad text following right brace");
+		}
+		# cannot check this because sub-blocks in
+		# the middle of code are ok
+		if ($in_function && /^\s+{/) {
+			err("possible left brace starting a line");
+		}
+	}
+	if (/^\s*else\W/) {
+		if ($prev =~ /^\s*}$/) {
+			err_prefix($prev,
+			    "else and right brace should be on same line");
+		}
+	}
+	$prev = $line;
+}
+
+if ($prev eq "") {
+	err("last line in file is blank");
+}
+
+}
+
+#
+# Continuation-line checking
+#
+# The rest of this file contains the code for the continuation checking
+# engine.  It's a pretty simple state machine which tracks the expression
+# depth (unmatched '('s and '['s).
+#
+# Keep in mind that the argument to process_indent() has already been heavily
+# processed; all comments have been replaced by control-A, and the contents of
+# strings and character constants have been elided.
+#
+
+my $cont_in;		# currently inside of a continuation
+my $cont_off;		# skipping an initializer or definition
+my $cont_noerr;		# suppress cascading errors
+my $cont_start;		# the line being continued
+my $cont_base;		# the base indentation
+my $cont_first;		# this is the first line of a statement
+my $cont_multiseg;	# this continuation has multiple segments
+
+my $cont_special;	# this is a C statement (if, for, etc.)
+my $cont_macro;		# this is a macro
+my $cont_case;		# this is a multi-line case
+
+my @cont_paren;		# the stack of unmatched ( and [s we've seen
+
+sub
+reset_indent()
+{
+	$cont_in = 0;
+	$cont_off = 0;
+}
+
+sub
+delabel($)
+{
+	#
+	# replace labels with tabs.  Note that there may be multiple
+	# labels on a line.
+	#
+	local $_ = $_[0];
+
+	while (/^(\t*)( *(?:(?:\w+\s*)|(?:case\b[^:]*)): *)(.*)$/) {
+		my ($pre_tabs, $label, $rest) = ($1, $2, $3);
+		$_ = $pre_tabs;
+		while ($label =~ s/^([^\t]*)(\t+)//) {
+			$_ .= "\t" x (length($2) + length($1) / 8);
+		}
+		$_ .= ("\t" x (length($label) / 8)).$rest;
+	}
+
+	return ($_);
+}
+
+sub
+process_indent($)
+{
+	require strict;
+	local $_ = $_[0];			# preserve the global $_
+
+	s///g;	# No comments
+	s/\s+$//;	# Strip trailing whitespace
+
+	return			if (/^$/);	# skip empty lines
+
+	# regexps used below; keywords taking (), macros, and continued cases
+	my $special = '(?:(?:\}\s*)?else\s+)?(?:if|for|while|switch)\b';
+	my $macro = '[A-Z_][A-Z_0-9]*\(';
+	my $case = 'case\b[^:]*$';
+
+	# skip over enumerations, array definitions, initializers, etc.
+	if ($cont_off <= 0 && !/^\s*$special/ &&
+	    (/(?:(?:\b(?:enum|struct|union)\s*[^\{]*)|(?:\s+=\s*)){/ ||
+	    (/^\s*{/ && $prev =~ /=\s*(?:\/\*.*\*\/\s*)*$/))) {
+		$cont_in = 0;
+		$cont_off = tr/{/{/ - tr/}/}/;
+		return;
+	}
+	if ($cont_off) {
+		$cont_off += tr/{/{/ - tr/}/}/;
+		return;
+	}
+
+	if (!$cont_in) {
+		$cont_start = $line;
+
+		if (/^\t* /) {
+			err("non-continuation indented 4 spaces");
+			$cont_noerr = 1;		# stop reporting
+		}
+		$_ = delabel($_);	# replace labels with tabs
+
+		# check if the statement is complete
+		return		if (/^\s*\}?$/);
+		return		if (/^\s*\}?\s*else\s*\{?$/);
+		return		if (/^\s*do\s*\{?$/);
+		return		if (/{$/);
+		return		if (/}[,;]?$/);
+
+		# Allow macros on their own lines
+		return		if (/^\s*[A-Z_][A-Z_0-9]*$/);
+
+		# cases we don't deal with, generally non-kosher
+		if (/{/) {
+			err("stuff after {");
+			return;
+		}
+
+		# Get the base line, and set up the state machine
+		/^(\t*)/;
+		$cont_base = $1;
+		$cont_in = 1;
+		@cont_paren = ();
+		$cont_first = 1;
+		$cont_multiseg = 0;
+
+		# certain things need special processing
+		$cont_special = /^\s*$special/? 1 : 0;
+		$cont_macro = /^\s*$macro/? 1 : 0;
+		$cont_case = /^\s*$case/? 1 : 0;
+	} else {
+		$cont_first = 0;
+
+		# Strings may be pulled back to an earlier (half-)tabstop
+		unless ($cont_noerr || /^$cont_base    / ||
+		    (/^\t*(?:    )?(?:gettext\()?\"/ && !/^$cont_base\t/)) {
+			err_prefix($cont_start,
+			    "continuation should be indented 4 spaces");
+		}
+	}
+
+	my $rest = $_;			# keeps the remainder of the line
+
+	#
+	# The split matches 0 characters, so that each 'special' character
+	# is processed separately.  Parens and brackets are pushed and
+	# popped off the @cont_paren stack.  For normal processing, we wait
+	# until a ; or { terminates the statement.  "special" processing
+	# (if/for/while/switch) is allowed to stop when the stack empties,
+	# as is macro processing.  Case statements are terminated with a :
+	# and an empty paren stack.
+	#
+	foreach $_ (split /[^\(\)\[\]\{\}\;\:]*/) {
+		next		if (length($_) == 0);
+
+		# rest contains the remainder of the line
+		my $rxp = "[^\Q$_\E]*\Q$_\E";
+		$rest =~ s/^$rxp//;
+
+		if (/\(/ || /\[/) {
+			push @cont_paren, $_;
+		} elsif (/\)/ || /\]/) {
+			my $cur = $_;
+			tr/\)\]/\(\[/;
+
+			my $old = (pop @cont_paren);
+			if (!defined($old)) {
+				err("unexpected '$cur'");
+				$cont_in = 0;
+				last;
+			} elsif ($old ne $_) {
+				err("'$cur' mismatched with '$old'");
+				$cont_in = 0;
+				last;
+			}
+
+			#
+			# If the stack is now empty, do special processing
+			# for if/for/while/switch and macro statements.
+			#
+			next		if (@cont_paren != 0);
+			if ($cont_special) {
+				if ($rest =~ /^\s*{?$/) {
+					$cont_in = 0;
+					last;
+				}
+				if ($rest =~ /^\s*;$/) {
+					err("empty if/for/while body ".
+					    "not on its own line");
+					$cont_in = 0;
+					last;
+				}
+				if (!$cont_first && $cont_multiseg == 1) {
+					err_prefix($cont_start,
+					    "multiple statements continued ".
+					    "over multiple lines");
+					$cont_multiseg = 2;
+				} elsif ($cont_multiseg == 0) {
+					$cont_multiseg = 1;
+				}
+				# We've finished this section, start
+				# processing the next.
+				goto section_ended;
+			}
+			if ($cont_macro) {
+				if ($rest =~ /^$/) {
+					$cont_in = 0;
+					last;
+				}
+			}
+		} elsif (/\;/) {
+			if ($cont_case) {
+				err("unexpected ;");
+			} elsif (!$cont_special) {
+				err("unexpected ;")	if (@cont_paren != 0);
+				if (!$cont_first && $cont_multiseg == 1) {
+					err_prefix($cont_start,
+					    "multiple statements continued ".
+					    "over multiple lines");
+					$cont_multiseg = 2;
+				} elsif ($cont_multiseg == 0) {
+					$cont_multiseg = 1;
+				}
+				if ($rest =~ /^$/) {
+					$cont_in = 0;
+					last;
+				}
+				if ($rest =~ /^\s*special/) {
+					err("if/for/while/switch not started ".
+					    "on its own line");
+				}
+				goto section_ended;
+			}
+		} elsif (/\{/) {
+			err("{ while in parens/brackets") if (@cont_paren != 0);
+			err("stuff after {")		if ($rest =~ /[^\s}]/);
+			$cont_in = 0;
+			last;
+		} elsif (/\}/) {
+			err("} while in parens/brackets") if (@cont_paren != 0);
+			if (!$cont_special && $rest !~ /^\s*(while|else)\b/) {
+				if ($rest =~ /^$/) {
+					err("unexpected }");
+				} else {
+					err("stuff after }");
+				}
+				$cont_in = 0;
+				last;
+			}
+		} elsif (/\:/ && $cont_case && @cont_paren == 0) {
+			err("stuff after multi-line case") if ($rest !~ /$^/);
+			$cont_in = 0;
+			last;
+		}
+		next;
+section_ended:
+		# End of a statement or if/while/for loop.  Reset
+		# cont_special and cont_macro based on the rest of the
+		# line.
+		$cont_special = ($rest =~ /^\s*$special/)? 1 : 0;
+		$cont_macro = ($rest =~ /^\s*$macro/)? 1 : 0;
+		$cont_case = 0;
+		next;
+	}
+	$cont_noerr = 0			if (!$cont_in);
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/float.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/float.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/float.json	(revision 517)
@@ -0,0 +1,13 @@
+{ "metadata":
+	{
+		"ctf2json_version": "1.0",
+		"created_at": 1316563626,
+		"derived_from": "/lib/libc.so",
+		"ctf_version": 2,
+		"requested_types": [ "float" ]
+	},
+"data":
+	[
+		{ "name": "float", "float": { "length": 4 } }
+	]
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/int.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/int.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/int.json	(revision 517)
@@ -0,0 +1,13 @@
+{ "metadata":
+	{
+		"ctf2json_version": "1.0",
+		"created_at": 1316563631,
+		"derived_from": "/lib/libc.so",
+		"ctf_version": 2,
+		"requested_types": [ "int" ]
+	},
+"data":
+	[
+		{ "name": "int", "integer": { "length": 4, "signed": true } }
+	]
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/psinfo.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/psinfo.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/psinfo.json	(revision 517)
@@ -0,0 +1,104 @@
+{ "metadata":
+	{
+		"ctf2json_version": "1.0",
+		"created_at": 1316563573,
+		"derived_from": "/lib/libc.so",
+		"ctf_version": 2,
+		"requested_types": [ "psinfo_t" ]
+	},
+"data":
+	[
+		{ "name": "int", "integer": { "length": 4, "signed": true } },
+		{ "name": "char", "integer": { "length": 1, "signed": true } },
+		{ "name": "unsigned short", "integer": { "length": 2, "signed": false } },
+		{ "name": "long", "integer": { "length": 4, "signed": true } },
+		{ "name": "unsigned", "integer": { "length": 4, "signed": false } },
+		{ "name": "size_t", "typedef": "unsigned" },
+		{ "name": "unsigned long", "integer": { "length": 4, "signed": false } },
+		{ "name": "time_t", "typedef": "long" },
+		{ "name": "struct timespec", "struct": [
+			{ "name": "tv_sec", "type": "time_t" },
+			{ "name": "tv_nsec", "type": "long" }
+		] },
+		{ "name": "zoneid_t", "typedef": "long" },
+		{ "name": "taskid_t", "typedef": "long" },
+		{ "name": "dev_t", "typedef": "unsigned long" },
+		{ "name": "uid_t", "typedef": "unsigned" },
+		{ "name": "gid_t", "typedef": "unsigned" },
+		{ "name": "timestruc_t", "typedef": "struct timespec" },
+		{ "name": "short", "integer": { "length": 2, "signed": true } },
+		{ "name": "projid_t", "typedef": "long" },
+		{ "name": "ushort_t", "typedef": "unsigned short" },
+		{ "name": "poolid_t", "typedef": "long" },
+		{ "name": "uintptr_t", "typedef": "unsigned" },
+		{ "name": "id_t", "typedef": "long" },
+		{ "name": "pid_t", "typedef": "long" },
+		{ "name": "processorid_t", "typedef": "int" },
+		{ "name": "psetid_t", "typedef": "int" },
+		{ "name": "struct lwpsinfo", "struct": [
+			{ "name": "pr_flag", "type": "int" },
+			{ "name": "pr_lwpid", "type": "id_t" },
+			{ "name": "pr_addr", "type": "uintptr_t" },
+			{ "name": "pr_wchan", "type": "uintptr_t" },
+			{ "name": "pr_stype", "type": "char" },
+			{ "name": "pr_state", "type": "char" },
+			{ "name": "pr_sname", "type": "char" },
+			{ "name": "pr_nice", "type": "char" },
+			{ "name": "pr_syscall", "type": "short" },
+			{ "name": "pr_oldpri", "type": "char" },
+			{ "name": "pr_cpu", "type": "char" },
+			{ "name": "pr_pri", "type": "int" },
+			{ "name": "pr_pctcpu", "type": "ushort_t" },
+			{ "name": "pr_pad", "type": "ushort_t" },
+			{ "name": "pr_start", "type": "timestruc_t" },
+			{ "name": "pr_time", "type": "timestruc_t" },
+			{ "name": "pr_clname", "type": "char [8]" },
+			{ "name": "pr_name", "type": "char [16]" },
+			{ "name": "pr_onpro", "type": "processorid_t" },
+			{ "name": "pr_bindpro", "type": "processorid_t" },
+			{ "name": "pr_bindpset", "type": "psetid_t" },
+			{ "name": "pr_lgrp", "type": "int" },
+			{ "name": "pr_filler", "type": "int [4]" }
+		] },
+		{ "name": "lwpsinfo_t", "typedef": "struct lwpsinfo" },
+		{ "name": "struct psinfo", "struct": [
+			{ "name": "pr_flag", "type": "int" },
+			{ "name": "pr_nlwp", "type": "int" },
+			{ "name": "pr_pid", "type": "pid_t" },
+			{ "name": "pr_ppid", "type": "pid_t" },
+			{ "name": "pr_pgid", "type": "pid_t" },
+			{ "name": "pr_sid", "type": "pid_t" },
+			{ "name": "pr_uid", "type": "uid_t" },
+			{ "name": "pr_euid", "type": "uid_t" },
+			{ "name": "pr_gid", "type": "gid_t" },
+			{ "name": "pr_egid", "type": "gid_t" },
+			{ "name": "pr_addr", "type": "uintptr_t" },
+			{ "name": "pr_size", "type": "size_t" },
+			{ "name": "pr_rssize", "type": "size_t" },
+			{ "name": "pr_pad1", "type": "size_t" },
+			{ "name": "pr_ttydev", "type": "dev_t" },
+			{ "name": "pr_pctcpu", "type": "ushort_t" },
+			{ "name": "pr_pctmem", "type": "ushort_t" },
+			{ "name": "pr_start", "type": "timestruc_t" },
+			{ "name": "pr_time", "type": "timestruc_t" },
+			{ "name": "pr_ctime", "type": "timestruc_t" },
+			{ "name": "pr_fname", "type": "char [16]" },
+			{ "name": "pr_psargs", "type": "char [80]" },
+			{ "name": "pr_wstat", "type": "int" },
+			{ "name": "pr_argc", "type": "int" },
+			{ "name": "pr_argv", "type": "uintptr_t" },
+			{ "name": "pr_envp", "type": "uintptr_t" },
+			{ "name": "pr_dmodel", "type": "char" },
+			{ "name": "pr_pad2", "type": "char [3]" },
+			{ "name": "pr_taskid", "type": "taskid_t" },
+			{ "name": "pr_projid", "type": "projid_t" },
+			{ "name": "pr_nzomb", "type": "int" },
+			{ "name": "pr_poolid", "type": "poolid_t" },
+			{ "name": "pr_zoneid", "type": "zoneid_t" },
+			{ "name": "pr_contract", "type": "id_t" },
+			{ "name": "pr_filler", "type": "int [1]" },
+			{ "name": "pr_lwp", "type": "lwpsinfo_t" }
+		] },
+		{ "name": "psinfo_t", "typedef": "struct psinfo" }
+	]
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/struct.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/struct.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/struct.json	(revision 517)
@@ -0,0 +1,19 @@
+{ "metadata":
+	{
+		"ctf2json_version": "1.0",
+		"created_at": 1316563648,
+		"derived_from": "/lib/libc.so",
+		"ctf_version": 2,
+		"requested_types": [ "timestruc_t" ]
+	},
+"data":
+	[
+		{ "name": "long", "integer": { "length": 4, "signed": true } },
+		{ "name": "time_t", "typedef": "long" },
+		{ "name": "struct timespec", "struct": [
+			{ "name": "tv_sec", "type": "time_t" },
+			{ "name": "tv_nsec", "type": "long" }
+		] },
+		{ "name": "timestruc_t", "typedef": "struct timespec" }
+	]
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.fail.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.fail.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.fail.js	(revision 517)
@@ -0,0 +1,39 @@
+/*
+ * Test several conditions that should always cause us to throw.
+ */
+var mod_assert = require('assert');
+var mod_ctype = require('../../ctype.js');
+
+var cases = [
+{ json: { }, msg: 'bad JSON - no metadata or data' },
+{ json: { metadata: {} }, msg: 'bad JSON - bad metadata section' },
+{ json: { metadata: { 'JSON version': [] } },
+    msg: 'bad JSON - bad JSON version' },
+{ json: { metadata: { 'JSON version': 2 } },
+    msg: 'bad JSON - bad JSON version' },
+{ json: { metadata: { 'JSON version': '100.20' } },
+    msg: 'bad JSON - bad JSON version' },
+{ json: { metadata: { 'JSON version': '1.0' } },
+    msg: 'missing data section' },
+{ json: { metadata: { 'JSON version': '1.0' }, data: 1 },
+    msg: 'invalid data section' },
+{ json: { metadata: { 'JSON version': '1.0' }, data: 1.1 },
+    msg: 'invalid data section' },
+{ json: { metadata: { 'JSON version': '1.0' }, data: '1.1' },
+    msg: 'invalid data section' },
+{ json: { metadata: { 'JSON version': '1.0' }, data: {} },
+    msg: 'invalid data section' }
+];
+
+function test()
+{
+	var ii;
+
+	for (ii = 0; ii < cases.length; ii++) {
+		mod_assert.throws(function () {
+		    mod_ctype.parseCTF(cases[ii].json);
+		}, Error, cases[ii].msg);
+	}
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.float.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.float.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.float.js	(revision 517)
@@ -0,0 +1,14 @@
+var mod_fs = require('fs');
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var data, parser;
+
+	data = JSON.parse(mod_fs.readFileSync('./float.json').toString());
+	parser = mod_ctype.parseCTF(data, { endian: 'big' });
+	mod_assert.deepEqual(parser.lstypes(), {});
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.int.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.int.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.int.js	(revision 517)
@@ -0,0 +1,14 @@
+var mod_fs = require('fs');
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var data, parser;
+
+	data = JSON.parse(mod_fs.readFileSync('./int.json').toString());
+	parser = mod_ctype.parseCTF(data, { endian: 'big' });
+	mod_assert.deepEqual(parser.lstypes(), { 'int': 'int32_t' });
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.psinfo.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.psinfo.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.psinfo.js	(revision 517)
@@ -0,0 +1,17 @@
+var mod_fs = require('fs');
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+/*
+ * This is too unwieldly to actually write out. Just make sure we can parse it
+ * without errrors.
+ */
+function test()
+{
+	var data;
+
+	data = JSON.parse(mod_fs.readFileSync('./psinfo.json').toString());
+	mod_ctype.parseCTF(data, { endian: 'big' });
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.struct.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.struct.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.struct.js	(revision 517)
@@ -0,0 +1,18 @@
+var mod_fs = require('fs');
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var data, parser;
+
+	data = JSON.parse(mod_fs.readFileSync('./struct.json').toString());
+	parser = mod_ctype.parseCTF(data, { endian: 'big' });
+	mod_assert.deepEqual(parser.lstypes(), { 'long': 'int32_t',
+	    'time_t': 'long',
+	    'timestruc_t': 'struct timespec',
+	    'struct timespec': [ { 'tv_sec': { 'type': 'time_t' } },
+	        { 'tv_nsec': { 'type': 'long' } } ] });
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.typedef.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.typedef.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/tst.typedef.js	(revision 517)
@@ -0,0 +1,15 @@
+var mod_fs = require('fs');
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var data, parser;
+
+	data = JSON.parse(mod_fs.readFileSync('./typedef.json').toString());
+	parser = mod_ctype.parseCTF(data, { endian: 'big' });
+	mod_assert.deepEqual(parser.lstypes(), { 'bar_t': 'int',
+	    'int': 'int32_t' });
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/typedef.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/typedef.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctf/typedef.json	(revision 517)
@@ -0,0 +1,14 @@
+{ "metadata":
+	{
+		"ctf2json_version": "1.0",
+		"created_at": 1316302348,
+		"derived_from": "/lib/libc.so",
+		"ctf_version": 2,
+		"requested_types": [ "bar_t" ]
+	},
+"data":
+	[
+		{ "name": "int", "integer": { "length": 4, "signed": true } },
+		{ "name": "bar_t", "typedef": "int" }
+	]
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/float/tst.rfloat.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/float/tst.rfloat.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/float/tst.rfloat.js	(revision 517)
@@ -0,0 +1,767 @@
+/*
+ * Battery of tests to break our floating point implementation. Oh ho ho.
+ *
+ * There are a few useful ways to generate the expected output. The first is
+ * just write a C program and write raw bytes out and inspect with xxd. Remember
+ * to consider whether or not you're on a big endian or little endian machine.
+ * Another useful site I found to help with some of this was:
+ *
+ * http://babbage.cs.qc.edu/IEEE-754/
+ */
+
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+function testfloat()
+{
+	var buffer = new Buffer(4);
+	/* Start off with some of the easy ones: +zero */
+	buffer[0] = 0;
+	buffer[1] = 0;
+	buffer[2] = 0;
+	buffer[3] = 0;
+
+	ASSERT.equal(0, mod_ctype.rfloat(buffer, 'big', 0));
+	ASSERT.equal(0, mod_ctype.rfloat(buffer, 'little', 0));
+
+	/* Test -0 */
+	buffer[0] = 0x80;
+	ASSERT.equal(0, mod_ctype.rfloat(buffer, 'big', 0));
+	buffer[3] = buffer[0];
+	buffer[0] = 0;
+	ASSERT.equal(0, mod_ctype.rfloat(buffer, 'little', 0));
+
+	/* Catch +infin */
+	buffer[0] = 0x7f;
+	buffer[1] = 0x80;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	ASSERT.equal(Number.POSITIVE_INFINITY,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+	buffer[3] = 0x7f;
+	buffer[2] = 0x80;
+	buffer[1] = 0x00;
+	buffer[0] = 0x00;
+	ASSERT.equal(Number.POSITIVE_INFINITY,
+	    mod_ctype.rfloat(buffer, 'litle', 0));
+
+	/* Catch -infin */
+	buffer[0] = 0xff;
+	buffer[1] = 0x80;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	ASSERT.equal(Number.NEGATIVE_INFINITY,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+	buffer[3] = 0xff;
+	buffer[2] = 0x80;
+	buffer[1] = 0x00;
+	buffer[0] = 0x00;
+	ASSERT.equal(Number.NEGATIVE_INFINITY,
+	    mod_ctype.rfloat(buffer, 'litle', 0));
+
+	/* Catch NaN */
+
+	buffer[0] = 0x7f;
+	buffer[1] = 0x80;
+	buffer[2] = 0x00;
+	buffer[3] = 0x23;
+	ASSERT.ok(isNaN(mod_ctype.rfloat(buffer, 'big', 0)));
+	buffer[3] = 0x7f;
+	buffer[2] = 0x80;
+	buffer[1] = 0x00;
+	buffer[0] = 0x23;
+	ASSERT.ok(isNaN(mod_ctype.rfloat(buffer, 'little', 0)));
+
+	/* Catch -infin */
+	buffer[0] = 0xff;
+	buffer[1] = 0x80;
+	buffer[2] = 0x00;
+	buffer[3] = 0x23;
+	ASSERT.ok(isNaN(mod_ctype.rfloat(buffer, 'big', 0)));
+	buffer[3] = 0xff;
+	buffer[2] = 0x80;
+	buffer[1] = 0x00;
+	buffer[0] = 0x23;
+	ASSERT.ok(isNaN(mod_ctype.rfloat(buffer, 'little', 0)));
+
+	/* On to some basic tests */
+	/* 1.125 */
+	buffer[0] = 0x3f;
+	buffer[1] = 0x90;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	ASSERT.equal(1.125, mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x3f;
+	buffer[2] = 0x90;
+	buffer[1] = 0x00;
+	buffer[0] = 0x00;
+	ASSERT.equal(1.125, mod_ctype.rfloat(buffer, 'little', 0));
+
+	/* ff34a2b0 -2.4010576103645774e+38 */
+	buffer[0] = 0xff;
+	buffer[1] = 0x34;
+	buffer[2] = 0xa2;
+	buffer[3] = 0xb0;
+	ASSERT.equal(-2.4010576103645774e+38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0xff;
+	buffer[2] = 0x34;
+	buffer[1] = 0xa2;
+	buffer[0] = 0xb0;
+	ASSERT.equal(-2.4010576103645774e+38,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	/* Denormalized tests */
+
+	/* 0003f89a +/- 3.6468792534053364e-40 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x03;
+	buffer[2] = 0xf8;
+	buffer[3] = 0x9a;
+	ASSERT.equal(3.6468792534053364e-40,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x00;
+	buffer[2] = 0x03;
+	buffer[1] = 0xf8;
+	buffer[0] = 0x9a;
+	ASSERT.equal(3.6468792534053364e-40,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x03;
+	buffer[2] = 0xf8;
+	buffer[3] = 0x9a;
+	ASSERT.equal(-3.6468792534053364e-40,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x80;
+	buffer[2] = 0x03;
+	buffer[1] = 0xf8;
+	buffer[0] = 0x9a;
+	ASSERT.equal(-3.6468792534053364e-40,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+
+	/* Maximum and minimum normalized and denormalized values */
+
+	/* Largest normalized number +/- 3.4028234663852886e+38 */
+
+	buffer[0] = 0x7f;
+	buffer[1] = 0x7f;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	ASSERT.equal(3.4028234663852886e+38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x7f;
+	buffer[2] = 0x7f;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(3.4028234663852886e+38,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	buffer[0] = 0xff;
+	buffer[1] = 0x7f;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	ASSERT.equal(-3.4028234663852886e+38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0xff;
+	buffer[2] = 0x7f;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(-3.4028234663852886e+38,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	/* Smallest normalied number +/- 1.1754943508222875e-38 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x80;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	ASSERT.equal(1.1754943508222875e-38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x00;
+	buffer[2] = 0x80;
+	buffer[1] = 0x00;
+	buffer[0] = 0x00;
+	ASSERT.equal(1.1754943508222875e-38,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x80;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	ASSERT.equal(-1.1754943508222875e-38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x80;
+	buffer[2] = 0x80;
+	buffer[1] = 0x00;
+	buffer[0] = 0x00;
+	ASSERT.equal(-1.1754943508222875e-38,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+
+	/* Smallest denormalized number 1.401298464324817e-45 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x00;
+	buffer[2] = 0x00;
+	buffer[3] = 0x01;
+	ASSERT.equal(1.401298464324817e-45,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x00;
+	buffer[2] = 0x00;
+	buffer[1] = 0x00;
+	buffer[0] = 0x01;
+	ASSERT.equal(1.401298464324817e-45,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x00;
+	buffer[2] = 0x00;
+	buffer[3] = 0x01;
+	ASSERT.equal(-1.401298464324817e-45,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x80;
+	buffer[2] = 0x00;
+	buffer[1] = 0x00;
+	buffer[0] = 0x01;
+	ASSERT.equal(-1.401298464324817e-45,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	/* Largest denormalized value +/- 1.1754942106924411e-38 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x7f;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	ASSERT.equal(1.1754942106924411e-38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x00;
+	buffer[2] = 0x7f;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(1.1754942106924411e-38,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x7f;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	ASSERT.equal(-1.1754942106924411e-38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+
+	buffer[3] = 0x80;
+	buffer[2] = 0x7f;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(-1.1754942106924411e-38,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+
+	/* Do some quick offset testing */
+	buffer = new Buffer(6);
+	buffer[0] = 0x7f;
+	buffer[1] = 0x4e;
+	buffer[2] = 0x8a;
+	buffer[3] = 0x79;
+	buffer[4] = 0xcd;
+	buffer[5] = 0x3f;
+
+	ASSERT.equal(2.745399582697325e+38,
+	    mod_ctype.rfloat(buffer, 'big', 0));
+	ASSERT.equal(1161619072,
+	    mod_ctype.rfloat(buffer, 'big', 1));
+	ASSERT.equal(-1.2027516403607578e-32,
+	    mod_ctype.rfloat(buffer, 'big', 2));
+
+	ASSERT.equal(8.97661320504413e+34,
+	    mod_ctype.rfloat(buffer, 'little', 0));
+	ASSERT.equal(-261661920,
+	    mod_ctype.rfloat(buffer, 'little', 1));
+	ASSERT.equal(1.605271577835083,
+	    mod_ctype.rfloat(buffer, 'little', 2));
+
+}
+
+function testdouble()
+{
+	var buffer = new Buffer(10);
+
+	/* Check 0 */
+	buffer[0] = 0;
+	buffer[1] = 0;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 0;
+	ASSERT.equal(0,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+	ASSERT.equal(0,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 0;
+	ASSERT.equal(0,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+	buffer[7] = 0x80;
+	buffer[6] = 0;
+	buffer[5] = 0;
+	buffer[4] = 0;
+	buffer[3] = 0;
+	buffer[2] = 0;
+	buffer[1] = 0;
+	buffer[0] = 0;
+	ASSERT.equal(0,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Check NaN */
+	buffer[0] = 0x7f;
+	buffer[1] = 0xf0;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 23;
+	ASSERT.ok(isNaN(mod_ctype.rdouble(buffer, 'big', 0)));
+
+	buffer[7] = 0x7f;
+	buffer[6] = 0xf0;
+	buffer[5] = 0;
+	buffer[4] = 0;
+	buffer[3] = 0;
+	buffer[2] = 0;
+	buffer[1] = 0;
+	buffer[0] = 23;
+	ASSERT.ok(isNaN(mod_ctype.rdouble(buffer, 'little', 0)));
+
+	buffer[0] = 0xff;
+	buffer[1] = 0xf0;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 23;
+	ASSERT.ok(isNaN(mod_ctype.rdouble(buffer, 'big', 0)));
+
+	buffer[7] = 0xff;
+	buffer[6] = 0xf0;
+	buffer[5] = 0;
+	buffer[4] = 0;
+	buffer[3] = 0;
+	buffer[2] = 0;
+	buffer[1] = 0;
+	buffer[0] = 23;
+	ASSERT.ok(isNaN(mod_ctype.rdouble(buffer, 'little', 0)));
+
+	/* pos inf */
+	buffer[0] = 0x7f;
+	buffer[1] = 0xf0;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 0;
+	ASSERT.equal(Number.POSITIVE_INFINITY,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x7f;
+	buffer[6] = 0xf0;
+	buffer[5] = 0;
+	buffer[4] = 0;
+	buffer[3] = 0;
+	buffer[2] = 0;
+	buffer[1] = 0;
+	buffer[0] = 0;
+	ASSERT.equal(Number.POSITIVE_INFINITY,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* neg inf */
+	buffer[0] = 0xff;
+	buffer[1] = 0xf0;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 0;
+	ASSERT.equal(Number.NEGATIVE_INFINITY,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0xff;
+	buffer[6] = 0xf0;
+	buffer[5] = 0;
+	buffer[4] = 0;
+	buffer[3] = 0;
+	buffer[2] = 0;
+	buffer[1] = 0;
+	buffer[0] = 0;
+	ASSERT.equal(Number.NEGATIVE_INFINITY,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Simple normalized values */
+
+	/* +/- 1.125 */
+	buffer[0] = 0x3f;
+	buffer[1] = 0xf2;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 0;
+	ASSERT.equal(1.125,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x3f;
+	buffer[6] = 0xf2;
+	buffer[5] = 0;
+	buffer[4] = 0;
+	buffer[3] = 0;
+	buffer[2] = 0;
+	buffer[1] = 0;
+	buffer[0] = 0;
+	ASSERT.equal(1.125,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0xbf;
+	buffer[1] = 0xf2;
+	buffer[2] = 0;
+	buffer[3] = 0;
+	buffer[4] = 0;
+	buffer[5] = 0;
+	buffer[6] = 0;
+	buffer[7] = 0;
+	ASSERT.equal(-1.125,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0xbf;
+	buffer[6] = 0xf2;
+	buffer[5] = 0;
+	buffer[4] = 0;
+	buffer[3] = 0;
+	buffer[2] = 0;
+	buffer[1] = 0;
+	buffer[0] = 0;
+	ASSERT.equal(-1.125,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* +/- 1.4397318913736026e+283 */
+	buffer[0] = 0x7a;
+	buffer[1] = 0xb8;
+	buffer[2] = 0xc9;
+	buffer[3] = 0x34;
+	buffer[4] = 0x72;
+	buffer[5] = 0x16;
+	buffer[6] = 0xf9;
+	buffer[7] = 0x0e;
+	ASSERT.equal(1.4397318913736026e+283,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x7a;
+	buffer[6] = 0xb8;
+	buffer[5] = 0xc9;
+	buffer[4] = 0x34;
+	buffer[3] = 0x72;
+	buffer[2] = 0x16;
+	buffer[1] = 0xf9;
+	buffer[0] = 0x0e;
+	ASSERT.equal(1.4397318913736026e+283,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0xfa;
+	buffer[1] = 0xb8;
+	buffer[2] = 0xc9;
+	buffer[3] = 0x34;
+	buffer[4] = 0x72;
+	buffer[5] = 0x16;
+	buffer[6] = 0xf9;
+	buffer[7] = 0x0e;
+	ASSERT.equal(-1.4397318913736026e+283,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0xfa;
+	buffer[6] = 0xb8;
+	buffer[5] = 0xc9;
+	buffer[4] = 0x34;
+	buffer[3] = 0x72;
+	buffer[2] = 0x16;
+	buffer[1] = 0xf9;
+	buffer[0] = 0x0e;
+	ASSERT.equal(-1.4397318913736026e+283,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Denormalized values */
+	/* +/- 8.82521232268344e-309 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x06;
+	buffer[2] = 0x58;
+	buffer[3] = 0x94;
+	buffer[4] = 0x13;
+	buffer[5] = 0x27;
+	buffer[6] = 0x8a;
+	buffer[7] = 0xcd;
+	ASSERT.equal(8.82521232268344e-309,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x00;
+	buffer[6] = 0x06;
+	buffer[5] = 0x58;
+	buffer[4] = 0x94;
+	buffer[3] = 0x13;
+	buffer[2] = 0x27;
+	buffer[1] = 0x8a;
+	buffer[0] = 0xcd;
+	ASSERT.equal(8.82521232268344e-309,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x06;
+	buffer[2] = 0x58;
+	buffer[3] = 0x94;
+	buffer[4] = 0x13;
+	buffer[5] = 0x27;
+	buffer[6] = 0x8a;
+	buffer[7] = 0xcd;
+	ASSERT.equal(-8.82521232268344e-309,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x80;
+	buffer[6] = 0x06;
+	buffer[5] = 0x58;
+	buffer[4] = 0x94;
+	buffer[3] = 0x13;
+	buffer[2] = 0x27;
+	buffer[1] = 0x8a;
+	buffer[0] = 0xcd;
+	ASSERT.equal(-8.82521232268344e-309,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Edge cases, maximum and minimum values */
+
+	/* Smallest denormalized value 5e-324 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x00;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	buffer[4] = 0x00;
+	buffer[5] = 0x00;
+	buffer[6] = 0x00;
+	buffer[7] = 0x01;
+	ASSERT.equal(5e-324,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x00;
+	buffer[6] = 0x00;
+	buffer[5] = 0x00;
+	buffer[4] = 0x00;
+	buffer[3] = 0x00;
+	buffer[2] = 0x00;
+	buffer[1] = 0x00;
+	buffer[0] = 0x01;
+	ASSERT.equal(5e-324,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x00;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	buffer[4] = 0x00;
+	buffer[5] = 0x00;
+	buffer[6] = 0x00;
+	buffer[7] = 0x01;
+	ASSERT.equal(-5e-324,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x80;
+	buffer[6] = 0x00;
+	buffer[5] = 0x00;
+	buffer[4] = 0x00;
+	buffer[3] = 0x00;
+	buffer[2] = 0x00;
+	buffer[1] = 0x00;
+	buffer[0] = 0x01;
+	ASSERT.equal(-5e-324,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Largest denormalized value 2.225073858507201e-308 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x0f;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	buffer[4] = 0xff;
+	buffer[5] = 0xff;
+	buffer[6] = 0xff;
+	buffer[7] = 0xff;
+	ASSERT.equal(2.225073858507201e-308,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x00;
+	buffer[6] = 0x0f;
+	buffer[5] = 0xff;
+	buffer[4] = 0xff;
+	buffer[3] = 0xff;
+	buffer[2] = 0xff;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(2.225073858507201e-308,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x0f;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	buffer[4] = 0xff;
+	buffer[5] = 0xff;
+	buffer[6] = 0xff;
+	buffer[7] = 0xff;
+	ASSERT.equal(-2.225073858507201e-308,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x80;
+	buffer[6] = 0x0f;
+	buffer[5] = 0xff;
+	buffer[4] = 0xff;
+	buffer[3] = 0xff;
+	buffer[2] = 0xff;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(-2.225073858507201e-308,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Smallest normalized value 2.2250738585072014e-308 */
+	buffer[0] = 0x00;
+	buffer[1] = 0x10;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	buffer[4] = 0x00;
+	buffer[5] = 0x00;
+	buffer[6] = 0x00;
+	buffer[7] = 0x00;
+	ASSERT.equal(2.2250738585072014e-308,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x00;
+	buffer[6] = 0x10;
+	buffer[5] = 0x00;
+	buffer[4] = 0x00;
+	buffer[3] = 0x00;
+	buffer[2] = 0x00;
+	buffer[1] = 0x00;
+	buffer[0] = 0x00;
+	ASSERT.equal(2.2250738585072014e-308,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0x80;
+	buffer[1] = 0x10;
+	buffer[2] = 0x00;
+	buffer[3] = 0x00;
+	buffer[4] = 0x00;
+	buffer[5] = 0x00;
+	buffer[6] = 0x00;
+	buffer[7] = 0x00;
+	ASSERT.equal(-2.2250738585072014e-308,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x80;
+	buffer[6] = 0x10;
+	buffer[5] = 0x00;
+	buffer[4] = 0x00;
+	buffer[3] = 0x00;
+	buffer[2] = 0x00;
+	buffer[1] = 0x00;
+	buffer[0] = 0x00;
+	ASSERT.equal(-2.2250738585072014e-308,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Largest normalized value 1.7976931348623157e+308 */
+	buffer[0] = 0x7f;
+	buffer[1] = 0xef;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	buffer[4] = 0xff;
+	buffer[5] = 0xff;
+	buffer[6] = 0xff;
+	buffer[7] = 0xff;
+	ASSERT.equal(1.7976931348623157e+308,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0x7f;
+	buffer[6] = 0xef;
+	buffer[5] = 0xff;
+	buffer[4] = 0xff;
+	buffer[3] = 0xff;
+	buffer[2] = 0xff;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(1.7976931348623157e+308,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	buffer[0] = 0xff;
+	buffer[1] = 0xef;
+	buffer[2] = 0xff;
+	buffer[3] = 0xff;
+	buffer[4] = 0xff;
+	buffer[5] = 0xff;
+	buffer[6] = 0xff;
+	buffer[7] = 0xff;
+	ASSERT.equal(-1.7976931348623157e+308,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+
+	buffer[7] = 0xff;
+	buffer[6] = 0xef;
+	buffer[5] = 0xff;
+	buffer[4] = 0xff;
+	buffer[3] = 0xff;
+	buffer[2] = 0xff;
+	buffer[1] = 0xff;
+	buffer[0] = 0xff;
+	ASSERT.equal(-1.7976931348623157e+308,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+
+	/* Try offsets */
+	buffer[0] = 0xde;
+	buffer[1] = 0xad;
+	buffer[2] = 0xbe;
+	buffer[3] = 0xef;
+	buffer[4] = 0xba;
+	buffer[5] = 0xdd;
+	buffer[6] = 0xca;
+	buffer[7] = 0xfe;
+	buffer[8] = 0x16;
+	buffer[9] = 0x79;
+
+	ASSERT.equal(-1.1885958404126936e+148,
+	    mod_ctype.rdouble(buffer, 'big', 0));
+	ASSERT.equal(-2.4299184080448593e-88,
+	    mod_ctype.rdouble(buffer, 'big', 1));
+	ASSERT.equal(-0.000015130017658081283,
+	    mod_ctype.rdouble(buffer, 'big', 2));
+
+	ASSERT.equal(-5.757458694845505e+302,
+	    mod_ctype.rdouble(buffer, 'little', 0));
+	ASSERT.equal(6.436459604192476e-198,
+	    mod_ctype.rdouble(buffer, 'little', 1));
+	ASSERT.equal(1.9903745632417286e+275,
+	    mod_ctype.rdouble(buffer, 'little', 2));
+}
+
+testfloat();
+testdouble();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/float/tst.wfloat.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/float/tst.wfloat.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/float/tst.wfloat.js	(revision 517)
@@ -0,0 +1,753 @@
+/*
+ * Another place to find bugs that may yet plague us. This time with writing out
+ * floats to arrays. We are lazy and did basically just take the opposite of our
+ * test code to read in values.
+ */
+
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+
+/*
+ *	A useful thing to keep around for debugging
+ *	console.log('buffer[0]: ' + buffer[0].toString(16));
+ *	console.log('buffer[1]: ' + buffer[1].toString(16));
+ *	console.log('buffer[2]: ' + buffer[2].toString(16));
+ *	console.log('buffer[3]: ' + buffer[3].toString(16));
+ *	console.log('buffer[4]: ' + buffer[4].toString(16));
+ *	console.log('buffer[5]: ' + buffer[5].toString(16));
+ * 	console.log('buffer[6]: ' + buffer[6].toString(16));
+ *	console.log('buffer[7]: ' + buffer[7].toString(16));
+ */
+
+function testfloat()
+{
+	var buffer = new Buffer(4);
+	mod_ctype.wfloat(0, 'big', buffer, 0);
+	/* Start off with some of the easy ones: +zero */
+	ASSERT.equal(0, buffer[0]);
+	ASSERT.equal(0, buffer[1]);
+	ASSERT.equal(0, buffer[2]);
+	ASSERT.equal(0, buffer[3]);
+	mod_ctype.wfloat(0, 'little', buffer, 0);
+	ASSERT.equal(0, buffer[0]);
+	ASSERT.equal(0, buffer[1]);
+	ASSERT.equal(0, buffer[2]);
+	ASSERT.equal(0, buffer[3]);
+
+	/* Catch +infin */
+	mod_ctype.wfloat(Number.POSITIVE_INFINITY, 'big', buffer, 0);
+	ASSERT.equal(0x7f, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	mod_ctype.wfloat(Number.POSITIVE_INFINITY, 'little', buffer, 0);
+	ASSERT.equal(0x7f, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	/* Catch -infin */
+	mod_ctype.wfloat(Number.NEGATIVE_INFINITY, 'big', buffer, 0);
+	ASSERT.equal(0xff, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	mod_ctype.wfloat(Number.NEGATIVE_INFINITY, 'little', buffer, 0);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	/* Catch NaN */
+
+	/*
+	 * NaN Is a litle weird in its requirements, so we're going to encode a
+	 * bit of how we actually implement it into this test. Probably not the
+	 * best, since technically the sign is a don't care and the mantissa
+	 * needs to just be non-zero.
+	 */
+	mod_ctype.wfloat(NaN, 'big', buffer, 0);
+	ASSERT.equal(0x7f, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x17, buffer[3]);
+	mod_ctype.wfloat(NaN, 'little', buffer, 0);
+	ASSERT.equal(0x7f, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x17, buffer[0]);
+
+	/* On to some basic tests */
+	/* 1.125 */
+	mod_ctype.wfloat(1.125, 'big', buffer, 0);
+	ASSERT.equal(0x3f, buffer[0]);
+	ASSERT.equal(0x90, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	mod_ctype.wfloat(1.125, 'little', buffer, 0);
+	ASSERT.equal(0x3f, buffer[3]);
+	ASSERT.equal(0x90, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	mod_ctype.wfloat(1.0000001192092896, 'big', buffer, 0);
+	ASSERT.equal(0x3f, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x01, buffer[3]);
+	mod_ctype.wfloat(1.0000001192092896, 'little', buffer, 0);
+	ASSERT.equal(0x3f, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x01, buffer[0]);
+
+	mod_ctype.wfloat(1.0000001192092896, 'big', buffer, 0);
+	ASSERT.equal(0x3f, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x01, buffer[3]);
+	mod_ctype.wfloat(1.0000001192092896, 'little', buffer, 0);
+	ASSERT.equal(0x3f, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x01, buffer[0]);
+
+	mod_ctype.wfloat(2.3283067140944524e-10, 'big', buffer, 0);
+	ASSERT.equal(0x2f, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x01, buffer[3]);
+	mod_ctype.wfloat(2.3283067140944524e-10, 'little', buffer, 0);
+	ASSERT.equal(0x2f, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x01, buffer[0]);
+
+	/* ff34a2b0 -2.4010576103645774e+38 */
+	mod_ctype.wfloat(-2.4010576103645774e+38,
+	    'big', buffer, 0);
+	ASSERT.equal(0xff, buffer[0]);
+	ASSERT.equal(0x34, buffer[1]);
+	ASSERT.equal(0xa2, buffer[2]);
+	ASSERT.equal(0xb0, buffer[3]);
+	mod_ctype.wfloat(-2.4010576103645774e+38,
+	    'little', buffer, 0);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0x34, buffer[2]);
+	ASSERT.equal(0xa2, buffer[1]);
+	ASSERT.equal(0xb0, buffer[0]);
+
+	/* Denormalized tests */
+
+	/* 0003f89a +/- 3.6468792534053364e-40 */
+	mod_ctype.wfloat(3.6468792534053364e-40,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x03, buffer[1]);
+	ASSERT.equal(0xf8, buffer[2]);
+	ASSERT.equal(0x9a, buffer[3]);
+	mod_ctype.wfloat(3.6468792534053364e-40,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x03, buffer[2]);
+	ASSERT.equal(0xf8, buffer[1]);
+	ASSERT.equal(0x9a, buffer[0]);
+
+	mod_ctype.wfloat(-3.6468792534053364e-40,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x03, buffer[1]);
+	ASSERT.equal(0xf8, buffer[2]);
+	ASSERT.equal(0x9a, buffer[3]);
+	mod_ctype.wfloat(-3.6468792534053364e-40,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[3]);
+	ASSERT.equal(0x03, buffer[2]);
+	ASSERT.equal(0xf8, buffer[1]);
+	ASSERT.equal(0x9a, buffer[0]);
+
+	/* Maximum and minimum normalized and denormalized values */
+
+	/* Largest normalized number +/- 3.4028234663852886e+38 */
+
+	mod_ctype.wfloat(3.4028234663852886e+38,
+	    'big', buffer, 0);
+	ASSERT.equal(0x7f, buffer[0]);
+	ASSERT.equal(0x7f, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	mod_ctype.wfloat(3.4028234663852886e+38,
+	    'little', buffer, 0);
+	ASSERT.equal(0x7f, buffer[3]);
+	ASSERT.equal(0x7f, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+	mod_ctype.wfloat(-3.4028234663852886e+38,
+	    'big', buffer, 0);
+	ASSERT.equal(0xff, buffer[0]);
+	ASSERT.equal(0x7f, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	mod_ctype.wfloat(-3.4028234663852886e+38,
+	    'little', buffer, 0);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0x7f, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+	/* Smallest normalied number +/- 1.1754943508222875e-38 */
+
+	mod_ctype.wfloat(1.1754943508222875e-38,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	mod_ctype.wfloat(1.1754943508222875e-38,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	mod_ctype.wfloat(-1.1754943508222875e-38,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x80, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	mod_ctype.wfloat(-1.1754943508222875e-38,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[3]);
+	ASSERT.equal(0x80, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	/* Smallest denormalized number 1.401298464324817e-45 */
+	mod_ctype.wfloat(1.401298464324817e-45,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x01, buffer[3]);
+	mod_ctype.wfloat(1.401298464324817e-45,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x01, buffer[0]);
+
+	mod_ctype.wfloat(-1.401298464324817e-45,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x01, buffer[3]);
+	mod_ctype.wfloat(-1.401298464324817e-45,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x01, buffer[0]);
+
+	/* Largest denormalized value +/- 1.1754942106924411e-38 */
+
+	mod_ctype.wfloat(1.1754942106924411e-38,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x7f, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	mod_ctype.wfloat(1.1754942106924411e-38,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x7f, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+	mod_ctype.wfloat(-1.1754942106924411e-38,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x7f, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	mod_ctype.wfloat(-1.1754942106924411e-38,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[3]);
+	ASSERT.equal(0x7f, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+	/* Do some quick offset testing */
+	buffer = new Buffer(6);
+	mod_ctype.wfloat(-1.2027516403607578e-32,
+	    'big', buffer, 2);
+	ASSERT.equal(0x8a, buffer[2]);
+	ASSERT.equal(0x79, buffer[3]);
+	ASSERT.equal(0xcd, buffer[4]);
+	ASSERT.equal(0x3f, buffer[5]);
+
+	mod_ctype.wfloat(-1.2027516403607578e-32,
+	    'little', buffer, 2);
+	ASSERT.equal(0x8a, buffer[5]);
+	ASSERT.equal(0x79, buffer[4]);
+	ASSERT.equal(0xcd, buffer[3]);
+	ASSERT.equal(0x3f, buffer[2]);
+
+}
+
+function testdouble()
+{
+	var buffer = new Buffer(10);
+
+	/* Check 0 */
+	mod_ctype.wdouble(0, 'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+	mod_ctype.wdouble(0, 'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[7]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	/* Check NaN */
+	/* Similar to floats we are only generating a subset of values */
+	mod_ctype.wdouble(NaN, 'big', buffer, 0);
+	ASSERT.equal(0x7f, buffer[0]);
+	ASSERT.equal(0xf0, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x17, buffer[7]);
+	mod_ctype.wdouble(NaN, 'little', buffer, 0);
+	ASSERT.equal(0x7f, buffer[7]);
+	ASSERT.equal(0xf0, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x17, buffer[0]);
+
+	/* pos inf */
+	mod_ctype.wdouble(Number.POSITIVE_INFINITY,
+	    'big', buffer, 0);
+	ASSERT.equal(0x7f, buffer[0]);
+	ASSERT.equal(0xf0, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+	mod_ctype.wdouble(Number.POSITIVE_INFINITY,
+	    'little', buffer, 0);
+	ASSERT.equal(0x7f, buffer[7]);
+	ASSERT.equal(0xf0, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	/* neg inf */
+	mod_ctype.wdouble(Number.NEGATIVE_INFINITY,
+	    'big', buffer, 0);
+	ASSERT.equal(0xff, buffer[0]);
+	ASSERT.equal(0xf0, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+	mod_ctype.wdouble(Number.NEGATIVE_INFINITY,
+	    'little', buffer, 0);
+	ASSERT.equal(0xff, buffer[7]);
+	ASSERT.equal(0xf0, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	/* Simple normalized values */
+
+	/* +/- 1.125 */
+	mod_ctype.wdouble(1.125,
+	    'big', buffer, 0);
+	ASSERT.equal(0x3f, buffer[0]);
+	ASSERT.equal(0xf2, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+
+	mod_ctype.wdouble(1.125,
+	    'little', buffer, 0);
+	ASSERT.equal(0x3f, buffer[7]);
+	ASSERT.equal(0xf2, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	mod_ctype.wdouble(-1.125,
+	    'big', buffer, 0);
+	ASSERT.equal(0xbf, buffer[0]);
+	ASSERT.equal(0xf2, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+
+	mod_ctype.wdouble(-1.125,
+	    'little', buffer, 0);
+	ASSERT.equal(0xbf, buffer[7]);
+	ASSERT.equal(0xf2, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+
+	/* +/- 1.4397318913736026e+283 */
+	mod_ctype.wdouble(1.4397318913736026e+283,
+	    'big', buffer, 0);
+	ASSERT.equal(0x7a, buffer[0]);
+	ASSERT.equal(0xb8, buffer[1]);
+	ASSERT.equal(0xc9, buffer[2]);
+	ASSERT.equal(0x34, buffer[3]);
+	ASSERT.equal(0x72, buffer[4]);
+	ASSERT.equal(0x16, buffer[5]);
+	ASSERT.equal(0xf9, buffer[6]);
+	ASSERT.equal(0x0e, buffer[7]);
+
+	mod_ctype.wdouble(1.4397318913736026e+283,
+	    'little', buffer, 0);
+	ASSERT.equal(0x7a, buffer[7]);
+	ASSERT.equal(0xb8, buffer[6]);
+	ASSERT.equal(0xc9, buffer[5]);
+	ASSERT.equal(0x34, buffer[4]);
+	ASSERT.equal(0x72, buffer[3]);
+	ASSERT.equal(0x16, buffer[2]);
+	ASSERT.equal(0xf9, buffer[1]);
+	ASSERT.equal(0x0e, buffer[0]);
+
+	mod_ctype.wdouble(-1.4397318913736026e+283,
+	    'big', buffer, 0);
+	ASSERT.equal(0xfa, buffer[0]);
+	ASSERT.equal(0xb8, buffer[1]);
+	ASSERT.equal(0xc9, buffer[2]);
+	ASSERT.equal(0x34, buffer[3]);
+	ASSERT.equal(0x72, buffer[4]);
+	ASSERT.equal(0x16, buffer[5]);
+	ASSERT.equal(0xf9, buffer[6]);
+	ASSERT.equal(0x0e, buffer[7]);
+
+	mod_ctype.wdouble(-1.4397318913736026e+283,
+	    'little', buffer, 0);
+	ASSERT.equal(0xfa, buffer[7]);
+	ASSERT.equal(0xb8, buffer[6]);
+	ASSERT.equal(0xc9, buffer[5]);
+	ASSERT.equal(0x34, buffer[4]);
+	ASSERT.equal(0x72, buffer[3]);
+	ASSERT.equal(0x16, buffer[2]);
+	ASSERT.equal(0xf9, buffer[1]);
+	ASSERT.equal(0x0e, buffer[0]);
+
+	/* Denormalized values */
+	/* +/- 8.82521232268344e-309 */
+	mod_ctype.wdouble(8.82521232268344e-309,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x06, buffer[1]);
+	ASSERT.equal(0x58, buffer[2]);
+	ASSERT.equal(0x94, buffer[3]);
+	ASSERT.equal(0x13, buffer[4]);
+	ASSERT.equal(0x27, buffer[5]);
+	ASSERT.equal(0x8a, buffer[6]);
+	ASSERT.equal(0xcd, buffer[7]);
+
+	mod_ctype.wdouble(8.82521232268344e-309,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[7]);
+	ASSERT.equal(0x06, buffer[6]);
+	ASSERT.equal(0x58, buffer[5]);
+	ASSERT.equal(0x94, buffer[4]);
+	ASSERT.equal(0x13, buffer[3]);
+	ASSERT.equal(0x27, buffer[2]);
+	ASSERT.equal(0x8a, buffer[1]);
+	ASSERT.equal(0xcd, buffer[0]);
+
+	mod_ctype.wdouble(-8.82521232268344e-309,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x06, buffer[1]);
+	ASSERT.equal(0x58, buffer[2]);
+	ASSERT.equal(0x94, buffer[3]);
+	ASSERT.equal(0x13, buffer[4]);
+	ASSERT.equal(0x27, buffer[5]);
+	ASSERT.equal(0x8a, buffer[6]);
+	ASSERT.equal(0xcd, buffer[7]);
+
+	mod_ctype.wdouble(-8.82521232268344e-309,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[7]);
+	ASSERT.equal(0x06, buffer[6]);
+	ASSERT.equal(0x58, buffer[5]);
+	ASSERT.equal(0x94, buffer[4]);
+	ASSERT.equal(0x13, buffer[3]);
+	ASSERT.equal(0x27, buffer[2]);
+	ASSERT.equal(0x8a, buffer[1]);
+	ASSERT.equal(0xcd, buffer[0]);
+
+
+	/* Edge cases, maximum and minimum values */
+
+	/* Smallest denormalized value 5e-324 */
+	mod_ctype.wdouble(5e-324,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x01, buffer[7]);
+
+	mod_ctype.wdouble(5e-324,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[7]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x01, buffer[0]);
+
+	mod_ctype.wdouble(-5e-324,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x01, buffer[7]);
+
+	mod_ctype.wdouble(-5e-324,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[7]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x01, buffer[0]);
+
+
+
+	/* Largest denormalized value 2.225073858507201e-308 */
+	mod_ctype.wdouble(2.225073858507201e-308,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x0f, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[6]);
+	ASSERT.equal(0xff, buffer[7]);
+
+	mod_ctype.wdouble(2.225073858507201e-308,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[7]);
+	ASSERT.equal(0x0f, buffer[6]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+	mod_ctype.wdouble(-2.225073858507201e-308,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x0f, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[6]);
+	ASSERT.equal(0xff, buffer[7]);
+
+	mod_ctype.wdouble(-2.225073858507201e-308,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[7]);
+	ASSERT.equal(0x0f, buffer[6]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+
+	/* Smallest normalized value 2.2250738585072014e-308 */
+	mod_ctype.wdouble(2.2250738585072014e-308,
+	    'big', buffer, 0);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x10, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+
+	mod_ctype.wdouble(2.2250738585072014e-308,
+	    'little', buffer, 0);
+	ASSERT.equal(0x00, buffer[7]);
+	ASSERT.equal(0x10, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+	mod_ctype.wdouble(-2.2250738585072014e-308,
+	    'big', buffer, 0);
+	ASSERT.equal(0x80, buffer[0]);
+	ASSERT.equal(0x10, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+
+	mod_ctype.wdouble(-2.2250738585072014e-308,
+	    'little', buffer, 0);
+	ASSERT.equal(0x80, buffer[7]);
+	ASSERT.equal(0x10, buffer[6]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[4]);
+	ASSERT.equal(0x00, buffer[3]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[0]);
+
+
+	/* Largest normalized value 1.7976931348623157e+308 */
+	mod_ctype.wdouble(1.7976931348623157e+308,
+	    'big', buffer, 0);
+	ASSERT.equal(0x7f, buffer[0]);
+	ASSERT.equal(0xef, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[6]);
+	ASSERT.equal(0xff, buffer[7]);
+
+	mod_ctype.wdouble(1.7976931348623157e+308,
+	    'little', buffer, 0);
+	ASSERT.equal(0x7f, buffer[7]);
+	ASSERT.equal(0xef, buffer[6]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+	mod_ctype.wdouble(-1.7976931348623157e+308,
+	    'big', buffer, 0);
+	ASSERT.equal(0xff, buffer[0]);
+	ASSERT.equal(0xef, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[6]);
+	ASSERT.equal(0xff, buffer[7]);
+
+	mod_ctype.wdouble(-1.7976931348623157e+308,
+	    'little', buffer, 0);
+	ASSERT.equal(0xff, buffer[7]);
+	ASSERT.equal(0xef, buffer[6]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[4]);
+	ASSERT.equal(0xff, buffer[3]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[0]);
+
+
+	/* Try offsets */
+	buffer[0] = 0xde;
+	buffer[1] = 0xad;
+	buffer[2] = 0xbe;
+	buffer[3] = 0xef;
+	buffer[4] = 0xba;
+	buffer[5] = 0xdd;
+	buffer[6] = 0xca;
+	buffer[7] = 0xfe;
+	buffer[8] = 0x16;
+	buffer[9] = 0x79;
+
+	mod_ctype.wdouble(-0.000015130017658081283,
+	    'big', buffer, 2);
+	ASSERT.equal(0xbe, buffer[2]);
+	ASSERT.equal(0xef, buffer[3]);
+	ASSERT.equal(0xba, buffer[4]);
+	ASSERT.equal(0xdd, buffer[5]);
+	ASSERT.equal(0xca, buffer[6]);
+	ASSERT.equal(0xfe, buffer[7]);
+	ASSERT.equal(0x16, buffer[8]);
+	ASSERT.equal(0x79, buffer[9]);
+
+	mod_ctype.wdouble(-0.000015130017658081283,
+	    'little', buffer, 2);
+	ASSERT.equal(0xbe, buffer[9]);
+	ASSERT.equal(0xef, buffer[8]);
+	ASSERT.equal(0xba, buffer[7]);
+	ASSERT.equal(0xdd, buffer[6]);
+	ASSERT.equal(0xca, buffer[5]);
+	ASSERT.equal(0xfe, buffer[4]);
+	ASSERT.equal(0x16, buffer[3]);
+	ASSERT.equal(0x79, buffer[2]);
+}
+
+testfloat();
+testdouble();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.64.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.64.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.64.js	(revision 517)
@@ -0,0 +1,638 @@
+/*
+ * Test our ability to read and write signed 64-bit integers.
+ */
+
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+function testRead()
+{
+	var res, data;
+	data = new Buffer(10);
+
+	data[0] = 0x32;
+	data[1] = 0x65;
+	data[2] = 0x42;
+	data[3] = 0x56;
+	data[4] = 0x23;
+	data[5] = 0xff;
+	data[6] = 0xff;
+	data[7] = 0xff;
+	data[8] = 0x89;
+	data[9] = 0x11;
+	res = mod_ctype.rsint64(data, 'big', 0);
+	ASSERT.equal(0x32654256, res[0]);
+	ASSERT.equal(0x23ffffff, res[1]);
+	res = mod_ctype.rsint64(data, 'big', 1);
+	ASSERT.equal(0x65425623, res[0]);
+	ASSERT.equal(0xffffff89, res[1]);
+	res = mod_ctype.rsint64(data, 'big', 2);
+	ASSERT.equal(0x425623ff, res[0]);
+	ASSERT.equal(0xffff8911, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 0);
+	ASSERT.equal(-0x000000dc, res[0]);
+	ASSERT.equal(-0xa9bd9ace, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 1);
+	ASSERT.equal(-0x76000000, res[0]);
+	ASSERT.equal(-0xdca9bd9b, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 2);
+	ASSERT.equal(0x1189ffff, res[0]);
+	ASSERT.equal(0xff235642, res[1]);
+
+	data.fill(0x00);
+	res = mod_ctype.rsint64(data, 'big', 0);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(0x00000000, res[1]);
+	res = mod_ctype.rsint64(data, 'big', 1);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(0x00000000, res[1]);
+	res = mod_ctype.rsint64(data, 'big', 2);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(0x00000000, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 0);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(0x00000000, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 1);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(0x00000000, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 2);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(0x00000000, res[1]);
+
+	data.fill(0xff);
+	res = mod_ctype.rsint64(data, 'big', 0);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(-1, res[1]);
+	res = mod_ctype.rsint64(data, 'big', 1);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(-1, res[1]);
+	res = mod_ctype.rsint64(data, 'big', 2);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(-1, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 0);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(-1, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 1);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(-1, res[1]);
+	res = mod_ctype.rsint64(data, 'little', 2);
+	ASSERT.equal(0x00000000, res[0]);
+	ASSERT.equal(-1, res[1]);
+
+	data[0] = 0x80;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	data[4] = 0x00;
+	data[5] = 0x00;
+	data[6] = 0x00;
+	data[7] = 0x00;
+	res = mod_ctype.rsint64(data, 'big', 0);
+	ASSERT.equal(-0x80000000, res[0]);
+	ASSERT.equal(0, res[1]);
+
+
+	data[7] = 0x80;
+	data[6] = 0x00;
+	data[5] = 0x00;
+	data[4] = 0x00;
+	data[3] = 0x00;
+	data[2] = 0x00;
+	data[1] = 0x00;
+	data[0] = 0x00;
+	res = mod_ctype.rsint64(data, 'little', 0);
+	ASSERT.equal(-0x80000000, res[0]);
+	ASSERT.equal(0, res[1]);
+
+	data[0] = 0x80;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	data[4] = 0x00;
+	data[5] = 0x00;
+	data[6] = 0x00;
+	data[7] = 0x01;
+	res = mod_ctype.rsint64(data, 'big', 0);
+	ASSERT.equal(-0x7fffffff, res[0]);
+	ASSERT.equal(-0xffffffff, res[1]);
+
+
+}
+
+function testWriteZero()
+{
+	var data, buf;
+	buf = new Buffer(10);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wsint64(data, 'big', buf, 0);
+	ASSERT.equal(0, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wsint64(data, 'big', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wsint64(data, 'big', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0, buf[9]);
+
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wsint64(data, 'little', buf, 0);
+	ASSERT.equal(0, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wsint64(data, 'little', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wsint64(data, 'little', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0, buf[9]);
+}
+
+/*
+ * Also include tests that are going to force us to go into a negative value and
+ * insure that it's written correctly.
+ */
+function testWrite()
+{
+	var data, buf;
+
+	buf = new Buffer(10);
+	data = [ 0x234456, 0x87 ];
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 0);
+	ASSERT.equal(0x00, buf[0]);
+	ASSERT.equal(0x23, buf[1]);
+	ASSERT.equal(0x44, buf[2]);
+	ASSERT.equal(0x56, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x87, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x23, buf[2]);
+	ASSERT.equal(0x44, buf[3]);
+	ASSERT.equal(0x56, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x87, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x23, buf[3]);
+	ASSERT.equal(0x44, buf[4]);
+	ASSERT.equal(0x56, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x00, buf[8]);
+	ASSERT.equal(0x87, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 0);
+	ASSERT.equal(0x87, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x56, buf[4]);
+	ASSERT.equal(0x44, buf[5]);
+	ASSERT.equal(0x23, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x87, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x56, buf[5]);
+	ASSERT.equal(0x44, buf[6]);
+	ASSERT.equal(0x23, buf[7]);
+	ASSERT.equal(0x00, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0x87, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x56, buf[6]);
+	ASSERT.equal(0x44, buf[7]);
+	ASSERT.equal(0x23, buf[8]);
+	ASSERT.equal(0x00, buf[9]);
+
+	data = [0x3421, 0x34abcdba];
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 0);
+	ASSERT.equal(0x00, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x34, buf[2]);
+	ASSERT.equal(0x21, buf[3]);
+	ASSERT.equal(0x34, buf[4]);
+	ASSERT.equal(0xab, buf[5]);
+	ASSERT.equal(0xcd, buf[6]);
+	ASSERT.equal(0xba, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x34, buf[3]);
+	ASSERT.equal(0x21, buf[4]);
+	ASSERT.equal(0x34, buf[5]);
+	ASSERT.equal(0xab, buf[6]);
+	ASSERT.equal(0xcd, buf[7]);
+	ASSERT.equal(0xba, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x34, buf[4]);
+	ASSERT.equal(0x21, buf[5]);
+	ASSERT.equal(0x34, buf[6]);
+	ASSERT.equal(0xab, buf[7]);
+	ASSERT.equal(0xcd, buf[8]);
+	ASSERT.equal(0xba, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 0);
+	ASSERT.equal(0xba, buf[0]);
+	ASSERT.equal(0xcd, buf[1]);
+	ASSERT.equal(0xab, buf[2]);
+	ASSERT.equal(0x34, buf[3]);
+	ASSERT.equal(0x21, buf[4]);
+	ASSERT.equal(0x34, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0xba, buf[1]);
+	ASSERT.equal(0xcd, buf[2]);
+	ASSERT.equal(0xab, buf[3]);
+	ASSERT.equal(0x34, buf[4]);
+	ASSERT.equal(0x21, buf[5]);
+	ASSERT.equal(0x34, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x00, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0xba, buf[2]);
+	ASSERT.equal(0xcd, buf[3]);
+	ASSERT.equal(0xab, buf[4]);
+	ASSERT.equal(0x34, buf[5]);
+	ASSERT.equal(0x21, buf[6]);
+	ASSERT.equal(0x34, buf[7]);
+	ASSERT.equal(0x00, buf[8]);
+	ASSERT.equal(0x00, buf[9]);
+
+
+	data = [ -0x80000000, 0 ];
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 0);
+	ASSERT.equal(0x80, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 0);
+	ASSERT.equal(0x00, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x80, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	data = [ -0x7fffffff, -0xffffffff ];
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 0);
+	ASSERT.equal(0x80, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x01, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 0);
+	ASSERT.equal(0x01, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x80, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	data = [ 0x0, -0x1];
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'big', buf, 0);
+	ASSERT.equal(0xff, buf[0]);
+	ASSERT.equal(0xff, buf[1]);
+	ASSERT.equal(0xff, buf[2]);
+	ASSERT.equal(0xff, buf[3]);
+	ASSERT.equal(0xff, buf[4]);
+	ASSERT.equal(0xff, buf[5]);
+	ASSERT.equal(0xff, buf[6]);
+	ASSERT.equal(0xff, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wsint64(data, 'little', buf, 0);
+	ASSERT.equal(0xff, buf[0]);
+	ASSERT.equal(0xff, buf[1]);
+	ASSERT.equal(0xff, buf[2]);
+	ASSERT.equal(0xff, buf[3]);
+	ASSERT.equal(0xff, buf[4]);
+	ASSERT.equal(0xff, buf[5]);
+	ASSERT.equal(0xff, buf[6]);
+	ASSERT.equal(0xff, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+}
+
+/*
+ * Make sure we catch invalid writes.
+ */
+function testWriteInvalid()
+{
+	var data, buf;
+
+	/* Buffer too small */
+	buf = new Buffer(4);
+	data = [ 0, 0];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 0);
+	}, Error, 'buffer too small');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 0);
+	}, Error, 'buffer too small');
+
+	/* Beyond the end of the buffer */
+	buf = new Buffer(12);
+	data = [ 0, 0];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 11);
+	}, Error, 'write beyond end of buffer');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 11);
+	}, Error, 'write beyond end of buffer');
+
+	/* Write fractional values */
+	buf = new Buffer(12);
+	data = [ 3.33, 0 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ 0, 3.3 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ -3.33, 0 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ 0, -3.3 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ 3.33, 2.42 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ 3.33, -2.42 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ -3.33, -2.42 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ -3.33, 2.42 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	/* Signs don't match */
+	buf = new Buffer(12);
+	data = [ 0x800000, -0x32 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ -0x800000, 0x32 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	/* Write values that are too large */
+	buf = new Buffer(12);
+	data = [ 0x80000000, 0 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ 0x7fffffff, 0x100000000 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ 0x00, 0x800000000 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ 0xffffffffff, 0xffffff238 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ 0x23, 0xffffff238 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ -0x80000000, -0xfff238 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ -0x80000004, -0xfff238 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wsint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+}
+
+
+testRead();
+testWrite();
+testWriteZero();
+testWriteInvalid();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.rint.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.rint.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.rint.js	(revision 517)
@@ -0,0 +1,101 @@
+/*
+ * Tests to verify we're reading in signed integers correctly
+ */
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+/*
+ * Test 8 bit signed integers
+ */
+function test8()
+{
+	var data = new Buffer(4);
+
+	data[0] = 0x23;
+	ASSERT.equal(0x23, mod_ctype.rsint8(data, 'big', 0));
+	ASSERT.equal(0x23, mod_ctype.rsint8(data, 'little', 0));
+
+	data[0] = 0xff;
+	ASSERT.equal(-1, mod_ctype.rsint8(data, 'big', 0));
+	ASSERT.equal(-1, mod_ctype.rsint8(data, 'little', 0));
+
+	data[0] = 0x87;
+	data[1] = 0xab;
+	data[2] = 0x7c;
+	data[3] = 0xef;
+	ASSERT.equal(-121, mod_ctype.rsint8(data, 'big', 0));
+	ASSERT.equal(-85, mod_ctype.rsint8(data, 'big', 1));
+	ASSERT.equal(124, mod_ctype.rsint8(data, 'big', 2));
+	ASSERT.equal(-17, mod_ctype.rsint8(data, 'big', 3));
+	ASSERT.equal(-121, mod_ctype.rsint8(data, 'little', 0));
+	ASSERT.equal(-85, mod_ctype.rsint8(data, 'little', 1));
+	ASSERT.equal(124, mod_ctype.rsint8(data, 'little', 2));
+	ASSERT.equal(-17, mod_ctype.rsint8(data, 'little', 3));
+}
+
+function test16()
+{
+	var buffer = new Buffer(6);
+	buffer[0] = 0x16;
+	buffer[1] = 0x79;
+	ASSERT.equal(0x1679, mod_ctype.rsint16(buffer, 'big', 0));
+	ASSERT.equal(0x7916, mod_ctype.rsint16(buffer, 'little', 0));
+
+	buffer[0] = 0xff;
+	buffer[1] = 0x80;
+	ASSERT.equal(-128, mod_ctype.rsint16(buffer, 'big', 0));
+	ASSERT.equal(-32513, mod_ctype.rsint16(buffer, 'little', 0));
+
+	/* test offset with weenix */
+	buffer[0] = 0x77;
+	buffer[1] = 0x65;
+	buffer[2] = 0x65;
+	buffer[3] = 0x6e;
+	buffer[4] = 0x69;
+	buffer[5] = 0x78;
+	ASSERT.equal(0x7765, mod_ctype.rsint16(buffer, 'big', 0));
+	ASSERT.equal(0x6565, mod_ctype.rsint16(buffer, 'big', 1));
+	ASSERT.equal(0x656e, mod_ctype.rsint16(buffer, 'big', 2));
+	ASSERT.equal(0x6e69, mod_ctype.rsint16(buffer, 'big', 3));
+	ASSERT.equal(0x6978, mod_ctype.rsint16(buffer, 'big', 4));
+	ASSERT.equal(0x6577, mod_ctype.rsint16(buffer, 'little', 0));
+	ASSERT.equal(0x6565, mod_ctype.rsint16(buffer, 'little', 1));
+	ASSERT.equal(0x6e65, mod_ctype.rsint16(buffer, 'little', 2));
+	ASSERT.equal(0x696e, mod_ctype.rsint16(buffer, 'little', 3));
+	ASSERT.equal(0x7869, mod_ctype.rsint16(buffer, 'little', 4));
+}
+
+function test32()
+{
+	var buffer = new Buffer(6);
+	buffer[0] = 0x43;
+	buffer[1] = 0x53;
+	buffer[2] = 0x16;
+	buffer[3] = 0x79;
+	ASSERT.equal(0x43531679, mod_ctype.rsint32(buffer, 'big', 0));
+	ASSERT.equal(0x79165343, mod_ctype.rsint32(buffer, 'little', 0));
+
+	buffer[0] = 0xff;
+	buffer[1] = 0xfe;
+	buffer[2] = 0xef;
+	buffer[3] = 0xfa;
+	ASSERT.equal(-69638, mod_ctype.rsint32(buffer, 'big', 0));
+	ASSERT.equal(-84934913, mod_ctype.rsint32(buffer, 'little', 0));
+
+	buffer[0] = 0x42;
+	buffer[1] = 0xc3;
+	buffer[2] = 0x95;
+	buffer[3] = 0xa9;
+	buffer[4] = 0x36;
+	buffer[5] = 0x17;
+	ASSERT.equal(0x42c395a9, mod_ctype.rsint32(buffer, 'big', 0));
+	ASSERT.equal(-1013601994, mod_ctype.rsint32(buffer, 'big', 1));
+	ASSERT.equal(-1784072681, mod_ctype.rsint32(buffer, 'big', 2));
+	ASSERT.equal(-1449802942, mod_ctype.rsint32(buffer, 'little', 0));
+	ASSERT.equal(917083587, mod_ctype.rsint32(buffer, 'little', 1));
+	ASSERT.equal(389458325, mod_ctype.rsint32(buffer, 'little', 2));
+}
+
+test8();
+test16();
+test32();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.wbounds.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.wbounds.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.wbounds.js	(revision 517)
@@ -0,0 +1,53 @@
+/*
+ * Test to make sure that we properly are erroring whenever we try to write
+ * beyond the size of the integer.
+ */
+
+var mod_ctio = require('../../../ctio.js');
+var mod_assert = require('assert');
+var tb = new Buffer(16); /* Largest buffer we'll need */
+
+var cases = [
+	{ func:
+	function () {
+		mod_ctio.wsint8(0x80, 'big', tb, 0);
+	}, test: '+int8_t' },
+	{ func:
+	function () {
+		mod_ctio.wsint8(-0x81, 'big', tb, 0);
+	}, test: '-int8_t' },
+
+	{ func:
+	function () {
+		mod_ctio.wsint16(0x8000, 'big', tb, 0);
+	}, test: '+int16_t' },
+	{ func:
+	function () {
+		mod_ctio.wsint16(-0x8001, 'big', tb, 0);
+	}, test: '-int16_t' },
+	{ func:
+	function () {
+		mod_ctio.wsint32(0x80000000, 'big', tb, 0);
+	}, test: '+int32_t' },
+	{ func:
+	function () {
+		mod_ctio.wsint32(-0x80000001, 'big', tb, 0);
+	}, test: '-int32_t' },
+	{ func:
+	function () {
+		mod_ctio.wsint64([ 0x80000000, 0 ], 'big', tb, 0);
+	}, test: '+int64_t' },
+	{ func:
+	function () {
+		mod_ctio.wsint64([ -0x80000000, -1 ], 'big', tb, 0);
+	}, test: '-int64_t' }
+];
+
+function test()
+{
+	var ii;
+	for (ii = 0; ii < cases.length; ii++)
+		mod_assert.throws(cases[ii]['func'], Error, cases[ii]['test']);
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.wint.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.wint.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/int/tst.wint.js	(revision 517)
@@ -0,0 +1,92 @@
+/*
+ * Tests to verify we're writing signed integers correctly
+ */
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+function test8()
+{
+	var buffer = new Buffer(4);
+	mod_ctype.wsint8(0x23, 'big', buffer, 0);
+	mod_ctype.wsint8(0x23, 'little', buffer, 1);
+	mod_ctype.wsint8(-5, 'big', buffer, 2);
+	mod_ctype.wsint8(-5, 'little', buffer, 3);
+
+	ASSERT.equal(0x23, buffer[0]);
+	ASSERT.equal(0x23, buffer[1]);
+	ASSERT.equal(0xfb, buffer[2]);
+	ASSERT.equal(0xfb, buffer[3]);
+
+	/* Make sure we handle truncation correctly */
+	ASSERT.throws(function () {
+	     mod_ctype.wsint8(0xabc, 'big', buffer, 0);
+	});
+	ASSERT.throws(function () {
+	     mod_ctype.wsint8(0xabc, 'little', buffer, 0);
+	});
+}
+
+function test16()
+{
+	var buffer = new Buffer(6);
+	mod_ctype.wsint16(0x0023, 'big', buffer, 0);
+	mod_ctype.wsint16(0x0023, 'little', buffer, 2);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x23, buffer[1]);
+	ASSERT.equal(0x23, buffer[2]);
+	ASSERT.equal(0x00, buffer[3]);
+	mod_ctype.wsint16(-5, 'big', buffer, 0);
+	mod_ctype.wsint16(-5, 'little', buffer, 2);
+	ASSERT.equal(0xff, buffer[0]);
+	ASSERT.equal(0xfb, buffer[1]);
+	ASSERT.equal(0xfb, buffer[2]);
+	ASSERT.equal(0xff, buffer[3]);
+
+	mod_ctype.wsint16(-1679, 'big', buffer, 1);
+	mod_ctype.wsint16(-1679, 'little', buffer, 3);
+	ASSERT.equal(0xf9, buffer[1]);
+	ASSERT.equal(0x71, buffer[2]);
+	ASSERT.equal(0x71, buffer[3]);
+	ASSERT.equal(0xf9, buffer[4]);
+}
+
+function test32()
+{
+	var buffer = new Buffer(8);
+	mod_ctype.wsint32(0x23, 'big', buffer, 0);
+	mod_ctype.wsint32(0x23, 'little', buffer, 4);
+	ASSERT.equal(0x00, buffer[0]);
+	ASSERT.equal(0x00, buffer[1]);
+	ASSERT.equal(0x00, buffer[2]);
+	ASSERT.equal(0x23, buffer[3]);
+	ASSERT.equal(0x23, buffer[4]);
+	ASSERT.equal(0x00, buffer[5]);
+	ASSERT.equal(0x00, buffer[6]);
+	ASSERT.equal(0x00, buffer[7]);
+
+	mod_ctype.wsint32(-5, 'big', buffer, 0);
+	mod_ctype.wsint32(-5, 'little', buffer, 4);
+	ASSERT.equal(0xff, buffer[0]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xff, buffer[2]);
+	ASSERT.equal(0xfb, buffer[3]);
+	ASSERT.equal(0xfb, buffer[4]);
+	ASSERT.equal(0xff, buffer[5]);
+	ASSERT.equal(0xff, buffer[6]);
+	ASSERT.equal(0xff, buffer[7]);
+
+	mod_ctype.wsint32(-805306713, 'big', buffer, 0);
+	mod_ctype.wsint32(-805306713, 'litle', buffer, 4);
+	ASSERT.equal(0xcf, buffer[0]);
+	ASSERT.equal(0xff, buffer[1]);
+	ASSERT.equal(0xfe, buffer[2]);
+	ASSERT.equal(0xa7, buffer[3]);
+	ASSERT.equal(0xa7, buffer[4]);
+	ASSERT.equal(0xfe, buffer[5]);
+	ASSERT.equal(0xff, buffer[6]);
+	ASSERT.equal(0xcf, buffer[7]);
+}
+
+test8();
+test16();
+test32();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.64.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.64.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.64.js	(revision 517)
@@ -0,0 +1,451 @@
+/*
+ * Test our ability to read and write unsigned 64-bit integers.
+ */
+
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+function testRead()
+{
+	var res, data;
+	data = new Buffer(10);
+
+	data[0] = 0x32;
+	data[1] = 0x65;
+	data[2] = 0x42;
+	data[3] = 0x56;
+	data[4] = 0x23;
+	data[5] = 0xff;
+	data[6] = 0xff;
+	data[7] = 0xff;
+	data[8] = 0x89;
+	data[9] = 0x11;
+	res = mod_ctype.ruint64(data, 'big', 0);
+	ASSERT.equal(0x32654256, res[0]);
+	ASSERT.equal(0x23ffffff, res[1]);
+	res = mod_ctype.ruint64(data, 'big', 1);
+	ASSERT.equal(0x65425623, res[0]);
+	ASSERT.equal(0xffffff89, res[1]);
+	res = mod_ctype.ruint64(data, 'big', 2);
+	ASSERT.equal(0x425623ff, res[0]);
+	ASSERT.equal(0xffff8911, res[1]);
+	res = mod_ctype.ruint64(data, 'little', 0);
+	ASSERT.equal(0xffffff23, res[0]);
+	ASSERT.equal(0x56426532, res[1]);
+	res = mod_ctype.ruint64(data, 'little', 1);
+	ASSERT.equal(0x89ffffff, res[0]);
+	ASSERT.equal(0x23564265, res[1]);
+	res = mod_ctype.ruint64(data, 'little', 2);
+	ASSERT.equal(0x1189ffff, res[0]);
+	ASSERT.equal(0xff235642, res[1]);
+
+}
+
+function testReadOver()
+{
+	var res, data;
+	data = new Buffer(10);
+
+	data[0] = 0x80;
+	data[1] = 0xff;
+	data[2] = 0x80;
+	data[3] = 0xff;
+	data[4] = 0x80;
+	data[5] = 0xff;
+	data[6] = 0x80;
+	data[7] = 0xff;
+	data[8] = 0x80;
+	data[9] = 0xff;
+	res = mod_ctype.ruint64(data, 'big', 0);
+	ASSERT.equal(0x80ff80ff, res[0]);
+	ASSERT.equal(0x80ff80ff, res[1]);
+	res = mod_ctype.ruint64(data, 'big', 1);
+	ASSERT.equal(0xff80ff80, res[0]);
+	ASSERT.equal(0xff80ff80, res[1]);
+	res = mod_ctype.ruint64(data, 'big', 2);
+	ASSERT.equal(0x80ff80ff, res[0]);
+	ASSERT.equal(0x80ff80ff, res[1]);
+	res = mod_ctype.ruint64(data, 'little', 0);
+	ASSERT.equal(0xff80ff80, res[0]);
+	ASSERT.equal(0xff80ff80, res[1]);
+	res = mod_ctype.ruint64(data, 'little', 1);
+	ASSERT.equal(0x80ff80ff, res[0]);
+	ASSERT.equal(0x80ff80ff, res[1]);
+	res = mod_ctype.ruint64(data, 'little', 2);
+	ASSERT.equal(0xff80ff80, res[0]);
+	ASSERT.equal(0xff80ff80, res[1]);
+}
+
+function testWriteZero()
+{
+	var data, buf;
+	buf = new Buffer(10);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wuint64(data, 'big', buf, 0);
+	ASSERT.equal(0, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wuint64(data, 'big', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wuint64(data, 'big', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0, buf[9]);
+
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wuint64(data, 'little', buf, 0);
+	ASSERT.equal(0, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wuint64(data, 'little', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	data = [0, 0];
+	mod_ctype.wuint64(data, 'little', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0, buf[2]);
+	ASSERT.equal(0, buf[3]);
+	ASSERT.equal(0, buf[4]);
+	ASSERT.equal(0, buf[5]);
+	ASSERT.equal(0, buf[6]);
+	ASSERT.equal(0, buf[7]);
+	ASSERT.equal(0, buf[8]);
+	ASSERT.equal(0, buf[9]);
+}
+
+/*
+ * Also include tests that are going to force us to go into a negative value and
+ * insure that it's written correctly.
+ */
+function testWrite()
+{
+	var data, buf;
+
+	buf = new Buffer(10);
+	data = [ 0x234456, 0x87 ];
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'big', buf, 0);
+	ASSERT.equal(0x00, buf[0]);
+	ASSERT.equal(0x23, buf[1]);
+	ASSERT.equal(0x44, buf[2]);
+	ASSERT.equal(0x56, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x87, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'big', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x23, buf[2]);
+	ASSERT.equal(0x44, buf[3]);
+	ASSERT.equal(0x56, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x87, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'big', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x23, buf[3]);
+	ASSERT.equal(0x44, buf[4]);
+	ASSERT.equal(0x56, buf[5]);
+	ASSERT.equal(0x00, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x00, buf[8]);
+	ASSERT.equal(0x87, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'little', buf, 0);
+	ASSERT.equal(0x87, buf[0]);
+	ASSERT.equal(0x00, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x56, buf[4]);
+	ASSERT.equal(0x44, buf[5]);
+	ASSERT.equal(0x23, buf[6]);
+	ASSERT.equal(0x00, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'little', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x87, buf[1]);
+	ASSERT.equal(0x00, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x56, buf[5]);
+	ASSERT.equal(0x44, buf[6]);
+	ASSERT.equal(0x23, buf[7]);
+	ASSERT.equal(0x00, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'little', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0x87, buf[2]);
+	ASSERT.equal(0x00, buf[3]);
+	ASSERT.equal(0x00, buf[4]);
+	ASSERT.equal(0x00, buf[5]);
+	ASSERT.equal(0x56, buf[6]);
+	ASSERT.equal(0x44, buf[7]);
+	ASSERT.equal(0x23, buf[8]);
+	ASSERT.equal(0x00, buf[9]);
+
+	data = [0xffff3421, 0x34abcdba];
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'big', buf, 0);
+	ASSERT.equal(0xff, buf[0]);
+	ASSERT.equal(0xff, buf[1]);
+	ASSERT.equal(0x34, buf[2]);
+	ASSERT.equal(0x21, buf[3]);
+	ASSERT.equal(0x34, buf[4]);
+	ASSERT.equal(0xab, buf[5]);
+	ASSERT.equal(0xcd, buf[6]);
+	ASSERT.equal(0xba, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'big', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0xff, buf[1]);
+	ASSERT.equal(0xff, buf[2]);
+	ASSERT.equal(0x34, buf[3]);
+	ASSERT.equal(0x21, buf[4]);
+	ASSERT.equal(0x34, buf[5]);
+	ASSERT.equal(0xab, buf[6]);
+	ASSERT.equal(0xcd, buf[7]);
+	ASSERT.equal(0xba, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'big', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0xff, buf[2]);
+	ASSERT.equal(0xff, buf[3]);
+	ASSERT.equal(0x34, buf[4]);
+	ASSERT.equal(0x21, buf[5]);
+	ASSERT.equal(0x34, buf[6]);
+	ASSERT.equal(0xab, buf[7]);
+	ASSERT.equal(0xcd, buf[8]);
+	ASSERT.equal(0xba, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'little', buf, 0);
+	ASSERT.equal(0xba, buf[0]);
+	ASSERT.equal(0xcd, buf[1]);
+	ASSERT.equal(0xab, buf[2]);
+	ASSERT.equal(0x34, buf[3]);
+	ASSERT.equal(0x21, buf[4]);
+	ASSERT.equal(0x34, buf[5]);
+	ASSERT.equal(0xff, buf[6]);
+	ASSERT.equal(0xff, buf[7]);
+	ASSERT.equal(0x66, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'little', buf, 1);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0xba, buf[1]);
+	ASSERT.equal(0xcd, buf[2]);
+	ASSERT.equal(0xab, buf[3]);
+	ASSERT.equal(0x34, buf[4]);
+	ASSERT.equal(0x21, buf[5]);
+	ASSERT.equal(0x34, buf[6]);
+	ASSERT.equal(0xff, buf[7]);
+	ASSERT.equal(0xff, buf[8]);
+	ASSERT.equal(0x66, buf[9]);
+
+	buf.fill(0x66);
+	mod_ctype.wuint64(data, 'little', buf, 2);
+	ASSERT.equal(0x66, buf[0]);
+	ASSERT.equal(0x66, buf[1]);
+	ASSERT.equal(0xba, buf[2]);
+	ASSERT.equal(0xcd, buf[3]);
+	ASSERT.equal(0xab, buf[4]);
+	ASSERT.equal(0x34, buf[5]);
+	ASSERT.equal(0x21, buf[6]);
+	ASSERT.equal(0x34, buf[7]);
+	ASSERT.equal(0xff, buf[8]);
+	ASSERT.equal(0xff, buf[9]);
+}
+
+/*
+ * Make sure we catch invalid writes.
+ */
+function testWriteInvalid()
+{
+	var data, buf;
+
+	/* Buffer too small */
+	buf = new Buffer(4);
+	data = [ 0, 0];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 0);
+	}, Error, 'buffer too small');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 0);
+	}, Error, 'buffer too small');
+
+	/* Beyond the end of the buffer */
+	buf = new Buffer(12);
+	data = [ 0, 0];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 11);
+	}, Error, 'write beyond end of buffer');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 11);
+	}, Error, 'write beyond end of buffer');
+
+	/* Write negative values */
+	buf = new Buffer(12);
+	data = [ -3, 0 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write negative number');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write negative number');
+
+	data = [ 0, -3 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write negative number');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write negative number');
+
+	data = [ -3, -3 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write negative number');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write negative number');
+
+
+	/* Write fractional values */
+	buf = new Buffer(12);
+	data = [ 3.33, 0 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ 0, 3.3 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	data = [ 3.33, 2.42 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write fractions');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write fractions');
+
+	/* Write values that are too large */
+	buf = new Buffer(12);
+	data = [ 0xffffffffff, 23 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ 0xffffffffff, 0xffffff238 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+
+	data = [ 0x23, 0xffffff238 ];
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'big', buf, 1);
+	}, Error, 'write too large');
+	ASSERT.throws(function () {
+	    mod_ctype.wuint64(data, 'little', buf, 1);
+	}, Error, 'write too large');
+}
+
+
+testRead();
+testReadOver();
+testWriteZero();
+testWrite();
+testWriteInvalid();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.roundtrip.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.roundtrip.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.roundtrip.js	(revision 517)
@@ -0,0 +1,81 @@
+/*
+ * A battery of tests for sucessful round-trip between writes and reads
+ */
+
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+
+/*
+ * What the heck, let's just test every value for 8-bits.
+ */
+
+function test8() {
+	var data = new Buffer(1);
+	var i;
+	for (i = 0; i < 256; i++) {
+		mod_ctype.wuint8(i, 'big', data, 0);
+		ASSERT.equal(i, mod_ctype.ruint8(data, 'big', 0));
+		mod_ctype.wuint8(i, 'little', data, 0);
+		ASSERT.equal(i, mod_ctype.ruint8(data, 'little', 0));
+	}
+	ASSERT.ok(true);
+}
+
+/*
+ * Test a random sample of 256 values in the 16-bit unsigned range
+ */
+
+function test16() {
+	var data = new Buffer(2);
+	var i = 0;
+	for (i = 0; i < 256; i++) {
+		var value = Math.round(Math.random() * Math.pow(2, 16));
+		mod_ctype.wuint16(value, 'big', data, 0);
+		ASSERT.equal(value, mod_ctype.ruint16(data, 'big', 0));
+		mod_ctype.wuint16(value, 'little', data, 0);
+		ASSERT.equal(value, mod_ctype.ruint16(data, 'little', 0));
+	}
+}
+
+/*
+ * Test a random sample of 256 values in the 32-bit unsigned range
+ */
+
+function test32() {
+	var data = new Buffer(4);
+	var i = 0;
+	for (i = 0; i < 256; i++) {
+		var value = Math.round(Math.random() * Math.pow(2, 32));
+		mod_ctype.wuint32(value, 'big', data, 0);
+		ASSERT.equal(value, mod_ctype.ruint32(data, 'big', 0));
+		mod_ctype.wuint32(value, 'little', data, 0);
+		ASSERT.equal(value, mod_ctype.ruint32(data, 'little', 0));
+	}
+}
+
+/*
+ * Test a random sample of 256 values in the 64-bit unsigned range
+ */
+
+function test64() {
+	var data = new Buffer(8);
+	var i = 0;
+	for (i = 0; i < 256; i++) {
+		var low = Math.round(Math.random() * Math.pow(2, 32));
+		var high = Math.round(Math.random() * Math.pow(2, 32));
+		mod_ctype.wuint64([high, low], 'big', data, 0);
+		var result = mod_ctype.ruint64(data, 'big', 0);
+		ASSERT.equal(high, result[0]);
+		ASSERT.equal(low, result[1]);
+		mod_ctype.wuint64([high, low], 'little', data, 0);
+		result = mod_ctype.ruint64(data, 'little', 0);
+		ASSERT.equal(high, result[0]);
+		ASSERT.equal(low, result[1]);
+	}
+}
+
+exports.test8 = test8;
+exports.test16 = test16;
+exports.test32 = test32;
+exports.test64 = test64;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.ruint.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.ruint.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.ruint.js	(revision 517)
@@ -0,0 +1,95 @@
+/*
+ * A battery of tests to help us read a series of uints
+ */
+
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+/*
+ * We need to check the following things:
+ *  - We are correctly resolving big endian (doesn't mean anything for 8 bit)
+ *  - Correctly resolving little endian (doesn't mean anything for 8 bit)
+ *  - Correctly using the offsets
+ *  - Correctly interpreting values that are beyond the signed range as unsigned
+ */
+function test8()
+{
+	var data = new Buffer(4);
+	data[0] = 23;
+	data[1] = 23;
+	data[2] = 23;
+	data[3] = 23;
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'big', 0));
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'little', 0));
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'big', 1));
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'little', 1));
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'big', 2));
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'little', 2));
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'big', 3));
+	ASSERT.equal(23, mod_ctype.ruint8(data, 'little', 3));
+	data[0] = 255; /* If it became a signed int, would be -1 */
+	ASSERT.equal(255, mod_ctype.ruint8(data, 'big', 0));
+	ASSERT.equal(255, mod_ctype.ruint8(data, 'little', 0));
+}
+
+/*
+ * Test 16 bit unsigned integers. We need to verify the same set as 8 bit, only
+ * now some of the issues actually matter:
+ *  - We are correctly resolving big endian
+ *  - Correctly resolving little endian
+ *  - Correctly using the offsets
+ *  - Correctly interpreting values that are beyond the signed range as unsigned
+ */
+function test16()
+{
+	var data = new Buffer(4);
+	/* Test signed values first */
+	data[0] = 0;
+	data[1] = 0x23;
+	data[2] = 0x42;
+	data[3] = 0x3f;
+
+	ASSERT.equal(0x23, mod_ctype.ruint16(data, 'big', 0));
+	ASSERT.equal(0x2342, mod_ctype.ruint16(data, 'big', 1));
+	ASSERT.equal(0x423f, mod_ctype.ruint16(data, 'big', 2));
+
+	ASSERT.equal(0x2300, mod_ctype.ruint16(data, 'little', 0));
+	ASSERT.equal(0x4223, mod_ctype.ruint16(data, 'little', 1));
+	ASSERT.equal(0x3f42, mod_ctype.ruint16(data, 'little', 2));
+
+	data[0] = 0xfe;
+	data[1] = 0xfe;
+
+	ASSERT.equal(0xfefe, mod_ctype.ruint16(data, 'big', 0));
+	ASSERT.equal(0xfefe, mod_ctype.ruint16(data, 'little', 0));
+}
+
+/*
+ * Test 32 bit unsigned integers. We need to verify the same set as 8 bit, only
+ * now some of the issues actually matter:
+ *  - We are correctly resolving big endian
+ *  - Correctly using the offsets
+ *  - Correctly interpreting values that are beyond the signed range as unsigned
+ */
+function test32()
+{
+	var data = new Buffer(8);
+	data[0] = 0x32;
+	data[1] = 0x65;
+	data[2] = 0x42;
+	data[3] = 0x56;
+	data[4] = 0x23;
+	data[5] = 0xff;
+
+	ASSERT.equal(0x32654256, mod_ctype.ruint32(data, 'big', 0));
+	ASSERT.equal(0x65425623, mod_ctype.ruint32(data, 'big', 1));
+	ASSERT.equal(0x425623ff, mod_ctype.ruint32(data, 'big', 2));
+
+	ASSERT.equal(0x56426532, mod_ctype.ruint32(data, 'little', 0));
+	ASSERT.equal(0x23564265, mod_ctype.ruint32(data, 'little', 1));
+	ASSERT.equal(0xff235642, mod_ctype.ruint32(data, 'little', 2));
+}
+
+test8();
+test16();
+test32();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.wuint.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.wuint.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctio/uint/tst.wuint.js	(revision 517)
@@ -0,0 +1,156 @@
+/*
+ * A battery of tests to help us read a series of uints
+ */
+
+var mod_ctype = require('../../../ctio.js');
+var ASSERT = require('assert');
+
+/*
+ * We need to check the following things:
+ *  - We are correctly resolving big endian (doesn't mean anything for 8 bit)
+ *  - Correctly resolving little endian (doesn't mean anything for 8 bit)
+ *  - Correctly using the offsets
+ *  - Correctly interpreting values that are beyond the signed range as unsigned
+ */
+function test8()
+{
+	var data = new Buffer(4);
+	mod_ctype.wuint8(23, 'big', data, 0);
+	mod_ctype.wuint8(23, 'big', data, 1);
+	mod_ctype.wuint8(23, 'big', data, 2);
+	mod_ctype.wuint8(23, 'big', data, 3);
+	ASSERT.equal(23, data[0]);
+	ASSERT.equal(23, data[1]);
+	ASSERT.equal(23, data[2]);
+	ASSERT.equal(23, data[3]);
+	mod_ctype.wuint8(23, 'little', data, 0);
+	mod_ctype.wuint8(23, 'little', data, 1);
+	mod_ctype.wuint8(23, 'little', data, 2);
+	mod_ctype.wuint8(23, 'little', data, 3);
+	ASSERT.equal(23, data[0]);
+	ASSERT.equal(23, data[1]);
+	ASSERT.equal(23, data[2]);
+	ASSERT.equal(23, data[3]);
+	mod_ctype.wuint8(255, 'big', data, 0);
+	ASSERT.equal(255, data[0]);
+	mod_ctype.wuint8(255, 'little', data, 0);
+	ASSERT.equal(255, data[0]);
+}
+
+function test16()
+{
+	var value = 0x2343;
+	var data = new Buffer(4);
+	mod_ctype.wuint16(value, 'big', data, 0);
+	ASSERT.equal(0x23, data[0]);
+	ASSERT.equal(0x43, data[1]);
+	mod_ctype.wuint16(value, 'big', data, 1);
+	ASSERT.equal(0x23, data[1]);
+	ASSERT.equal(0x43, data[2]);
+	mod_ctype.wuint16(value, 'big', data, 2);
+	ASSERT.equal(0x23, data[2]);
+	ASSERT.equal(0x43, data[3]);
+
+	mod_ctype.wuint16(value, 'little', data, 0);
+	ASSERT.equal(0x23, data[1]);
+	ASSERT.equal(0x43, data[0]);
+
+	mod_ctype.wuint16(value, 'little', data, 1);
+	ASSERT.equal(0x23, data[2]);
+	ASSERT.equal(0x43, data[1]);
+
+	mod_ctype.wuint16(value, 'little', data, 2);
+	ASSERT.equal(0x23, data[3]);
+	ASSERT.equal(0x43, data[2]);
+
+	value = 0xff80;
+	mod_ctype.wuint16(value, 'little', data, 0);
+	ASSERT.equal(0xff, data[1]);
+	ASSERT.equal(0x80, data[0]);
+
+	mod_ctype.wuint16(value, 'big', data, 0);
+	ASSERT.equal(0xff, data[0]);
+	ASSERT.equal(0x80, data[1]);
+}
+
+function test32()
+{
+	var data = new Buffer(6);
+	var value = 0xe7f90a6d;
+
+	mod_ctype.wuint32(value, 'big', data, 0);
+	ASSERT.equal(0xe7, data[0]);
+	ASSERT.equal(0xf9, data[1]);
+	ASSERT.equal(0x0a, data[2]);
+	ASSERT.equal(0x6d, data[3]);
+
+	mod_ctype.wuint32(value, 'big', data, 1);
+	ASSERT.equal(0xe7, data[1]);
+	ASSERT.equal(0xf9, data[2]);
+	ASSERT.equal(0x0a, data[3]);
+	ASSERT.equal(0x6d, data[4]);
+
+	mod_ctype.wuint32(value, 'big', data, 2);
+	ASSERT.equal(0xe7, data[2]);
+	ASSERT.equal(0xf9, data[3]);
+	ASSERT.equal(0x0a, data[4]);
+	ASSERT.equal(0x6d, data[5]);
+
+	mod_ctype.wuint32(value, 'little', data, 0);
+	ASSERT.equal(0xe7, data[3]);
+	ASSERT.equal(0xf9, data[2]);
+	ASSERT.equal(0x0a, data[1]);
+	ASSERT.equal(0x6d, data[0]);
+
+	mod_ctype.wuint32(value, 'little', data, 1);
+	ASSERT.equal(0xe7, data[4]);
+	ASSERT.equal(0xf9, data[3]);
+	ASSERT.equal(0x0a, data[2]);
+	ASSERT.equal(0x6d, data[1]);
+
+	mod_ctype.wuint32(value, 'little', data, 2);
+	ASSERT.equal(0xe7, data[5]);
+	ASSERT.equal(0xf9, data[4]);
+	ASSERT.equal(0x0a, data[3]);
+	ASSERT.equal(0x6d, data[2]);
+}
+
+function test64()
+{
+	var data = new Buffer(10);
+	var value = 0x0007cda8e7f90a6d;
+	var high = Math.floor(value / Math.pow(2, 32));
+	var low = value - (high * Math.pow(2, 32));
+	ASSERT.equal(0x0007cda8, high);
+	ASSERT.equal(0xe7f90a6d, low);
+
+	mod_ctype.wuint64([high, low], 'big', data, 0);
+	ASSERT.equal(0x00, data[0]);
+	ASSERT.equal(0x07, data[1]);
+	ASSERT.equal(0xcd, data[2]);
+	ASSERT.equal(0xa8, data[3]);
+	ASSERT.equal(0xe7, data[4]);
+	ASSERT.equal(0xf9, data[5]);
+	ASSERT.equal(0x0a, data[6]);
+	ASSERT.equal(0x6d, data[7]);
+
+	mod_ctype.wuint64([high, low], 'little', data, 0);
+	ASSERT.equal(0x6d, data[0]);
+	ASSERT.equal(0x0a, data[1]);
+	ASSERT.equal(0xf9, data[2]);
+	ASSERT.equal(0xe7, data[3]);
+	ASSERT.equal(0xa8, data[4]);
+	ASSERT.equal(0xcd, data[5]);
+	ASSERT.equal(0x07, data[6]);
+	ASSERT.equal(0x00, data[7]);
+}
+
+test8();
+test16();
+test32();
+test64();
+
+exports.test8 = test8;
+exports.test16 = test16;
+exports.test32 = test32;
+exports.test64 = test64;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.basicr.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.basicr.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.basicr.js	(revision 517)
@@ -0,0 +1,50 @@
+/*
+ * Simple does to see if it works at all
+ */
+var mod_ctype = require('../../ctype');
+var ASSERT = require('assert');
+var mod_sys = require('sys');
+
+function test()
+{
+	var ii, p, result, buffer;
+
+	p = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer(4);
+	buffer[0] = 23;
+	buffer[3] = 42;
+	result = p.readData([ { x: { type: 'uint8_t' }},
+	    { y: { type: 'uint8_t', offset: 3 }}
+	], buffer, 0);
+	ASSERT.equal(23, result['x']);
+	ASSERT.equal(42, result['y']);
+
+	buffer = new Buffer(23);
+	for (ii = 0; ii < 23; ii++)
+		buffer[ii] = 0;
+
+	buffer.write('Hello, world!');
+	result = p.readData([ { x: { type: 'char[20]' }} ], buffer, 0);
+
+	/*
+	 * This is currently broken behvaior, need to redesign check
+	 * ASSERT.equal('Hello, world!', result['x'].toString('utf-8', 0,
+	 *  result['x'].length));
+	 */
+
+	buffer = new Buffer(4);
+	buffer[0] = 0x03;
+	buffer[1] = 0x24;
+	buffer[2] = 0x25;
+	buffer[3] = 0x26;
+	result = p.readData([ { y: { type: 'uint8_t' }},
+	    { x: { type: 'uint8_t[y]' }}], buffer, 0);
+	console.log(mod_sys.inspect(result, true));
+
+	p.typedef('ssize_t', 'int32_t');
+	ASSERT.deepEqual({ 'ssize_t': 'int32_t' }, p.lstypes());
+	result = p.readData([ { x: { type: 'ssize_t' } } ], buffer, 0);
+	ASSERT.equal(0x26252403, result['x']);
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.basicw.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.basicw.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.basicw.js	(revision 517)
@@ -0,0 +1,44 @@
+/*
+ * Simple does it fucking work at all test
+ */
+
+var mod_ctype = require('../../ctype');
+var ASSERT = require('assert');
+var mod_sys = require('sys');
+
+function test()
+{
+	var ii, p, buffer, buf2;
+
+	p = new mod_ctype.Parser({ endian: 'big' });
+	buffer = new Buffer(4);
+	p.writeData([ { x: { type: 'uint8_t', value: 23 }},
+	    { y: { type: 'uint8_t', offset: 3, value: 42 }}
+	], buffer, 0);
+	ASSERT.equal(23, buffer[0]);
+	ASSERT.equal(42, buffer[3]);
+
+	buffer = new Buffer(20);
+	for (ii = 0; ii < 20; ii++)
+		buffer[ii] = 0;
+
+	buffer.write('Hello, world!');
+	buf2 = new Buffer(22);
+	p.writeData([ { x: { type: 'char[20]', value: buffer }} ], buf2, 0);
+	for (ii = 0; ii < 20; ii++)
+		ASSERT.equal(buffer[ii], buf2[ii]);
+	/*
+	 * This is currently broken behvaior, need to redesign check
+	 * ASSERT.equal('Hello, world!', result['x'].toString('utf-8', 0,
+	 *   result['x'].length));
+	 */
+
+	buffer = new Buffer(4);
+	p.writeData([ { y: { type: 'uint8_t', value: 3 }},
+	    { x: { type: 'uint8_t[y]', value: [ 0x24, 0x25, 0x26] }}],
+	    buffer, 0);
+	console.log(mod_sys.inspect(buffer));
+
+	p.typedef('ssize_t', 'int32_t');
+	ASSERT.deepEqual({ 'ssize_t': 'int32_t' }, p.lstypes());
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.char.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.char.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.char.js	(revision 517)
@@ -0,0 +1,42 @@
+/*
+ * Test the different forms of reading characters:
+ *
+ *  - the default, a single element buffer
+ *  - uint8, values are uint8_ts
+ *  - int8, values are int8_ts
+ */
+var mod_ctype = require('../../ctype');
+var mod_assert = require('assert');
+
+function test()
+{
+	var p, buf, res;
+
+	buf = new Buffer(1);
+	buf[0] = 255;
+
+	p = new mod_ctype.Parser({ endian: 'little'});
+	res = p.readData([ { c: { type: 'char' }} ], buf, 0);
+	res = res['c'];
+	mod_assert.ok(res instanceof Buffer);
+	mod_assert.equal(255, res[0]);
+
+	p = new mod_ctype.Parser({ endian: 'little',
+	    'char-type': 'int8' });
+	res = p.readData([ { c: { type: 'char' }} ], buf, 0);
+	res = res['c'];
+	mod_assert.ok(typeof (res) == 'number', 'got typeof (res): ' +
+	    typeof (res));
+	mod_assert.equal(-1, res);
+
+	p = new mod_ctype.Parser({ endian: 'little',
+	    'char-type': 'uint8' });
+	res = p.readData([ { c: { type: 'char' }} ], buf, 0);
+	res = res['c'];
+	mod_assert.ok(typeof (res) == 'number', 'got typeof (res): ' +
+	    typeof (res));
+	mod_assert.equal(255, res);
+
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.endian.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.endian.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.endian.js	(revision 517)
@@ -0,0 +1,45 @@
+/*
+ * Simple test to make sure that the endian setting works.
+ */
+
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var parser, buf;
+
+	parser = new mod_ctype.Parser({
+	    endian: 'little'
+	});
+
+	buf = new Buffer(2);
+	parser.writeData([ { key: { type: 'uint16_t' } } ], buf, 0, [ 0x1234 ]);
+	mod_assert.equal(buf[0], 0x34);
+	mod_assert.equal(buf[1], 0x12);
+	parser.setEndian('big');
+
+	parser.writeData([ { key: { type: 'uint16_t' } } ], buf, 0, [ 0x1234 ]);
+	mod_assert.equal(buf[0], 0x12);
+	mod_assert.equal(buf[1], 0x34);
+
+	parser.setEndian('little');
+	parser.writeData([ { key: { type: 'uint16_t' } } ], buf, 0, [ 0x1234 ]);
+	mod_assert.equal(buf[0], 0x34);
+	mod_assert.equal(buf[1], 0x12);
+}
+
+function fail()
+{
+	var parser;
+
+	parser = new mod_ctype.Parser({
+	    endian: 'little'
+	});
+	mod_assert.throws(function () {
+		parser.setEndian('littlebigwrong');
+	});
+}
+
+test();
+fail();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.oldwrite.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.oldwrite.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.oldwrite.js	(revision 517)
@@ -0,0 +1,28 @@
+/*
+ * A long overdue test to go through and verify that we can read and write
+ * structures as well as nested structures.
+ */
+
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var parser, buf, data;
+	parser = new mod_ctype.Parser({
+	    endian: 'little'
+	});
+	parser.typedef('point_t', [
+	    { x: { type: 'uint8_t' } },
+	    { y: { type: 'uint8_t' } }
+	]);
+	buf = new Buffer(2);
+	data = [
+	    { point: { type: 'point_t', value: [ 23, 42 ] } }
+	];
+	parser.writeData(data, buf, 0);
+	mod_assert.ok(buf[0] == 23);
+	mod_assert.ok(buf[1] == 42);
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.readSize.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.readSize.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.readSize.js	(revision 517)
@@ -0,0 +1,128 @@
+/*
+ * Testing to ensure we're reading the expected number bytes
+ */
+var mod_ctype = require('../../ctype');
+var ASSERT = require('assert');
+
+function testUint8()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('80', 'hex');
+	result = parser.readStruct([ { item: { type: 'uint8_t' } } ], buffer,
+	    0);
+	ASSERT.equal(result['size'], 1);
+}
+
+function testSint8()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('80', 'hex');
+	result = parser.readStruct([ { item: { type: 'int8_t' } } ], buffer, 0);
+	ASSERT.equal(result['size'], 1);
+}
+
+function testUint16()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('8000', 'hex');
+	result = parser.readStruct([ { item: { type: 'uint16_t' } } ], buffer,
+	    0);
+	ASSERT.equal(result['size'], 2);
+}
+
+function testSint16()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('8000', 'hex');
+	result = parser.readStruct([ { item: { type: 'int16_t' } } ], buffer,
+	    0);
+	ASSERT.equal(result['size'], 2);
+}
+
+function testUint32()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('80000000', 'hex');
+	result = parser.readStruct([ { item: { type: 'uint32_t' } } ], buffer,
+	    0);
+	ASSERT.equal(result['size'], 4);
+}
+
+function testSint32()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('80000000', 'hex');
+	result = parser.readStruct([ { item: { type: 'int32_t' } } ], buffer,
+	    0);
+	ASSERT.equal(result['size'], 4);
+}
+
+function testUint64()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('8000000000000000', 'hex');
+	result = parser.readStruct([ { item: { type: 'uint64_t' } } ], buffer,
+	    0);
+	ASSERT.equal(result['size'], 8);
+}
+
+function testSint64()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('8000000000000000', 'hex');
+	result = parser.readStruct([ { item: { type: 'int64_t' } } ], buffer,
+	    0);
+	ASSERT.equal(result['size'], 8);
+}
+
+function testFloat()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('ABAAAA3E', 'hex');
+	result = parser.readStruct([ { item: { type: 'float' } } ], buffer, 0);
+	ASSERT.equal(result['size'], 4);
+}
+
+function testDouble()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('000000000000F03F', 'hex');
+	result = parser.readStruct([ { item: { type: 'double' } } ], buffer, 0);
+	ASSERT.equal(result['size'], 8);
+}
+
+function testChar()
+{
+	var parser, result, buffer;
+	parser = new mod_ctype.Parser({ endian: 'little' });
+	buffer = new Buffer('t');
+	result = parser.readStruct([ { item: { type: 'char' } } ], buffer, 0);
+	ASSERT.equal(result['size'], 1);
+}
+
+function test()
+{
+	testSint8();
+	testUint8();
+	testSint16();
+	testUint16();
+	testSint32();
+	testUint32();
+	testSint64();
+	testUint64();
+	testFloat();
+	testDouble();
+	testChar();
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.structw.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.structw.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.structw.js	(revision 517)
@@ -0,0 +1,28 @@
+/*
+ * A long overdue test to go through and verify that we can read and write
+ * structures as well as nested structures.
+ */
+
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var parser, buf, data;
+	parser = new mod_ctype.Parser({
+	    endian: 'little'
+	});
+	parser.typedef('point_t', [
+	    { x: { type: 'uint8_t' } },
+	    { y: { type: 'uint8_t' } }
+	]);
+	buf = new Buffer(2);
+	data = [
+	    { point: { type: 'point_t' } }
+	];
+	parser.writeData(data, buf, 0, [ [ 23, 42 ] ]);
+	mod_assert.ok(buf[0] == 23);
+	mod_assert.ok(buf[1] == 42);
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.writeStruct.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.writeStruct.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/node_modules/ctype/tst/ctype/tst.writeStruct.js	(revision 517)
@@ -0,0 +1,31 @@
+/*
+ * Test to verify that the offset is incremented when structures are written to.
+ * Hopefully we will not regress issue #41
+ */
+
+var mod_ctype = require('../../ctype.js');
+var mod_assert = require('assert');
+
+function test()
+{
+	var parser, buf, data;
+	parser = new mod_ctype.Parser({
+	    endian: 'little'
+	});
+	parser.typedef('point_t', [
+	    { x: { type: 'uint8_t' } },
+	    { y: { type: 'uint8_t' } }
+	]);
+	buf = new Buffer(4);
+	data = [
+	    { point1: { type: 'point_t' } },
+	    { point2: { type: 'point_t' } }
+	];
+	parser.writeData(data, buf, 0, [ [ 23, 42 ], [ 91, 18 ] ]);
+	mod_assert.ok(buf[0] == 23);
+	mod_assert.ok(buf[1] == 42);
+	mod_assert.ok(buf[2] == 91);
+	mod_assert.ok(buf[3] == 18);
+}
+
+test();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/http-signature/package.json	(revision 517)
@@ -0,0 +1,36 @@
+{
+  "author": {
+    "name": "Joyent, Inc"
+  },
+  "name": "http-signature",
+  "description": "Reference implementation of Joyent's HTTP Signature Scheme",
+  "version": "0.10.0",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/joyent/node-http-signature.git"
+  },
+  "engines": {
+    "node": ">=0.8"
+  },
+  "main": "lib/index.js",
+  "scripts": {
+    "test": "tap tst/*.js"
+  },
+  "dependencies": {
+    "assert-plus": "0.1.2",
+    "asn1": "0.1.11",
+    "ctype": "0.5.2"
+  },
+  "devDependencies": {
+    "node-uuid": "1.4.0",
+    "tap": "0.4.2"
+  },
+  "readme": "# node-http-signature\n\nnode-http-signature is a node.js library that has client and server components\nfor Joyent's [HTTP Signature Scheme](http_signing.md).\n\n## Usage\n\nNote the example below signs a request with the same key/cert used to start an\nHTTP server. This is almost certainly not what you actaully want, but is just\nused to illustrate the API calls; you will need to provide your own key\nmanagement in addition to this library.\n\n### Client\n\n    var fs = require('fs');\n    var https = require('https');\n    var httpSignature = require('http-signature');\n\n    var key = fs.readFileSync('./key.pem', 'ascii');\n\n    var options = {\n      host: 'localhost',\n      port: 8443,\n      path: '/',\n      method: 'GET',\n      headers: {}\n    };\n\n    // Adds a 'Date' header in, signs it, and adds the\n    // 'Authorization' header in.\n    var req = https.request(options, function(res) {\n      console.log(res.statusCode);\n    });\n\n\n    httpSignature.sign(req, {\n      key: key,\n      keyId: './cert.pem'\n    });\n\n    req.end();\n\n### Server\n\n    var fs = require('fs');\n    var https = require('https');\n    var httpSignature = require('http-signature');\n\n    var options = {\n      key: fs.readFileSync('./key.pem'),\n      cert: fs.readFileSync('./cert.pem')\n    };\n\n    https.createServer(options, function (req, res) {\n      var rc = 200;\n      var parsed = httpSignature.parseRequest(req);\n      var pub = fs.readFileSync(parsed.keyId, 'ascii');\n      if (!httpSignature.verifySignature(parsed, pub))\n        rc = 401;\n\n      res.writeHead(rc);\n      res.end();\n    }).listen(8443);\n\n## Installation\n\n    npm install http-signature\n\n## License\n\nMIT.\n\n## Bugs\n\nSee <https://github.com/joyent/node-http-signature/issues>.\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/joyent/node-http-signature/issues"
+  },
+  "homepage": "https://github.com/joyent/node-http-signature",
+  "_id": "http-signature@0.10.0",
+  "_from": "http-signature@~0.10.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/LICENSE	(revision 517)
@@ -0,0 +1,27 @@
+Copyright (c) Isaac Z. Schlueter ("Author")
+All rights reserved.
+
+The BSD License
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/README.md	(revision 517)
@@ -0,0 +1,49 @@
+# json-stringify-safe
+
+Like JSON.stringify, but doesn't throw on circular references.
+
+## Usage
+
+Takes the same arguments as `JSON.stringify`.
+
+```javascript
+var stringify = require('json-stringify-safe');
+var circularObj = {};
+circularObj.circularRef = circularObj;
+circularObj.list = [ circularObj, circularObj ];
+console.log(stringify(circularObj, null, 2));
+```
+
+Output:
+
+```json
+{
+  "circularRef": "[Circular]",
+  "list": [
+    "[Circular]",
+    "[Circular]"
+  ]
+}
+```
+
+## Details
+
+```
+stringify(obj, serializer, indent, decycler)
+```
+
+The first three arguments are the same as to JSON.stringify.  The last
+is an argument that's only used when the object has been seen already.
+
+The default `decycler` function returns the string `'[Circular]'`.
+If, for example, you pass in `function(k,v){}` (return nothing) then it
+will prune cycles.  If you pass in `function(k,v){ return {foo: 'bar'}}`,
+then cyclical objects will always be represented as `{"foo":"bar"}` in
+the result.
+
+```
+stringify.getSerialize(serializer, decycler)
+```
+
+Returns a serializer that can be used elsewhere.  This is the actual
+function that's passed to JSON.stringify.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/package.json	(revision 517)
@@ -0,0 +1,33 @@
+{
+  "name": "json-stringify-safe",
+  "version": "5.0.0",
+  "description": "Like JSON.stringify, but doesn't blow up on circular refs",
+  "main": "stringify.js",
+  "scripts": {
+    "test": "node test.js"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/isaacs/json-stringify-safe"
+  },
+  "keywords": [
+    "json",
+    "stringify",
+    "circular",
+    "safe"
+  ],
+  "author": {
+    "name": "Isaac Z. Schlueter",
+    "email": "i@izs.me",
+    "url": "http://blog.izs.me"
+  },
+  "license": "BSD",
+  "readmeFilename": "README.md",
+  "readme": "# json-stringify-safe\n\nLike JSON.stringify, but doesn't throw on circular references.\n\n## Usage\n\nTakes the same arguments as `JSON.stringify`.\n\n```javascript\nvar stringify = require('json-stringify-safe');\nvar circularObj = {};\ncircularObj.circularRef = circularObj;\ncircularObj.list = [ circularObj, circularObj ];\nconsole.log(stringify(circularObj, null, 2));\n```\n\nOutput:\n\n```json\n{\n  \"circularRef\": \"[Circular]\",\n  \"list\": [\n    \"[Circular]\",\n    \"[Circular]\"\n  ]\n}\n```\n\n## Details\n\n```\nstringify(obj, serializer, indent, decycler)\n```\n\nThe first three arguments are the same as to JSON.stringify.  The last\nis an argument that's only used when the object has been seen already.\n\nThe default `decycler` function returns the string `'[Circular]'`.\nIf, for example, you pass in `function(k,v){}` (return nothing) then it\nwill prune cycles.  If you pass in `function(k,v){ return {foo: 'bar'}}`,\nthen cyclical objects will always be represented as `{\"foo\":\"bar\"}` in\nthe result.\n\n```\nstringify.getSerialize(serializer, decycler)\n```\n\nReturns a serializer that can be used elsewhere.  This is the actual\nfunction that's passed to JSON.stringify.\n",
+  "bugs": {
+    "url": "https://github.com/isaacs/json-stringify-safe/issues"
+  },
+  "homepage": "https://github.com/isaacs/json-stringify-safe",
+  "_id": "json-stringify-safe@5.0.0",
+  "_from": "json-stringify-safe@~5.0.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/stringify.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/stringify.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/stringify.js	(revision 517)
@@ -0,0 +1,39 @@
+module.exports = stringify;
+
+function getSerialize (fn, decycle) {
+  var seen = [], keys = [];
+  decycle = decycle || function(key, value) {
+    return '[Circular ' + getPath(value, seen, keys) + ']'
+  };
+  return function(key, value) {
+    var ret = value;
+    if (typeof value === 'object' && value) {
+      if (seen.indexOf(value) !== -1)
+        ret = decycle(key, value);
+      else {
+        seen.push(value);
+        keys.push(key);
+      }
+    }
+    if (fn) ret = fn(key, ret);
+    return ret;
+  }
+}
+
+function getPath (value, seen, keys) {
+  var index = seen.indexOf(value);
+  var path = [ keys[index] ];
+  for (index--; index >= 0; index--) {
+    if (seen[index][ path[0] ] === value) {
+      value = seen[index];
+      path.unshift(keys[index]);
+    }
+  }
+  return '~' + path.join('.');
+}
+
+function stringify(obj, fn, spaces, decycle) {
+  return JSON.stringify(obj, getSerialize(fn, decycle), spaces);
+}
+
+stringify.getSerialize = getSerialize;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/json-stringify-safe/test.js	(revision 517)
@@ -0,0 +1,128 @@
+var stringify = require('./stringify.js');
+
+var circularObj = { a: 'b' };
+circularObj.circularRef = circularObj;
+circularObj.list = [ circularObj, circularObj ];
+
+//////////
+// default
+var testObj = {
+  "a": "b",
+  "circularRef": "[Circular ~]",
+  "list": [
+    "[Circular ~]",
+    "[Circular ~]"
+  ]
+};
+
+var assert = require('assert');
+assert.equal(JSON.stringify(testObj, null, 2),
+             stringify(circularObj, null, 2));
+
+assert.equal(JSON.stringify(testObj, null, 2),
+            JSON.stringify(circularObj, stringify.getSerialize(), 2));
+
+
+////////
+// prune
+testObj = {
+  "a": "b",
+  "list": [
+    null,
+    null
+  ]
+};
+
+function prune(k, v) {}
+
+assert.equal(JSON.stringify(testObj, null, 2),
+             stringify(circularObj, null, 2, prune));
+
+///////////
+// re-cycle
+// (throws)
+function recycle(k, v) {
+  return v;
+}
+
+assert.throws(function() {
+  stringify(circularObj, null, 2, recycle);
+});
+
+////////
+// fancy
+testObj = {
+  "a": "b",
+  "circularRef": "circularRef{a:string,circularRef:Object,list:Array}",
+  "list": [
+    "0{a:string,circularRef:Object,list:Array}",
+    "1{a:string,circularRef:Object,list:Array}"
+  ]
+};
+
+function signer(key, value) {
+  var ret = key + '{';
+  var f = false;
+  for (var i in value) {
+    if (f)
+      ret += ',';
+    f = true;
+    ret += i + ':';
+    var v = value[i];
+    switch (typeof v) {
+      case 'object':
+        if (!v)
+          ret += 'null';
+        else if (Array.isArray(v))
+          ret += 'Array'
+        else
+          ret += v.constructor && v.constructor.name || 'Object';
+        break;
+      default:
+        ret += typeof v;
+        break;
+    }
+  }
+  ret += '}';
+  return ret;
+}
+
+assert.equal(JSON.stringify(testObj, null, 2),
+             stringify(circularObj, null, 2, signer));
+
+
+///////
+//multi
+var a = { x: 1 };
+a.a = a;
+var b = { x: 2 };
+b.a = a;
+
+var c = { a: a, b: b };
+var d = { list: [ a, b, c ] };
+d.d = d;
+
+var multi = {
+  "list": [
+    {
+      "x": 1,
+      "a": "[Circular ~.list.0]"
+    },
+    {
+      "x": 2,
+      "a": "[Circular ~.list.0]"
+    },
+    {
+      "a": "[Circular ~.list.0]",
+      "b": "[Circular ~.list.1]"
+    }
+  ],
+  "d": "[Circular ~]"
+};
+
+assert.equal(JSON.stringify(multi, null, 2),
+             stringify(d, null, 2));
+
+////////
+// pass!
+console.log('ok');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/LICENSE	(revision 517)
@@ -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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/README.md	(revision 517)
@@ -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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/mime.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/mime.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/mime.js	(revision 517)
@@ -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;
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/package.json	(revision 517)
@@ -0,0 +1,36 @@
+{
+  "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.11",
+  "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"
+  },
+  "homepage": "https://github.com/broofa/node-mime",
+  "_id": "mime@1.2.11",
+  "_from": "mime@~1.2.9"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/test.js	(revision 517)
@@ -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'));     // normal file
+eq('text/plain', mime.lookup('TEXT.TXT'));     // uppercase
+eq('text/plain', mime.lookup('dir/text.txt')); // dir + file
+eq('text/plain', mime.lookup('.text.txt'));    // hidden file
+eq('text/plain', mime.lookup('.txt'));         // nameless
+eq('text/plain', mime.lookup('txt'));          // extension-only
+eq('text/plain', mime.lookup('/txt'));         // extension-less ()
+eq('text/plain', mime.lookup('\\txt'));        // Windows, extension-less
+eq('application/octet-stream', mime.lookup('text.nope')); // unrecognized
+eq('fallback', mime.lookup('text.fallback', 'fallback')); // alternate default
+
+//
+// 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('unrecognized'));
+
+//
+// Test node.types lookups
+//
+
+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');
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/types/mime.types
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/types/mime.types	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/types/mime.types	(revision 517)
@@ -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 <http://www.iana.org/assignments/media-types/>.
+#
+# 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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/types/node.types
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/types/node.types	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/mime/types/node.types	(revision 517)
@@ -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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/.npmignore	(revision 517)
@@ -0,0 +1,2 @@
+node_modules
+.DS_Store
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/LICENSE.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/LICENSE.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/LICENSE.md	(revision 517)
@@ -0,0 +1,2 @@
+Copyright (c) 2010-2012 Robert Kieffer
+MIT License - http://opensource.org/licenses/mit-license.php
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/README.md	(revision 517)
@@ -0,0 +1,207 @@
+# node-uuid
+
+Simple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS.
+
+Features:
+
+* Generate RFC4122 version 1 or version 4 UUIDs
+* Runs in node.js and all browsers.
+* Registered as a [ComponentJS](https://github.com/component/component) [component](https://github.com/component/component/wiki/Components) ('broofa/node-uuid').
+* Cryptographically strong random # generation on supporting platforms
+* 1.1K minified and gzip'ed  (Want something smaller?  Check this [crazy shit](https://gist.github.com/982883) out! )
+* [Annotated source code](http://broofa.github.com/node-uuid/docs/uuid.html)
+
+## Getting Started
+
+Install it in your browser:
+
+```html
+<script src="uuid.js"></script>
+```
+
+Or in node.js:
+
+```
+npm install node-uuid
+```
+
+```javascript
+var uuid = require('node-uuid');
+```
+
+Then create some ids ...
+
+```javascript
+// Generate a v1 (time-based) id
+uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
+
+// Generate a v4 (random) id
+uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
+```
+
+## API
+
+### uuid.v1([`options` [, `buffer` [, `offset`]]])
+
+Generate and return a RFC4122 v1 (timestamp-based) UUID.
+
+* `options` - (Object) Optional uuid state to apply. Properties may include:
+
+  * `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomly generated ID.  See note 1.
+  * `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence.  Default: An internally maintained clockseq is used.
+  * `msecs` - (Number | Date) Time in milliseconds since unix Epoch.  Default: The current time is used.
+  * `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2.
+
+* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written.
+* `offset` - (Number) Starting index in `buffer` at which to begin writing.
+
+Returns `buffer`, if specified, otherwise the string form of the UUID
+
+Notes:
+
+1. The randomly generated node id is only guaranteed to stay constant for the lifetime of the current JS runtime. (Future versions of this module may use persistent storage mechanisms to extend this guarantee.)
+
+Example: Generate string UUID with fully-specified options
+
+```javascript
+uuid.v1({
+  node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
+  clockseq: 0x1234,
+  msecs: new Date('2011-11-01').getTime(),
+  nsecs: 5678
+});   // -> "710b962e-041c-11e1-9234-0123456789ab"
+```
+
+Example: In-place generation of two binary IDs
+
+```javascript
+// Generate two ids in an array
+var arr = new Array(32); // -> []
+uuid.v1(null, arr, 0);   // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15]
+uuid.v1(null, arr, 16);  // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15 02 a3 1c b0 14 32 11 e1 85 58 0b 48 8e 4f c1 15]
+
+// Optionally use uuid.unparse() to get stringify the ids
+uuid.unparse(buffer);    // -> '02a2ce90-1432-11e1-8558-0b488e4fc115'
+uuid.unparse(buffer, 16) // -> '02a31cb0-1432-11e1-8558-0b488e4fc115'
+```
+
+### uuid.v4([`options` [, `buffer` [, `offset`]]])
+
+Generate and return a RFC4122 v4 UUID.
+
+* `options` - (Object) Optional uuid state to apply. Properties may include:
+
+  * `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values
+  * `rng` - (Function) Random # generator to use.  Set to one of the built-in generators - `uuid.mathRNG` (all platforms), `uuid.nodeRNG` (node.js only), `uuid.whatwgRNG` (WebKit only) - or a custom function that returns an array[16] of byte values.
+
+* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written.
+* `offset` - (Number) Starting index in `buffer` at which to begin writing.
+
+Returns `buffer`, if specified, otherwise the string form of the UUID
+
+Example: Generate string UUID with fully-specified options
+
+```javascript
+uuid.v4({
+  random: [
+    0x10, 0x91, 0x56, 0xbe, 0xc4, 0xfb, 0xc1, 0xea,
+    0x71, 0xb4, 0xef, 0xe1, 0x67, 0x1c, 0x58, 0x36
+  ]
+});
+// -> "109156be-c4fb-41ea-b1b4-efe1671c5836"
+```
+
+Example: Generate two IDs in a single buffer
+
+```javascript
+var buffer = new Array(32); // (or 'new Buffer' in node.js)
+uuid.v4(null, buffer, 0);
+uuid.v4(null, buffer, 16);
+```
+
+### uuid.parse(id[, buffer[, offset]])
+### uuid.unparse(buffer[, offset])
+
+Parse and unparse UUIDs
+
+  * `id` - (String) UUID(-like) string
+  * `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. Default: A new Array or Buffer is used
+  * `offset` - (Number) Starting index in `buffer` at which to begin writing. Default: 0
+
+Example parsing and unparsing a UUID string
+
+```javascript
+var bytes = uuid.parse('797ff043-11eb-11e1-80d6-510998755d10'); // -> <Buffer 79 7f f0 43 11 eb 11 e1 80 d6 51 09 98 75 5d 10>
+var string = uuid.unparse(bytes); // -> '797ff043-11eb-11e1-80d6-510998755d10'
+```
+
+### uuid.noConflict()
+
+(Browsers only) Set `uuid` property back to it's previous value.
+
+Returns the node-uuid object.
+
+Example:
+
+```javascript
+var myUuid = uuid.noConflict();
+myUuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
+```
+
+## Deprecated APIs
+
+Support for the following v1.2 APIs is available in v1.3, but is deprecated and will be removed in the next major version.
+
+### uuid([format [, buffer [, offset]]])
+
+uuid() has become uuid.v4(), and the `format` argument is now implicit in the `buffer` argument. (i.e. if you specify a buffer, the format is assumed to be binary).
+
+### uuid.BufferClass
+
+The class of container created when generating binary uuid data if no buffer argument is specified.  This is expected to go away, with no replacement API.
+
+## Testing
+
+In node.js
+
+```
+> cd test
+> node test.js
+```
+
+In Browser
+
+```
+open test/test.html
+```
+
+### Benchmarking
+
+Requires node.js
+
+```
+npm install uuid uuid-js
+node benchmark/benchmark.js
+```
+
+For a more complete discussion of node-uuid performance, please see the `benchmark/README.md` file, and the [benchmark wiki](https://github.com/broofa/node-uuid/wiki/Benchmark)
+
+For browser performance [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance).
+
+## Release notes
+
+### 1.4.0
+
+* Improved module context detection
+* Removed public RNG functions
+
+### 1.3.2
+
+* Improve tests and handling of v1() options (Issue #24)
+* Expose RNG option to allow for perf testing with different generators
+
+### 1.3.0
+
+* Support for version 1 ids, thanks to [@ctavan](https://github.com/ctavan)!
+* Support for node.js crypto API
+* De-emphasizing performance in favor of a) cryptographic quality PRNGs where available and b) more manageable code
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/README.md	(revision 517)
@@ -0,0 +1,53 @@
+# node-uuid Benchmarks
+
+### Results
+
+To see the results of our benchmarks visit https://github.com/broofa/node-uuid/wiki/Benchmark
+
+### Run them yourself
+
+node-uuid comes with some benchmarks to measure performance of generating UUIDs. These can be run using node.js. node-uuid is being benchmarked against some other uuid modules, that are available through npm namely `uuid` and `uuid-js`.
+
+To prepare and run the benchmark issue;
+
+```
+npm install uuid uuid-js
+node benchmark/benchmark.js
+```
+
+You'll see an output like this one:
+
+```
+# v4
+nodeuuid.v4(): 854700 uuids/second
+nodeuuid.v4('binary'): 788643 uuids/second
+nodeuuid.v4('binary', buffer): 1336898 uuids/second
+uuid(): 479386 uuids/second
+uuid('binary'): 582072 uuids/second
+uuidjs.create(4): 312304 uuids/second
+
+# v1
+nodeuuid.v1(): 938086 uuids/second
+nodeuuid.v1('binary'): 683060 uuids/second
+nodeuuid.v1('binary', buffer): 1644736 uuids/second
+uuidjs.create(1): 190621 uuids/second
+```
+
+* The `uuid()` entries are for Nikhil Marathe's [uuid module](https://bitbucket.org/nikhilm/uuidjs) which is a wrapper around the native libuuid library.
+* The `uuidjs()` entries are for Patrick Negri's [uuid-js module](https://github.com/pnegri/uuid-js) which is a pure javascript implementation based on [UUID.js](https://github.com/LiosK/UUID.js) by LiosK.
+
+If you want to get more reliable results you can run the benchmark multiple times and write the output into a log file:
+
+```
+for i in {0..9}; do node benchmark/benchmark.js >> benchmark/bench_0.4.12.log; done;
+```
+
+If you're interested in how performance varies between different node versions, you can issue the above command multiple times.
+
+You can then use the shell script `bench.sh` provided in this directory to calculate the averages over all benchmark runs and draw a nice plot:
+
+```
+(cd benchmark/ && ./bench.sh)
+```
+
+This assumes you have [gnuplot](http://www.gnuplot.info/) and [ImageMagick](http://www.imagemagick.org/) installed. You'll find a nice `bench.png` graph in the `benchmark/` directory then.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/bench.gnu
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/bench.gnu	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/bench.gnu	(revision 517)
@@ -0,0 +1,174 @@
+#!/opt/local/bin/gnuplot -persist
+#
+#    
+#    	G N U P L O T
+#    	Version 4.4 patchlevel 3
+#    	last modified March 2011
+#    	System: Darwin 10.8.0
+#    
+#    	Copyright (C) 1986-1993, 1998, 2004, 2007-2010
+#    	Thomas Williams, Colin Kelley and many others
+#    
+#    	gnuplot home:     http://www.gnuplot.info
+#    	faq, bugs, etc:   type "help seeking-assistance"
+#    	immediate help:   type "help"
+#    	plot window:      hit 'h'
+set terminal postscript eps noenhanced defaultplex \
+ leveldefault color colortext \
+ solid linewidth 1.2 butt noclip \
+ palfuncparam 2000,0.003 \
+ "Helvetica" 14 
+set output 'bench.eps'
+unset clip points
+set clip one
+unset clip two
+set bar 1.000000 front
+set border 31 front linetype -1 linewidth 1.000
+set xdata
+set ydata
+set zdata
+set x2data
+set y2data
+set timefmt x "%d/%m/%y,%H:%M"
+set timefmt y "%d/%m/%y,%H:%M"
+set timefmt z "%d/%m/%y,%H:%M"
+set timefmt x2 "%d/%m/%y,%H:%M"
+set timefmt y2 "%d/%m/%y,%H:%M"
+set timefmt cb "%d/%m/%y,%H:%M"
+set boxwidth
+set style fill  empty border
+set style rectangle back fc lt -3 fillstyle   solid 1.00 border lt -1
+set style circle radius graph 0.02, first 0, 0 
+set dummy x,y
+set format x "% g"
+set format y "% g"
+set format x2 "% g"
+set format y2 "% g"
+set format z "% g"
+set format cb "% g"
+set angles radians
+unset grid
+set key title ""
+set key outside left top horizontal Right noreverse enhanced autotitles columnhead nobox
+set key noinvert samplen 4 spacing 1 width 0 height 0 
+set key maxcolumns 2 maxrows 0
+unset label
+unset arrow
+set style increment default
+unset style line
+set style line 1  linetype 1 linewidth 2.000 pointtype 1 pointsize default pointinterval 0
+unset style arrow
+set style histogram clustered gap 2 title  offset character 0, 0, 0
+unset logscale
+set offsets graph 0.05, 0.15, 0, 0
+set pointsize 1.5
+set pointintervalbox 1
+set encoding default
+unset polar
+unset parametric
+unset decimalsign
+set view 60, 30, 1, 1
+set samples 100, 100
+set isosamples 10, 10
+set surface
+unset contour
+set clabel '%8.3g'
+set mapping cartesian
+set datafile separator whitespace
+unset hidden3d
+set cntrparam order 4
+set cntrparam linear
+set cntrparam levels auto 5
+set cntrparam points 5
+set size ratio 0 1,1
+set origin 0,0
+set style data points
+set style function lines
+set xzeroaxis linetype -2 linewidth 1.000
+set yzeroaxis linetype -2 linewidth 1.000
+set zzeroaxis linetype -2 linewidth 1.000
+set x2zeroaxis linetype -2 linewidth 1.000
+set y2zeroaxis linetype -2 linewidth 1.000
+set ticslevel 0.5
+set mxtics default
+set mytics default
+set mztics default
+set mx2tics default
+set my2tics default
+set mcbtics default
+set xtics border in scale 1,0.5 mirror norotate  offset character 0, 0, 0
+set xtics  norangelimit
+set xtics   ()
+set ytics border in scale 1,0.5 mirror norotate  offset character 0, 0, 0
+set ytics autofreq  norangelimit
+set ztics border in scale 1,0.5 nomirror norotate  offset character 0, 0, 0
+set ztics autofreq  norangelimit
+set nox2tics
+set noy2tics
+set cbtics border in scale 1,0.5 mirror norotate  offset character 0, 0, 0
+set cbtics autofreq  norangelimit
+set title "" 
+set title  offset character 0, 0, 0 font "" norotate
+set timestamp bottom 
+set timestamp "" 
+set timestamp  offset character 0, 0, 0 font "" norotate
+set rrange [ * : * ] noreverse nowriteback  # (currently [8.98847e+307:-8.98847e+307] )
+set autoscale rfixmin
+set autoscale rfixmax
+set trange [ * : * ] noreverse nowriteback  # (currently [-5.00000:5.00000] )
+set autoscale tfixmin
+set autoscale tfixmax
+set urange [ * : * ] noreverse nowriteback  # (currently [-10.0000:10.0000] )
+set autoscale ufixmin
+set autoscale ufixmax
+set vrange [ * : * ] noreverse nowriteback  # (currently [-10.0000:10.0000] )
+set autoscale vfixmin
+set autoscale vfixmax
+set xlabel "" 
+set xlabel  offset character 0, 0, 0 font "" textcolor lt -1 norotate
+set x2label "" 
+set x2label  offset character 0, 0, 0 font "" textcolor lt -1 norotate
+set xrange [ * : * ] noreverse nowriteback  # (currently [-0.150000:3.15000] )
+set autoscale xfixmin
+set autoscale xfixmax
+set x2range [ * : * ] noreverse nowriteback  # (currently [0.00000:3.00000] )
+set autoscale x2fixmin
+set autoscale x2fixmax
+set ylabel "" 
+set ylabel  offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270
+set y2label "" 
+set y2label  offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270
+set yrange [ 0.00000 : 1.90000e+06 ] noreverse nowriteback  # (currently [:] )
+set autoscale yfixmin
+set autoscale yfixmax
+set y2range [ * : * ] noreverse nowriteback  # (currently [0.00000:1.90000e+06] )
+set autoscale y2fixmin
+set autoscale y2fixmax
+set zlabel "" 
+set zlabel  offset character 0, 0, 0 font "" textcolor lt -1 norotate
+set zrange [ * : * ] noreverse nowriteback  # (currently [-10.0000:10.0000] )
+set autoscale zfixmin
+set autoscale zfixmax
+set cblabel "" 
+set cblabel  offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270
+set cbrange [ * : * ] noreverse nowriteback  # (currently [8.98847e+307:-8.98847e+307] )
+set autoscale cbfixmin
+set autoscale cbfixmax
+set zero 1e-08
+set lmargin  -1
+set bmargin  -1
+set rmargin  -1
+set tmargin  -1
+set pm3d explicit at s
+set pm3d scansautomatic
+set pm3d interpolate 1,1 flush begin noftriangles nohidden3d corners2color mean
+set palette positive nops_allcF maxcolors 0 gamma 1.5 color model RGB 
+set palette rgbformulae 7, 5, 15
+set colorbox default
+set colorbox vertical origin screen 0.9, 0.2, 0 size screen 0.05, 0.6, 0 front bdefault
+set loadpath 
+set fontpath 
+set fit noerrorvariables
+GNUTERM = "aqua"
+plot 'bench_results.txt' using 2:xticlabel(1) w lp lw 2, '' using 3:xticlabel(1) w lp lw 2, '' using 4:xticlabel(1) w lp lw 2, '' using 5:xticlabel(1) w lp lw 2, '' using 6:xticlabel(1) w lp lw 2, '' using 7:xticlabel(1) w lp lw 2, '' using 8:xticlabel(1) w lp lw 2, '' using 9:xticlabel(1) w lp lw 2
+#    EOF
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/bench.sh
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/bench.sh	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/bench.sh	(revision 517)
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# for a given node version run:
+# for i in {0..9}; do node benchmark.js >> bench_0.6.2.log; done;
+
+PATTERNS=('nodeuuid.v1()' "nodeuuid.v1('binary'," 'nodeuuid.v4()' "nodeuuid.v4('binary'," "uuid()" "uuid('binary')" 'uuidjs.create(1)' 'uuidjs.create(4)' '140byte')
+FILES=(node_uuid_v1_string node_uuid_v1_buf node_uuid_v4_string node_uuid_v4_buf libuuid_v4_string libuuid_v4_binary uuidjs_v1_string uuidjs_v4_string 140byte_es)
+INDICES=(2 3 2 3 2 2 2 2 2)
+VERSIONS=$( ls bench_*.log | sed -e 's/^bench_\([0-9\.]*\)\.log/\1/' | tr "\\n" " " )
+TMPJOIN="tmp_join"
+OUTPUT="bench_results.txt"
+
+for I in ${!FILES[*]}; do
+  F=${FILES[$I]}
+  P=${PATTERNS[$I]}
+  INDEX=${INDICES[$I]}
+  echo "version $F" > $F
+  for V in $VERSIONS; do
+    (VAL=$( grep "$P" bench_$V.log | LC_ALL=en_US awk '{ sum += $'$INDEX' } END { print sum/NR }' ); echo $V $VAL) >> $F
+  done
+  if [ $I == 0 ]; then
+    cat $F > $TMPJOIN
+  else
+    join $TMPJOIN $F > $OUTPUT
+    cp $OUTPUT $TMPJOIN
+  fi
+  rm $F
+done
+
+rm $TMPJOIN
+
+gnuplot bench.gnu
+convert -density 200 -resize 800x560 -flatten bench.eps bench.png
+rm bench.eps
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/benchmark-native.c
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/benchmark-native.c	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/benchmark-native.c	(revision 517)
@@ -0,0 +1,34 @@
+/*
+Test performance of native C UUID generation
+
+To Compile: cc -luuid benchmark-native.c -o benchmark-native
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <uuid/uuid.h>
+
+int main() {
+  uuid_t myid;
+  char buf[36+1];
+  int i;
+  struct timeval t;
+  double start, finish;
+
+  gettimeofday(&t, NULL);
+  start = t.tv_sec + t.tv_usec/1e6;
+
+  int n = 2e5;
+  for (i = 0; i < n; i++) {
+    uuid_generate(myid);
+    uuid_unparse(myid, buf);
+  }
+
+  gettimeofday(&t, NULL);
+  finish = t.tv_sec + t.tv_usec/1e6;
+  double dur = finish - start;
+
+  printf("%d uuids/sec", (int)(n/dur));
+  return 0;
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/benchmark.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/benchmark.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/benchmark/benchmark.js	(revision 517)
@@ -0,0 +1,84 @@
+try {
+  var nodeuuid = require('../uuid');
+} catch (e) {
+  console.error('node-uuid require failed - skipping tests');
+}
+
+try {
+  var uuid = require('uuid');
+} catch (e) {
+  console.error('uuid require failed - skipping tests');
+}
+
+try {
+  var uuidjs = require('uuid-js');
+} catch (e) {
+  console.error('uuid-js require failed - skipping tests');
+}
+
+var N = 5e5;
+
+function rate(msg, t) {
+  console.log(msg + ': ' +
+    (N / (Date.now() - t) * 1e3 | 0) +
+    ' uuids/second');
+}
+
+console.log('# v4');
+
+// node-uuid - string form
+if (nodeuuid) {
+  for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4();
+  rate('nodeuuid.v4() - using node.js crypto RNG', t);
+
+  for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4({rng: nodeuuid.mathRNG});
+  rate('nodeuuid.v4() - using Math.random() RNG', t);
+
+  for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4('binary');
+  rate('nodeuuid.v4(\'binary\')', t);
+
+  var buffer = new nodeuuid.BufferClass(16);
+  for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4('binary', buffer);
+  rate('nodeuuid.v4(\'binary\', buffer)', t);
+}
+
+// libuuid - string form
+if (uuid) {
+  for (var i = 0, t = Date.now(); i < N; i++) uuid();
+  rate('uuid()', t);
+
+  for (var i = 0, t = Date.now(); i < N; i++) uuid('binary');
+  rate('uuid(\'binary\')', t);
+}
+
+// uuid-js - string form
+if (uuidjs) {
+  for (var i = 0, t = Date.now(); i < N; i++) uuidjs.create(4);
+  rate('uuidjs.create(4)', t);
+}
+
+// 140byte.es
+for (var i = 0, t = Date.now(); i < N; i++) 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(s,r){r=Math.random()*16|0;return (s=='x'?r:r&0x3|0x8).toString(16)});
+rate('140byte.es_v4', t);
+
+console.log('');
+console.log('# v1');
+
+// node-uuid - v1 string form
+if (nodeuuid) {
+  for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1();
+  rate('nodeuuid.v1()', t);
+
+  for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1('binary');
+  rate('nodeuuid.v1(\'binary\')', t);
+
+  var buffer = new nodeuuid.BufferClass(16);
+  for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1('binary', buffer);
+  rate('nodeuuid.v1(\'binary\', buffer)', t);
+}
+
+// uuid-js - v1 string form
+if (uuidjs) {
+  for (var i = 0, t = Date.now(); i < N; i++) uuidjs.create(1);
+  rate('uuidjs.create(1)', t);
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/component.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/component.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/component.json	(revision 517)
@@ -0,0 +1,18 @@
+{
+  "name": "node-uuid",
+  "repo": "broofa/node-uuid",
+  "description": "Rigorous implementation of RFC4122 (v1 and v4) UUIDs.",
+  "version": "1.4.0",
+  "author": "Robert Kieffer <robert@broofa.com>",
+  "contributors": [
+    {"name": "Christoph Tavan <dev@tavan.de>", "github": "https://github.com/ctavan"}
+  ],
+  "keywords": ["uuid", "guid", "rfc4122"],
+  "dependencies": {},
+  "development": {},
+  "main": "uuid.js",
+  "scripts": [
+    "uuid.js"
+  ],
+  "license": "MIT"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/package.json	(revision 517)
@@ -0,0 +1,35 @@
+{
+  "name": "node-uuid",
+  "description": "Rigorous implementation of RFC4122 (v1 and v4) UUIDs.",
+  "url": "http://github.com/broofa/node-uuid",
+  "keywords": [
+    "uuid",
+    "guid",
+    "rfc4122"
+  ],
+  "author": {
+    "name": "Robert Kieffer",
+    "email": "robert@broofa.com"
+  },
+  "contributors": [
+    {
+      "name": "Christoph Tavan",
+      "email": "dev@tavan.de"
+    }
+  ],
+  "lib": ".",
+  "main": "./uuid.js",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/broofa/node-uuid.git"
+  },
+  "version": "1.4.1",
+  "readme": "# node-uuid\n\nSimple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS.\n\nFeatures:\n\n* Generate RFC4122 version 1 or version 4 UUIDs\n* Runs in node.js and all browsers.\n* Registered as a [ComponentJS](https://github.com/component/component) [component](https://github.com/component/component/wiki/Components) ('broofa/node-uuid').\n* Cryptographically strong random # generation on supporting platforms\n* 1.1K minified and gzip'ed  (Want something smaller?  Check this [crazy shit](https://gist.github.com/982883) out! )\n* [Annotated source code](http://broofa.github.com/node-uuid/docs/uuid.html)\n\n## Getting Started\n\nInstall it in your browser:\n\n```html\n<script src=\"uuid.js\"></script>\n```\n\nOr in node.js:\n\n```\nnpm install node-uuid\n```\n\n```javascript\nvar uuid = require('node-uuid');\n```\n\nThen create some ids ...\n\n```javascript\n// Generate a v1 (time-based) id\nuuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'\n\n// Generate a v4 (random) id\nuuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'\n```\n\n## API\n\n### uuid.v1([`options` [, `buffer` [, `offset`]]])\n\nGenerate and return a RFC4122 v1 (timestamp-based) UUID.\n\n* `options` - (Object) Optional uuid state to apply. Properties may include:\n\n  * `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomly generated ID.  See note 1.\n  * `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence.  Default: An internally maintained clockseq is used.\n  * `msecs` - (Number | Date) Time in milliseconds since unix Epoch.  Default: The current time is used.\n  * `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2.\n\n* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written.\n* `offset` - (Number) Starting index in `buffer` at which to begin writing.\n\nReturns `buffer`, if specified, otherwise the string form of the UUID\n\nNotes:\n\n1. The randomly generated node id is only guaranteed to stay constant for the lifetime of the current JS runtime. (Future versions of this module may use persistent storage mechanisms to extend this guarantee.)\n\nExample: Generate string UUID with fully-specified options\n\n```javascript\nuuid.v1({\n  node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],\n  clockseq: 0x1234,\n  msecs: new Date('2011-11-01').getTime(),\n  nsecs: 5678\n});   // -> \"710b962e-041c-11e1-9234-0123456789ab\"\n```\n\nExample: In-place generation of two binary IDs\n\n```javascript\n// Generate two ids in an array\nvar arr = new Array(32); // -> []\nuuid.v1(null, arr, 0);   // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15]\nuuid.v1(null, arr, 16);  // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15 02 a3 1c b0 14 32 11 e1 85 58 0b 48 8e 4f c1 15]\n\n// Optionally use uuid.unparse() to get stringify the ids\nuuid.unparse(buffer);    // -> '02a2ce90-1432-11e1-8558-0b488e4fc115'\nuuid.unparse(buffer, 16) // -> '02a31cb0-1432-11e1-8558-0b488e4fc115'\n```\n\n### uuid.v4([`options` [, `buffer` [, `offset`]]])\n\nGenerate and return a RFC4122 v4 UUID.\n\n* `options` - (Object) Optional uuid state to apply. Properties may include:\n\n  * `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values\n  * `rng` - (Function) Random # generator to use.  Set to one of the built-in generators - `uuid.mathRNG` (all platforms), `uuid.nodeRNG` (node.js only), `uuid.whatwgRNG` (WebKit only) - or a custom function that returns an array[16] of byte values.\n\n* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written.\n* `offset` - (Number) Starting index in `buffer` at which to begin writing.\n\nReturns `buffer`, if specified, otherwise the string form of the UUID\n\nExample: Generate string UUID with fully-specified options\n\n```javascript\nuuid.v4({\n  random: [\n    0x10, 0x91, 0x56, 0xbe, 0xc4, 0xfb, 0xc1, 0xea,\n    0x71, 0xb4, 0xef, 0xe1, 0x67, 0x1c, 0x58, 0x36\n  ]\n});\n// -> \"109156be-c4fb-41ea-b1b4-efe1671c5836\"\n```\n\nExample: Generate two IDs in a single buffer\n\n```javascript\nvar buffer = new Array(32); // (or 'new Buffer' in node.js)\nuuid.v4(null, buffer, 0);\nuuid.v4(null, buffer, 16);\n```\n\n### uuid.parse(id[, buffer[, offset]])\n### uuid.unparse(buffer[, offset])\n\nParse and unparse UUIDs\n\n  * `id` - (String) UUID(-like) string\n  * `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. Default: A new Array or Buffer is used\n  * `offset` - (Number) Starting index in `buffer` at which to begin writing. Default: 0\n\nExample parsing and unparsing a UUID string\n\n```javascript\nvar bytes = uuid.parse('797ff043-11eb-11e1-80d6-510998755d10'); // -> <Buffer 79 7f f0 43 11 eb 11 e1 80 d6 51 09 98 75 5d 10>\nvar string = uuid.unparse(bytes); // -> '797ff043-11eb-11e1-80d6-510998755d10'\n```\n\n### uuid.noConflict()\n\n(Browsers only) Set `uuid` property back to it's previous value.\n\nReturns the node-uuid object.\n\nExample:\n\n```javascript\nvar myUuid = uuid.noConflict();\nmyUuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'\n```\n\n## Deprecated APIs\n\nSupport for the following v1.2 APIs is available in v1.3, but is deprecated and will be removed in the next major version.\n\n### uuid([format [, buffer [, offset]]])\n\nuuid() has become uuid.v4(), and the `format` argument is now implicit in the `buffer` argument. (i.e. if you specify a buffer, the format is assumed to be binary).\n\n### uuid.BufferClass\n\nThe class of container created when generating binary uuid data if no buffer argument is specified.  This is expected to go away, with no replacement API.\n\n## Testing\n\nIn node.js\n\n```\n> cd test\n> node test.js\n```\n\nIn Browser\n\n```\nopen test/test.html\n```\n\n### Benchmarking\n\nRequires node.js\n\n```\nnpm install uuid uuid-js\nnode benchmark/benchmark.js\n```\n\nFor a more complete discussion of node-uuid performance, please see the `benchmark/README.md` file, and the [benchmark wiki](https://github.com/broofa/node-uuid/wiki/Benchmark)\n\nFor browser performance [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance).\n\n## Release notes\n\n### 1.4.0\n\n* Improved module context detection\n* Removed public RNG functions\n\n### 1.3.2\n\n* Improve tests and handling of v1() options (Issue #24)\n* Expose RNG option to allow for perf testing with different generators\n\n### 1.3.0\n\n* Support for version 1 ids, thanks to [@ctavan](https://github.com/ctavan)!\n* Support for node.js crypto API\n* De-emphasizing performance in favor of a) cryptographic quality PRNGs where available and b) more manageable code\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/broofa/node-uuid/issues"
+  },
+  "homepage": "https://github.com/broofa/node-uuid",
+  "_id": "node-uuid@1.4.1",
+  "_from": "node-uuid@~1.4.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/compare_v1.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/compare_v1.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/compare_v1.js	(revision 517)
@@ -0,0 +1,63 @@
+var assert = require('assert'),
+    nodeuuid = require('../uuid'),
+    uuidjs = require('uuid-js'),
+    libuuid = require('uuid').generate,
+    util = require('util'),
+    exec = require('child_process').exec,
+    os = require('os');
+
+// On Mac Os X / macports there's only the ossp-uuid package that provides uuid
+// On Linux there's uuid-runtime which provides uuidgen
+var uuidCmd = os.type() === 'Darwin' ? 'uuid -1' : 'uuidgen -t';
+
+function compare(ids) {
+  console.log(ids);
+  for (var i = 0; i < ids.length; i++) {
+    var id = ids[i].split('-');
+    id = [id[2], id[1], id[0]].join('');
+    ids[i] = id;
+  }
+  var sorted = ([].concat(ids)).sort();
+
+  if (sorted.toString() !== ids.toString()) {
+    console.log('Warning: sorted !== ids');
+  } else {
+    console.log('everything in order!');
+  }
+}
+
+// Test time order of v1 uuids
+var ids = [];
+while (ids.length < 10e3) ids.push(nodeuuid.v1());
+
+var max = 10;
+console.log('node-uuid:');
+ids = [];
+for (var i = 0; i < max; i++) ids.push(nodeuuid.v1());
+compare(ids);
+
+console.log('');
+console.log('uuidjs:');
+ids = [];
+for (var i = 0; i < max; i++) ids.push(uuidjs.create(1).toString());
+compare(ids);
+
+console.log('');
+console.log('libuuid:');
+ids = [];
+var count = 0;
+var last = function() {
+  compare(ids);
+}
+var cb = function(err, stdout, stderr) {
+  ids.push(stdout.substring(0, stdout.length-1));
+  count++;
+  if (count < max) {
+    return next();
+  }
+  last();
+};
+var next = function() {
+  exec(uuidCmd, cb);
+};
+next();
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/test.html
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/test.html	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/test.html	(revision 517)
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <style>
+      div {
+        font-family: monospace;
+        font-size: 8pt;
+      }
+      div.log {color: #444;}
+      div.warn {color: #550;}
+      div.error {color: #800; font-weight: bold;}
+    </style>
+    <script src="../uuid.js"></script>
+  </head>
+  <body>
+    <script src="./test.js"></script>
+  </body>
+</html>
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/test/test.js	(revision 517)
@@ -0,0 +1,228 @@
+if (!this.uuid) {
+  // node.js
+  uuid = require('../uuid');
+}
+
+//
+// x-platform log/assert shims
+//
+
+function _log(msg, type) {
+  type = type || 'log';
+
+  if (typeof(document) != 'undefined') {
+    document.write('<div class="' + type + '">' + msg.replace(/\n/g, '<br />') + '</div>');
+  }
+  if (typeof(console) != 'undefined') {
+    var color = {
+      log: '\033[39m',
+      warn: '\033[33m',
+      error: '\033[31m'
+    };
+    console[type](color[type] + msg + color.log);
+  }
+}
+
+function log(msg) {_log(msg, 'log');}
+function warn(msg) {_log(msg, 'warn');}
+function error(msg) {_log(msg, 'error');}
+
+function assert(res, msg) {
+  if (!res) {
+    error('FAIL: ' + msg);
+  } else {
+    log('Pass: ' + msg);
+  }
+}
+
+//
+// Unit tests
+//
+
+// Verify ordering of v1 ids created with explicit times
+var TIME = 1321644961388; // 2011-11-18 11:36:01.388-08:00
+
+function compare(name, ids) {
+  ids = ids.map(function(id) {
+    return id.split('-').reverse().join('-');
+  }).sort();
+  var sorted = ([].concat(ids)).sort();
+
+  assert(sorted.toString() == ids.toString(), name + ' have expected order');
+}
+
+// Verify ordering of v1 ids created using default behavior
+compare('uuids with current time', [
+  uuid.v1(),
+  uuid.v1(),
+  uuid.v1(),
+  uuid.v1(),
+  uuid.v1()
+]);
+
+// Verify ordering of v1 ids created with explicit times
+compare('uuids with time option', [
+  uuid.v1({msecs: TIME - 10*3600*1000}),
+  uuid.v1({msecs: TIME - 1}),
+  uuid.v1({msecs: TIME}),
+  uuid.v1({msecs: TIME + 1}),
+  uuid.v1({msecs: TIME + 28*24*3600*1000})
+]);
+
+assert(
+  uuid.v1({msecs: TIME}) != uuid.v1({msecs: TIME}),
+  'IDs created at same msec are different'
+);
+
+// Verify throw if too many ids created
+var thrown = false;
+try {
+  uuid.v1({msecs: TIME, nsecs: 10000});
+} catch (e) {
+  thrown = true;
+}
+assert(thrown, 'Exception thrown when > 10K ids created in 1 ms');
+
+// Verify clock regression bumps clockseq
+var uidt = uuid.v1({msecs: TIME});
+var uidtb = uuid.v1({msecs: TIME - 1});
+assert(
+  parseInt(uidtb.split('-')[3], 16) - parseInt(uidt.split('-')[3], 16) === 1,
+  'Clock regression by msec increments the clockseq'
+);
+
+// Verify clock regression bumps clockseq
+var uidtn = uuid.v1({msecs: TIME, nsecs: 10});
+var uidtnb = uuid.v1({msecs: TIME, nsecs: 9});
+assert(
+  parseInt(uidtnb.split('-')[3], 16) - parseInt(uidtn.split('-')[3], 16) === 1,
+  'Clock regression by nsec increments the clockseq'
+);
+
+// Verify explicit options produce expected id
+var id = uuid.v1({
+  msecs: 1321651533573,
+  nsecs: 5432,
+  clockseq: 0x385c,
+  node: [ 0x61, 0xcd, 0x3c, 0xbb, 0x32, 0x10 ]
+});
+assert(id == 'd9428888-122b-11e1-b85c-61cd3cbb3210', 'Explicit options produce expected id');
+
+// Verify adjacent ids across a msec boundary are 1 time unit apart
+var u0 = uuid.v1({msecs: TIME, nsecs: 9999});
+var u1 = uuid.v1({msecs: TIME + 1, nsecs: 0});
+
+var before = u0.split('-')[0], after = u1.split('-')[0];
+var dt = parseInt(after, 16) - parseInt(before, 16);
+assert(dt === 1, 'Ids spanning 1ms boundary are 100ns apart');
+
+//
+// Test parse/unparse
+//
+
+id = '00112233445566778899aabbccddeeff';
+assert(uuid.unparse(uuid.parse(id.substr(0,10))) ==
+  '00112233-4400-0000-0000-000000000000', 'Short parse');
+assert(uuid.unparse(uuid.parse('(this is the uuid -> ' + id + id)) ==
+  '00112233-4455-6677-8899-aabbccddeeff', 'Dirty parse');
+
+//
+// Perf tests
+//
+
+var generators = {
+  v1: uuid.v1,
+  v4: uuid.v4
+};
+
+var UUID_FORMAT = {
+  v1: /[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i,
+  v4: /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i
+};
+
+var N = 1e4;
+
+// Get %'age an actual value differs from the ideal value
+function divergence(actual, ideal) {
+  return Math.round(100*100*(actual - ideal)/ideal)/100;
+}
+
+function rate(msg, t) {
+  log(msg + ': ' + (N / (Date.now() - t) * 1e3 | 0) + ' uuids\/second');
+}
+
+for (var version in generators) {
+  var counts = {}, max = 0;
+  var generator = generators[version];
+  var format = UUID_FORMAT[version];
+
+  log('\nSanity check ' + N + ' ' + version + ' uuids');
+  for (var i = 0, ok = 0; i < N; i++) {
+    id = generator();
+    if (!format.test(id)) {
+      throw Error(id + ' is not a valid UUID string');
+    }
+
+    if (id != uuid.unparse(uuid.parse(id))) {
+      assert(fail, id + ' is not a valid id');
+    }
+
+    // Count digits for our randomness check
+    if (version == 'v4') {
+      var digits = id.replace(/-/g, '').split('');
+      for (var j = digits.length-1; j >= 0; j--) {
+        var c = digits[j];
+        max = Math.max(max, counts[c] = (counts[c] || 0) + 1);
+      }
+    }
+  }
+
+  // Check randomness for v4 UUIDs
+  if (version == 'v4') {
+    // Limit that we get worried about randomness. (Purely empirical choice, this!)
+    var limit = 2*100*Math.sqrt(1/N);
+
+    log('\nChecking v4 randomness.  Distribution of Hex Digits (% deviation from ideal)');
+
+    for (var i = 0; i < 16; i++) {
+      var c = i.toString(16);
+      var bar = '', n = counts[c], p = Math.round(n/max*100|0);
+
+      // 1-3,5-8, and D-F: 1:16 odds over 30 digits
+      var ideal = N*30/16;
+      if (i == 4) {
+        // 4: 1:1 odds on 1 digit, plus 1:16 odds on 30 digits
+        ideal = N*(1 + 30/16);
+      } else if (i >= 8 && i <= 11) {
+        // 8-B: 1:4 odds on 1 digit, plus 1:16 odds on 30 digits
+        ideal = N*(1/4 + 30/16);
+      } else {
+        // Otherwise: 1:16 odds on 30 digits
+        ideal = N*30/16;
+      }
+      var d = divergence(n, ideal);
+
+      // Draw bar using UTF squares (just for grins)
+      var s = n/max*50 | 0;
+      while (s--) bar += '=';
+
+      assert(Math.abs(d) < limit, c + ' |' + bar + '| ' + counts[c] + ' (' + d + '% < ' + limit + '%)');
+    }
+  }
+}
+
+// Perf tests
+for (var version in generators) {
+  log('\nPerformance testing ' + version + ' UUIDs');
+  var generator = generators[version];
+  var buf = new uuid.BufferClass(16);
+
+  for (var i = 0, t = Date.now(); i < N; i++) generator();
+  rate('uuid.' + version + '()', t);
+
+  for (var i = 0, t = Date.now(); i < N; i++) generator('binary');
+  rate('uuid.' + version + '(\'binary\')', t);
+
+  for (var i = 0, t = Date.now(); i < N; i++) generator('binary', buf);
+  rate('uuid.' + version + '(\'binary\', buffer)', t);
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/uuid.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/uuid.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/node-uuid/uuid.js	(revision 517)
@@ -0,0 +1,245 @@
+//     uuid.js
+//
+//     Copyright (c) 2010-2012 Robert Kieffer
+//     MIT License - http://opensource.org/licenses/mit-license.php
+
+(function() {
+  var _global = this;
+
+  // Unique ID creation requires a high quality random # generator.  We feature
+  // detect to determine the best RNG source, normalizing to a function that
+  // returns 128-bits of randomness, since that's what's usually required
+  var _rng;
+
+  // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
+  //
+  // Moderately fast, high quality
+  if (typeof(require) == 'function') {
+    try {
+      var _rb = require('crypto').randomBytes;
+      _rng = _rb && function() {return _rb(16);};
+    } catch(e) {}
+  }
+
+  if (!_rng && _global.crypto && crypto.getRandomValues) {
+    // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
+    //
+    // Moderately fast, high quality
+    var _rnds8 = new Uint8Array(16);
+    _rng = function whatwgRNG() {
+      crypto.getRandomValues(_rnds8);
+      return _rnds8;
+    };
+  }
+
+  if (!_rng) {
+    // Math.random()-based (RNG)
+    //
+    // If all else fails, use Math.random().  It's fast, but is of unspecified
+    // quality.
+    var  _rnds = new Array(16);
+    _rng = function() {
+      for (var i = 0, r; i < 16; i++) {
+        if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
+        _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
+      }
+
+      return _rnds;
+    };
+  }
+
+  // Buffer class to use
+  var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array;
+
+  // Maps for number <-> hex string conversion
+  var _byteToHex = [];
+  var _hexToByte = {};
+  for (var i = 0; i < 256; i++) {
+    _byteToHex[i] = (i + 0x100).toString(16).substr(1);
+    _hexToByte[_byteToHex[i]] = i;
+  }
+
+  // **`parse()` - Parse a UUID into it's component bytes**
+  function parse(s, buf, offset) {
+    var i = (buf && offset) || 0, ii = 0;
+
+    buf = buf || [];
+    s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
+      if (ii < 16) { // Don't overflow!
+        buf[i + ii++] = _hexToByte[oct];
+      }
+    });
+
+    // Zero out remaining bytes if string was short
+    while (ii < 16) {
+      buf[i + ii++] = 0;
+    }
+
+    return buf;
+  }
+
+  // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
+  function unparse(buf, offset) {
+    var i = offset || 0, bth = _byteToHex;
+    return  bth[buf[i++]] + bth[buf[i++]] +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] +
+            bth[buf[i++]] + bth[buf[i++]] +
+            bth[buf[i++]] + bth[buf[i++]];
+  }
+
+  // **`v1()` - Generate time-based UUID**
+  //
+  // Inspired by https://github.com/LiosK/UUID.js
+  // and http://docs.python.org/library/uuid.html
+
+  // random #'s we need to init node and clockseq
+  var _seedBytes = _rng();
+
+  // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
+  var _nodeId = [
+    _seedBytes[0] | 0x01,
+    _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
+  ];
+
+  // Per 4.2.2, randomize (14 bit) clockseq
+  var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
+
+  // Previous uuid creation time
+  var _lastMSecs = 0, _lastNSecs = 0;
+
+  // See https://github.com/broofa/node-uuid for API details
+  function v1(options, buf, offset) {
+    var i = buf && offset || 0;
+    var b = buf || [];
+
+    options = options || {};
+
+    var clockseq = options.clockseq != null ? options.clockseq : _clockseq;
+
+    // UUID timestamps are 100 nano-second units since the Gregorian epoch,
+    // (1582-10-15 00:00).  JSNumbers aren't precise enough for this, so
+    // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
+    // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
+    var msecs = options.msecs != null ? options.msecs : new Date().getTime();
+
+    // Per 4.2.1.2, use count of uuid's generated during the current clock
+    // cycle to simulate higher resolution clock
+    var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;
+
+    // Time since last uuid creation (in msecs)
+    var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
+
+    // Per 4.2.1.2, Bump clockseq on clock regression
+    if (dt < 0 && options.clockseq == null) {
+      clockseq = clockseq + 1 & 0x3fff;
+    }
+
+    // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
+    // time interval
+    if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
+      nsecs = 0;
+    }
+
+    // Per 4.2.1.2 Throw error if too many uuids are requested
+    if (nsecs >= 10000) {
+      throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
+    }
+
+    _lastMSecs = msecs;
+    _lastNSecs = nsecs;
+    _clockseq = clockseq;
+
+    // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
+    msecs += 12219292800000;
+
+    // `time_low`
+    var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
+    b[i++] = tl >>> 24 & 0xff;
+    b[i++] = tl >>> 16 & 0xff;
+    b[i++] = tl >>> 8 & 0xff;
+    b[i++] = tl & 0xff;
+
+    // `time_mid`
+    var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
+    b[i++] = tmh >>> 8 & 0xff;
+    b[i++] = tmh & 0xff;
+
+    // `time_high_and_version`
+    b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
+    b[i++] = tmh >>> 16 & 0xff;
+
+    // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
+    b[i++] = clockseq >>> 8 | 0x80;
+
+    // `clock_seq_low`
+    b[i++] = clockseq & 0xff;
+
+    // `node`
+    var node = options.node || _nodeId;
+    for (var n = 0; n < 6; n++) {
+      b[i + n] = node[n];
+    }
+
+    return buf ? buf : unparse(b);
+  }
+
+  // **`v4()` - Generate random UUID**
+
+  // See https://github.com/broofa/node-uuid for API details
+  function v4(options, buf, offset) {
+    // Deprecated - 'format' argument, as supported in v1.2
+    var i = buf && offset || 0;
+
+    if (typeof(options) == 'string') {
+      buf = options == 'binary' ? new BufferClass(16) : null;
+      options = null;
+    }
+    options = options || {};
+
+    var rnds = options.random || (options.rng || _rng)();
+
+    // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
+    rnds[6] = (rnds[6] & 0x0f) | 0x40;
+    rnds[8] = (rnds[8] & 0x3f) | 0x80;
+
+    // Copy bytes to buffer, if provided
+    if (buf) {
+      for (var ii = 0; ii < 16; ii++) {
+        buf[i + ii] = rnds[ii];
+      }
+    }
+
+    return buf || unparse(rnds);
+  }
+
+  // Export public API
+  var uuid = v4;
+  uuid.v1 = v1;
+  uuid.v4 = v4;
+  uuid.parse = parse;
+  uuid.unparse = unparse;
+  uuid.BufferClass = BufferClass;
+
+  if (typeof define === 'function' && define.amd) {
+    // Publish as AMD module
+    define(function() {return uuid;});
+  } else if (typeof(module) != 'undefined' && module.exports) {
+    // Publish as node.js module
+    module.exports = uuid;
+  } else {
+    // Publish as global (in browsers)
+    var _previousRoot = _global.uuid;
+
+    // **`noConflict()` - (browser only) to reset global 'uuid' var**
+    uuid.noConflict = function() {
+      _global.uuid = _previousRoot;
+      return uuid;
+    };
+
+    _global.uuid = uuid;
+  }
+}).call(this);
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/LICENSE	(revision 517)
@@ -0,0 +1,55 @@
+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:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+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
+
+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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/README.md	(revision 517)
@@ -0,0 +1,4 @@
+oauth-sign
+==========
+
+OAuth 1 signing. Formerly a vendor lib in mikeal/request, now a standalone module. 
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/index.js	(revision 517)
@@ -0,0 +1,43 @@
+var crypto = require('crypto')
+  , qs = require('querystring')
+  ;
+
+function sha1 (key, body) {
+  return crypto.createHmac('sha1', key).update(body).digest('base64')
+}
+
+function rfc3986 (str) {
+  return encodeURIComponent(str)
+    .replace(/!/g,'%21')
+    .replace(/\*/g,'%2A')
+    .replace(/\(/g,'%28')
+    .replace(/\)/g,'%29')
+    .replace(/'/g,'%27')
+    ;
+}
+
+function hmacsign (httpMethod, base_uri, params, consumer_secret, token_secret) {
+  // adapted from https://dev.twitter.com/docs/auth/oauth and 
+  // https://dev.twitter.com/docs/auth/creating-signature
+
+  var querystring = Object.keys(params).sort().map(function(key){
+    // big WTF here with the escape + encoding but it's what twitter wants
+    return escape(rfc3986(key)) + "%3D" + escape(rfc3986(params[key]))
+  }).join('%26')
+
+  var base = [
+    httpMethod ? httpMethod.toUpperCase() : 'GET',
+    rfc3986(base_uri),
+    querystring
+  ].join('&')
+
+  var key = [
+    consumer_secret,
+    token_secret || ''
+  ].map(rfc3986).join('&')
+
+  return sha1(key, base)
+}
+
+exports.hmacsign = hmacsign
+exports.rfc3986 = rfc3986
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/package.json	(revision 517)
@@ -0,0 +1,31 @@
+{
+  "author": {
+    "name": "Mikeal Rogers",
+    "email": "mikeal.rogers@gmail.com",
+    "url": "http://www.futurealoof.com"
+  },
+  "name": "oauth-sign",
+  "description": "OAuth 1 signing. Formerly a vendor lib in mikeal/request, now a standalone module.",
+  "version": "0.3.0",
+  "repository": {
+    "url": "https://github.com/mikeal/oauth-sign"
+  },
+  "main": "index.js",
+  "dependencies": {},
+  "devDependencies": {},
+  "optionalDependencies": {},
+  "engines": {
+    "node": "*"
+  },
+  "scripts": {
+    "test": "node test.js"
+  },
+  "readme": "oauth-sign\n==========\n\nOAuth 1 signing. Formerly a vendor lib in mikeal/request, now a standalone module. \n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/mikeal/oauth-sign/issues"
+  },
+  "homepage": "https://github.com/mikeal/oauth-sign",
+  "_id": "oauth-sign@0.3.0",
+  "_from": "oauth-sign@~0.3.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/oauth-sign/test.js	(revision 517)
@@ -0,0 +1,49 @@
+var hmacsign = require('./index').hmacsign
+  , assert = require('assert')
+  , qs = require('querystring')
+  ;
+
+// Tests from Twitter documentation https://dev.twitter.com/docs/auth/oauth
+
+var reqsign = hmacsign('POST', 'https://api.twitter.com/oauth/request_token', 
+  { oauth_callback: 'http://localhost:3005/the_dance/process_callback?service_provider_id=11'
+  , oauth_consumer_key: 'GDdmIQH6jhtmLUypg82g'
+  , oauth_nonce: 'QP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk'
+  , oauth_signature_method: 'HMAC-SHA1'
+  , oauth_timestamp: '1272323042'
+  , oauth_version: '1.0'
+  }, "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98")
+
+console.log(reqsign)
+console.log('8wUi7m5HFQy76nowoCThusfgB+Q=')
+assert.equal(reqsign, '8wUi7m5HFQy76nowoCThusfgB+Q=')
+
+var accsign = hmacsign('POST', 'https://api.twitter.com/oauth/access_token',
+  { oauth_consumer_key: 'GDdmIQH6jhtmLUypg82g'
+  , oauth_nonce: '9zWH6qe0qG7Lc1telCn7FhUbLyVdjEaL3MO5uHxn8'
+  , oauth_signature_method: 'HMAC-SHA1'
+  , oauth_token: '8ldIZyxQeVrFZXFOZH5tAwj6vzJYuLQpl0WUEYtWc'
+  , oauth_timestamp: '1272323047'
+  , oauth_verifier: 'pDNg57prOHapMbhv25RNf75lVRd6JDsni1AJJIDYoTY'
+  , oauth_version: '1.0'
+  }, "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98", "x6qpRnlEmW9JbQn4PQVVeVG8ZLPEx6A0TOebgwcuA")
+  
+console.log(accsign)
+console.log('PUw/dHA4fnlJYM6RhXk5IU/0fCc=')
+assert.equal(accsign, 'PUw/dHA4fnlJYM6RhXk5IU/0fCc=')
+
+var upsign = hmacsign('POST', 'http://api.twitter.com/1/statuses/update.json', 
+  { oauth_consumer_key: "GDdmIQH6jhtmLUypg82g"
+  , oauth_nonce: "oElnnMTQIZvqvlfXM56aBLAf5noGD0AQR3Fmi7Q6Y"
+  , oauth_signature_method: "HMAC-SHA1"
+  , oauth_token: "819797-Jxq8aYUDRmykzVKrgoLhXSq67TEa5ruc4GJC2rWimw"
+  , oauth_timestamp: "1272325550"
+  , oauth_version: "1.0"
+  , status: 'setting up my twitter ç§ã®ãããããèš­å®ãã'
+  }, "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98", "J6zix3FfA9LofH0awS24M3HcBYXO5nI1iYe8EfBA")
+
+console.log(upsign)
+console.log('yOahq5m0YjDDjfjxHaXEsW9D+X0=')
+assert.equal(upsign, 'yOahq5m0YjDDjfjxHaXEsW9D+X0=')
+
+
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/.gitmodules
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/.gitmodules	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/.gitmodules	(revision 517)
@@ -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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/.npmignore	(revision 517)
@@ -0,0 +1,7 @@
+test
+.travis.yml
+benchmark.js
+component.json
+examples.js
+History.md
+Makefile
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/Readme.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/Readme.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/Readme.md	(revision 517)
@@ -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 &lt;tj@vision-media.ca&gt;
+
+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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/index.js	(revision 517)
@@ -0,0 +1,366 @@
+/**
+ * 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) {
+    if (obj.hasOwnProperty(key)) {
+      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;
+};
+
+/**
+ * Cache non-integer test regexp.
+ */
+
+var isint = /^[0-9]+$/;
+
+function promote(parent, key) {
+  if (parent[key].length == 0) return parent[key] = {}
+  var t = {};
+  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();
+  
+  // illegal
+  if (Object.getOwnPropertyDescriptor(Object.prototype, key)) return;
+  
+  // 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 = {};
+      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;
+}
+
+/**
+ * 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: {} }).base;
+
+  return 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 (Object.getOwnPropertyDescriptor(Object.prototype, key)) return;
+  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;
+  }
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/qs/package.json	(revision 517)
@@ -0,0 +1,38 @@
+{
+  "name": "qs",
+  "description": "querystring parser",
+  "version": "0.6.6",
+  "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 &lt;tj@vision-media.ca&gt;\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"
+  },
+  "homepage": "https://github.com/visionmedia/node-querystring",
+  "_id": "qs@0.6.6",
+  "_from": "qs@~0.6.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.jshintrc
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.jshintrc	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.jshintrc	(revision 517)
@@ -0,0 +1,70 @@
+{
+    "passfail"      : false,
+    "maxerr"        : 100,
+
+    "browser"       : false,
+    "node"          : true,
+    "rhino"         : false,
+    "couch"         : false,
+    "wsh"           : false,
+
+    "jquery"        : false,
+    "prototypejs"   : false,
+    "mootools"      : false,
+    "dojo"          : false,
+
+    "debug"         : false,
+    "devel"         : false,
+
+    "esnext"        : true,
+    "strict"        : true,
+    "globalstrict"  : true,
+
+    "asi"           : false,
+    "laxbreak"      : false,
+    "bitwise"       : true,
+    "boss"          : false,
+    "curly"         : true,
+    "eqeqeq"        : false,
+    "eqnull"        : true,
+    "evil"          : false,
+    "expr"          : false,
+    "forin"         : false,
+    "immed"         : true,
+    "lastsemic"     : true,
+    "latedef"       : false,
+    "loopfunc"      : false,
+    "noarg"         : true,
+    "regexp"        : false,
+    "regexdash"     : false,
+    "scripturl"     : false,
+    "shadow"        : false,
+    "supernew"      : false,
+    "undef"         : true,
+    "unused"         : true,
+
+    "newcap"        : true,
+    "noempty"       : true,
+    "nonew"         : true,
+    "nomen"         : false,
+    "onevar"        : false,
+    "onecase"       : true,
+    "plusplus"      : false,
+    "proto"         : false,
+    "sub"           : true,
+    "trailing"      : true,
+    "white"         : false,
+
+    "predef": [
+      "describe",
+      "it",
+      "before",
+      "beforeEach",
+      "after",
+      "afterEach",
+      "expect",
+      "setTimeout",
+      "clearTimeout"
+    ],
+    "maxlen": 0
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.npmignore
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.npmignore	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.npmignore	(revision 517)
@@ -0,0 +1,3 @@
+node_modules/
+.*.sw[nmop]
+npm-debug.log
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.travis.yml
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.travis.yml	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/.travis.yml	(revision 517)
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+- "0.10"
+- "0.11"
+matrix:
+  fast_finish: true
+  allow_failures:
+    - node_js: 0.11
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/LICENSE	(revision 517)
@@ -0,0 +1,78 @@
+Copyright GoInstant, Inc. and other contributors. All rights reserved.
+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.
+
+The following exceptions apply:
+
+===
+
+`pubSufTest()` of generate-pubsuffix.js is in the public domain.
+
+  // Any copyright is dedicated to the Public Domain.
+  // http://creativecommons.org/publicdomain/zero/1.0/
+
+===
+
+`public-suffix.txt` was obtained from
+<https://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1>
+via <http://publicsuffix.org>.
+
+That file contains the usual Mozilla triple-license, for which this project uses it
+under the terms of the MPL 1.1:
+
+    // ***** BEGIN LICENSE BLOCK *****
+    // Version: MPL 1.1/GPL 2.0/LGPL 2.1
+    // 
+    // The contents of this file are subject to the Mozilla Public License Version 
+    // 1.1 (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.mozilla.org/MPL/
+    // 
+    // Software distributed under the License is distributed on an "AS IS" basis,
+    // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+    // for the specific language governing rights and limitations under the
+    // License.
+    // 
+    // The Original Code is the Public Suffix List.
+    // 
+    // The Initial Developer of the Original Code is
+    // Jo Hermans <jo.hermans@gmail.com>.
+    // Portions created by the Initial Developer are Copyright (C) 2007
+    // the Initial Developer. All Rights Reserved.
+    // 
+    // Contributor(s):
+    //   Ruben Arakelyan <ruben@rubenarakelyan.com>
+    //   Gervase Markham <gerv@gerv.net>
+    //   Pamela Greene <pamg.bugs@gmail.com>
+    //   David Triendl <david@triendl.name>
+    //   Jothan Frakes <jothan@gmail.com>
+    //   The kind representatives of many TLD registries
+    // 
+    // Alternatively, the contents of this file may be used under the terms of
+    // either the GNU General Public License Version 2 or later (the "GPL"), or
+    // the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+    // in which case the provisions of the GPL or the LGPL are applicable instead
+    // of those above. If you wish to allow use of your version of this file only
+    // under the terms of either the GPL or the LGPL, and not to allow others to
+    // use your version of this file under the terms of the MPL, indicate your
+    // decision by deleting the provisions above and replace them with the notice
+    // and other provisions required by the GPL or the LGPL. If you do not delete
+    // the provisions above, a recipient may use your version of this file under
+    // the terms of any one of the MPL, the GPL or the LGPL.
+    // 
+    // ***** END LICENSE BLOCK *****
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/README.md	(revision 517)
@@ -0,0 +1,412 @@
+[RFC6265](http://tools.ietf.org/html/rfc6265) Cookies and CookieJar for Node.js
+
+![Tough Cookie](http://www.goinstant.com.s3.amazonaws.com/tough-cookie.jpg)
+
+[![Build Status](https://travis-ci.org/goinstant/node-cookie.png?branch=master)](https://travis-ci.org/goinstant/node-cookie)
+
+[![NPM Stats](https://nodei.co/npm/tough-cookie.png?downloads=true&stars=true)](https://npmjs.org/package/tough-cookie)
+![NPM Downloads](https://nodei.co/npm-dl/tough-cookie.png?months=9)
+
+# Synopsis
+
+``` javascript
+var tough = require('tough-cookie'); // note: not 'cookie', 'cookies' or 'node-cookie'
+var Cookie = tough.Cookie;
+var cookie = Cookie.parse(header);
+cookie.value = 'somethingdifferent';
+header = cookie.toString();
+
+var cookiejar = new tough.CookieJar();
+cookiejar.setCookie(cookie, 'http://currentdomain.example.com/path', cb);
+// ...
+cookiejar.getCookies('http://example.com/otherpath',function(err,cookies) {
+  res.headers['cookie'] = cookies.join('; ');
+});
+```
+
+# Installation
+
+It's _so_ easy!
+
+`npm install tough-cookie`
+
+Requires `punycode`, which should get installed automatically for you.  Note that node.js v0.6.2+ bundles punycode by default.
+
+Why the name?  NPM modules `cookie`, `cookies` and `cookiejar` were already taken.
+
+# API
+
+tough
+=====
+
+Functions on the module you get from `require('tough-cookie')`.  All can be used as pure functions and don't need to be "bound".
+
+parseDate(string[,strict])
+-----------------
+
+Parse a cookie date string into a `Date`.  Parses according to RFC6265 Section 5.1.1, not `Date.parse()`.  If strict is set to true then leading/trailing non-seperator characters around the time part will cause the parsing to fail (e.g. "Thu, 01 Jan 1970 00:00:010 GMT" has an extra trailing zero but Chrome, an assumedly RFC-compliant browser, treats this as valid).
+
+formatDate(date)
+----------------
+
+Format a Date into a RFC1123 string (the RFC6265-recommended format).
+
+canonicalDomain(str)
+--------------------
+
+Transforms a domain-name into a canonical domain-name.  The canonical domain-name is a trimmed, lowercased, stripped-of-leading-dot and optionally punycode-encoded domain-name (Section 5.1.2 of RFC6265).  For the most part, this function is idempotent (can be run again on its output without ill effects).
+
+domainMatch(str,domStr[,canonicalize=true])
+-------------------------------------------
+
+Answers "does this real domain match the domain in a cookie?".  The `str` is the "current" domain-name and the `domStr` is the "cookie" domain-name.  Matches according to RFC6265 Section 5.1.3, but it helps to think of it as a "suffix match".
+
+The `canonicalize` parameter will run the other two paramters through `canonicalDomain` or not.
+
+defaultPath(path)
+-----------------
+
+Given a current request/response path, gives the Path apropriate for storing in a cookie.  This is basically the "directory" of a "file" in the path, but is specified by Section 5.1.4 of the RFC.
+
+The `path` parameter MUST be _only_ the pathname part of a URI (i.e. excludes the hostname, query, fragment, etc.).  This is the `.pathname` property of node's `uri.parse()` output.
+
+pathMatch(reqPath,cookiePath)
+-----------------------------
+
+Answers "does the request-path path-match a given cookie-path?" as per RFC6265 Section 5.1.4.  Returns a boolean.
+
+This is essentially a prefix-match where `cookiePath` is a prefix of `reqPath`.
+
+parse(header[,strict=false])
+----------------------------
+
+alias for `Cookie.parse(header[,strict])`
+
+fromJSON(string)
+----------------
+
+alias for `Cookie.fromJSON(string)`
+
+getPublicSuffix(hostname)
+-------------------------
+
+Returns the public suffix of this hostname.  The public suffix is the shortest domain-name upon which a cookie can be set.  Returns `null` if the hostname cannot have cookies set for it.
+
+For example: `www.example.com` and `www.subdomain.example.com` both have public suffix `example.com`.
+
+For further information, see http://publicsuffix.org/.  This module derives its list from that site.
+
+cookieCompare(a,b)
+------------------
+
+For use with `.sort()`, sorts a list of cookies into the recommended order given in the RFC (Section 5.4 step 2).  Longest `.path`s go first, then sorted oldest to youngest.
+
+``` javascript
+var cookies = [ /* unsorted array of Cookie objects */ ];
+cookies = cookies.sort(cookieCompare);
+```
+
+permuteDomain(domain)
+---------------------
+
+Generates a list of all possible domains that `domainMatch()` the parameter.  May be handy for implementing cookie stores.
+
+
+permutePath(path)
+-----------------
+
+Generates a list of all possible paths that `pathMatch()` the parameter.  May be handy for implementing cookie stores.
+
+Cookie
+======
+
+Cookie.parse(header[,strict=false])
+-----------------------------------
+
+Parses a single Cookie or Set-Cookie HTTP header into a `Cookie` object.  Returns `undefined` if the string can't be parsed.  If in strict mode, returns `undefined` if the cookie doesn't follow the guidelines in section 4 of RFC6265.  Generally speaking, strict mode can be used to validate your own generated Set-Cookie headers, but acting as a client you want to be lenient and leave strict mode off.
+
+Here's how to process the Set-Cookie header(s) on a node HTTP/HTTPS response:
+
+``` javascript
+if (res.headers['set-cookie'] instanceof Array)
+  cookies = res.headers['set-cookie'].map(function (c) { return (Cookie.parse(c)); });
+else
+  cookies = [Cookie.parse(res.headers['set-cookie'])];
+```
+
+Cookie.fromJSON(string)
+-----------------------
+
+Convert a JSON string to a `Cookie` object.  Does a `JSON.parse()` and converts the `.created`, `.lastAccessed` and `.expires` properties into `Date` objects.
+
+Properties
+==========
+
+  * _key_ - string - the name or key of the cookie (default "")
+  * _value_ - string - the value of the cookie (default "")
+  * _expires_ - `Date` - if set, the `Expires=` attribute of the cookie (defaults to the string `"Infinity"`). See `setExpires()`
+  * _maxAge_ - seconds - if set, the `Max-Age=` attribute _in seconds_ of the cookie.  May also be set to strings `"Infinity"` and `"-Infinity"` for non-expiry and immediate-expiry, respectively.  See `setMaxAge()`
+  * _domain_ - string - the `Domain=` attribute of the cookie
+  * _path_ - string - the `Path=` of the cookie
+  * _secure_ - boolean - the `Secure` cookie flag
+  * _httpOnly_ - boolean - the `HttpOnly` cookie flag
+  * _extensions_ - `Array` - any unrecognized cookie attributes as strings (even if equal-signs inside)
+
+After a cookie has been passed through `CookieJar.setCookie()` it will have the following additional attributes:
+
+  * _hostOnly_ - boolean - is this a host-only cookie (i.e. no Domain field was set, but was instead implied)
+  * _pathIsDefault_ - boolean - if true, there was no Path field on the cookie and `defaultPath()` was used to derive one.
+  * _created_ - `Date` - when this cookie was added to the jar
+  * _lastAccessed_ - `Date` - last time the cookie got accessed. Will affect cookie cleaning once implemented.  Using `cookiejar.getCookies(...)` will update this attribute.
+
+Construction([{options}])
+------------
+
+Receives an options object that can contain any Cookie properties, uses the default for unspecified properties.
+
+.toString()
+-----------
+
+encode to a Set-Cookie header value.  The Expires cookie field is set using `formatDate()`, but is omitted entirely if `.expires` is `Infinity`.
+
+.cookieString()
+---------------
+
+encode to a Cookie header value (i.e. the `.key` and `.value` properties joined with '=').
+
+.setExpires(String)
+-------------------
+
+sets the expiry based on a date-string passed through `parseDate()`.  If parseDate returns `null` (i.e. can't parse this date string), `.expires` is set to `"Infinity"` (a string) is set.
+
+.setMaxAge(number)
+-------------------
+
+sets the maxAge in seconds.  Coerces `-Infinity` to `"-Infinity"` and `Infinity` to `"Infinity"` so it JSON serializes correctly.
+
+.expiryTime([now=Date.now()])
+-----------------------------
+
+.expiryDate([now=Date.now()])
+-----------------------------
+
+expiryTime() Computes the absolute unix-epoch milliseconds that this cookie expires. expiryDate() works similarly, except it returns a `Date` object.  Note that in both cases the `now` parameter should be milliseconds.
+
+Max-Age takes precedence over Expires (as per the RFC). The `.created` attribute -- or, by default, the `now` paramter -- is used to offset the `.maxAge` attribute.
+
+If Expires (`.expires`) is set, that's returned.
+
+Otherwise, `expiryTime()` returns `Infinity` and `expiryDate()` returns a `Date` object for "Tue, 19 Jan 2038 03:14:07 GMT" (latest date that can be expressed by a 32-bit `time_t`; the common limit for most user-agents).
+
+.TTL([now=Date.now()])
+---------
+
+compute the TTL relative to `now` (milliseconds).  The same precedence rules as for `expiryTime`/`expiryDate` apply.
+
+The "number" `Infinity` is returned for cookies without an explicit expiry and `0` is returned if the cookie is expired.  Otherwise a time-to-live in milliseconds is returned.
+
+.canonicalizedDoman()
+---------------------
+
+.cdomain()
+----------
+
+return the canonicalized `.domain` field.  This is lower-cased and punycode (RFC3490) encoded if the domain has any non-ASCII characters.
+
+.validate()
+-----------
+
+Status: *IN PROGRESS*. Works for a few things, but is by no means comprehensive.
+
+validates cookie attributes for semantic correctness.  Useful for "lint" checking any Set-Cookie headers you generate.  For now, it returns a boolean, but eventually could return a reason string -- you can future-proof with this construct:
+
+``` javascript
+if (cookie.validate() === true) {
+  // it's tasty
+} else {
+  // yuck!
+}
+```
+
+CookieJar
+=========
+
+Construction([store = new MemoryCookieStore()][, rejectPublicSuffixes])
+------------
+
+Simply use `new CookieJar()`.  If you'd like to use a custom store, pass that to the constructor otherwise a `MemoryCookieStore` will be created and used.
+
+
+Attributes
+----------
+
+  * _rejectPublicSuffixes_ - boolean - reject cookies with domains like "com" and "co.uk" (default: `true`)
+
+Since eventually this module would like to support database/remote/etc. CookieJars, continuation passing style is used for CookieJar methods.
+
+.setCookie(cookieOrString, currentUrl, [{options},] cb(err,cookie))
+-------------------------------------------------------------------
+
+Attempt to set the cookie in the cookie jar.  If the operation fails, an error will be given to the callback `cb`, otherwise the cookie is passed through.  The cookie will have updated `.created`, `.lastAccessed` and `.hostOnly` properties.
+
+The `options` object can be omitted and can have the following properties:
+
+  * _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API.  Affects HttpOnly cookies.
+  * _secure_ - boolean - autodetect from url - indicates if this is a "Secure" API.  If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.
+  * _now_ - Date - default `new Date()` - what to use for the creation/access time of cookies
+  * _strict_ - boolean - default `false` - perform extra checks
+  * _ignoreError_ - boolean - default `false` - silently ignore things like parse errors and invalid domains.  CookieStore errors aren't ignored by this option.
+
+As per the RFC, the `.hostOnly` property is set if there was no "Domain=" parameter in the cookie string (or `.domain` was null on the Cookie object).  The `.domain` property is set to the fully-qualified hostname of `currentUrl` in this case.  Matching this cookie requires an exact hostname match (not a `domainMatch` as per usual).
+
+.setCookieSync(cookieOrString, currentUrl, [{options}])
+-------------------------------------------------------
+
+Synchronous version of `setCookie`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
+
+.storeCookie(cookie, [{options},] cb(err,cookie))
+-------------------------------------------------
+
+__REMOVED__ removed in lieu of the CookieStore API below
+
+.getCookies(currentUrl, [{options},] cb(err,cookies))
+-----------------------------------------------------
+
+Retrieve the list of cookies that can be sent in a Cookie header for the current url.
+
+If an error is encountered, that's passed as `err` to the callback, otherwise an `Array` of `Cookie` objects is passed.  The array is sorted with `cookieCompare()` unless the `{sort:false}` option is given.
+
+The `options` object can be omitted and can have the following properties:
+
+  * _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API.  Affects HttpOnly cookies.
+  * _secure_ - boolean - autodetect from url - indicates if this is a "Secure" API.  If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.
+  * _now_ - Date - default `new Date()` - what to use for the creation/access time of cookies
+  * _expire_ - boolean - default `true` - perform expiry-time checking of cookies and asynchronously remove expired cookies from the store.  Using `false` will return expired cookies and **not** remove them from the store (which is useful for replaying Set-Cookie headers, potentially).
+  * _allPaths_ - boolean - default `false` - if `true`, do not scope cookies by path. The default uses RFC-compliant path scoping. **Note**: may not be supported by the CookieStore `fetchCookies` function (the default MemoryCookieStore supports it).
+
+The `.lastAccessed` property of the returned cookies will have been updated.
+
+.getCookiesSync(currentUrl, [{options}])
+----------------------------------------
+
+Synchronous version of `getCookies`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
+
+.getCookieString(...)
+---------------------
+
+Accepts the same options as `.getCookies()` but passes a string suitable for a Cookie header rather than an array to the callback.  Simply maps the `Cookie` array via `.cookieString()`.
+
+.getCookieStringSync(...)
+-------------------------
+
+Synchronous version of `getCookieString`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
+
+.getSetCookieStrings(...)
+-------------------------
+
+Returns an array of strings suitable for **Set-Cookie** headers. Accepts the same options as `.getCookies()`.  Simply maps the cookie array via `.toString()`.
+
+.getSetCookieStringsSync(...)
+-----------------------------
+
+Synchronous version of `getSetCookieStrings`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
+
+Store
+=====
+
+Base class for CookieJar stores.
+
+# CookieStore API
+
+The storage model for each `CookieJar` instance can be replaced with a custom implementation.  The default is `MemoryCookieStore` which can be found in the `lib/memstore.js` file.  The API uses continuation-passing-style to allow for asynchronous stores.
+
+Stores should inherit from the base `Store` class, which is available as `require('tough-cookie').Store`.  Stores are asynchronous by default, but if `store.synchronous` is set, then the `*Sync` methods on the CookieJar can be used.
+
+All `domain` parameters will have been normalized before calling.
+
+The Cookie store must have all of the following methods.
+
+store.findCookie(domain, path, key, cb(err,cookie))
+---------------------------------------------------
+
+Retrieve a cookie with the given domain, path and key (a.k.a. name).  The RFC maintains that exactly one of these cookies should exist in a store.  If the store is using versioning, this means that the latest/newest such cookie should be returned.
+
+Callback takes an error and the resulting `Cookie` object.  If no cookie is found then `null` MUST be passed instead (i.e. not an error).
+
+store.findCookies(domain, path, cb(err,cookies))
+------------------------------------------------
+
+Locates cookies matching the given domain and path.  This is most often called in the context of `cookiejar.getCookies()` above.
+
+If no cookies are found, the callback MUST be passed an empty array.
+
+The resulting list will be checked for applicability to the current request according to the RFC (domain-match, path-match, http-only-flag, secure-flag, expiry, etc.), so it's OK to use an optimistic search algorithm when implementing this method.  However, the search algorithm used SHOULD try to find cookies that `domainMatch()` the domain and `pathMatch()` the path in order to limit the amount of checking that needs to be done.
+
+As of version 0.9.12, the `allPaths` option to `cookiejar.getCookies()` above will cause the path here to be `null`.  If the path is `null`, path-matching MUST NOT be performed (i.e. domain-matching only).
+
+store.putCookie(cookie, cb(err))
+--------------------------------
+
+Adds a new cookie to the store.  The implementation SHOULD replace any existing cookie with the same `.domain`, `.path`, and `.key` properties -- depending on the nature of the implementation, it's possible that between the call to `fetchCookie` and `putCookie` that a duplicate `putCookie` can occur.
+
+The `cookie` object MUST NOT be modified; the caller will have already updated the `.creation` and `.lastAccessed` properties.
+
+Pass an error if the cookie cannot be stored.
+
+store.updateCookie(oldCookie, newCookie, cb(err))
+-------------------------------------------------
+
+Update an existing cookie.  The implementation MUST update the `.value` for a cookie with the same `domain`, `.path` and `.key`.  The implementation SHOULD check that the old value in the store is equivalent to `oldCookie` - how the conflict is resolved is up to the store.
+
+The `.lastAccessed` property will always be different between the two objects and `.created` will always be the same.  Stores MAY ignore or defer the `.lastAccessed` change at the cost of affecting how cookies are sorted (or selected for deletion).
+
+Stores may wish to optimize changing the `.value` of the cookie in the store versus storing a new cookie.  If the implementation doesn't define this method a stub that calls `putCookie(newCookie,cb)` will be added to the store object.
+
+The `newCookie` and `oldCookie` objects MUST NOT be modified.
+
+Pass an error if the newCookie cannot be stored.
+
+store.removeCookie(domain, path, key, cb(err))
+----------------------------------------------
+
+Remove a cookie from the store (see notes on `findCookie` about the uniqueness constraint).
+
+The implementation MUST NOT pass an error if the cookie doesn't exist; only pass an error due to the failure to remove an existing cookie.
+
+store.removeCookies(domain, path, cb(err))
+------------------------------------------
+
+Removes matching cookies from the store.  The `path` paramter is optional, and if missing means all paths in a domain should be removed.
+
+Pass an error ONLY if removing any existing cookies failed.
+
+# TODO
+
+  * _full_ RFC5890/RFC5891 canonicalization for domains in `cdomain()`
+    * the optional `punycode` requirement implements RFC3492, but RFC6265 requires RFC5891
+  * better tests for `validate()`?
+
+# Copyright and License
+
+(tl;dr: MIT with some MPL/1.1)
+
+Copyright 2012- GoInstant, Inc. and other contributors. All rights reserved.
+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.
+
+Portions may be licensed under different licenses (in particular public-suffix.txt is MPL/1.1); please read the LICENSE file for full details.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/generate-pubsuffix.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/generate-pubsuffix.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/generate-pubsuffix.js	(revision 517)
@@ -0,0 +1,239 @@
+/*
+ * Copyright GoInstant, Inc. and other contributors. All rights reserved.
+ * 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.
+ */
+'use strict';
+var fs = require('fs');
+var assert = require('assert');
+var punycode = require('punycode');
+
+fs.readFile('./public-suffix.txt', 'utf8', function(err,string) {
+  if (err) {
+    throw err;
+  }
+  var lines = string.split("\n");
+  process.nextTick(function() {
+    processList(lines);
+  });
+});
+
+var index = {};
+
+var COMMENT = new RegExp('//.+');
+function processList(lines) {
+  while (lines.length) {
+    var line = lines.shift();
+    line = line.replace(COMMENT,'').trim();
+    if (!line) {
+      continue;
+    }
+    addToIndex(index,line);
+  }
+
+  pubSufTest();
+
+  var w = fs.createWriteStream('./lib/pubsuffix.js',{
+    flags: 'w',
+    encoding: 'utf8',
+    mode: parseInt('644',8)
+  });
+  w.on('end', process.exit);
+  w.write("/****************************************************\n");
+  w.write(" * AUTOMATICALLY GENERATED by generate-pubsuffix.js *\n");
+  w.write(" *                  DO NOT EDIT!                    *\n");
+  w.write(" ****************************************************/\n\n");
+
+  w.write("module.exports.getPublicSuffix = ");
+  w.write(getPublicSuffix.toString());
+  w.write(";\n\n");
+
+  w.write("// The following generated structure is used under the MPL version 1.1\n");
+  w.write("// See public-suffix.txt for more information\n\n");
+  w.write("var index = module.exports.index = Object.freeze(\n");
+  w.write(JSON.stringify(index));
+  w.write(");\n\n");
+  w.write("// END of automatically generated file\n");
+
+  w.end();
+}
+
+function addToIndex(index,line) {
+  var prefix = '';
+  if (line.replace(/^(!|\*\.)/)) {
+    prefix = RegExp.$1;
+    line = line.slice(prefix.length);
+  }
+  line = prefix + punycode.toASCII(line);
+
+  if (line.substr(0,1) == '!') {
+    index[line.substr(1)] = false;
+  } else {
+    index[line] = true;
+  }
+}
+
+// include the licence in the function since it gets written to pubsuffix.js
+function getPublicSuffix(domain) {
+  /*
+   * Copyright GoInstant, Inc. and other contributors. All rights reserved.
+   * 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.
+   */
+  if (!domain) {
+    return null;
+  }
+  if (domain.match(/^\./)) {
+    return null;
+  }
+
+  domain = domain.toLowerCase();
+  var parts = domain.split('.').reverse();
+
+  var suffix = '';
+  var suffixLen = 0;
+  for (var i=0; i<parts.length; i++) {
+    var part = parts[i];
+    var starstr = '*'+suffix;
+    var partstr = part+suffix;
+
+    if (index[starstr]) { // star rule matches
+      suffixLen = i+1;
+      if (index[partstr] === false) { // exception rule matches (NB: false, not undefined)
+        suffixLen--;
+      }
+    } else if (index[partstr]) { // exact match, not exception
+      suffixLen = i+1;
+    }
+
+    suffix = '.'+part+suffix;
+  }
+
+  if (index['*'+suffix]) { // *.domain exists (e.g. *.kyoto.jp for domain='kyoto.jp');
+    return null;
+  }
+
+  if (suffixLen && parts.length > suffixLen) {
+    return parts.slice(0,suffixLen+1).reverse().join('.');
+  }
+
+  return null;
+}
+
+function checkPublicSuffix(give,get) {
+  var got = getPublicSuffix(give);
+  assert.equal(got, get, give+' should be '+(get==null?'NULL':get)+' but got '+got);
+}
+
+// pubSufTest() was converted to JavaScript from http://publicsuffix.org/list/test.txt
+function pubSufTest() {
+  // For this function-scope and this function-scope ONLY:
+  // Any copyright is dedicated to the Public Domain.
+  // http://creativecommons.org/publicdomain/zero/1.0/
+
+  // NULL input.
+  checkPublicSuffix(null, null);
+  // Mixed case.
+  checkPublicSuffix('COM', null);
+  checkPublicSuffix('example.COM', 'example.com');
+  checkPublicSuffix('WwW.example.COM', 'example.com');
+  // Leading dot.
+  checkPublicSuffix('.com', null);
+  checkPublicSuffix('.example', null);
+  checkPublicSuffix('.example.com', null);
+  checkPublicSuffix('.example.example', null);
+  // Unlisted TLD.
+  checkPublicSuffix('example', null);
+  checkPublicSuffix('example.example', null);
+  checkPublicSuffix('b.example.example', null);
+  checkPublicSuffix('a.b.example.example', null);
+  // Listed, but non-Internet, TLD.
+  checkPublicSuffix('local', null);
+  checkPublicSuffix('example.local', null);
+  checkPublicSuffix('b.example.local', null);
+  checkPublicSuffix('a.b.example.local', null);
+  // TLD with only 1 rule.
+  checkPublicSuffix('biz', null);
+  checkPublicSuffix('domain.biz', 'domain.biz');
+  checkPublicSuffix('b.domain.biz', 'domain.biz');
+  checkPublicSuffix('a.b.domain.biz', 'domain.biz');
+  // TLD with some 2-level rules.
+  checkPublicSuffix('com', null);
+  checkPublicSuffix('example.com', 'example.com');
+  checkPublicSuffix('b.example.com', 'example.com');
+  checkPublicSuffix('a.b.example.com', 'example.com');
+  checkPublicSuffix('uk.com', null);
+  checkPublicSuffix('example.uk.com', 'example.uk.com');
+  checkPublicSuffix('b.example.uk.com', 'example.uk.com');
+  checkPublicSuffix('a.b.example.uk.com', 'example.uk.com');
+  checkPublicSuffix('test.ac', 'test.ac');
+  // TLD with only 1 (wildcard) rule.
+  checkPublicSuffix('cy', null);
+  checkPublicSuffix('c.cy', null);
+  checkPublicSuffix('b.c.cy', 'b.c.cy');
+  checkPublicSuffix('a.b.c.cy', 'b.c.cy');
+  // More complex TLD.
+  checkPublicSuffix('jp', null);
+  checkPublicSuffix('test.jp', 'test.jp');
+  checkPublicSuffix('www.test.jp', 'test.jp');
+  checkPublicSuffix('ac.jp', null);
+  checkPublicSuffix('test.ac.jp', 'test.ac.jp');
+  checkPublicSuffix('www.test.ac.jp', 'test.ac.jp');
+  checkPublicSuffix('kyoto.jp', null);
+  checkPublicSuffix('c.kyoto.jp', null);
+  checkPublicSuffix('b.c.kyoto.jp', 'b.c.kyoto.jp');
+  checkPublicSuffix('a.b.c.kyoto.jp', 'b.c.kyoto.jp');
+  checkPublicSuffix('pref.kyoto.jp', 'pref.kyoto.jp');  // Exception rule.
+  checkPublicSuffix('www.pref.kyoto.jp', 'pref.kyoto.jp');  // Exception rule.
+  checkPublicSuffix('city.kyoto.jp', 'city.kyoto.jp');  // Exception rule.
+  checkPublicSuffix('www.city.kyoto.jp', 'city.kyoto.jp');  // Exception rule.
+  // TLD with a wildcard rule and exceptions.
+  checkPublicSuffix('om', null);
+  checkPublicSuffix('test.om', null);
+  checkPublicSuffix('b.test.om', 'b.test.om');
+  checkPublicSuffix('a.b.test.om', 'b.test.om');
+  checkPublicSuffix('songfest.om', 'songfest.om');
+  checkPublicSuffix('www.songfest.om', 'songfest.om');
+  // US K12.
+  checkPublicSuffix('us', null);
+  checkPublicSuffix('test.us', 'test.us');
+  checkPublicSuffix('www.test.us', 'test.us');
+  checkPublicSuffix('ak.us', null);
+  checkPublicSuffix('test.ak.us', 'test.ak.us');
+  checkPublicSuffix('www.test.ak.us', 'test.ak.us');
+  checkPublicSuffix('k12.ak.us', null);
+  checkPublicSuffix('test.k12.ak.us', 'test.k12.ak.us');
+  checkPublicSuffix('www.test.k12.ak.us', 'test.k12.ak.us');
+
+
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/cookie.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/cookie.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/cookie.js	(revision 517)
@@ -0,0 +1,1107 @@
+/*
+ * Copyright GoInstant, Inc. and other contributors. All rights reserved.
+ * 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.
+ */
+
+'use strict';
+var net = require('net');
+var urlParse = require('url').parse;
+var pubsuffix = require('./pubsuffix');
+var Store = require('./store').Store;
+
+var punycode;
+try {
+  punycode = require('punycode');
+} catch(e) {
+  console.warn("cookie: can't load punycode; won't use punycode for domain normalization");
+}
+
+var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
+
+// From RFC2616 S2.2:
+var TOKEN = /[\x21\x23-\x26\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
+
+// From RFC6265 S4.1.1
+// note that it excludes \x3B ";"
+var COOKIE_OCTET  = /[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/;
+var COOKIE_OCTETS = new RegExp('^'+COOKIE_OCTET.source+'$');
+
+// The name/key cannot be empty but the value can (S5.2):
+var COOKIE_PAIR_STRICT = new RegExp('^('+TOKEN.source+'+)=("?)('+COOKIE_OCTET.source+'*)\\2$');
+var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/;
+
+// RFC6265 S4.1.1 defines extension-av as 'any CHAR except CTLs or ";"'
+// Note ';' is \x3B
+var NON_CTL_SEMICOLON = /[\x20-\x3A\x3C-\x7E]+/;
+var EXTENSION_AV = NON_CTL_SEMICOLON;
+var PATH_VALUE = NON_CTL_SEMICOLON;
+
+// Used for checking whether or not there is a trailing semi-colon
+var TRAILING_SEMICOLON = /;+$/;
+
+/* RFC6265 S5.1.1.5:
+ * [fail if] the day-of-month-value is less than 1 or greater than 31
+ */
+var DAY_OF_MONTH = /^(0?[1-9]|[12][0-9]|3[01])$/;
+
+/* RFC6265 S5.1.1.5:
+ * [fail if]
+ * *  the hour-value is greater than 23,
+ * *  the minute-value is greater than 59, or
+ * *  the second-value is greater than 59.
+ */
+var TIME = /(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])/;
+var STRICT_TIME = /^(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/;
+
+var MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$/i;
+var MONTH_TO_NUM = {
+  jan:0, feb:1, mar:2, apr:3, may:4, jun:5,
+  jul:6, aug:7, sep:8, oct:9, nov:10, dec:11
+};
+var NUM_TO_MONTH = [
+  'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'
+];
+var NUM_TO_DAY = [
+  'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
+];
+
+var YEAR = /^([1-9][0-9]{1,3})$/; // 2 to 4 digits
+
+var MAX_TIME = 2147483647000; // 31-bit max
+var MIN_TIME = 0; // 31-bit min
+
+
+// RFC6265 S5.1.1 date parser:
+function parseDate(str,strict) {
+  if (!str) {
+    return;
+  }
+  var found_time, found_dom, found_month, found_year;
+
+  /* RFC6265 S5.1.1:
+   * 2. Process each date-token sequentially in the order the date-tokens
+   * appear in the cookie-date
+   */
+  var tokens = str.split(DATE_DELIM);
+  if (!tokens) {
+    return;
+  }
+
+  var date = new Date();
+  date.setMilliseconds(0);
+
+  for (var i=0; i<tokens.length; i++) {
+    var token = tokens[i].trim();
+    if (!token.length) {
+      continue;
+    }
+
+    var result;
+
+    /* 2.1. If the found-time flag is not set and the token matches the time
+     * production, set the found-time flag and set the hour- value,
+     * minute-value, and second-value to the numbers denoted by the digits in
+     * the date-token, respectively.  Skip the remaining sub-steps and continue
+     * to the next date-token.
+     */
+    if (!found_time) {
+      result = (strict ? STRICT_TIME : TIME).exec(token);
+      if (result) {
+        found_time = true;
+        date.setUTCHours(result[1]);
+        date.setUTCMinutes(result[2]);
+        date.setUTCSeconds(result[3]);
+        continue;
+      }
+    }
+
+    /* 2.2. If the found-day-of-month flag is not set and the date-token matches
+     * the day-of-month production, set the found-day-of- month flag and set
+     * the day-of-month-value to the number denoted by the date-token.  Skip
+     * the remaining sub-steps and continue to the next date-token.
+     */
+    if (!found_dom) {
+      result = DAY_OF_MONTH.exec(token);
+      if (result) {
+        found_dom = true;
+        date.setUTCDate(result[1]);
+        continue;
+      }
+    }
+
+    /* 2.3. If the found-month flag is not set and the date-token matches the
+     * month production, set the found-month flag and set the month-value to
+     * the month denoted by the date-token.  Skip the remaining sub-steps and
+     * continue to the next date-token.
+     */
+    if (!found_month) {
+      result = MONTH.exec(token);
+      if (result) {
+        found_month = true;
+        date.setUTCMonth(MONTH_TO_NUM[result[1].toLowerCase()]);
+        continue;
+      }
+    }
+
+    /* 2.4. If the found-year flag is not set and the date-token matches the year
+     * production, set the found-year flag and set the year-value to the number
+     * denoted by the date-token.  Skip the remaining sub-steps and continue to
+     * the next date-token.
+     */
+    if (!found_year) {
+      result = YEAR.exec(token);
+      if (result) {
+        var year = result[0];
+        /* From S5.1.1:
+         * 3.  If the year-value is greater than or equal to 70 and less
+         * than or equal to 99, increment the year-value by 1900.
+         * 4.  If the year-value is greater than or equal to 0 and less
+         * than or equal to 69, increment the year-value by 2000.
+         */
+        if (70 <= year && year <= 99) {
+          year += 1900;
+        } else if (0 <= year && year <= 69) {
+          year += 2000;
+        }
+
+        if (year < 1601) {
+          return; // 5. ... the year-value is less than 1601
+        }
+
+        found_year = true;
+        date.setUTCFullYear(year);
+        continue;
+      }
+    }
+  }
+
+  if (!(found_time && found_dom && found_month && found_year)) {
+    return; // 5. ... at least one of the found-day-of-month, found-month, found-
+            // year, or found-time flags is not set,
+  }
+
+  return date;
+}
+
+function formatDate(date) {
+  var d = date.getUTCDate(); d = d >= 10 ? d : '0'+d;
+  var h = date.getUTCHours(); h = h >= 10 ? h : '0'+h;
+  var m = date.getUTCMinutes(); m = m >= 10 ? m : '0'+m;
+  var s = date.getUTCSeconds(); s = s >= 10 ? s : '0'+s;
+  return NUM_TO_DAY[date.getUTCDay()] + ', ' +
+    d+' '+ NUM_TO_MONTH[date.getUTCMonth()] +' '+ date.getUTCFullYear() +' '+
+    h+':'+m+':'+s+' GMT';
+}
+
+// S5.1.2 Canonicalized Host Names
+function canonicalDomain(str) {
+  if (str == null) {
+    return null;
+  }
+  str = str.trim().replace(/^\./,''); // S4.1.2.3 & S5.2.3: ignore leading .
+
+  // convert to IDN if any non-ASCII characters
+  if (punycode && /[^\u0001-\u007f]/.test(str)) {
+    str = punycode.toASCII(str);
+  }
+
+  return str.toLowerCase();
+}
+
+// S5.1.3 Domain Matching
+function domainMatch(str, domStr, canonicalize) {
+  if (str == null || domStr == null) {
+    return null;
+  }
+  if (canonicalize !== false) {
+    str = canonicalDomain(str);
+    domStr = canonicalDomain(domStr);
+  }
+
+  /*
+   * "The domain string and the string are identical. (Note that both the
+   * domain string and the string will have been canonicalized to lower case at
+   * this point)"
+   */
+  if (str == domStr) {
+    return true;
+  }
+
+  /* "All of the following [three] conditions hold:" (order adjusted from the RFC) */
+
+  /* "* The string is a host name (i.e., not an IP address)." */
+  if (net.isIP(str)) {
+    return false;
+  }
+
+  /* "* The domain string is a suffix of the string" */
+  var idx = str.indexOf(domStr);
+  if (idx <= 0) {
+    return false; // it's a non-match (-1) or prefix (0)
+  }
+
+  // e.g "a.b.c".indexOf("b.c") === 2
+  // 5 === 3+2
+  if (str.length !== domStr.length + idx) { // it's not a suffix
+    return false;
+  }
+
+  /* "* The last character of the string that is not included in the domain
+  * string is a %x2E (".") character." */
+  if (str.substr(idx-1,1) !== '.') {
+    return false;
+  }
+
+  return true;
+}
+
+
+// RFC6265 S5.1.4 Paths and Path-Match
+
+/*
+ * "The user agent MUST use an algorithm equivalent to the following algorithm
+ * to compute the default-path of a cookie:"
+ *
+ * Assumption: the path (and not query part or absolute uri) is passed in.
+ */
+function defaultPath(path) {
+  // "2. If the uri-path is empty or if the first character of the uri-path is not
+  // a %x2F ("/") character, output %x2F ("/") and skip the remaining steps.
+  if (!path || path.substr(0,1) !== "/") {
+    return "/";
+  }
+
+  // "3. If the uri-path contains no more than one %x2F ("/") character, output
+  // %x2F ("/") and skip the remaining step."
+  if (path === "/") {
+    return path;
+  }
+
+  var rightSlash = path.lastIndexOf("/");
+  if (rightSlash === 0) {
+    return "/";
+  }
+
+  // "4. Output the characters of the uri-path from the first character up to,
+  // but not including, the right-most %x2F ("/")."
+  return path.slice(0, rightSlash);
+}
+
+/*
+ * "A request-path path-matches a given cookie-path if at least one of the
+ * following conditions holds:"
+ */
+function pathMatch(reqPath,cookiePath) {
+  // "o  The cookie-path and the request-path are identical."
+  if (cookiePath === reqPath) {
+    return true;
+  }
+
+  var idx = reqPath.indexOf(cookiePath);
+  if (idx === 0) {
+    // "o  The cookie-path is a prefix of the request-path, and the last
+    // character of the cookie-path is %x2F ("/")."
+    if (cookiePath.substr(-1) === "/") {
+      return true;
+    }
+
+    // " o  The cookie-path is a prefix of the request-path, and the first
+    // character of the request-path that is not included in the cookie- path
+    // is a %x2F ("/") character."
+    if (reqPath.substr(cookiePath.length,1) === "/") {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+function parse(str, strict) {
+  str = str.trim();
+
+  // S4.1.1 Trailing semi-colons are not part of the specification.
+  // If we are not in strict mode we remove the trailing semi-colons.
+  var semiColonCheck = TRAILING_SEMICOLON.exec(str);
+  if (semiColonCheck) {
+    if (strict) {
+      return;
+    }
+    str = str.slice(0, semiColonCheck.index);
+  }
+
+  // We use a regex to parse the "name-value-pair" part of S5.2
+  var firstSemi = str.indexOf(';'); // S5.2 step 1
+  var pairRx = strict ? COOKIE_PAIR_STRICT : COOKIE_PAIR;
+  var result = pairRx.exec(firstSemi === -1 ? str : str.substr(0,firstSemi));
+
+  // Rx satisfies the "the name string is empty" and "lacks a %x3D ("=")"
+  // constraints as well as trimming any whitespace.
+  if (!result) {
+    return;
+  }
+
+  var c = new Cookie();
+  c.key = result[1]; // the regexp should trim() already
+  c.value = result[3]; // [2] is quotes or empty-string
+
+  if (firstSemi === -1) {
+    return c;
+  }
+
+  // S5.2.3 "unparsed-attributes consist of the remainder of the set-cookie-string
+  // (including the %x3B (";") in question)." plus later on in the same section
+  // "discard the first ";" and trim".
+  var unparsed = str.slice(firstSemi).replace(/^\s*;\s*/,'').trim();
+
+  // "If the unparsed-attributes string is empty, skip the rest of these
+  // steps."
+  if (unparsed.length === 0) {
+    return c;
+  }
+
+  /*
+   * S5.2 says that when looping over the items "[p]rocess the attribute-name
+   * and attribute-value according to the requirements in the following
+   * subsections" for every item.  Plus, for many of the individual attributes
+   * in S5.3 it says to use the "attribute-value of the last attribute in the
+   * cookie-attribute-list".  Therefore, in this implementation, we overwrite
+   * the previous value.
+   */
+  var cookie_avs = unparsed.split(/\s*;\s*/);
+  while (cookie_avs.length) {
+    var av = cookie_avs.shift();
+
+    if (strict && !EXTENSION_AV.test(av)) {
+      return;
+    }
+
+    var av_sep = av.indexOf('=');
+    var av_key, av_value;
+    if (av_sep === -1) {
+      av_key = av;
+      av_value = null;
+    } else {
+      av_key = av.substr(0,av_sep);
+      av_value = av.substr(av_sep+1);
+    }
+
+    av_key = av_key.trim().toLowerCase();
+    if (av_value) {
+      av_value = av_value.trim();
+    }
+
+    switch(av_key) {
+    case 'expires': // S5.2.1
+      if (!av_value) {if(strict){return;}else{break;} }
+      var exp = parseDate(av_value,strict);
+      // "If the attribute-value failed to parse as a cookie date, ignore the
+      // cookie-av."
+      if (exp == null) { if(strict){return;}else{break;} }
+      c.expires = exp;
+      // over and underflow not realistically a concern: V8's getTime() seems to
+      // store something larger than a 32-bit time_t (even with 32-bit node)
+      break;
+
+    case 'max-age': // S5.2.2
+      if (!av_value) { if(strict){return;}else{break;} }
+      // "If the first character of the attribute-value is not a DIGIT or a "-"
+      // character ...[or]... If the remainder of attribute-value contains a
+      // non-DIGIT character, ignore the cookie-av."
+      if (!/^-?[0-9]+$/.test(av_value)) { if(strict){return;}else{break;} }
+      var delta = parseInt(av_value,10);
+      if (strict && delta <= 0) {
+        return; // S4.1.1
+      }
+      // "If delta-seconds is less than or equal to zero (0), let expiry-time
+      // be the earliest representable date and time."
+      c.setMaxAge(delta);
+      break;
+
+    case 'domain': // S5.2.3
+      // "If the attribute-value is empty, the behavior is undefined.  However,
+      // the user agent SHOULD ignore the cookie-av entirely."
+      if (!av_value) { if(strict){return;}else{break;} }
+      // S5.2.3 "Let cookie-domain be the attribute-value without the leading %x2E
+      // (".") character."
+      var domain = av_value.trim().replace(/^\./,'');
+      if (!domain) { if(strict){return;}else{break;} } // see "is empty" above
+      // "Convert the cookie-domain to lower case."
+      c.domain = domain.toLowerCase();
+      break;
+
+    case 'path': // S5.2.4
+      /*
+       * "If the attribute-value is empty or if the first character of the
+       * attribute-value is not %x2F ("/"):
+       *   Let cookie-path be the default-path.
+       * Otherwise:
+       *   Let cookie-path be the attribute-value."
+       *
+       * We'll represent the default-path as null since it depends on the
+       * context of the parsing.
+       */
+      if (!av_value || av_value.substr(0,1) != "/") {
+        if(strict){return;}else{break;}
+      }
+      c.path = av_value;
+      break;
+
+    case 'secure': // S5.2.5
+      /*
+       * "If the attribute-name case-insensitively matches the string "Secure",
+       * the user agent MUST append an attribute to the cookie-attribute-list
+       * with an attribute-name of Secure and an empty attribute-value."
+       */
+      if (av_value != null) { if(strict){return;} }
+      c.secure = true;
+      break;
+
+    case 'httponly': // S5.2.6 -- effectively the same as 'secure'
+      if (av_value != null) { if(strict){return;} }
+      c.httpOnly = true;
+      break;
+
+    default:
+      c.extensions = c.extensions || [];
+      c.extensions.push(av);
+      break;
+    }
+  }
+
+  // ensure a default date for sorting:
+  c.creation = new Date();
+  return c;
+}
+
+function fromJSON(str) {
+  if (!str) {
+    return null;
+  }
+
+  var obj;
+  try {
+    obj = JSON.parse(str);
+  } catch (e) {
+    return null;
+  }
+
+  var c = new Cookie();
+  for (var i=0; i<numCookieProperties; i++) {
+    var prop = cookieProperties[i];
+    if (obj[prop] == null) {
+      continue;
+    }
+    if (prop === 'expires' ||
+        prop === 'creation' ||
+        prop === 'lastAccessed')
+    {
+      c[prop] = obj[prop] == "Infinity" ? "Infinity" : new Date(obj[prop]);
+    } else {
+      c[prop] = obj[prop];
+    }
+  }
+
+
+  // ensure a default date for sorting:
+  c.creation = c.creation || new Date();
+
+  return c;
+}
+
+/* Section 5.4 part 2:
+ * "*  Cookies with longer paths are listed before cookies with
+ *     shorter paths.
+ *
+ *  *  Among cookies that have equal-length path fields, cookies with
+ *     earlier creation-times are listed before cookies with later
+ *     creation-times."
+ */
+
+function cookieCompare(a,b) {
+  // descending for length: b CMP a
+  var deltaLen = (b.path ? b.path.length : 0) - (a.path ? a.path.length : 0);
+  if (deltaLen !== 0) {
+    return deltaLen;
+  }
+  // ascending for time: a CMP b
+  return (a.creation ? a.creation.getTime() : MAX_TIME) -
+         (b.creation ? b.creation.getTime() : MAX_TIME);
+}
+
+// Gives the permutation of all possible domainMatch()es of a given domain. The
+// array is in shortest-to-longest order.  Handy for indexing.
+function permuteDomain(domain) {
+  var pubSuf = pubsuffix.getPublicSuffix(domain);
+  if (!pubSuf) {
+    return null;
+  }
+  if (pubSuf == domain) {
+    return [domain];
+  }
+
+  var prefix = domain.slice(0,-(pubSuf.length+1)); // ".example.com"
+  var parts = prefix.split('.').reverse();
+  var cur = pubSuf;
+  var permutations = [cur];
+  while (parts.length) {
+    cur = parts.shift()+'.'+cur;
+    permutations.push(cur);
+  }
+  return permutations;
+}
+
+// Gives the permutation of all possible pathMatch()es of a given path. The
+// array is in longest-to-shortest order.  Handy for indexing.
+function permutePath(path) {
+  if (path === '/') {
+    return ['/'];
+  }
+  if (path.lastIndexOf('/') === path.length-1) {
+    path = path.substr(0,path.length-1);
+  }
+  var permutations = [path];
+  while (path.length > 1) {
+    var lindex = path.lastIndexOf('/');
+    if (lindex === 0) {
+      break;
+    }
+    path = path.substr(0,lindex);
+    permutations.push(path);
+  }
+  permutations.push('/');
+  return permutations;
+}
+
+
+function Cookie (opts) {
+  if (typeof opts !== "object") {
+    return;
+  }
+  Object.keys(opts).forEach(function (key) {
+    if (Cookie.prototype.hasOwnProperty(key)) {
+      this[key] = opts[key] || Cookie.prototype[key];
+    }
+  }.bind(this));
+}
+
+Cookie.parse = parse;
+Cookie.fromJSON = fromJSON;
+
+Cookie.prototype.key = "";
+Cookie.prototype.value = "";
+
+// the order in which the RFC has them:
+Cookie.prototype.expires = "Infinity"; // coerces to literal Infinity
+Cookie.prototype.maxAge = null; // takes precedence over expires for TTL
+Cookie.prototype.domain = null;
+Cookie.prototype.path = null;
+Cookie.prototype.secure = false;
+Cookie.prototype.httpOnly = false;
+Cookie.prototype.extensions = null;
+
+// set by the CookieJar:
+Cookie.prototype.hostOnly = null; // boolean when set
+Cookie.prototype.pathIsDefault = null; // boolean when set
+Cookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse
+Cookie.prototype.lastAccessed = null; // Date when set
+
+var cookieProperties = Object.freeze(Object.keys(Cookie.prototype).map(function(p) {
+  if (p instanceof Function) {
+    return;
+  }
+  return p;
+}));
+var numCookieProperties = cookieProperties.length;
+
+Cookie.prototype.inspect = function inspect() {
+  var now = Date.now();
+  return 'Cookie="'+this.toString() +
+    '; hostOnly='+(this.hostOnly != null ? this.hostOnly : '?') +
+    '; aAge='+(this.lastAccessed ? (now-this.lastAccessed.getTime())+'ms' : '?') +
+    '; cAge='+(this.creation ? (now-this.creation.getTime())+'ms' : '?') +
+    '"';
+};
+
+Cookie.prototype.validate = function validate() {
+  if (!COOKIE_OCTETS.test(this.value)) {
+    return false;
+  }
+  if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires,true)) {
+    return false;
+  }
+  if (this.maxAge != null && this.maxAge <= 0) {
+    return false; // "Max-Age=" non-zero-digit *DIGIT
+  }
+  if (this.path != null && !PATH_VALUE.test(this.path)) {
+    return false;
+  }
+
+  var cdomain = this.cdomain();
+  if (cdomain) {
+    if (cdomain.match(/\.$/)) {
+      return false; // S4.1.2.3 suggests that this is bad. domainMatch() tests confirm this
+    }
+    var suffix = pubsuffix.getPublicSuffix(cdomain);
+    if (suffix == null) { // it's a public suffix
+      return false;
+    }
+  }
+  return true;
+};
+
+Cookie.prototype.setExpires = function setExpires(exp) {
+  if (exp instanceof Date) {
+    this.expires = exp;
+  } else {
+    this.expires = parseDate(exp) || "Infinity";
+  }
+};
+
+Cookie.prototype.setMaxAge = function setMaxAge(age) {
+  if (age === Infinity || age === -Infinity) {
+    this.maxAge = age.toString(); // so JSON.stringify() works
+  } else {
+    this.maxAge = age;
+  }
+};
+
+// gives Cookie header format
+Cookie.prototype.cookieString = function cookieString() {
+  var val = this.value;
+  if (val == null) {
+    val = '';
+  }
+  return this.key+'='+val;
+};
+
+// gives Set-Cookie header format
+Cookie.prototype.toString = function toString() {
+  var str = this.cookieString();
+
+  if (this.expires != Infinity) {
+    if (this.expires instanceof Date) {
+      str += '; Expires='+formatDate(this.expires);
+    } else {
+      str += '; Expires='+this.expires;
+    }
+  }
+
+  if (this.maxAge != null && this.maxAge != Infinity) {
+    str += '; Max-Age='+this.maxAge;
+  }
+
+  if (this.domain && !this.hostOnly) {
+    str += '; Domain='+this.domain;
+  }
+  if (this.path) {
+    str += '; Path='+this.path;
+  }
+
+  if (this.secure) {
+    str += '; Secure';
+  }
+  if (this.httpOnly) {
+    str += '; HttpOnly';
+  }
+  if (this.extensions) {
+    this.extensions.forEach(function(ext) {
+      str += '; '+ext;
+    });
+  }
+
+  return str;
+};
+
+// TTL() partially replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+// elsewhere)
+// S5.3 says to give the "latest representable date" for which we use Infinity
+// For "expired" we use 0
+Cookie.prototype.TTL = function TTL(now) {
+  /* RFC6265 S4.1.2.2 If a cookie has both the Max-Age and the Expires
+   * attribute, the Max-Age attribute has precedence and controls the
+   * expiration date of the cookie.
+   * (Concurs with S5.3 step 3)
+   */
+  if (this.maxAge != null) {
+    return this.maxAge<=0 ? 0 : this.maxAge*1000;
+  }
+
+  var expires = this.expires;
+  if (expires != Infinity) {
+    if (!(expires instanceof Date)) {
+      expires = parseDate(expires) || Infinity;
+    }
+
+    if (expires == Infinity) {
+      return Infinity;
+    }
+
+    return expires.getTime() - (now || Date.now());
+  }
+
+  return Infinity;
+};
+
+// expiryTime() replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+// elsewhere)
+Cookie.prototype.expiryTime = function expiryTime(now) {
+  if (this.maxAge != null) {
+    var relativeTo = this.creation || now || new Date();
+    var age = (this.maxAge <= 0) ? -Infinity : this.maxAge*1000;
+    return relativeTo.getTime() + age;
+  }
+
+  if (this.expires == Infinity) {
+    return Infinity;
+  }
+  return this.expires.getTime();
+};
+
+// expiryDate() replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+// elsewhere), except it returns a Date
+Cookie.prototype.expiryDate = function expiryDate(now) {
+  var millisec = this.expiryTime(now);
+  if (millisec == Infinity) {
+    return new Date(MAX_TIME);
+  } else if (millisec == -Infinity) {
+    return new Date(MIN_TIME);
+  } else {
+    return new Date(millisec);
+  }
+};
+
+// This replaces the "persistent-flag" parts of S5.3 step 3
+Cookie.prototype.isPersistent = function isPersistent() {
+  return (this.maxAge != null || this.expires != Infinity);
+};
+
+// Mostly S5.1.2 and S5.2.3:
+Cookie.prototype.cdomain =
+Cookie.prototype.canonicalizedDomain = function canonicalizedDomain() {
+  if (this.domain == null) {
+    return null;
+  }
+  return canonicalDomain(this.domain);
+};
+
+
+var memstore;
+function CookieJar(store, rejectPublicSuffixes) {
+  if (rejectPublicSuffixes != null) {
+    this.rejectPublicSuffixes = rejectPublicSuffixes;
+  }
+
+  if (!store) {
+    memstore = memstore || require('./memstore');
+    store = new memstore.MemoryCookieStore();
+  }
+  this.store = store;
+}
+CookieJar.prototype.store = null;
+CookieJar.prototype.rejectPublicSuffixes = true;
+var CAN_BE_SYNC = [];
+
+CAN_BE_SYNC.push('setCookie');
+CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
+  var err;
+  var context = (url instanceof Object) ? url : urlParse(url);
+  if (options instanceof Function) {
+    cb = options;
+    options = {};
+  }
+
+  var host = canonicalDomain(context.hostname);
+
+  // S5.3 step 1
+  if (!(cookie instanceof Cookie)) {
+    cookie = Cookie.parse(cookie, options.strict === true);
+  }
+  if (!cookie) {
+    err = new Error("Cookie failed to parse");
+    return cb(options.ignoreError ? null : err);
+  }
+
+  // S5.3 step 2
+  var now = options.now || new Date(); // will assign later to save effort in the face of errors
+
+  // S5.3 step 3: NOOP; persistent-flag and expiry-time is handled by getCookie()
+
+  // S5.3 step 4: NOOP; domain is null by default
+
+  // S5.3 step 5: public suffixes
+  if (this.rejectPublicSuffixes && cookie.domain) {
+    var suffix = pubsuffix.getPublicSuffix(cookie.cdomain());
+    if (suffix == null) { // e.g. "com"
+      err = new Error("Cookie has domain set to a public suffix");
+      return cb(options.ignoreError ? null : err);
+    }
+  }
+
+  // S5.3 step 6:
+  if (cookie.domain) {
+    if (!domainMatch(host, cookie.cdomain(), false)) {
+      err = new Error("Cookie not in this host's domain. Cookie:"+cookie.cdomain()+" Request:"+host);
+      return cb(options.ignoreError ? null : err);
+    }
+
+    if (cookie.hostOnly == null) { // don't reset if already set
+      cookie.hostOnly = false;
+    }
+
+  } else {
+    cookie.hostOnly = true;
+    cookie.domain = host;
+  }
+
+  // S5.3 step 7: "Otherwise, set the cookie's path to the default-path of the
+  // request-uri"
+  if (!cookie.path) {
+    cookie.path = defaultPath(context.pathname);
+    cookie.pathIsDefault = true;
+  } else {
+    if (cookie.path.length > 1 && cookie.path.substr(-1) == '/') {
+      cookie.path = cookie.path.slice(0,-1);
+    }
+  }
+
+  // S5.3 step 8: NOOP; secure attribute
+  // S5.3 step 9: NOOP; httpOnly attribute
+
+  // S5.3 step 10
+  if (options.http === false && cookie.httpOnly) {
+    err = new Error("Cookie is HttpOnly and this isn't an HTTP API");
+    return cb(options.ignoreError ? null : err);
+  }
+
+  var store = this.store;
+
+  if (!store.updateCookie) {
+    store.updateCookie = function(oldCookie, newCookie, cb) {
+      this.putCookie(newCookie, cb);
+    };
+  }
+
+  function withCookie(err, oldCookie) {
+    if (err) {
+      return cb(err);
+    }
+
+    var next = function(err) {
+      if (err) {
+        return cb(err);
+      } else {
+        cb(null, cookie);
+      }
+    };
+
+    if (oldCookie) {
+      // S5.3 step 11 - "If the cookie store contains a cookie with the same name,
+      // domain, and path as the newly created cookie:"
+      if (options.http === false && oldCookie.httpOnly) { // step 11.2
+        err = new Error("old Cookie is HttpOnly and this isn't an HTTP API");
+        return cb(options.ignoreError ? null : err);
+      }
+      cookie.creation = oldCookie.creation; // step 11.3
+      cookie.lastAccessed = now;
+      // Step 11.4 (delete cookie) is implied by just setting the new one:
+      store.updateCookie(oldCookie, cookie, next); // step 12
+
+    } else {
+      cookie.creation = cookie.lastAccessed = now;
+      store.putCookie(cookie, next); // step 12
+    }
+  }
+
+  store.findCookie(cookie.domain, cookie.path, cookie.key, withCookie);
+};
+
+// RFC6365 S5.4
+CAN_BE_SYNC.push('getCookies');
+CookieJar.prototype.getCookies = function(url, options, cb) {
+  var context = (url instanceof Object) ? url : urlParse(url);
+  if (options instanceof Function) {
+    cb = options;
+    options = {};
+  }
+
+  var host = canonicalDomain(context.hostname);
+  var path = context.pathname || '/';
+
+  var secure = options.secure;
+  if (secure == null && context.protocol &&
+      (context.protocol == 'https:' || context.protocol == 'wss:'))
+  {
+    secure = true;
+  }
+
+  var http = options.http;
+  if (http == null) {
+    http = true;
+  }
+
+  var now = options.now || Date.now();
+  var expireCheck = options.expire !== false;
+  var allPaths = !!options.allPaths;
+  var store = this.store;
+
+  function matchingCookie(c) {
+    // "Either:
+    //   The cookie's host-only-flag is true and the canonicalized
+    //   request-host is identical to the cookie's domain.
+    // Or:
+    //   The cookie's host-only-flag is false and the canonicalized
+    //   request-host domain-matches the cookie's domain."
+    if (c.hostOnly) {
+      if (c.domain != host) {
+        return false;
+      }
+    } else {
+      if (!domainMatch(host, c.domain, false)) {
+        return false;
+      }
+    }
+
+    // "The request-uri's path path-matches the cookie's path."
+    if (!allPaths && !pathMatch(path, c.path)) {
+      return false;
+    }
+
+    // "If the cookie's secure-only-flag is true, then the request-uri's
+    // scheme must denote a "secure" protocol"
+    if (c.secure && !secure) {
+      return false;
+    }
+
+    // "If the cookie's http-only-flag is true, then exclude the cookie if the
+    // cookie-string is being generated for a "non-HTTP" API"
+    if (c.httpOnly && !http) {
+      return false;
+    }
+
+    // deferred from S5.3
+    // non-RFC: allow retention of expired cookies by choice
+    if (expireCheck && c.expiryTime() <= now) {
+      store.removeCookie(c.domain, c.path, c.key, function(){}); // result ignored
+      return false;
+    }
+
+    return true;
+  }
+
+  store.findCookies(host, allPaths ? null : path, function(err,cookies) {
+    if (err) {
+      return cb(err);
+    }
+
+    cookies = cookies.filter(matchingCookie);
+
+    // sorting of S5.4 part 2
+    if (options.sort !== false) {
+      cookies = cookies.sort(cookieCompare);
+    }
+
+    // S5.4 part 3
+    var now = new Date();
+    cookies.forEach(function(c) {
+      c.lastAccessed = now;
+    });
+    // TODO persist lastAccessed
+
+    cb(null,cookies);
+  });
+};
+
+CAN_BE_SYNC.push('getCookieString');
+CookieJar.prototype.getCookieString = function(/*..., cb*/) {
+  var args = Array.prototype.slice.call(arguments,0);
+  var cb = args.pop();
+  var next = function(err,cookies) {
+    if (err) {
+      cb(err);
+    } else {
+      cb(null, cookies.map(function(c){
+        return c.cookieString();
+      }).join('; '));
+    }
+  };
+  args.push(next);
+  this.getCookies.apply(this,args);
+};
+
+CAN_BE_SYNC.push('getSetCookieStrings');
+CookieJar.prototype.getSetCookieStrings = function(/*..., cb*/) {
+  var args = Array.prototype.slice.call(arguments,0);
+  var cb = args.pop();
+  var next = function(err,cookies) {
+    if (err) {
+      cb(err);
+    } else {
+      cb(null, cookies.map(function(c){
+        return c.toString();
+      }));
+    }
+  };
+  args.push(next);
+  this.getCookies.apply(this,args);
+};
+
+// Use a closure to provide a true imperative API for synchronous stores.
+function syncWrap(method) {
+  return function() {
+    if (!this.store.synchronous) {
+      throw new Error('CookieJar store is not synchronous; use async API instead.');
+    }
+
+    var args = Array.prototype.slice.call(arguments);
+    var syncErr, syncResult;
+    args.push(function syncCb(err, result) {
+      syncErr = err;
+      syncResult = result;
+    });
+    this[method].apply(this, args);
+
+    if (syncErr) {
+      throw syncErr;
+    }
+    return syncResult;
+  };
+}
+
+// wrap all declared CAN_BE_SYNC methods in the sync wrapper
+CAN_BE_SYNC.forEach(function(method) {
+  CookieJar.prototype[method+'Sync'] = syncWrap(method);
+});
+
+module.exports = {
+  CookieJar: CookieJar,
+  Cookie: Cookie,
+  Store: Store,
+  parseDate: parseDate,
+  formatDate: formatDate,
+  parse: parse,
+  fromJSON: fromJSON,
+  domainMatch: domainMatch,
+  defaultPath: defaultPath,
+  pathMatch: pathMatch,
+  getPublicSuffix: pubsuffix.getPublicSuffix,
+  cookieCompare: cookieCompare,
+  permuteDomain: permuteDomain,
+  permutePath: permutePath,
+  canonicalDomain: canonicalDomain,
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/memstore.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/memstore.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/memstore.js	(revision 517)
@@ -0,0 +1,123 @@
+'use strict';
+var tough = require('./cookie');
+var Store = require('./store').Store;
+var permuteDomain = tough.permuteDomain;
+var permutePath = tough.permutePath;
+var util = require('util');
+
+function MemoryCookieStore() {
+  Store.call(this);
+  this.idx = {};
+}
+util.inherits(MemoryCookieStore, Store);
+exports.MemoryCookieStore = MemoryCookieStore;
+MemoryCookieStore.prototype.idx = null;
+MemoryCookieStore.prototype.synchronous = true;
+
+// force a default depth:
+MemoryCookieStore.prototype.inspect = function() {
+  return "{ idx: "+util.inspect(this.idx, false, 2)+' }';
+};
+
+MemoryCookieStore.prototype.findCookie = function(domain, path, key, cb) {
+  if (!this.idx[domain]) {
+    return cb(null,undefined);
+  }
+  if (!this.idx[domain][path]) {
+    return cb(null,undefined);
+  }
+  return cb(null,this.idx[domain][path][key]||null);
+};
+
+MemoryCookieStore.prototype.findCookies = function(domain, path, cb) {
+  var results = [];
+  if (!domain) {
+    return cb(null,[]);
+  }
+
+  var pathMatcher;
+  if (!path) {
+    // null or '/' means "all paths"
+    pathMatcher = function matchAll(domainIndex) {
+      for (var curPath in domainIndex) {
+        var pathIndex = domainIndex[curPath];
+        for (var key in pathIndex) {
+          results.push(pathIndex[key]);
+        }
+      }
+    };
+
+  } else if (path === '/') {
+    pathMatcher = function matchSlash(domainIndex) {
+      var pathIndex = domainIndex['/'];
+      if (!pathIndex) {
+        return;
+      }
+      for (var key in pathIndex) {
+        results.push(pathIndex[key]);
+      }
+    };
+
+  } else {
+    var paths = permutePath(path) || [path];
+    pathMatcher = function matchRFC(domainIndex) {
+      paths.forEach(function(curPath) {
+        var pathIndex = domainIndex[curPath];
+        if (!pathIndex) {
+          return;
+        }
+        for (var key in pathIndex) {
+          results.push(pathIndex[key]);
+        }
+      });
+    };
+  }
+
+  var domains = permuteDomain(domain) || [domain];
+  var idx = this.idx;
+  domains.forEach(function(curDomain) {
+    var domainIndex = idx[curDomain];
+    if (!domainIndex) {
+      return;
+    }
+    pathMatcher(domainIndex);
+  });
+
+  cb(null,results);
+};
+
+MemoryCookieStore.prototype.putCookie = function(cookie, cb) {
+  if (!this.idx[cookie.domain]) {
+    this.idx[cookie.domain] = {};
+  }
+  if (!this.idx[cookie.domain][cookie.path]) {
+    this.idx[cookie.domain][cookie.path] = {};
+  }
+  this.idx[cookie.domain][cookie.path][cookie.key] = cookie;
+  cb(null);
+};
+
+MemoryCookieStore.prototype.updateCookie = function updateCookie(oldCookie, newCookie, cb) {
+  // updateCookie() may avoid updating cookies that are identical.  For example,
+  // lastAccessed may not be important to some stores and an equality
+  // comparison could exclude that field.
+  this.putCookie(newCookie,cb);
+};
+
+MemoryCookieStore.prototype.removeCookie = function removeCookie(domain, path, key, cb) {
+  if (this.idx[domain] && this.idx[domain][path] && this.idx[domain][path][key]) {
+    delete this.idx[domain][path][key];
+  }
+  cb(null);
+};
+
+MemoryCookieStore.prototype.removeCookies = function removeCookies(domain, path, cb) {
+  if (this.idx[domain]) {
+    if (path) {
+      delete this.idx[domain][path];
+    } else {
+      delete this.idx[domain];
+    }
+  }
+  return cb(null);
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js	(revision 517)
@@ -0,0 +1,69 @@
+/****************************************************
+ * AUTOMATICALLY GENERATED by generate-pubsuffix.js *
+ *                  DO NOT EDIT!                    *
+ ****************************************************/
+
+module.exports.getPublicSuffix = function getPublicSuffix(domain) {
+  /*
+   * Copyright GoInstant, Inc. and other contributors. All rights reserved.
+   * 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.
+   */
+  if (!domain) return null;
+  if (domain.match(/^\./)) return null;
+
+  domain = domain.toLowerCase();
+  var parts = domain.split('.').reverse();
+
+  var suffix = '';
+  var suffixLen = 0;
+  for (var i=0; i<parts.length; i++) {
+    var part = parts[i];
+    var starstr = '*'+suffix;
+    var partstr = part+suffix;
+
+    if (index[starstr]) { // star rule matches
+      suffixLen = i+1;
+      if (index[partstr] === false) { // exception rule matches (NB: false, not undefined)
+        suffixLen--;
+      }
+    } else if (index[partstr]) { // exact match, not exception
+      suffixLen = i+1;
+    }
+
+    suffix = '.'+part+suffix;
+  }
+
+  if (index['*'+suffix]) { // *.domain exists (e.g. *.kyoto.jp for domain='kyoto.jp');
+    return null;
+  }
+
+  if (suffixLen && parts.length > suffixLen) {
+    return parts.slice(0,suffixLen+1).reverse().join('.');
+  }
+
+  return null;
+};
+
+// The following generated structure is used under the MPL version 1.1
+// See public-suffix.txt for more information
+
+var index = module.exports.index = Object.freeze(
+{"ac":true,"com.ac":true,"edu.ac":true,"gov.ac":true,"net.ac":true,"mil.ac":true,"org.ac":true,"ad":true,"nom.ad":true,"ae":true,"co.ae":true,"net.ae":true,"org.ae":true,"sch.ae":true,"ac.ae":true,"gov.ae":true,"mil.ae":true,"aero":true,"accident-investigation.aero":true,"accident-prevention.aero":true,"aerobatic.aero":true,"aeroclub.aero":true,"aerodrome.aero":true,"agents.aero":true,"aircraft.aero":true,"airline.aero":true,"airport.aero":true,"air-surveillance.aero":true,"airtraffic.aero":true,"air-traffic-control.aero":true,"ambulance.aero":true,"amusement.aero":true,"association.aero":true,"author.aero":true,"ballooning.aero":true,"broker.aero":true,"caa.aero":true,"cargo.aero":true,"catering.aero":true,"certification.aero":true,"championship.aero":true,"charter.aero":true,"civilaviation.aero":true,"club.aero":true,"conference.aero":true,"consultant.aero":true,"consulting.aero":true,"control.aero":true,"council.aero":true,"crew.aero":true,"design.aero":true,"dgca.aero":true,"educator.aero":true,"emergency.aero":true,"engine.aero":true,"engineer.aero":true,"entertainment.aero":true,"equipment.aero":true,"exchange.aero":true,"express.aero":true,"federation.aero":true,"flight.aero":true,"freight.aero":true,"fuel.aero":true,"gliding.aero":true,"government.aero":true,"groundhandling.aero":true,"group.aero":true,"hanggliding.aero":true,"homebuilt.aero":true,"insurance.aero":true,"journal.aero":true,"journalist.aero":true,"leasing.aero":true,"logistics.aero":true,"magazine.aero":true,"maintenance.aero":true,"marketplace.aero":true,"media.aero":true,"microlight.aero":true,"modelling.aero":true,"navigation.aero":true,"parachuting.aero":true,"paragliding.aero":true,"passenger-association.aero":true,"pilot.aero":true,"press.aero":true,"production.aero":true,"recreation.aero":true,"repbody.aero":true,"res.aero":true,"research.aero":true,"rotorcraft.aero":true,"safety.aero":true,"scientist.aero":true,"services.aero":true,"show.aero":true,"skydiving.aero":true,"software.aero":true,"student.aero":true,"taxi.aero":true,"trader.aero":true,"trading.aero":true,"trainer.aero":true,"union.aero":true,"workinggroup.aero":true,"works.aero":true,"af":true,"gov.af":true,"com.af":true,"org.af":true,"net.af":true,"edu.af":true,"ag":true,"com.ag":true,"org.ag":true,"net.ag":true,"co.ag":true,"nom.ag":true,"ai":true,"off.ai":true,"com.ai":true,"net.ai":true,"org.ai":true,"al":true,"com.al":true,"edu.al":true,"gov.al":true,"mil.al":true,"net.al":true,"org.al":true,"am":true,"an":true,"com.an":true,"net.an":true,"org.an":true,"edu.an":true,"ao":true,"ed.ao":true,"gv.ao":true,"og.ao":true,"co.ao":true,"pb.ao":true,"it.ao":true,"aq":true,"*.ar":true,"congresodelalengua3.ar":false,"educ.ar":false,"gobiernoelectronico.ar":false,"mecon.ar":false,"nacion.ar":false,"nic.ar":false,"promocion.ar":false,"retina.ar":false,"uba.ar":false,"e164.arpa":true,"in-addr.arpa":true,"ip6.arpa":true,"iris.arpa":true,"uri.arpa":true,"urn.arpa":true,"as":true,"gov.as":true,"asia":true,"at":true,"ac.at":true,"co.at":true,"gv.at":true,"or.at":true,"com.au":true,"net.au":true,"org.au":true,"edu.au":true,"gov.au":true,"csiro.au":true,"asn.au":true,"id.au":true,"info.au":true,"conf.au":true,"oz.au":true,"act.au":true,"nsw.au":true,"nt.au":true,"qld.au":true,"sa.au":true,"tas.au":true,"vic.au":true,"wa.au":true,"act.edu.au":true,"nsw.edu.au":true,"nt.edu.au":true,"qld.edu.au":true,"sa.edu.au":true,"tas.edu.au":true,"vic.edu.au":true,"wa.edu.au":true,"act.gov.au":true,"nt.gov.au":true,"qld.gov.au":true,"sa.gov.au":true,"tas.gov.au":true,"vic.gov.au":true,"wa.gov.au":true,"aw":true,"com.aw":true,"ax":true,"az":true,"com.az":true,"net.az":true,"int.az":true,"gov.az":true,"org.az":true,"edu.az":true,"info.az":true,"pp.az":true,"mil.az":true,"name.az":true,"pro.az":true,"biz.az":true,"ba":true,"org.ba":true,"net.ba":true,"edu.ba":true,"gov.ba":true,"mil.ba":true,"unsa.ba":true,"unbi.ba":true,"co.ba":true,"com.ba":true,"rs.ba":true,"bb":true,"biz.bb":true,"com.bb":true,"edu.bb":true,"gov.bb":true,"info.bb":true,"net.bb":true,"org.bb":true,"store.bb":true,"*.bd":true,"be":true,"ac.be":true,"bf":true,"gov.bf":true,"bg":true,"a.bg":true,"b.bg":true,"c.bg":true,"d.bg":true,"e.bg":true,"f.bg":true,"g.bg":true,"h.bg":true,"i.bg":true,"j.bg":true,"k.bg":true,"l.bg":true,"m.bg":true,"n.bg":true,"o.bg":true,"p.bg":true,"q.bg":true,"r.bg":true,"s.bg":true,"t.bg":true,"u.bg":true,"v.bg":true,"w.bg":true,"x.bg":true,"y.bg":true,"z.bg":true,"0.bg":true,"1.bg":true,"2.bg":true,"3.bg":true,"4.bg":true,"5.bg":true,"6.bg":true,"7.bg":true,"8.bg":true,"9.bg":true,"bh":true,"com.bh":true,"edu.bh":true,"net.bh":true,"org.bh":true,"gov.bh":true,"bi":true,"co.bi":true,"com.bi":true,"edu.bi":true,"or.bi":true,"org.bi":true,"biz":true,"bj":true,"asso.bj":true,"barreau.bj":true,"gouv.bj":true,"bm":true,"com.bm":true,"edu.bm":true,"gov.bm":true,"net.bm":true,"org.bm":true,"*.bn":true,"bo":true,"com.bo":true,"edu.bo":true,"gov.bo":true,"gob.bo":true,"int.bo":true,"org.bo":true,"net.bo":true,"mil.bo":true,"tv.bo":true,"br":true,"adm.br":true,"adv.br":true,"agr.br":true,"am.br":true,"arq.br":true,"art.br":true,"ato.br":true,"b.br":true,"bio.br":true,"blog.br":true,"bmd.br":true,"can.br":true,"cim.br":true,"cng.br":true,"cnt.br":true,"com.br":true,"coop.br":true,"ecn.br":true,"edu.br":true,"emp.br":true,"eng.br":true,"esp.br":true,"etc.br":true,"eti.br":true,"far.br":true,"flog.br":true,"fm.br":true,"fnd.br":true,"fot.br":true,"fst.br":true,"g12.br":true,"ggf.br":true,"gov.br":true,"imb.br":true,"ind.br":true,"inf.br":true,"jor.br":true,"jus.br":true,"lel.br":true,"mat.br":true,"med.br":true,"mil.br":true,"mus.br":true,"net.br":true,"nom.br":true,"not.br":true,"ntr.br":true,"odo.br":true,"org.br":true,"ppg.br":true,"pro.br":true,"psc.br":true,"psi.br":true,"qsl.br":true,"radio.br":true,"rec.br":true,"slg.br":true,"srv.br":true,"taxi.br":true,"teo.br":true,"tmp.br":true,"trd.br":true,"tur.br":true,"tv.br":true,"vet.br":true,"vlog.br":true,"wiki.br":true,"zlg.br":true,"bs":true,"com.bs":true,"net.bs":true,"org.bs":true,"edu.bs":true,"gov.bs":true,"bt":true,"com.bt":true,"edu.bt":true,"gov.bt":true,"net.bt":true,"org.bt":true,"bw":true,"co.bw":true,"org.bw":true,"by":true,"gov.by":true,"mil.by":true,"com.by":true,"of.by":true,"bz":true,"com.bz":true,"net.bz":true,"org.bz":true,"edu.bz":true,"gov.bz":true,"ca":true,"ab.ca":true,"bc.ca":true,"mb.ca":true,"nb.ca":true,"nf.ca":true,"nl.ca":true,"ns.ca":true,"nt.ca":true,"nu.ca":true,"on.ca":true,"pe.ca":true,"qc.ca":true,"sk.ca":true,"yk.ca":true,"gc.ca":true,"cat":true,"cc":true,"cd":true,"gov.cd":true,"cf":true,"cg":true,"ch":true,"ci":true,"org.ci":true,"or.ci":true,"com.ci":true,"co.ci":true,"edu.ci":true,"ed.ci":true,"ac.ci":true,"net.ci":true,"go.ci":true,"asso.ci":true,"xn--aroport-bya.ci":true,"int.ci":true,"presse.ci":true,"md.ci":true,"gouv.ci":true,"*.ck":true,"www.ck":false,"cl":true,"gov.cl":true,"gob.cl":true,"co.cl":true,"mil.cl":true,"cm":true,"gov.cm":true,"cn":true,"ac.cn":true,"com.cn":true,"edu.cn":true,"gov.cn":true,"net.cn":true,"org.cn":true,"mil.cn":true,"xn--55qx5d.cn":true,"xn--io0a7i.cn":true,"xn--od0alg.cn":true,"ah.cn":true,"bj.cn":true,"cq.cn":true,"fj.cn":true,"gd.cn":true,"gs.cn":true,"gz.cn":true,"gx.cn":true,"ha.cn":true,"hb.cn":true,"he.cn":true,"hi.cn":true,"hl.cn":true,"hn.cn":true,"jl.cn":true,"js.cn":true,"jx.cn":true,"ln.cn":true,"nm.cn":true,"nx.cn":true,"qh.cn":true,"sc.cn":true,"sd.cn":true,"sh.cn":true,"sn.cn":true,"sx.cn":true,"tj.cn":true,"xj.cn":true,"xz.cn":true,"yn.cn":true,"zj.cn":true,"hk.cn":true,"mo.cn":true,"tw.cn":true,"co":true,"arts.co":true,"com.co":true,"edu.co":true,"firm.co":true,"gov.co":true,"info.co":true,"int.co":true,"mil.co":true,"net.co":true,"nom.co":true,"org.co":true,"rec.co":true,"web.co":true,"com":true,"coop":true,"cr":true,"ac.cr":true,"co.cr":true,"ed.cr":true,"fi.cr":true,"go.cr":true,"or.cr":true,"sa.cr":true,"cu":true,"com.cu":true,"edu.cu":true,"org.cu":true,"net.cu":true,"gov.cu":true,"inf.cu":true,"cv":true,"cx":true,"gov.cx":true,"*.cy":true,"cz":true,"de":true,"dj":true,"dk":true,"dm":true,"com.dm":true,"net.dm":true,"org.dm":true,"edu.dm":true,"gov.dm":true,"do":true,"art.do":true,"com.do":true,"edu.do":true,"gob.do":true,"gov.do":true,"mil.do":true,"net.do":true,"org.do":true,"sld.do":true,"web.do":true,"dz":true,"com.dz":true,"org.dz":true,"net.dz":true,"gov.dz":true,"edu.dz":true,"asso.dz":true,"pol.dz":true,"art.dz":true,"ec":true,"com.ec":true,"info.ec":true,"net.ec":true,"fin.ec":true,"k12.ec":true,"med.ec":true,"pro.ec":true,"org.ec":true,"edu.ec":true,"gov.ec":true,"gob.ec":true,"mil.ec":true,"edu":true,"ee":true,"edu.ee":true,"gov.ee":true,"riik.ee":true,"lib.ee":true,"med.ee":true,"com.ee":true,"pri.ee":true,"aip.ee":true,"org.ee":true,"fie.ee":true,"eg":true,"com.eg":true,"edu.eg":true,"eun.eg":true,"gov.eg":true,"mil.eg":true,"name.eg":true,"net.eg":true,"org.eg":true,"sci.eg":true,"*.er":true,"es":true,"com.es":true,"nom.es":true,"org.es":true,"gob.es":true,"edu.es":true,"*.et":true,"eu":true,"fi":true,"aland.fi":true,"*.fj":true,"*.fk":true,"fm":true,"fo":true,"fr":true,"com.fr":true,"asso.fr":true,"nom.fr":true,"prd.fr":true,"presse.fr":true,"tm.fr":true,"aeroport.fr":true,"assedic.fr":true,"avocat.fr":true,"avoues.fr":true,"cci.fr":true,"chambagri.fr":true,"chirurgiens-dentistes.fr":true,"experts-comptables.fr":true,"geometre-expert.fr":true,"gouv.fr":true,"greta.fr":true,"huissier-justice.fr":true,"medecin.fr":true,"notaires.fr":true,"pharmacien.fr":true,"port.fr":true,"veterinaire.fr":true,"ga":true,"gd":true,"ge":true,"com.ge":true,"edu.ge":true,"gov.ge":true,"org.ge":true,"mil.ge":true,"net.ge":true,"pvt.ge":true,"gf":true,"gg":true,"co.gg":true,"org.gg":true,"net.gg":true,"sch.gg":true,"gov.gg":true,"gh":true,"com.gh":true,"edu.gh":true,"gov.gh":true,"org.gh":true,"mil.gh":true,"gi":true,"com.gi":true,"ltd.gi":true,"gov.gi":true,"mod.gi":true,"edu.gi":true,"org.gi":true,"gl":true,"gm":true,"ac.gn":true,"com.gn":true,"edu.gn":true,"gov.gn":true,"org.gn":true,"net.gn":true,"gov":true,"gp":true,"com.gp":true,"net.gp":true,"mobi.gp":true,"edu.gp":true,"org.gp":true,"asso.gp":true,"gq":true,"gr":true,"com.gr":true,"edu.gr":true,"net.gr":true,"org.gr":true,"gov.gr":true,"gs":true,"*.gt":true,"www.gt":false,"*.gu":true,"gw":true,"gy":true,"co.gy":true,"com.gy":true,"net.gy":true,"hk":true,"com.hk":true,"edu.hk":true,"gov.hk":true,"idv.hk":true,"net.hk":true,"org.hk":true,"xn--55qx5d.hk":true,"xn--wcvs22d.hk":true,"xn--lcvr32d.hk":true,"xn--mxtq1m.hk":true,"xn--gmqw5a.hk":true,"xn--ciqpn.hk":true,"xn--gmq050i.hk":true,"xn--zf0avx.hk":true,"xn--io0a7i.hk":true,"xn--mk0axi.hk":true,"xn--od0alg.hk":true,"xn--od0aq3b.hk":true,"xn--tn0ag.hk":true,"xn--uc0atv.hk":true,"xn--uc0ay4a.hk":true,"hm":true,"hn":true,"com.hn":true,"edu.hn":true,"org.hn":true,"net.hn":true,"mil.hn":true,"gob.hn":true,"hr":true,"iz.hr":true,"from.hr":true,"name.hr":true,"com.hr":true,"ht":true,"com.ht":true,"shop.ht":true,"firm.ht":true,"info.ht":true,"adult.ht":true,"net.ht":true,"pro.ht":true,"org.ht":true,"med.ht":true,"art.ht":true,"coop.ht":true,"pol.ht":true,"asso.ht":true,"edu.ht":true,"rel.ht":true,"gouv.ht":true,"perso.ht":true,"hu":true,"co.hu":true,"info.hu":true,"org.hu":true,"priv.hu":true,"sport.hu":true,"tm.hu":true,"2000.hu":true,"agrar.hu":true,"bolt.hu":true,"casino.hu":true,"city.hu":true,"erotica.hu":true,"erotika.hu":true,"film.hu":true,"forum.hu":true,"games.hu":true,"hotel.hu":true,"ingatlan.hu":true,"jogasz.hu":true,"konyvelo.hu":true,"lakas.hu":true,"media.hu":true,"news.hu":true,"reklam.hu":true,"sex.hu":true,"shop.hu":true,"suli.hu":true,"szex.hu":true,"tozsde.hu":true,"utazas.hu":true,"video.hu":true,"id":true,"ac.id":true,"co.id":true,"go.id":true,"mil.id":true,"net.id":true,"or.id":true,"sch.id":true,"web.id":true,"ie":true,"gov.ie":true,"*.il":true,"im":true,"co.im":true,"ltd.co.im":true,"plc.co.im":true,"net.im":true,"gov.im":true,"org.im":true,"nic.im":true,"ac.im":true,"in":true,"co.in":true,"firm.in":true,"net.in":true,"org.in":true,"gen.in":true,"ind.in":true,"nic.in":true,"ac.in":true,"edu.in":true,"res.in":true,"gov.in":true,"mil.in":true,"info":true,"int":true,"eu.int":true,"io":true,"com.io":true,"iq":true,"gov.iq":true,"edu.iq":true,"mil.iq":true,"com.iq":true,"org.iq":true,"net.iq":true,"ir":true,"ac.ir":true,"co.ir":true,"gov.ir":true,"id.ir":true,"net.ir":true,"org.ir":true,"sch.ir":true,"xn--mgba3a4f16a.ir":true,"xn--mgba3a4fra.ir":true,"is":true,"net.is":true,"com.is":true,"edu.is":true,"gov.is":true,"org.is":true,"int.is":true,"it":true,"gov.it":true,"edu.it":true,"agrigento.it":true,"ag.it":true,"alessandria.it":true,"al.it":true,"ancona.it":true,"an.it":true,"aosta.it":true,"aoste.it":true,"ao.it":true,"arezzo.it":true,"ar.it":true,"ascoli-piceno.it":true,"ascolipiceno.it":true,"ap.it":true,"asti.it":true,"at.it":true,"avellino.it":true,"av.it":true,"bari.it":true,"ba.it":true,"andria-barletta-trani.it":true,"andriabarlettatrani.it":true,"trani-barletta-andria.it":true,"tranibarlettaandria.it":true,"barletta-trani-andria.it":true,"barlettatraniandria.it":true,"andria-trani-barletta.it":true,"andriatranibarletta.it":true,"trani-andria-barletta.it":true,"traniandriabarletta.it":true,"bt.it":true,"belluno.it":true,"bl.it":true,"benevento.it":true,"bn.it":true,"bergamo.it":true,"bg.it":true,"biella.it":true,"bi.it":true,"bologna.it":true,"bo.it":true,"bolzano.it":true,"bozen.it":true,"balsan.it":true,"alto-adige.it":true,"altoadige.it":true,"suedtirol.it":true,"bz.it":true,"brescia.it":true,"bs.it":true,"brindisi.it":true,"br.it":true,"cagliari.it":true,"ca.it":true,"caltanissetta.it":true,"cl.it":true,"campobasso.it":true,"cb.it":true,"carboniaiglesias.it":true,"carbonia-iglesias.it":true,"iglesias-carbonia.it":true,"iglesiascarbonia.it":true,"ci.it":true,"caserta.it":true,"ce.it":true,"catania.it":true,"ct.it":true,"catanzaro.it":true,"cz.it":true,"chieti.it":true,"ch.it":true,"como.it":true,"co.it":true,"cosenza.it":true,"cs.it":true,"cremona.it":true,"cr.it":true,"crotone.it":true,"kr.it":true,"cuneo.it":true,"cn.it":true,"dell-ogliastra.it":true,"dellogliastra.it":true,"ogliastra.it":true,"og.it":true,"enna.it":true,"en.it":true,"ferrara.it":true,"fe.it":true,"fermo.it":true,"fm.it":true,"firenze.it":true,"florence.it":true,"fi.it":true,"foggia.it":true,"fg.it":true,"forli-cesena.it":true,"forlicesena.it":true,"cesena-forli.it":true,"cesenaforli.it":true,"fc.it":true,"frosinone.it":true,"fr.it":true,"genova.it":true,"genoa.it":true,"ge.it":true,"gorizia.it":true,"go.it":true,"grosseto.it":true,"gr.it":true,"imperia.it":true,"im.it":true,"isernia.it":true,"is.it":true,"laquila.it":true,"aquila.it":true,"aq.it":true,"la-spezia.it":true,"laspezia.it":true,"sp.it":true,"latina.it":true,"lt.it":true,"lecce.it":true,"le.it":true,"lecco.it":true,"lc.it":true,"livorno.it":true,"li.it":true,"lodi.it":true,"lo.it":true,"lucca.it":true,"lu.it":true,"macerata.it":true,"mc.it":true,"mantova.it":true,"mn.it":true,"massa-carrara.it":true,"massacarrara.it":true,"carrara-massa.it":true,"carraramassa.it":true,"ms.it":true,"matera.it":true,"mt.it":true,"medio-campidano.it":true,"mediocampidano.it":true,"campidano-medio.it":true,"campidanomedio.it":true,"vs.it":true,"messina.it":true,"me.it":true,"milano.it":true,"milan.it":true,"mi.it":true,"modena.it":true,"mo.it":true,"monza.it":true,"monza-brianza.it":true,"monzabrianza.it":true,"monzaebrianza.it":true,"monzaedellabrianza.it":true,"monza-e-della-brianza.it":true,"mb.it":true,"napoli.it":true,"naples.it":true,"na.it":true,"novara.it":true,"no.it":true,"nuoro.it":true,"nu.it":true,"oristano.it":true,"or.it":true,"padova.it":true,"padua.it":true,"pd.it":true,"palermo.it":true,"pa.it":true,"parma.it":true,"pr.it":true,"pavia.it":true,"pv.it":true,"perugia.it":true,"pg.it":true,"pescara.it":true,"pe.it":true,"pesaro-urbino.it":true,"pesarourbino.it":true,"urbino-pesaro.it":true,"urbinopesaro.it":true,"pu.it":true,"piacenza.it":true,"pc.it":true,"pisa.it":true,"pi.it":true,"pistoia.it":true,"pt.it":true,"pordenone.it":true,"pn.it":true,"potenza.it":true,"pz.it":true,"prato.it":true,"po.it":true,"ragusa.it":true,"rg.it":true,"ravenna.it":true,"ra.it":true,"reggio-calabria.it":true,"reggiocalabria.it":true,"rc.it":true,"reggio-emilia.it":true,"reggioemilia.it":true,"re.it":true,"rieti.it":true,"ri.it":true,"rimini.it":true,"rn.it":true,"roma.it":true,"rome.it":true,"rm.it":true,"rovigo.it":true,"ro.it":true,"salerno.it":true,"sa.it":true,"sassari.it":true,"ss.it":true,"savona.it":true,"sv.it":true,"siena.it":true,"si.it":true,"siracusa.it":true,"sr.it":true,"sondrio.it":true,"so.it":true,"taranto.it":true,"ta.it":true,"tempio-olbia.it":true,"tempioolbia.it":true,"olbia-tempio.it":true,"olbiatempio.it":true,"ot.it":true,"teramo.it":true,"te.it":true,"terni.it":true,"tr.it":true,"torino.it":true,"turin.it":true,"to.it":true,"trapani.it":true,"tp.it":true,"trento.it":true,"trentino.it":true,"tn.it":true,"treviso.it":true,"tv.it":true,"trieste.it":true,"ts.it":true,"udine.it":true,"ud.it":true,"varese.it":true,"va.it":true,"venezia.it":true,"venice.it":true,"ve.it":true,"verbania.it":true,"vb.it":true,"vercelli.it":true,"vc.it":true,"verona.it":true,"vr.it":true,"vibo-valentia.it":true,"vibovalentia.it":true,"vv.it":true,"vicenza.it":true,"vi.it":true,"viterbo.it":true,"vt.it":true,"je":true,"co.je":true,"org.je":true,"net.je":true,"sch.je":true,"gov.je":true,"*.jm":true,"jo":true,"com.jo":true,"org.jo":true,"net.jo":true,"edu.jo":true,"sch.jo":true,"gov.jo":true,"mil.jo":true,"name.jo":true,"jobs":true,"jp":true,"ac.jp":true,"ad.jp":true,"co.jp":true,"ed.jp":true,"go.jp":true,"gr.jp":true,"lg.jp":true,"ne.jp":true,"or.jp":true,"*.aichi.jp":true,"*.akita.jp":true,"*.aomori.jp":true,"*.chiba.jp":true,"*.ehime.jp":true,"*.fukui.jp":true,"*.fukuoka.jp":true,"*.fukushima.jp":true,"*.gifu.jp":true,"*.gunma.jp":true,"*.hiroshima.jp":true,"*.hokkaido.jp":true,"*.hyogo.jp":true,"*.ibaraki.jp":true,"*.ishikawa.jp":true,"*.iwate.jp":true,"*.kagawa.jp":true,"*.kagoshima.jp":true,"*.kanagawa.jp":true,"*.kawasaki.jp":true,"*.kitakyushu.jp":true,"*.kobe.jp":true,"*.kochi.jp":true,"*.kumamoto.jp":true,"*.kyoto.jp":true,"*.mie.jp":true,"*.miyagi.jp":true,"*.miyazaki.jp":true,"*.nagano.jp":true,"*.nagasaki.jp":true,"*.nagoya.jp":true,"*.nara.jp":true,"*.niigata.jp":true,"*.oita.jp":true,"*.okayama.jp":true,"*.okinawa.jp":true,"*.osaka.jp":true,"*.saga.jp":true,"*.saitama.jp":true,"*.sapporo.jp":true,"*.sendai.jp":true,"*.shiga.jp":true,"*.shimane.jp":true,"*.shizuoka.jp":true,"*.tochigi.jp":true,"*.tokushima.jp":true,"*.tokyo.jp":true,"*.tottori.jp":true,"*.toyama.jp":true,"*.wakayama.jp":true,"*.yamagata.jp":true,"*.yamaguchi.jp":true,"*.yamanashi.jp":true,"*.yokohama.jp":true,"metro.tokyo.jp":false,"pref.aichi.jp":false,"pref.akita.jp":false,"pref.aomori.jp":false,"pref.chiba.jp":false,"pref.ehime.jp":false,"pref.fukui.jp":false,"pref.fukuoka.jp":false,"pref.fukushima.jp":false,"pref.gifu.jp":false,"pref.gunma.jp":false,"pref.hiroshima.jp":false,"pref.hokkaido.jp":false,"pref.hyogo.jp":false,"pref.ibaraki.jp":false,"pref.ishikawa.jp":false,"pref.iwate.jp":false,"pref.kagawa.jp":false,"pref.kagoshima.jp":false,"pref.kanagawa.jp":false,"pref.kochi.jp":false,"pref.kumamoto.jp":false,"pref.kyoto.jp":false,"pref.mie.jp":false,"pref.miyagi.jp":false,"pref.miyazaki.jp":false,"pref.nagano.jp":false,"pref.nagasaki.jp":false,"pref.nara.jp":false,"pref.niigata.jp":false,"pref.oita.jp":false,"pref.okayama.jp":false,"pref.okinawa.jp":false,"pref.osaka.jp":false,"pref.saga.jp":false,"pref.saitama.jp":false,"pref.shiga.jp":false,"pref.shimane.jp":false,"pref.shizuoka.jp":false,"pref.tochigi.jp":false,"pref.tokushima.jp":false,"pref.tottori.jp":false,"pref.toyama.jp":false,"pref.wakayama.jp":false,"pref.yamagata.jp":false,"pref.yamaguchi.jp":false,"pref.yamanashi.jp":false,"city.chiba.jp":false,"city.fukuoka.jp":false,"city.hiroshima.jp":false,"city.kawasaki.jp":false,"city.kitakyushu.jp":false,"city.kobe.jp":false,"city.kyoto.jp":false,"city.nagoya.jp":false,"city.niigata.jp":false,"city.okayama.jp":false,"city.osaka.jp":false,"city.saitama.jp":false,"city.sapporo.jp":false,"city.sendai.jp":false,"city.shizuoka.jp":false,"city.yokohama.jp":false,"*.ke":true,"kg":true,"org.kg":true,"net.kg":true,"com.kg":true,"edu.kg":true,"gov.kg":true,"mil.kg":true,"*.kh":true,"ki":true,"edu.ki":true,"biz.ki":true,"net.ki":true,"org.ki":true,"gov.ki":true,"info.ki":true,"com.ki":true,"km":true,"org.km":true,"nom.km":true,"gov.km":true,"prd.km":true,"tm.km":true,"edu.km":true,"mil.km":true,"ass.km":true,"com.km":true,"coop.km":true,"asso.km":true,"presse.km":true,"medecin.km":true,"notaires.km":true,"pharmaciens.km":true,"veterinaire.km":true,"gouv.km":true,"kn":true,"net.kn":true,"org.kn":true,"edu.kn":true,"gov.kn":true,"com.kp":true,"edu.kp":true,"gov.kp":true,"org.kp":true,"rep.kp":true,"tra.kp":true,"kr":true,"ac.kr":true,"co.kr":true,"es.kr":true,"go.kr":true,"hs.kr":true,"kg.kr":true,"mil.kr":true,"ms.kr":true,"ne.kr":true,"or.kr":true,"pe.kr":true,"re.kr":true,"sc.kr":true,"busan.kr":true,"chungbuk.kr":true,"chungnam.kr":true,"daegu.kr":true,"daejeon.kr":true,"gangwon.kr":true,"gwangju.kr":true,"gyeongbuk.kr":true,"gyeonggi.kr":true,"gyeongnam.kr":true,"incheon.kr":true,"jeju.kr":true,"jeonbuk.kr":true,"jeonnam.kr":true,"seoul.kr":true,"ulsan.kr":true,"*.kw":true,"ky":true,"edu.ky":true,"gov.ky":true,"com.ky":true,"org.ky":true,"net.ky":true,"kz":true,"org.kz":true,"edu.kz":true,"net.kz":true,"gov.kz":true,"mil.kz":true,"com.kz":true,"la":true,"int.la":true,"net.la":true,"info.la":true,"edu.la":true,"gov.la":true,"per.la":true,"com.la":true,"org.la":true,"com.lb":true,"edu.lb":true,"gov.lb":true,"net.lb":true,"org.lb":true,"lc":true,"com.lc":true,"net.lc":true,"co.lc":true,"org.lc":true,"edu.lc":true,"gov.lc":true,"li":true,"lk":true,"gov.lk":true,"sch.lk":true,"net.lk":true,"int.lk":true,"com.lk":true,"org.lk":true,"edu.lk":true,"ngo.lk":true,"soc.lk":true,"web.lk":true,"ltd.lk":true,"assn.lk":true,"grp.lk":true,"hotel.lk":true,"com.lr":true,"edu.lr":true,"gov.lr":true,"org.lr":true,"net.lr":true,"ls":true,"co.ls":true,"org.ls":true,"lt":true,"gov.lt":true,"lu":true,"lv":true,"com.lv":true,"edu.lv":true,"gov.lv":true,"org.lv":true,"mil.lv":true,"id.lv":true,"net.lv":true,"asn.lv":true,"conf.lv":true,"ly":true,"com.ly":true,"net.ly":true,"gov.ly":true,"plc.ly":true,"edu.ly":true,"sch.ly":true,"med.ly":true,"org.ly":true,"id.ly":true,"ma":true,"co.ma":true,"net.ma":true,"gov.ma":true,"org.ma":true,"ac.ma":true,"press.ma":true,"mc":true,"tm.mc":true,"asso.mc":true,"md":true,"me":true,"co.me":true,"net.me":true,"org.me":true,"edu.me":true,"ac.me":true,"gov.me":true,"its.me":true,"priv.me":true,"mg":true,"org.mg":true,"nom.mg":true,"gov.mg":true,"prd.mg":true,"tm.mg":true,"edu.mg":true,"mil.mg":true,"com.mg":true,"mh":true,"mil":true,"mk":true,"com.mk":true,"org.mk":true,"net.mk":true,"edu.mk":true,"gov.mk":true,"inf.mk":true,"name.mk":true,"ml":true,"com.ml":true,"edu.ml":true,"gouv.ml":true,"gov.ml":true,"net.ml":true,"org.ml":true,"presse.ml":true,"*.mm":true,"mn":true,"gov.mn":true,"edu.mn":true,"org.mn":true,"mo":true,"com.mo":true,"net.mo":true,"org.mo":true,"edu.mo":true,"gov.mo":true,"mobi":true,"mp":true,"mq":true,"mr":true,"gov.mr":true,"ms":true,"*.mt":true,"mu":true,"com.mu":true,"net.mu":true,"org.mu":true,"gov.mu":true,"ac.mu":true,"co.mu":true,"or.mu":true,"museum":true,"academy.museum":true,"agriculture.museum":true,"air.museum":true,"airguard.museum":true,"alabama.museum":true,"alaska.museum":true,"amber.museum":true,"ambulance.museum":true,"american.museum":true,"americana.museum":true,"americanantiques.museum":true,"americanart.museum":true,"amsterdam.museum":true,"and.museum":true,"annefrank.museum":true,"anthro.museum":true,"anthropology.museum":true,"antiques.museum":true,"aquarium.museum":true,"arboretum.museum":true,"archaeological.museum":true,"archaeology.museum":true,"architecture.museum":true,"art.museum":true,"artanddesign.museum":true,"artcenter.museum":true,"artdeco.museum":true,"arteducation.museum":true,"artgallery.museum":true,"arts.museum":true,"artsandcrafts.museum":true,"asmatart.museum":true,"assassination.museum":true,"assisi.museum":true,"association.museum":true,"astronomy.museum":true,"atlanta.museum":true,"austin.museum":true,"australia.museum":true,"automotive.museum":true,"aviation.museum":true,"axis.museum":true,"badajoz.museum":true,"baghdad.museum":true,"bahn.museum":true,"bale.museum":true,"baltimore.museum":true,"barcelona.museum":true,"baseball.museum":true,"basel.museum":true,"baths.museum":true,"bauern.museum":true,"beauxarts.museum":true,"beeldengeluid.museum":true,"bellevue.museum":true,"bergbau.museum":true,"berkeley.museum":true,"berlin.museum":true,"bern.museum":true,"bible.museum":true,"bilbao.museum":true,"bill.museum":true,"birdart.museum":true,"birthplace.museum":true,"bonn.museum":true,"boston.museum":true,"botanical.museum":true,"botanicalgarden.museum":true,"botanicgarden.museum":true,"botany.museum":true,"brandywinevalley.museum":true,"brasil.museum":true,"bristol.museum":true,"british.museum":true,"britishcolumbia.museum":true,"broadcast.museum":true,"brunel.museum":true,"brussel.museum":true,"brussels.museum":true,"bruxelles.museum":true,"building.museum":true,"burghof.museum":true,"bus.museum":true,"bushey.museum":true,"cadaques.museum":true,"california.museum":true,"cambridge.museum":true,"can.museum":true,"canada.museum":true,"capebreton.museum":true,"carrier.museum":true,"cartoonart.museum":true,"casadelamoneda.museum":true,"castle.museum":true,"castres.museum":true,"celtic.museum":true,"center.museum":true,"chattanooga.museum":true,"cheltenham.museum":true,"chesapeakebay.museum":true,"chicago.museum":true,"children.museum":true,"childrens.museum":true,"childrensgarden.museum":true,"chiropractic.museum":true,"chocolate.museum":true,"christiansburg.museum":true,"cincinnati.museum":true,"cinema.museum":true,"circus.museum":true,"civilisation.museum":true,"civilization.museum":true,"civilwar.museum":true,"clinton.museum":true,"clock.museum":true,"coal.museum":true,"coastaldefence.museum":true,"cody.museum":true,"coldwar.museum":true,"collection.museum":true,"colonialwilliamsburg.museum":true,"coloradoplateau.museum":true,"columbia.museum":true,"columbus.museum":true,"communication.museum":true,"communications.museum":true,"community.museum":true,"computer.museum":true,"computerhistory.museum":true,"xn--comunicaes-v6a2o.museum":true,"contemporary.museum":true,"contemporaryart.museum":true,"convent.museum":true,"copenhagen.museum":true,"corporation.museum":true,"xn--correios-e-telecomunicaes-ghc29a.museum":true,"corvette.museum":true,"costume.museum":true,"countryestate.museum":true,"county.museum":true,"crafts.museum":true,"cranbrook.museum":true,"creation.museum":true,"cultural.museum":true,"culturalcenter.museum":true,"culture.museum":true,"cyber.museum":true,"cymru.museum":true,"dali.museum":true,"dallas.museum":true,"database.museum":true,"ddr.museum":true,"decorativearts.museum":true,"delaware.museum":true,"delmenhorst.museum":true,"denmark.museum":true,"depot.museum":true,"design.museum":true,"detroit.museum":true,"dinosaur.museum":true,"discovery.museum":true,"dolls.museum":true,"donostia.museum":true,"durham.museum":true,"eastafrica.museum":true,"eastcoast.museum":true,"education.museum":true,"educational.museum":true,"egyptian.museum":true,"eisenbahn.museum":true,"elburg.museum":true,"elvendrell.museum":true,"embroidery.museum":true,"encyclopedic.museum":true,"england.museum":true,"entomology.museum":true,"environment.museum":true,"environmentalconservation.museum":true,"epilepsy.museum":true,"essex.museum":true,"estate.museum":true,"ethnology.museum":true,"exeter.museum":true,"exhibition.museum":true,"family.museum":true,"farm.museum":true,"farmequipment.museum":true,"farmers.museum":true,"farmstead.museum":true,"field.museum":true,"figueres.museum":true,"filatelia.museum":true,"film.museum":true,"fineart.museum":true,"finearts.museum":true,"finland.museum":true,"flanders.museum":true,"florida.museum":true,"force.museum":true,"fortmissoula.museum":true,"fortworth.museum":true,"foundation.museum":true,"francaise.museum":true,"frankfurt.museum":true,"franziskaner.museum":true,"freemasonry.museum":true,"freiburg.museum":true,"fribourg.museum":true,"frog.museum":true,"fundacio.museum":true,"furniture.museum":true,"gallery.museum":true,"garden.museum":true,"gateway.museum":true,"geelvinck.museum":true,"gemological.museum":true,"geology.museum":true,"georgia.museum":true,"giessen.museum":true,"glas.museum":true,"glass.museum":true,"gorge.museum":true,"grandrapids.museum":true,"graz.museum":true,"guernsey.museum":true,"halloffame.museum":true,"hamburg.museum":true,"handson.museum":true,"harvestcelebration.museum":true,"hawaii.museum":true,"health.museum":true,"heimatunduhren.museum":true,"hellas.museum":true,"helsinki.museum":true,"hembygdsforbund.museum":true,"heritage.museum":true,"histoire.museum":true,"historical.museum":true,"historicalsociety.museum":true,"historichouses.museum":true,"historisch.museum":true,"historisches.museum":true,"history.museum":true,"historyofscience.museum":true,"horology.museum":true,"house.museum":true,"humanities.museum":true,"illustration.museum":true,"imageandsound.museum":true,"indian.museum":true,"indiana.museum":true,"indianapolis.museum":true,"indianmarket.museum":true,"intelligence.museum":true,"interactive.museum":true,"iraq.museum":true,"iron.museum":true,"isleofman.museum":true,"jamison.museum":true,"jefferson.museum":true,"jerusalem.museum":true,"jewelry.museum":true,"jewish.museum":true,"jewishart.museum":true,"jfk.museum":true,"journalism.museum":true,"judaica.museum":true,"judygarland.museum":true,"juedisches.museum":true,"juif.museum":true,"karate.museum":true,"karikatur.museum":true,"kids.museum":true,"koebenhavn.museum":true,"koeln.museum":true,"kunst.museum":true,"kunstsammlung.museum":true,"kunstunddesign.museum":true,"labor.museum":true,"labour.museum":true,"lajolla.museum":true,"lancashire.museum":true,"landes.museum":true,"lans.museum":true,"xn--lns-qla.museum":true,"larsson.museum":true,"lewismiller.museum":true,"lincoln.museum":true,"linz.museum":true,"living.museum":true,"livinghistory.museum":true,"localhistory.museum":true,"london.museum":true,"losangeles.museum":true,"louvre.museum":true,"loyalist.museum":true,"lucerne.museum":true,"luxembourg.museum":true,"luzern.museum":true,"mad.museum":true,"madrid.museum":true,"mallorca.museum":true,"manchester.museum":true,"mansion.museum":true,"mansions.museum":true,"manx.museum":true,"marburg.museum":true,"maritime.museum":true,"maritimo.museum":true,"maryland.museum":true,"marylhurst.museum":true,"media.museum":true,"medical.museum":true,"medizinhistorisches.museum":true,"meeres.museum":true,"memorial.museum":true,"mesaverde.museum":true,"michigan.museum":true,"midatlantic.museum":true,"military.museum":true,"mill.museum":true,"miners.museum":true,"mining.museum":true,"minnesota.museum":true,"missile.museum":true,"missoula.museum":true,"modern.museum":true,"moma.museum":true,"money.museum":true,"monmouth.museum":true,"monticello.museum":true,"montreal.museum":true,"moscow.museum":true,"motorcycle.museum":true,"muenchen.museum":true,"muenster.museum":true,"mulhouse.museum":true,"muncie.museum":true,"museet.museum":true,"museumcenter.museum":true,"museumvereniging.museum":true,"music.museum":true,"national.museum":true,"nationalfirearms.museum":true,"nationalheritage.museum":true,"nativeamerican.museum":true,"naturalhistory.museum":true,"naturalhistorymuseum.museum":true,"naturalsciences.museum":true,"nature.museum":true,"naturhistorisches.museum":true,"natuurwetenschappen.museum":true,"naumburg.museum":true,"naval.museum":true,"nebraska.museum":true,"neues.museum":true,"newhampshire.museum":true,"newjersey.museum":true,"newmexico.museum":true,"newport.museum":true,"newspaper.museum":true,"newyork.museum":true,"niepce.museum":true,"norfolk.museum":true,"north.museum":true,"nrw.museum":true,"nuernberg.museum":true,"nuremberg.museum":true,"nyc.museum":true,"nyny.museum":true,"oceanographic.museum":true,"oceanographique.museum":true,"omaha.museum":true,"online.museum":true,"ontario.museum":true,"openair.museum":true,"oregon.museum":true,"oregontrail.museum":true,"otago.museum":true,"oxford.museum":true,"pacific.museum":true,"paderborn.museum":true,"palace.museum":true,"paleo.museum":true,"palmsprings.museum":true,"panama.museum":true,"paris.museum":true,"pasadena.museum":true,"pharmacy.museum":true,"philadelphia.museum":true,"philadelphiaarea.museum":true,"philately.museum":true,"phoenix.museum":true,"photography.museum":true,"pilots.museum":true,"pittsburgh.museum":true,"planetarium.museum":true,"plantation.museum":true,"plants.museum":true,"plaza.museum":true,"portal.museum":true,"portland.museum":true,"portlligat.museum":true,"posts-and-telecommunications.museum":true,"preservation.museum":true,"presidio.museum":true,"press.museum":true,"project.museum":true,"public.museum":true,"pubol.museum":true,"quebec.museum":true,"railroad.museum":true,"railway.museum":true,"research.museum":true,"resistance.museum":true,"riodejaneiro.museum":true,"rochester.museum":true,"rockart.museum":true,"roma.museum":true,"russia.museum":true,"saintlouis.museum":true,"salem.museum":true,"salvadordali.museum":true,"salzburg.museum":true,"sandiego.museum":true,"sanfrancisco.museum":true,"santabarbara.museum":true,"santacruz.museum":true,"santafe.museum":true,"saskatchewan.museum":true,"satx.museum":true,"savannahga.museum":true,"schlesisches.museum":true,"schoenbrunn.museum":true,"schokoladen.museum":true,"school.museum":true,"schweiz.museum":true,"science.museum":true,"scienceandhistory.museum":true,"scienceandindustry.museum":true,"sciencecenter.museum":true,"sciencecenters.museum":true,"science-fiction.museum":true,"sciencehistory.museum":true,"sciences.museum":true,"sciencesnaturelles.museum":true,"scotland.museum":true,"seaport.museum":true,"settlement.museum":true,"settlers.museum":true,"shell.museum":true,"sherbrooke.museum":true,"sibenik.museum":true,"silk.museum":true,"ski.museum":true,"skole.museum":true,"society.museum":true,"sologne.museum":true,"soundandvision.museum":true,"southcarolina.museum":true,"southwest.museum":true,"space.museum":true,"spy.museum":true,"square.museum":true,"stadt.museum":true,"stalbans.museum":true,"starnberg.museum":true,"state.museum":true,"stateofdelaware.museum":true,"station.museum":true,"steam.museum":true,"steiermark.museum":true,"stjohn.museum":true,"stockholm.museum":true,"stpetersburg.museum":true,"stuttgart.museum":true,"suisse.museum":true,"surgeonshall.museum":true,"surrey.museum":true,"svizzera.museum":true,"sweden.museum":true,"sydney.museum":true,"tank.museum":true,"tcm.museum":true,"technology.museum":true,"telekommunikation.museum":true,"television.museum":true,"texas.museum":true,"textile.museum":true,"theater.museum":true,"time.museum":true,"timekeeping.museum":true,"topology.museum":true,"torino.museum":true,"touch.museum":true,"town.museum":true,"transport.museum":true,"tree.museum":true,"trolley.museum":true,"trust.museum":true,"trustee.museum":true,"uhren.museum":true,"ulm.museum":true,"undersea.museum":true,"university.museum":true,"usa.museum":true,"usantiques.museum":true,"usarts.museum":true,"uscountryestate.museum":true,"usculture.museum":true,"usdecorativearts.museum":true,"usgarden.museum":true,"ushistory.museum":true,"ushuaia.museum":true,"uslivinghistory.museum":true,"utah.museum":true,"uvic.museum":true,"valley.museum":true,"vantaa.museum":true,"versailles.museum":true,"viking.museum":true,"village.museum":true,"virginia.museum":true,"virtual.museum":true,"virtuel.museum":true,"vlaanderen.museum":true,"volkenkunde.museum":true,"wales.museum":true,"wallonie.museum":true,"war.museum":true,"washingtondc.museum":true,"watchandclock.museum":true,"watch-and-clock.museum":true,"western.museum":true,"westfalen.museum":true,"whaling.museum":true,"wildlife.museum":true,"williamsburg.museum":true,"windmill.museum":true,"workshop.museum":true,"york.museum":true,"yorkshire.museum":true,"yosemite.museum":true,"youth.museum":true,"zoological.museum":true,"zoology.museum":true,"xn--9dbhblg6di.museum":true,"xn--h1aegh.museum":true,"mv":true,"aero.mv":true,"biz.mv":true,"com.mv":true,"coop.mv":true,"edu.mv":true,"gov.mv":true,"info.mv":true,"int.mv":true,"mil.mv":true,"museum.mv":true,"name.mv":true,"net.mv":true,"org.mv":true,"pro.mv":true,"mw":true,"ac.mw":true,"biz.mw":true,"co.mw":true,"com.mw":true,"coop.mw":true,"edu.mw":true,"gov.mw":true,"int.mw":true,"museum.mw":true,"net.mw":true,"org.mw":true,"mx":true,"com.mx":true,"org.mx":true,"gob.mx":true,"edu.mx":true,"net.mx":true,"my":true,"com.my":true,"net.my":true,"org.my":true,"gov.my":true,"edu.my":true,"mil.my":true,"name.my":true,"*.mz":true,"na":true,"info.na":true,"pro.na":true,"name.na":true,"school.na":true,"or.na":true,"dr.na":true,"us.na":true,"mx.na":true,"ca.na":true,"in.na":true,"cc.na":true,"tv.na":true,"ws.na":true,"mobi.na":true,"co.na":true,"com.na":true,"org.na":true,"name":true,"nc":true,"asso.nc":true,"ne":true,"net":true,"nf":true,"com.nf":true,"net.nf":true,"per.nf":true,"rec.nf":true,"web.nf":true,"arts.nf":true,"firm.nf":true,"info.nf":true,"other.nf":true,"store.nf":true,"ac.ng":true,"com.ng":true,"edu.ng":true,"gov.ng":true,"net.ng":true,"org.ng":true,"*.ni":true,"nl":true,"bv.nl":true,"no":true,"fhs.no":true,"vgs.no":true,"fylkesbibl.no":true,"folkebibl.no":true,"museum.no":true,"idrett.no":true,"priv.no":true,"mil.no":true,"stat.no":true,"dep.no":true,"kommune.no":true,"herad.no":true,"aa.no":true,"ah.no":true,"bu.no":true,"fm.no":true,"hl.no":true,"hm.no":true,"jan-mayen.no":true,"mr.no":true,"nl.no":true,"nt.no":true,"of.no":true,"ol.no":true,"oslo.no":true,"rl.no":true,"sf.no":true,"st.no":true,"svalbard.no":true,"tm.no":true,"tr.no":true,"va.no":true,"vf.no":true,"gs.aa.no":true,"gs.ah.no":true,"gs.bu.no":true,"gs.fm.no":true,"gs.hl.no":true,"gs.hm.no":true,"gs.jan-mayen.no":true,"gs.mr.no":true,"gs.nl.no":true,"gs.nt.no":true,"gs.of.no":true,"gs.ol.no":true,"gs.oslo.no":true,"gs.rl.no":true,"gs.sf.no":true,"gs.st.no":true,"gs.svalbard.no":true,"gs.tm.no":true,"gs.tr.no":true,"gs.va.no":true,"gs.vf.no":true,"akrehamn.no":true,"xn--krehamn-dxa.no":true,"algard.no":true,"xn--lgrd-poac.no":true,"arna.no":true,"brumunddal.no":true,"bryne.no":true,"bronnoysund.no":true,"xn--brnnysund-m8ac.no":true,"drobak.no":true,"xn--drbak-wua.no":true,"egersund.no":true,"fetsund.no":true,"floro.no":true,"xn--flor-jra.no":true,"fredrikstad.no":true,"hokksund.no":true,"honefoss.no":true,"xn--hnefoss-q1a.no":true,"jessheim.no":true,"jorpeland.no":true,"xn--jrpeland-54a.no":true,"kirkenes.no":true,"kopervik.no":true,"krokstadelva.no":true,"langevag.no":true,"xn--langevg-jxa.no":true,"leirvik.no":true,"mjondalen.no":true,"xn--mjndalen-64a.no":true,"mo-i-rana.no":true,"mosjoen.no":true,"xn--mosjen-eya.no":true,"nesoddtangen.no":true,"orkanger.no":true,"osoyro.no":true,"xn--osyro-wua.no":true,"raholt.no":true,"xn--rholt-mra.no":true,"sandnessjoen.no":true,"xn--sandnessjen-ogb.no":true,"skedsmokorset.no":true,"slattum.no":true,"spjelkavik.no":true,"stathelle.no":true,"stavern.no":true,"stjordalshalsen.no":true,"xn--stjrdalshalsen-sqb.no":true,"tananger.no":true,"tranby.no":true,"vossevangen.no":true,"afjord.no":true,"xn--fjord-lra.no":true,"agdenes.no":true,"al.no":true,"xn--l-1fa.no":true,"alesund.no":true,"xn--lesund-hua.no":true,"alstahaug.no":true,"alta.no":true,"xn--lt-liac.no":true,"alaheadju.no":true,"xn--laheadju-7ya.no":true,"alvdal.no":true,"amli.no":true,"xn--mli-tla.no":true,"amot.no":true,"xn--mot-tla.no":true,"andebu.no":true,"andoy.no":true,"xn--andy-ira.no":true,"andasuolo.no":true,"ardal.no":true,"xn--rdal-poa.no":true,"aremark.no":true,"arendal.no":true,"xn--s-1fa.no":true,"aseral.no":true,"xn--seral-lra.no":true,"asker.no":true,"askim.no":true,"askvoll.no":true,"askoy.no":true,"xn--asky-ira.no":true,"asnes.no":true,"xn--snes-poa.no":true,"audnedaln.no":true,"aukra.no":true,"aure.no":true,"aurland.no":true,"aurskog-holand.no":true,"xn--aurskog-hland-jnb.no":true,"austevoll.no":true,"austrheim.no":true,"averoy.no":true,"xn--avery-yua.no":true,"balestrand.no":true,"ballangen.no":true,"balat.no":true,"xn--blt-elab.no":true,"balsfjord.no":true,"bahccavuotna.no":true,"xn--bhccavuotna-k7a.no":true,"bamble.no":true,"bardu.no":true,"beardu.no":true,"beiarn.no":true,"bajddar.no":true,"xn--bjddar-pta.no":true,"baidar.no":true,"xn--bidr-5nac.no":true,"berg.no":true,"bergen.no":true,"berlevag.no":true,"xn--berlevg-jxa.no":true,"bearalvahki.no":true,"xn--bearalvhki-y4a.no":true,"bindal.no":true,"birkenes.no":true,"bjarkoy.no":true,"xn--bjarky-fya.no":true,"bjerkreim.no":true,"bjugn.no":true,"bodo.no":true,"xn--bod-2na.no":true,"badaddja.no":true,"xn--bdddj-mrabd.no":true,"budejju.no":true,"bokn.no":true,"bremanger.no":true,"bronnoy.no":true,"xn--brnny-wuac.no":true,"bygland.no":true,"bykle.no":true,"barum.no":true,"xn--brum-voa.no":true,"bo.telemark.no":true,"xn--b-5ga.telemark.no":true,"bo.nordland.no":true,"xn--b-5ga.nordland.no":true,"bievat.no":true,"xn--bievt-0qa.no":true,"bomlo.no":true,"xn--bmlo-gra.no":true,"batsfjord.no":true,"xn--btsfjord-9za.no":true,"bahcavuotna.no":true,"xn--bhcavuotna-s4a.no":true,"dovre.no":true,"drammen.no":true,"drangedal.no":true,"dyroy.no":true,"xn--dyry-ira.no":true,"donna.no":true,"xn--dnna-gra.no":true,"eid.no":true,"eidfjord.no":true,"eidsberg.no":true,"eidskog.no":true,"eidsvoll.no":true,"eigersund.no":true,"elverum.no":true,"enebakk.no":true,"engerdal.no":true,"etne.no":true,"etnedal.no":true,"evenes.no":true,"evenassi.no":true,"xn--eveni-0qa01ga.no":true,"evje-og-hornnes.no":true,"farsund.no":true,"fauske.no":true,"fuossko.no":true,"fuoisku.no":true,"fedje.no":true,"fet.no":true,"finnoy.no":true,"xn--finny-yua.no":true,"fitjar.no":true,"fjaler.no":true,"fjell.no":true,"flakstad.no":true,"flatanger.no":true,"flekkefjord.no":true,"flesberg.no":true,"flora.no":true,"fla.no":true,"xn--fl-zia.no":true,"folldal.no":true,"forsand.no":true,"fosnes.no":true,"frei.no":true,"frogn.no":true,"froland.no":true,"frosta.no":true,"frana.no":true,"xn--frna-woa.no":true,"froya.no":true,"xn--frya-hra.no":true,"fusa.no":true,"fyresdal.no":true,"forde.no":true,"xn--frde-gra.no":true,"gamvik.no":true,"gangaviika.no":true,"xn--ggaviika-8ya47h.no":true,"gaular.no":true,"gausdal.no":true,"gildeskal.no":true,"xn--gildeskl-g0a.no":true,"giske.no":true,"gjemnes.no":true,"gjerdrum.no":true,"gjerstad.no":true,"gjesdal.no":true,"gjovik.no":true,"xn--gjvik-wua.no":true,"gloppen.no":true,"gol.no":true,"gran.no":true,"grane.no":true,"granvin.no":true,"gratangen.no":true,"grimstad.no":true,"grong.no":true,"kraanghke.no":true,"xn--kranghke-b0a.no":true,"grue.no":true,"gulen.no":true,"hadsel.no":true,"halden.no":true,"halsa.no":true,"hamar.no":true,"hamaroy.no":true,"habmer.no":true,"xn--hbmer-xqa.no":true,"hapmir.no":true,"xn--hpmir-xqa.no":true,"hammerfest.no":true,"hammarfeasta.no":true,"xn--hmmrfeasta-s4ac.no":true,"haram.no":true,"hareid.no":true,"harstad.no":true,"hasvik.no":true,"aknoluokta.no":true,"xn--koluokta-7ya57h.no":true,"hattfjelldal.no":true,"aarborte.no":true,"haugesund.no":true,"hemne.no":true,"hemnes.no":true,"hemsedal.no":true,"heroy.more-og-romsdal.no":true,"xn--hery-ira.xn--mre-og-romsdal-qqb.no":true,"heroy.nordland.no":true,"xn--hery-ira.nordland.no":true,"hitra.no":true,"hjartdal.no":true,"hjelmeland.no":true,"hobol.no":true,"xn--hobl-ira.no":true,"hof.no":true,"hol.no":true,"hole.no":true,"holmestrand.no":true,"holtalen.no":true,"xn--holtlen-hxa.no":true,"hornindal.no":true,"horten.no":true,"hurdal.no":true,"hurum.no":true,"hvaler.no":true,"hyllestad.no":true,"hagebostad.no":true,"xn--hgebostad-g3a.no":true,"hoyanger.no":true,"xn--hyanger-q1a.no":true,"hoylandet.no":true,"xn--hylandet-54a.no":true,"ha.no":true,"xn--h-2fa.no":true,"ibestad.no":true,"inderoy.no":true,"xn--indery-fya.no":true,"iveland.no":true,"jevnaker.no":true,"jondal.no":true,"jolster.no":true,"xn--jlster-bya.no":true,"karasjok.no":true,"karasjohka.no":true,"xn--krjohka-hwab49j.no":true,"karlsoy.no":true,"galsa.no":true,"xn--gls-elac.no":true,"karmoy.no":true,"xn--karmy-yua.no":true,"kautokeino.no":true,"guovdageaidnu.no":true,"klepp.no":true,"klabu.no":true,"xn--klbu-woa.no":true,"kongsberg.no":true,"kongsvinger.no":true,"kragero.no":true,"xn--krager-gya.no":true,"kristiansand.no":true,"kristiansund.no":true,"krodsherad.no":true,"xn--krdsherad-m8a.no":true,"kvalsund.no":true,"rahkkeravju.no":true,"xn--rhkkervju-01af.no":true,"kvam.no":true,"kvinesdal.no":true,"kvinnherad.no":true,"kviteseid.no":true,"kvitsoy.no":true,"xn--kvitsy-fya.no":true,"kvafjord.no":true,"xn--kvfjord-nxa.no":true,"giehtavuoatna.no":true,"kvanangen.no":true,"xn--kvnangen-k0a.no":true,"navuotna.no":true,"xn--nvuotna-hwa.no":true,"kafjord.no":true,"xn--kfjord-iua.no":true,"gaivuotna.no":true,"xn--givuotna-8ya.no":true,"larvik.no":true,"lavangen.no":true,"lavagis.no":true,"loabat.no":true,"xn--loabt-0qa.no":true,"lebesby.no":true,"davvesiida.no":true,"leikanger.no":true,"leirfjord.no":true,"leka.no":true,"leksvik.no":true,"lenvik.no":true,"leangaviika.no":true,"xn--leagaviika-52b.no":true,"lesja.no":true,"levanger.no":true,"lier.no":true,"lierne.no":true,"lillehammer.no":true,"lillesand.no":true,"lindesnes.no":true,"lindas.no":true,"xn--linds-pra.no":true,"lom.no":true,"loppa.no":true,"lahppi.no":true,"xn--lhppi-xqa.no":true,"lund.no":true,"lunner.no":true,"luroy.no":true,"xn--lury-ira.no":true,"luster.no":true,"lyngdal.no":true,"lyngen.no":true,"ivgu.no":true,"lardal.no":true,"lerdal.no":true,"xn--lrdal-sra.no":true,"lodingen.no":true,"xn--ldingen-q1a.no":true,"lorenskog.no":true,"xn--lrenskog-54a.no":true,"loten.no":true,"xn--lten-gra.no":true,"malvik.no":true,"masoy.no":true,"xn--msy-ula0h.no":true,"muosat.no":true,"xn--muost-0qa.no":true,"mandal.no":true,"marker.no":true,"marnardal.no":true,"masfjorden.no":true,"meland.no":true,"meldal.no":true,"melhus.no":true,"meloy.no":true,"xn--mely-ira.no":true,"meraker.no":true,"xn--merker-kua.no":true,"moareke.no":true,"xn--moreke-jua.no":true,"midsund.no":true,"midtre-gauldal.no":true,"modalen.no":true,"modum.no":true,"molde.no":true,"moskenes.no":true,"moss.no":true,"mosvik.no":true,"malselv.no":true,"xn--mlselv-iua.no":true,"malatvuopmi.no":true,"xn--mlatvuopmi-s4a.no":true,"namdalseid.no":true,"aejrie.no":true,"namsos.no":true,"namsskogan.no":true,"naamesjevuemie.no":true,"xn--nmesjevuemie-tcba.no":true,"laakesvuemie.no":true,"nannestad.no":true,"narvik.no":true,"narviika.no":true,"naustdal.no":true,"nedre-eiker.no":true,"nes.akershus.no":true,"nes.buskerud.no":true,"nesna.no":true,"nesodden.no":true,"nesseby.no":true,"unjarga.no":true,"xn--unjrga-rta.no":true,"nesset.no":true,"nissedal.no":true,"nittedal.no":true,"nord-aurdal.no":true,"nord-fron.no":true,"nord-odal.no":true,"norddal.no":true,"nordkapp.no":true,"davvenjarga.no":true,"xn--davvenjrga-y4a.no":true,"nordre-land.no":true,"nordreisa.no":true,"raisa.no":true,"xn--risa-5na.no":true,"nore-og-uvdal.no":true,"notodden.no":true,"naroy.no":true,"xn--nry-yla5g.no":true,"notteroy.no":true,"xn--nttery-byae.no":true,"odda.no":true,"oksnes.no":true,"xn--ksnes-uua.no":true,"oppdal.no":true,"oppegard.no":true,"xn--oppegrd-ixa.no":true,"orkdal.no":true,"orland.no":true,"xn--rland-uua.no":true,"orskog.no":true,"xn--rskog-uua.no":true,"orsta.no":true,"xn--rsta-fra.no":true,"os.hedmark.no":true,"os.hordaland.no":true,"osen.no":true,"osteroy.no":true,"xn--ostery-fya.no":true,"ostre-toten.no":true,"xn--stre-toten-zcb.no":true,"overhalla.no":true,"ovre-eiker.no":true,"xn--vre-eiker-k8a.no":true,"oyer.no":true,"xn--yer-zna.no":true,"oygarden.no":true,"xn--ygarden-p1a.no":true,"oystre-slidre.no":true,"xn--ystre-slidre-ujb.no":true,"porsanger.no":true,"porsangu.no":true,"xn--porsgu-sta26f.no":true,"porsgrunn.no":true,"radoy.no":true,"xn--rady-ira.no":true,"rakkestad.no":true,"rana.no":true,"ruovat.no":true,"randaberg.no":true,"rauma.no":true,"rendalen.no":true,"rennebu.no":true,"rennesoy.no":true,"xn--rennesy-v1a.no":true,"rindal.no":true,"ringebu.no":true,"ringerike.no":true,"ringsaker.no":true,"rissa.no":true,"risor.no":true,"xn--risr-ira.no":true,"roan.no":true,"rollag.no":true,"rygge.no":true,"ralingen.no":true,"xn--rlingen-mxa.no":true,"rodoy.no":true,"xn--rdy-0nab.no":true,"romskog.no":true,"xn--rmskog-bya.no":true,"roros.no":true,"xn--rros-gra.no":true,"rost.no":true,"xn--rst-0na.no":true,"royken.no":true,"xn--ryken-vua.no":true,"royrvik.no":true,"xn--ryrvik-bya.no":true,"rade.no":true,"xn--rde-ula.no":true,"salangen.no":true,"siellak.no":true,"saltdal.no":true,"salat.no":true,"xn--slt-elab.no":true,"xn--slat-5na.no":true,"samnanger.no":true,"sande.more-og-romsdal.no":true,"sande.xn--mre-og-romsdal-qqb.no":true,"sande.vestfold.no":true,"sandefjord.no":true,"sandnes.no":true,"sandoy.no":true,"xn--sandy-yua.no":true,"sarpsborg.no":true,"sauda.no":true,"sauherad.no":true,"sel.no":true,"selbu.no":true,"selje.no":true,"seljord.no":true,"sigdal.no":true,"siljan.no":true,"sirdal.no":true,"skaun.no":true,"skedsmo.no":true,"ski.no":true,"skien.no":true,"skiptvet.no":true,"skjervoy.no":true,"xn--skjervy-v1a.no":true,"skierva.no":true,"xn--skierv-uta.no":true,"skjak.no":true,"xn--skjk-soa.no":true,"skodje.no":true,"skanland.no":true,"xn--sknland-fxa.no":true,"skanit.no":true,"xn--sknit-yqa.no":true,"smola.no":true,"xn--smla-hra.no":true,"snillfjord.no":true,"snasa.no":true,"xn--snsa-roa.no":true,"snoasa.no":true,"snaase.no":true,"xn--snase-nra.no":true,"sogndal.no":true,"sokndal.no":true,"sola.no":true,"solund.no":true,"songdalen.no":true,"sortland.no":true,"spydeberg.no":true,"stange.no":true,"stavanger.no":true,"steigen.no":true,"steinkjer.no":true,"stjordal.no":true,"xn--stjrdal-s1a.no":true,"stokke.no":true,"stor-elvdal.no":true,"stord.no":true,"stordal.no":true,"storfjord.no":true,"omasvuotna.no":true,"strand.no":true,"stranda.no":true,"stryn.no":true,"sula.no":true,"suldal.no":true,"sund.no":true,"sunndal.no":true,"surnadal.no":true,"sveio.no":true,"svelvik.no":true,"sykkylven.no":true,"sogne.no":true,"xn--sgne-gra.no":true,"somna.no":true,"xn--smna-gra.no":true,"sondre-land.no":true,"xn--sndre-land-0cb.no":true,"sor-aurdal.no":true,"xn--sr-aurdal-l8a.no":true,"sor-fron.no":true,"xn--sr-fron-q1a.no":true,"sor-odal.no":true,"xn--sr-odal-q1a.no":true,"sor-varanger.no":true,"xn--sr-varanger-ggb.no":true,"matta-varjjat.no":true,"xn--mtta-vrjjat-k7af.no":true,"sorfold.no":true,"xn--srfold-bya.no":true,"sorreisa.no":true,"xn--srreisa-q1a.no":true,"sorum.no":true,"xn--srum-gra.no":true,"tana.no":true,"deatnu.no":true,"time.no":true,"tingvoll.no":true,"tinn.no":true,"tjeldsund.no":true,"dielddanuorri.no":true,"tjome.no":true,"xn--tjme-hra.no":true,"tokke.no":true,"tolga.no":true,"torsken.no":true,"tranoy.no":true,"xn--trany-yua.no":true,"tromso.no":true,"xn--troms-zua.no":true,"tromsa.no":true,"romsa.no":true,"trondheim.no":true,"troandin.no":true,"trysil.no":true,"trana.no":true,"xn--trna-woa.no":true,"trogstad.no":true,"xn--trgstad-r1a.no":true,"tvedestrand.no":true,"tydal.no":true,"tynset.no":true,"tysfjord.no":true,"divtasvuodna.no":true,"divttasvuotna.no":true,"tysnes.no":true,"tysvar.no":true,"xn--tysvr-vra.no":true,"tonsberg.no":true,"xn--tnsberg-q1a.no":true,"ullensaker.no":true,"ullensvang.no":true,"ulvik.no":true,"utsira.no":true,"vadso.no":true,"xn--vads-jra.no":true,"cahcesuolo.no":true,"xn--hcesuolo-7ya35b.no":true,"vaksdal.no":true,"valle.no":true,"vang.no":true,"vanylven.no":true,"vardo.no":true,"xn--vard-jra.no":true,"varggat.no":true,"xn--vrggt-xqad.no":true,"vefsn.no":true,"vaapste.no":true,"vega.no":true,"vegarshei.no":true,"xn--vegrshei-c0a.no":true,"vennesla.no":true,"verdal.no":true,"verran.no":true,"vestby.no":true,"vestnes.no":true,"vestre-slidre.no":true,"vestre-toten.no":true,"vestvagoy.no":true,"xn--vestvgy-ixa6o.no":true,"vevelstad.no":true,"vik.no":true,"vikna.no":true,"vindafjord.no":true,"volda.no":true,"voss.no":true,"varoy.no":true,"xn--vry-yla5g.no":true,"vagan.no":true,"xn--vgan-qoa.no":true,"voagat.no":true,"vagsoy.no":true,"xn--vgsy-qoa0j.no":true,"vaga.no":true,"xn--vg-yiab.no":true,"valer.ostfold.no":true,"xn--vler-qoa.xn--stfold-9xa.no":true,"valer.hedmark.no":true,"xn--vler-qoa.hedmark.no":true,"*.np":true,"nr":true,"biz.nr":true,"info.nr":true,"gov.nr":true,"edu.nr":true,"org.nr":true,"net.nr":true,"com.nr":true,"nu":true,"*.nz":true,"*.om":true,"mediaphone.om":false,"nawrastelecom.om":false,"nawras.om":false,"omanmobile.om":false,"omanpost.om":false,"omantel.om":false,"rakpetroleum.om":false,"siemens.om":false,"songfest.om":false,"statecouncil.om":false,"org":true,"pa":true,"ac.pa":true,"gob.pa":true,"com.pa":true,"org.pa":true,"sld.pa":true,"edu.pa":true,"net.pa":true,"ing.pa":true,"abo.pa":true,"med.pa":true,"nom.pa":true,"pe":true,"edu.pe":true,"gob.pe":true,"nom.pe":true,"mil.pe":true,"org.pe":true,"com.pe":true,"net.pe":true,"pf":true,"com.pf":true,"org.pf":true,"edu.pf":true,"*.pg":true,"ph":true,"com.ph":true,"net.ph":true,"org.ph":true,"gov.ph":true,"edu.ph":true,"ngo.ph":true,"mil.ph":true,"i.ph":true,"pk":true,"com.pk":true,"net.pk":true,"edu.pk":true,"org.pk":true,"fam.pk":true,"biz.pk":true,"web.pk":true,"gov.pk":true,"gob.pk":true,"gok.pk":true,"gon.pk":true,"gop.pk":true,"gos.pk":true,"info.pk":true,"pl":true,"aid.pl":true,"agro.pl":true,"atm.pl":true,"auto.pl":true,"biz.pl":true,"com.pl":true,"edu.pl":true,"gmina.pl":true,"gsm.pl":true,"info.pl":true,"mail.pl":true,"miasta.pl":true,"media.pl":true,"mil.pl":true,"net.pl":true,"nieruchomosci.pl":true,"nom.pl":true,"org.pl":true,"pc.pl":true,"powiat.pl":true,"priv.pl":true,"realestate.pl":true,"rel.pl":true,"sex.pl":true,"shop.pl":true,"sklep.pl":true,"sos.pl":true,"szkola.pl":true,"targi.pl":true,"tm.pl":true,"tourism.pl":true,"travel.pl":true,"turystyka.pl":true,"6bone.pl":true,"art.pl":true,"mbone.pl":true,"gov.pl":true,"uw.gov.pl":true,"um.gov.pl":true,"ug.gov.pl":true,"upow.gov.pl":true,"starostwo.gov.pl":true,"so.gov.pl":true,"sr.gov.pl":true,"po.gov.pl":true,"pa.gov.pl":true,"ngo.pl":true,"irc.pl":true,"usenet.pl":true,"augustow.pl":true,"babia-gora.pl":true,"bedzin.pl":true,"beskidy.pl":true,"bialowieza.pl":true,"bialystok.pl":true,"bielawa.pl":true,"bieszczady.pl":true,"boleslawiec.pl":true,"bydgoszcz.pl":true,"bytom.pl":true,"cieszyn.pl":true,"czeladz.pl":true,"czest.pl":true,"dlugoleka.pl":true,"elblag.pl":true,"elk.pl":true,"glogow.pl":true,"gniezno.pl":true,"gorlice.pl":true,"grajewo.pl":true,"ilawa.pl":true,"jaworzno.pl":true,"jelenia-gora.pl":true,"jgora.pl":true,"kalisz.pl":true,"kazimierz-dolny.pl":true,"karpacz.pl":true,"kartuzy.pl":true,"kaszuby.pl":true,"katowice.pl":true,"kepno.pl":true,"ketrzyn.pl":true,"klodzko.pl":true,"kobierzyce.pl":true,"kolobrzeg.pl":true,"konin.pl":true,"konskowola.pl":true,"kutno.pl":true,"lapy.pl":true,"lebork.pl":true,"legnica.pl":true,"lezajsk.pl":true,"limanowa.pl":true,"lomza.pl":true,"lowicz.pl":true,"lubin.pl":true,"lukow.pl":true,"malbork.pl":true,"malopolska.pl":true,"mazowsze.pl":true,"mazury.pl":true,"mielec.pl":true,"mielno.pl":true,"mragowo.pl":true,"naklo.pl":true,"nowaruda.pl":true,"nysa.pl":true,"olawa.pl":true,"olecko.pl":true,"olkusz.pl":true,"olsztyn.pl":true,"opoczno.pl":true,"opole.pl":true,"ostroda.pl":true,"ostroleka.pl":true,"ostrowiec.pl":true,"ostrowwlkp.pl":true,"pila.pl":true,"pisz.pl":true,"podhale.pl":true,"podlasie.pl":true,"polkowice.pl":true,"pomorze.pl":true,"pomorskie.pl":true,"prochowice.pl":true,"pruszkow.pl":true,"przeworsk.pl":true,"pulawy.pl":true,"radom.pl":true,"rawa-maz.pl":true,"rybnik.pl":true,"rzeszow.pl":true,"sanok.pl":true,"sejny.pl":true,"siedlce.pl":true,"slask.pl":true,"slupsk.pl":true,"sosnowiec.pl":true,"stalowa-wola.pl":true,"skoczow.pl":true,"starachowice.pl":true,"stargard.pl":true,"suwalki.pl":true,"swidnica.pl":true,"swiebodzin.pl":true,"swinoujscie.pl":true,"szczecin.pl":true,"szczytno.pl":true,"tarnobrzeg.pl":true,"tgory.pl":true,"turek.pl":true,"tychy.pl":true,"ustka.pl":true,"walbrzych.pl":true,"warmia.pl":true,"warszawa.pl":true,"waw.pl":true,"wegrow.pl":true,"wielun.pl":true,"wlocl.pl":true,"wloclawek.pl":true,"wodzislaw.pl":true,"wolomin.pl":true,"wroclaw.pl":true,"zachpomor.pl":true,"zagan.pl":true,"zarow.pl":true,"zgora.pl":true,"zgorzelec.pl":true,"gda.pl":true,"gdansk.pl":true,"gdynia.pl":true,"med.pl":true,"sopot.pl":true,"gliwice.pl":true,"krakow.pl":true,"poznan.pl":true,"wroc.pl":true,"zakopane.pl":true,"pm":true,"pn":true,"gov.pn":true,"co.pn":true,"org.pn":true,"edu.pn":true,"net.pn":true,"pr":true,"com.pr":true,"net.pr":true,"org.pr":true,"gov.pr":true,"edu.pr":true,"isla.pr":true,"pro.pr":true,"biz.pr":true,"info.pr":true,"name.pr":true,"est.pr":true,"prof.pr":true,"ac.pr":true,"pro":true,"aca.pro":true,"bar.pro":true,"cpa.pro":true,"jur.pro":true,"law.pro":true,"med.pro":true,"eng.pro":true,"ps":true,"edu.ps":true,"gov.ps":true,"sec.ps":true,"plo.ps":true,"com.ps":true,"org.ps":true,"net.ps":true,"pt":true,"net.pt":true,"gov.pt":true,"org.pt":true,"edu.pt":true,"int.pt":true,"publ.pt":true,"com.pt":true,"nome.pt":true,"pw":true,"co.pw":true,"ne.pw":true,"or.pw":true,"ed.pw":true,"go.pw":true,"belau.pw":true,"*.py":true,"qa":true,"com.qa":true,"edu.qa":true,"gov.qa":true,"mil.qa":true,"name.qa":true,"net.qa":true,"org.qa":true,"sch.qa":true,"re":true,"com.re":true,"asso.re":true,"nom.re":true,"ro":true,"com.ro":true,"org.ro":true,"tm.ro":true,"nt.ro":true,"nom.ro":true,"info.ro":true,"rec.ro":true,"arts.ro":true,"firm.ro":true,"store.ro":true,"www.ro":true,"rs":true,"co.rs":true,"org.rs":true,"edu.rs":true,"ac.rs":true,"gov.rs":true,"in.rs":true,"ru":true,"ac.ru":true,"com.ru":true,"edu.ru":true,"int.ru":true,"net.ru":true,"org.ru":true,"pp.ru":true,"adygeya.ru":true,"altai.ru":true,"amur.ru":true,"arkhangelsk.ru":true,"astrakhan.ru":true,"bashkiria.ru":true,"belgorod.ru":true,"bir.ru":true,"bryansk.ru":true,"buryatia.ru":true,"cbg.ru":true,"chel.ru":true,"chelyabinsk.ru":true,"chita.ru":true,"chukotka.ru":true,"chuvashia.ru":true,"dagestan.ru":true,"dudinka.ru":true,"e-burg.ru":true,"grozny.ru":true,"irkutsk.ru":true,"ivanovo.ru":true,"izhevsk.ru":true,"jar.ru":true,"joshkar-ola.ru":true,"kalmykia.ru":true,"kaluga.ru":true,"kamchatka.ru":true,"karelia.ru":true,"kazan.ru":true,"kchr.ru":true,"kemerovo.ru":true,"khabarovsk.ru":true,"khakassia.ru":true,"khv.ru":true,"kirov.ru":true,"koenig.ru":true,"komi.ru":true,"kostroma.ru":true,"krasnoyarsk.ru":true,"kuban.ru":true,"kurgan.ru":true,"kursk.ru":true,"lipetsk.ru":true,"magadan.ru":true,"mari.ru":true,"mari-el.ru":true,"marine.ru":true,"mordovia.ru":true,"mosreg.ru":true,"msk.ru":true,"murmansk.ru":true,"nalchik.ru":true,"nnov.ru":true,"nov.ru":true,"novosibirsk.ru":true,"nsk.ru":true,"omsk.ru":true,"orenburg.ru":true,"oryol.ru":true,"palana.ru":true,"penza.ru":true,"perm.ru":true,"pskov.ru":true,"ptz.ru":true,"rnd.ru":true,"ryazan.ru":true,"sakhalin.ru":true,"samara.ru":true,"saratov.ru":true,"simbirsk.ru":true,"smolensk.ru":true,"spb.ru":true,"stavropol.ru":true,"stv.ru":true,"surgut.ru":true,"tambov.ru":true,"tatarstan.ru":true,"tom.ru":true,"tomsk.ru":true,"tsaritsyn.ru":true,"tsk.ru":true,"tula.ru":true,"tuva.ru":true,"tver.ru":true,"tyumen.ru":true,"udm.ru":true,"udmurtia.ru":true,"ulan-ude.ru":true,"vladikavkaz.ru":true,"vladimir.ru":true,"vladivostok.ru":true,"volgograd.ru":true,"vologda.ru":true,"voronezh.ru":true,"vrn.ru":true,"vyatka.ru":true,"yakutia.ru":true,"yamal.ru":true,"yaroslavl.ru":true,"yekaterinburg.ru":true,"yuzhno-sakhalinsk.ru":true,"amursk.ru":true,"baikal.ru":true,"cmw.ru":true,"fareast.ru":true,"jamal.ru":true,"kms.ru":true,"k-uralsk.ru":true,"kustanai.ru":true,"kuzbass.ru":true,"magnitka.ru":true,"mytis.ru":true,"nakhodka.ru":true,"nkz.ru":true,"norilsk.ru":true,"oskol.ru":true,"pyatigorsk.ru":true,"rubtsovsk.ru":true,"snz.ru":true,"syzran.ru":true,"vdonsk.ru":true,"zgrad.ru":true,"gov.ru":true,"mil.ru":true,"test.ru":true,"rw":true,"gov.rw":true,"net.rw":true,"edu.rw":true,"ac.rw":true,"com.rw":true,"co.rw":true,"int.rw":true,"mil.rw":true,"gouv.rw":true,"sa":true,"com.sa":true,"net.sa":true,"org.sa":true,"gov.sa":true,"med.sa":true,"pub.sa":true,"edu.sa":true,"sch.sa":true,"sb":true,"com.sb":true,"edu.sb":true,"gov.sb":true,"net.sb":true,"org.sb":true,"sc":true,"com.sc":true,"gov.sc":true,"net.sc":true,"org.sc":true,"edu.sc":true,"sd":true,"com.sd":true,"net.sd":true,"org.sd":true,"edu.sd":true,"med.sd":true,"gov.sd":true,"info.sd":true,"se":true,"a.se":true,"ac.se":true,"b.se":true,"bd.se":true,"brand.se":true,"c.se":true,"d.se":true,"e.se":true,"f.se":true,"fh.se":true,"fhsk.se":true,"fhv.se":true,"g.se":true,"h.se":true,"i.se":true,"k.se":true,"komforb.se":true,"kommunalforbund.se":true,"komvux.se":true,"l.se":true,"lanbib.se":true,"m.se":true,"n.se":true,"naturbruksgymn.se":true,"o.se":true,"org.se":true,"p.se":true,"parti.se":true,"pp.se":true,"press.se":true,"r.se":true,"s.se":true,"sshn.se":true,"t.se":true,"tm.se":true,"u.se":true,"w.se":true,"x.se":true,"y.se":true,"z.se":true,"sg":true,"com.sg":true,"net.sg":true,"org.sg":true,"gov.sg":true,"edu.sg":true,"per.sg":true,"sh":true,"si":true,"sk":true,"sl":true,"com.sl":true,"net.sl":true,"edu.sl":true,"gov.sl":true,"org.sl":true,"sm":true,"sn":true,"art.sn":true,"com.sn":true,"edu.sn":true,"gouv.sn":true,"org.sn":true,"perso.sn":true,"univ.sn":true,"so":true,"com.so":true,"net.so":true,"org.so":true,"sr":true,"st":true,"co.st":true,"com.st":true,"consulado.st":true,"edu.st":true,"embaixada.st":true,"gov.st":true,"mil.st":true,"net.st":true,"org.st":true,"principe.st":true,"saotome.st":true,"store.st":true,"su":true,"*.sv":true,"sy":true,"edu.sy":true,"gov.sy":true,"net.sy":true,"mil.sy":true,"com.sy":true,"org.sy":true,"sz":true,"co.sz":true,"ac.sz":true,"org.sz":true,"tc":true,"td":true,"tel":true,"tf":true,"tg":true,"th":true,"ac.th":true,"co.th":true,"go.th":true,"in.th":true,"mi.th":true,"net.th":true,"or.th":true,"tj":true,"ac.tj":true,"biz.tj":true,"co.tj":true,"com.tj":true,"edu.tj":true,"go.tj":true,"gov.tj":true,"int.tj":true,"mil.tj":true,"name.tj":true,"net.tj":true,"nic.tj":true,"org.tj":true,"test.tj":true,"web.tj":true,"tk":true,"tl":true,"gov.tl":true,"tm":true,"tn":true,"com.tn":true,"ens.tn":true,"fin.tn":true,"gov.tn":true,"ind.tn":true,"intl.tn":true,"nat.tn":true,"net.tn":true,"org.tn":true,"info.tn":true,"perso.tn":true,"tourism.tn":true,"edunet.tn":true,"rnrt.tn":true,"rns.tn":true,"rnu.tn":true,"mincom.tn":true,"agrinet.tn":true,"defense.tn":true,"turen.tn":true,"to":true,"com.to":true,"gov.to":true,"net.to":true,"org.to":true,"edu.to":true,"mil.to":true,"*.tr":true,"nic.tr":false,"gov.nc.tr":true,"travel":true,"tt":true,"co.tt":true,"com.tt":true,"org.tt":true,"net.tt":true,"biz.tt":true,"info.tt":true,"pro.tt":true,"int.tt":true,"coop.tt":true,"jobs.tt":true,"mobi.tt":true,"travel.tt":true,"museum.tt":true,"aero.tt":true,"name.tt":true,"gov.tt":true,"edu.tt":true,"tv":true,"tw":true,"edu.tw":true,"gov.tw":true,"mil.tw":true,"com.tw":true,"net.tw":true,"org.tw":true,"idv.tw":true,"game.tw":true,"ebiz.tw":true,"club.tw":true,"xn--zf0ao64a.tw":true,"xn--uc0atv.tw":true,"xn--czrw28b.tw":true,"ac.tz":true,"co.tz":true,"go.tz":true,"mil.tz":true,"ne.tz":true,"or.tz":true,"sc.tz":true,"ua":true,"com.ua":true,"edu.ua":true,"gov.ua":true,"in.ua":true,"net.ua":true,"org.ua":true,"cherkassy.ua":true,"chernigov.ua":true,"chernovtsy.ua":true,"ck.ua":true,"cn.ua":true,"crimea.ua":true,"cv.ua":true,"dn.ua":true,"dnepropetrovsk.ua":true,"donetsk.ua":true,"dp.ua":true,"if.ua":true,"ivano-frankivsk.ua":true,"kh.ua":true,"kharkov.ua":true,"kherson.ua":true,"khmelnitskiy.ua":true,"kiev.ua":true,"kirovograd.ua":true,"km.ua":true,"kr.ua":true,"ks.ua":true,"kv.ua":true,"lg.ua":true,"lugansk.ua":true,"lutsk.ua":true,"lviv.ua":true,"mk.ua":true,"nikolaev.ua":true,"od.ua":true,"odessa.ua":true,"pl.ua":true,"poltava.ua":true,"rovno.ua":true,"rv.ua":true,"sebastopol.ua":true,"sumy.ua":true,"te.ua":true,"ternopil.ua":true,"uzhgorod.ua":true,"vinnica.ua":true,"vn.ua":true,"zaporizhzhe.ua":true,"zp.ua":true,"zhitomir.ua":true,"zt.ua":true,"co.ua":true,"pp.ua":true,"ug":true,"co.ug":true,"ac.ug":true,"sc.ug":true,"go.ug":true,"ne.ug":true,"or.ug":true,"*.uk":true,"*.sch.uk":true,"bl.uk":false,"british-library.uk":false,"icnet.uk":false,"jet.uk":false,"mod.uk":false,"nel.uk":false,"nhs.uk":false,"nic.uk":false,"nls.uk":false,"national-library-scotland.uk":false,"parliament.uk":false,"police.uk":false,"us":true,"dni.us":true,"fed.us":true,"isa.us":true,"kids.us":true,"nsn.us":true,"ak.us":true,"al.us":true,"ar.us":true,"as.us":true,"az.us":true,"ca.us":true,"co.us":true,"ct.us":true,"dc.us":true,"de.us":true,"fl.us":true,"ga.us":true,"gu.us":true,"hi.us":true,"ia.us":true,"id.us":true,"il.us":true,"in.us":true,"ks.us":true,"ky.us":true,"la.us":true,"ma.us":true,"md.us":true,"me.us":true,"mi.us":true,"mn.us":true,"mo.us":true,"ms.us":true,"mt.us":true,"nc.us":true,"nd.us":true,"ne.us":true,"nh.us":true,"nj.us":true,"nm.us":true,"nv.us":true,"ny.us":true,"oh.us":true,"ok.us":true,"or.us":true,"pa.us":true,"pr.us":true,"ri.us":true,"sc.us":true,"sd.us":true,"tn.us":true,"tx.us":true,"ut.us":true,"vi.us":true,"vt.us":true,"va.us":true,"wa.us":true,"wi.us":true,"wv.us":true,"wy.us":true,"k12.ak.us":true,"k12.al.us":true,"k12.ar.us":true,"k12.as.us":true,"k12.az.us":true,"k12.ca.us":true,"k12.co.us":true,"k12.ct.us":true,"k12.dc.us":true,"k12.de.us":true,"k12.fl.us":true,"k12.ga.us":true,"k12.gu.us":true,"k12.ia.us":true,"k12.id.us":true,"k12.il.us":true,"k12.in.us":true,"k12.ks.us":true,"k12.ky.us":true,"k12.la.us":true,"k12.ma.us":true,"k12.md.us":true,"k12.me.us":true,"k12.mi.us":true,"k12.mn.us":true,"k12.mo.us":true,"k12.ms.us":true,"k12.mt.us":true,"k12.nc.us":true,"k12.nd.us":true,"k12.ne.us":true,"k12.nh.us":true,"k12.nj.us":true,"k12.nm.us":true,"k12.nv.us":true,"k12.ny.us":true,"k12.oh.us":true,"k12.ok.us":true,"k12.or.us":true,"k12.pa.us":true,"k12.pr.us":true,"k12.ri.us":true,"k12.sc.us":true,"k12.sd.us":true,"k12.tn.us":true,"k12.tx.us":true,"k12.ut.us":true,"k12.vi.us":true,"k12.vt.us":true,"k12.va.us":true,"k12.wa.us":true,"k12.wi.us":true,"k12.wv.us":true,"k12.wy.us":true,"cc.ak.us":true,"cc.al.us":true,"cc.ar.us":true,"cc.as.us":true,"cc.az.us":true,"cc.ca.us":true,"cc.co.us":true,"cc.ct.us":true,"cc.dc.us":true,"cc.de.us":true,"cc.fl.us":true,"cc.ga.us":true,"cc.gu.us":true,"cc.hi.us":true,"cc.ia.us":true,"cc.id.us":true,"cc.il.us":true,"cc.in.us":true,"cc.ks.us":true,"cc.ky.us":true,"cc.la.us":true,"cc.ma.us":true,"cc.md.us":true,"cc.me.us":true,"cc.mi.us":true,"cc.mn.us":true,"cc.mo.us":true,"cc.ms.us":true,"cc.mt.us":true,"cc.nc.us":true,"cc.nd.us":true,"cc.ne.us":true,"cc.nh.us":true,"cc.nj.us":true,"cc.nm.us":true,"cc.nv.us":true,"cc.ny.us":true,"cc.oh.us":true,"cc.ok.us":true,"cc.or.us":true,"cc.pa.us":true,"cc.pr.us":true,"cc.ri.us":true,"cc.sc.us":true,"cc.sd.us":true,"cc.tn.us":true,"cc.tx.us":true,"cc.ut.us":true,"cc.vi.us":true,"cc.vt.us":true,"cc.va.us":true,"cc.wa.us":true,"cc.wi.us":true,"cc.wv.us":true,"cc.wy.us":true,"lib.ak.us":true,"lib.al.us":true,"lib.ar.us":true,"lib.as.us":true,"lib.az.us":true,"lib.ca.us":true,"lib.co.us":true,"lib.ct.us":true,"lib.dc.us":true,"lib.de.us":true,"lib.fl.us":true,"lib.ga.us":true,"lib.gu.us":true,"lib.hi.us":true,"lib.ia.us":true,"lib.id.us":true,"lib.il.us":true,"lib.in.us":true,"lib.ks.us":true,"lib.ky.us":true,"lib.la.us":true,"lib.ma.us":true,"lib.md.us":true,"lib.me.us":true,"lib.mi.us":true,"lib.mn.us":true,"lib.mo.us":true,"lib.ms.us":true,"lib.mt.us":true,"lib.nc.us":true,"lib.nd.us":true,"lib.ne.us":true,"lib.nh.us":true,"lib.nj.us":true,"lib.nm.us":true,"lib.nv.us":true,"lib.ny.us":true,"lib.oh.us":true,"lib.ok.us":true,"lib.or.us":true,"lib.pa.us":true,"lib.pr.us":true,"lib.ri.us":true,"lib.sc.us":true,"lib.sd.us":true,"lib.tn.us":true,"lib.tx.us":true,"lib.ut.us":true,"lib.vi.us":true,"lib.vt.us":true,"lib.va.us":true,"lib.wa.us":true,"lib.wi.us":true,"lib.wv.us":true,"lib.wy.us":true,"pvt.k12.ma.us":true,"chtr.k12.ma.us":true,"paroch.k12.ma.us":true,"*.uy":true,"uz":true,"com.uz":true,"co.uz":true,"va":true,"vc":true,"com.vc":true,"net.vc":true,"org.vc":true,"gov.vc":true,"mil.vc":true,"edu.vc":true,"*.ve":true,"vg":true,"vi":true,"co.vi":true,"com.vi":true,"k12.vi":true,"net.vi":true,"org.vi":true,"vn":true,"com.vn":true,"net.vn":true,"org.vn":true,"edu.vn":true,"gov.vn":true,"int.vn":true,"ac.vn":true,"biz.vn":true,"info.vn":true,"name.vn":true,"pro.vn":true,"health.vn":true,"vu":true,"wf":true,"ws":true,"com.ws":true,"net.ws":true,"org.ws":true,"gov.ws":true,"edu.ws":true,"yt":true,"xn--mgbaam7a8h":true,"xn--54b7fta0cc":true,"xn--fiqs8s":true,"xn--fiqz9s":true,"xn--lgbbat1ad8j":true,"xn--wgbh1c":true,"xn--node":true,"xn--j6w193g":true,"xn--h2brj9c":true,"xn--mgbbh1a71e":true,"xn--fpcrj9c3d":true,"xn--gecrj9c":true,"xn--s9brj9c":true,"xn--45brj9c":true,"xn--xkc2dl3a5ee0h":true,"xn--mgba3a4f16a":true,"xn--mgba3a4fra":true,"xn--mgbayh7gpa":true,"xn--3e0b707e":true,"xn--fzc2c9e2c":true,"xn--xkc2al3hye2a":true,"xn--mgbc0a9azcg":true,"xn--mgb9awbf":true,"xn--ygbi2ammx":true,"xn--90a3ac":true,"xn--p1ai":true,"xn--wgbl6a":true,"xn--mgberp4a5d4ar":true,"xn--mgberp4a5d4a87g":true,"xn--mgbqly7c0a67fbc":true,"xn--mgbqly7cvafr":true,"xn--ogbpf8fl":true,"xn--mgbtf8fl":true,"xn--yfro4i67o":true,"xn--clchc0ea0b2g2a9gcd":true,"xn--o3cw4h":true,"xn--pgbs0dh":true,"xn--kpry57d":true,"xn--kprw13d":true,"xn--nnx388a":true,"xn--j1amh":true,"xn--mgb2ddes":true,"xxx":true,"*.ye":true,"*.za":true,"*.zm":true,"*.zw":true,"biz.at":true,"info.at":true,"priv.at":true,"co.ca":true,"ar.com":true,"br.com":true,"cn.com":true,"de.com":true,"eu.com":true,"gb.com":true,"gr.com":true,"hu.com":true,"jpn.com":true,"kr.com":true,"no.com":true,"qc.com":true,"ru.com":true,"sa.com":true,"se.com":true,"uk.com":true,"us.com":true,"uy.com":true,"za.com":true,"gb.net":true,"jp.net":true,"se.net":true,"uk.net":true,"ae.org":true,"us.org":true,"com.de":true,"operaunite.com":true,"appspot.com":true,"iki.fi":true,"c.la":true,"za.net":true,"za.org":true,"co.nl":true,"co.no":true,"co.pl":true,"dyndns-at-home.com":true,"dyndns-at-work.com":true,"dyndns-blog.com":true,"dyndns-free.com":true,"dyndns-home.com":true,"dyndns-ip.com":true,"dyndns-mail.com":true,"dyndns-office.com":true,"dyndns-pics.com":true,"dyndns-remote.com":true,"dyndns-server.com":true,"dyndns-web.com":true,"dyndns-wiki.com":true,"dyndns-work.com":true,"dyndns.biz":true,"dyndns.info":true,"dyndns.org":true,"dyndns.tv":true,"at-band-camp.net":true,"ath.cx":true,"barrel-of-knowledge.info":true,"barrell-of-knowledge.info":true,"better-than.tv":true,"blogdns.com":true,"blogdns.net":true,"blogdns.org":true,"blogsite.org":true,"boldlygoingnowhere.org":true,"broke-it.net":true,"buyshouses.net":true,"cechire.com":true,"dnsalias.com":true,"dnsalias.net":true,"dnsalias.org":true,"dnsdojo.com":true,"dnsdojo.net":true,"dnsdojo.org":true,"does-it.net":true,"doesntexist.com":true,"doesntexist.org":true,"dontexist.com":true,"dontexist.net":true,"dontexist.org":true,"doomdns.com":true,"doomdns.org":true,"dvrdns.org":true,"dyn-o-saur.com":true,"dynalias.com":true,"dynalias.net":true,"dynalias.org":true,"dynathome.net":true,"dyndns.ws":true,"endofinternet.net":true,"endofinternet.org":true,"endoftheinternet.org":true,"est-a-la-maison.com":true,"est-a-la-masion.com":true,"est-le-patron.com":true,"est-mon-blogueur.com":true,"for-better.biz":true,"for-more.biz":true,"for-our.info":true,"for-some.biz":true,"for-the.biz":true,"forgot.her.name":true,"forgot.his.name":true,"from-ak.com":true,"from-al.com":true,"from-ar.com":true,"from-az.net":true,"from-ca.com":true,"from-co.net":true,"from-ct.com":true,"from-dc.com":true,"from-de.com":true,"from-fl.com":true,"from-ga.com":true,"from-hi.com":true,"from-ia.com":true,"from-id.com":true,"from-il.com":true,"from-in.com":true,"from-ks.com":true,"from-ky.com":true,"from-la.net":true,"from-ma.com":true,"from-md.com":true,"from-me.org":true,"from-mi.com":true,"from-mn.com":true,"from-mo.com":true,"from-ms.com":true,"from-mt.com":true,"from-nc.com":true,"from-nd.com":true,"from-ne.com":true,"from-nh.com":true,"from-nj.com":true,"from-nm.com":true,"from-nv.com":true,"from-ny.net":true,"from-oh.com":true,"from-ok.com":true,"from-or.com":true,"from-pa.com":true,"from-pr.com":true,"from-ri.com":true,"from-sc.com":true,"from-sd.com":true,"from-tn.com":true,"from-tx.com":true,"from-ut.com":true,"from-va.com":true,"from-vt.com":true,"from-wa.com":true,"from-wi.com":true,"from-wv.com":true,"from-wy.com":true,"ftpaccess.cc":true,"fuettertdasnetz.de":true,"game-host.org":true,"game-server.cc":true,"getmyip.com":true,"gets-it.net":true,"go.dyndns.org":true,"gotdns.com":true,"gotdns.org":true,"groks-the.info":true,"groks-this.info":true,"ham-radio-op.net":true,"here-for-more.info":true,"hobby-site.com":true,"hobby-site.org":true,"home.dyndns.org":true,"homedns.org":true,"homeftp.net":true,"homeftp.org":true,"homeip.net":true,"homelinux.com":true,"homelinux.net":true,"homelinux.org":true,"homeunix.com":true,"homeunix.net":true,"homeunix.org":true,"iamallama.com":true,"in-the-band.net":true,"is-a-anarchist.com":true,"is-a-blogger.com":true,"is-a-bookkeeper.com":true,"is-a-bruinsfan.org":true,"is-a-bulls-fan.com":true,"is-a-candidate.org":true,"is-a-caterer.com":true,"is-a-celticsfan.org":true,"is-a-chef.com":true,"is-a-chef.net":true,"is-a-chef.org":true,"is-a-conservative.com":true,"is-a-cpa.com":true,"is-a-cubicle-slave.com":true,"is-a-democrat.com":true,"is-a-designer.com":true,"is-a-doctor.com":true,"is-a-financialadvisor.com":true,"is-a-geek.com":true,"is-a-geek.net":true,"is-a-geek.org":true,"is-a-green.com":true,"is-a-guru.com":true,"is-a-hard-worker.com":true,"is-a-hunter.com":true,"is-a-knight.org":true,"is-a-landscaper.com":true,"is-a-lawyer.com":true,"is-a-liberal.com":true,"is-a-libertarian.com":true,"is-a-linux-user.org":true,"is-a-llama.com":true,"is-a-musician.com":true,"is-a-nascarfan.com":true,"is-a-nurse.com":true,"is-a-painter.com":true,"is-a-patsfan.org":true,"is-a-personaltrainer.com":true,"is-a-photographer.com":true,"is-a-player.com":true,"is-a-republican.com":true,"is-a-rockstar.com":true,"is-a-socialist.com":true,"is-a-soxfan.org":true,"is-a-student.com":true,"is-a-teacher.com":true,"is-a-techie.com":true,"is-a-therapist.com":true,"is-an-accountant.com":true,"is-an-actor.com":true,"is-an-actress.com":true,"is-an-anarchist.com":true,"is-an-artist.com":true,"is-an-engineer.com":true,"is-an-entertainer.com":true,"is-by.us":true,"is-certified.com":true,"is-found.org":true,"is-gone.com":true,"is-into-anime.com":true,"is-into-cars.com":true,"is-into-cartoons.com":true,"is-into-games.com":true,"is-leet.com":true,"is-lost.org":true,"is-not-certified.com":true,"is-saved.org":true,"is-slick.com":true,"is-uberleet.com":true,"is-very-bad.org":true,"is-very-evil.org":true,"is-very-good.org":true,"is-very-nice.org":true,"is-very-sweet.org":true,"is-with-theband.com":true,"isa-geek.com":true,"isa-geek.net":true,"isa-geek.org":true,"isa-hockeynut.com":true,"issmarterthanyou.com":true,"isteingeek.de":true,"istmein.de":true,"kicks-ass.net":true,"kicks-ass.org":true,"knowsitall.info":true,"land-4-sale.us":true,"lebtimnetz.de":true,"leitungsen.de":true,"likes-pie.com":true,"likescandy.com":true,"merseine.nu":true,"mine.nu":true,"misconfused.org":true,"mypets.ws":true,"myphotos.cc":true,"neat-url.com":true,"office-on-the.net":true,"on-the-web.tv":true,"podzone.net":true,"podzone.org":true,"readmyblog.org":true,"saves-the-whales.com":true,"scrapper-site.net":true,"scrapping.cc":true,"selfip.biz":true,"selfip.com":true,"selfip.info":true,"selfip.net":true,"selfip.org":true,"sells-for-less.com":true,"sells-for-u.com":true,"sells-it.net":true,"sellsyourhome.org":true,"servebbs.com":true,"servebbs.net":true,"servebbs.org":true,"serveftp.net":true,"serveftp.org":true,"servegame.org":true,"shacknet.nu":true,"simple-url.com":true,"space-to-rent.com":true,"stuff-4-sale.org":true,"stuff-4-sale.us":true,"teaches-yoga.com":true,"thruhere.net":true,"traeumtgerade.de":true,"webhop.biz":true,"webhop.info":true,"webhop.net":true,"webhop.org":true,"worse-than.tv":true,"writesthisblog.com":true});
+
+// END of automatically generated file
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/store.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/store.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/lib/store.js	(revision 517)
@@ -0,0 +1,37 @@
+'use strict';
+/*jshint unused:false */
+
+function Store() {
+}
+exports.Store = Store;
+
+// Stores may be synchronous, but are still required to use a
+// Continuation-Passing Style API.  The CookieJar itself will expose a "*Sync"
+// API that converts from synchronous-callbacks to imperative style.
+Store.prototype.synchronous = false;
+
+Store.prototype.findCookie = function(domain, path, key, cb) {
+  throw new Error('findCookie is not implemented');
+};
+
+Store.prototype.findCookies = function(domain, path, cb) {
+  throw new Error('findCookies is not implemented');
+};
+
+Store.prototype.putCookie = function(cookie, cb) {
+  throw new Error('putCookie is not implemented');
+};
+
+Store.prototype.updateCookie = function(oldCookie, newCookie, cb) {
+  // recommended default implementation:
+  // return this.putCookie(newCookie, cb);
+  throw new Error('updateCookie is not implemented');
+};
+
+Store.prototype.removeCookie = function(domain, path, key, cb) {
+  throw new Error('removeCookie is not implemented');
+};
+
+Store.prototype.removeCookies = function removeCookies(domain, path, cb) {
+  throw new Error('removeCookies is not implemented');
+};
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/LICENSE-GPL.txt
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/LICENSE-GPL.txt	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/LICENSE-GPL.txt	(revision 517)
@@ -0,0 +1,278 @@
+        GNU GENERAL PUBLIC LICENSE
+           Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+          Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+        GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+          NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/LICENSE-MIT.txt
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/LICENSE-MIT.txt	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/LICENSE-MIT.txt	(revision 517)
@@ -0,0 +1,20 @@
+Copyright Mathias Bynens <http://mathiasbynens.be/>
+
+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.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/README.md	(revision 517)
@@ -0,0 +1,162 @@
+# Punycode.js [![Build status](https://travis-ci.org/bestiejs/punycode.js.png?branch=master)](https://travis-ci.org/bestiejs/punycode.js) [![Dependency status](https://gemnasium.com/bestiejs/punycode.js.png)](https://gemnasium.com/bestiejs/punycode.js)
+
+A robust Punycode converter that fully complies to [RFC 3492](http://tools.ietf.org/html/rfc3492) and [RFC 5891](http://tools.ietf.org/html/rfc5891), and works on nearly all JavaScript platforms.
+
+This JavaScript library is the result of comparing, optimizing and documenting different open-source implementations of the Punycode algorithm:
+
+* [The C example code from RFC 3492](http://tools.ietf.org/html/rfc3492#appendix-C)
+* [`punycode.c` by _Markus W. Scherer_ (IBM)](http://opensource.apple.com/source/ICU/ICU-400.42/icuSources/common/punycode.c)
+* [`punycode.c` by _Ben Noordhuis_](https://github.com/bnoordhuis/punycode/blob/master/punycode.c)
+* [JavaScript implementation by _some_](http://stackoverflow.com/questions/183485/can-anyone-recommend-a-good-free-javascript-for-punycode-to-unicode-conversion/301287#301287)
+* [`punycode.js` by _Ben Noordhuis_](https://github.com/joyent/node/blob/426298c8c1c0d5b5224ac3658c41e7c2a3fe9377/lib/punycode.js) (note: [not fully compliant](https://github.com/joyent/node/issues/2072))
+
+This project is [bundled](https://github.com/joyent/node/blob/master/lib/punycode.js) with [Node.js v0.6.2+](https://github.com/joyent/node/compare/975f1930b1...61e796decc).
+
+## Installation
+
+Via [npm](http://npmjs.org/) (only required for Node.js releases older than v0.6.2):
+
+```bash
+npm install punycode
+```
+
+Via [Bower](http://bower.io/):
+
+```bash
+bower install punycode
+```
+
+Via [Component](https://github.com/component/component):
+
+```bash
+component install bestiejs/punycode.js
+```
+
+In a browser:
+
+```html
+<script src="punycode.js"></script>
+```
+
+In [Narwhal](http://narwhaljs.org/), [Node.js](http://nodejs.org/), and [RingoJS](http://ringojs.org/):
+
+```js
+var punycode = require('punycode');
+```
+
+In [Rhino](http://www.mozilla.org/rhino/):
+
+```js
+load('punycode.js');
+```
+
+Using an AMD loader like [RequireJS](http://requirejs.org/):
+
+```js
+require(
+  {
+    'paths': {
+      'punycode': 'path/to/punycode'
+    }
+  },
+  ['punycode'],
+  function(punycode) {
+    console.log(punycode);
+  }
+);
+```
+
+## API
+
+### `punycode.decode(string)`
+
+Converts a Punycode string of ASCII symbols to a string of Unicode symbols.
+
+```js
+// decode domain name parts
+punycode.decode('maana-pta'); // 'maÃ±ana'
+punycode.decode('--dqo34k'); // 'â-â'
+```
+
+### `punycode.encode(string)`
+
+Converts a string of Unicode symbols to a Punycode string of ASCII symbols.
+
+```js
+// encode domain name parts
+punycode.encode('maÃ±ana'); // 'maana-pta'
+punycode.encode('â-â'); // '--dqo34k'
+```
+
+### `punycode.toUnicode(domain)`
+
+Converts a Punycode string representing a domain name to Unicode. Only the Punycoded parts of the domain name will be converted, i.e. it doesnât matter if you call it on a string that has already been converted to Unicode.
+
+```js
+// decode domain names
+punycode.toUnicode('xn--maana-pta.com'); // 'maÃ±ana.com'
+punycode.toUnicode('xn----dqo34k.com'); // 'â-â.com'
+```
+
+### `punycode.toASCII(domain)`
+
+Converts a Unicode string representing a domain name to Punycode. Only the non-ASCII parts of the domain name will be converted, i.e. it doesnât matter if you call it with a domain that's already in ASCII.
+
+```js
+// encode domain names
+punycode.toASCII('maÃ±ana.com'); // 'xn--maana-pta.com'
+punycode.toASCII('â-â.com'); // 'xn----dqo34k.com'
+```
+
+### `punycode.ucs2`
+
+#### `punycode.ucs2.decode(string)`
+
+Creates an array containing the numeric code point values of each Unicode symbol in the string. While [JavaScript uses UCS-2 internally](http://mathiasbynens.be/notes/javascript-encoding), this function will convert a pair of surrogate halves (each of which UCS-2 exposes as separate characters) into a single code point, matching UTF-16.
+
+```js
+punycode.ucs2.decode('abc'); // [0x61, 0x62, 0x63]
+// surrogate pair for U+1D306 TETRAGRAM FOR CENTRE:
+punycode.ucs2.decode('\uD834\uDF06'); // [0x1D306]
+```
+
+#### `punycode.ucs2.encode(codePoints)`
+
+Creates a string based on an array of numeric code point values.
+
+```js
+punycode.ucs2.encode([0x61, 0x62, 0x63]); // 'abc'
+punycode.ucs2.encode([0x1D306]); // '\uD834\uDF06'
+```
+
+### `punycode.version`
+
+A string representing the current Punycode.js version number.
+
+[Full API documentation is available.](https://github.com/bestiejs/punycode.js/tree/master/docs#readme)
+
+## Unit tests & code coverage
+
+After cloning this repository, run `npm install --dev` to install the dependencies needed for Punycode.js development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.
+
+Once thatâs done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, PhantomJS, and web browsers as well, use `grunt test`.
+
+To generate [the code coverage report](http://rawgithub.com/bestiejs/punycode.js/master/coverage/punycode.js/punycode.js.html), use `grunt cover`.
+
+Feel free to fork if you see possible improvements!
+
+## Author
+
+| [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](http://twitter.com/mathias "Follow @mathias on Twitter") |
+|---|
+| [Mathias Bynens](http://mathiasbynens.be/) |
+
+## Contributors
+
+| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](http://twitter.com/jdalton "Follow @jdalton on Twitter") |
+|---|
+| [John-David Dalton](http://allyoucanleet.com/) |
+
+## License
+
+Punycode.js is dual licensed under the [MIT](http://mths.be/mit) and [GPL](http://mths.be/gpl) licenses.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/package.json	(revision 517)
@@ -0,0 +1,74 @@
+{
+  "name": "punycode",
+  "version": "1.2.4",
+  "description": "A robust Punycode converter that fully complies to RFC 3492 and RFC 5891, and works on nearly all JavaScript platforms.",
+  "homepage": "http://mths.be/punycode",
+  "main": "punycode.js",
+  "keywords": [
+    "punycode",
+    "unicode",
+    "idn",
+    "idna",
+    "dns",
+    "url",
+    "domain"
+  ],
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "http://mths.be/mit"
+    },
+    {
+      "type": "GPL",
+      "url": "http://mths.be/gpl"
+    }
+  ],
+  "author": {
+    "name": "Mathias Bynens",
+    "email": "mathias@qiwi.be",
+    "url": "http://mathiasbynens.be/"
+  },
+  "contributors": [
+    {
+      "name": "Mathias Bynens",
+      "email": "mathias@qiwi.be",
+      "url": "http://mathiasbynens.be/"
+    },
+    {
+      "name": "John-David Dalton",
+      "email": "john.david.dalton@gmail.com",
+      "url": "http://allyoucanleet.com/"
+    }
+  ],
+  "bugs": {
+    "url": "https://github.com/bestiejs/punycode.js/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/bestiejs/punycode.js.git"
+  },
+  "engines": [
+    "node",
+    "rhino"
+  ],
+  "directories": {
+    "doc": "docs",
+    "test": "tests"
+  },
+  "scripts": {
+    "test": "node tests/tests.js"
+  },
+  "devDependencies": {
+    "grunt": "~0.4.1",
+    "grunt-contrib-uglify": "~0.2.2",
+    "grunt-shell": "~0.6.4",
+    "istanbul": "~0.2.4",
+    "qunit-clib": "~1.3.0",
+    "qunitjs": "~1.11.0",
+    "requirejs": "~2.1.6"
+  },
+  "readme": "# Punycode.js [![Build status](https://travis-ci.org/bestiejs/punycode.js.png?branch=master)](https://travis-ci.org/bestiejs/punycode.js) [![Dependency status](https://gemnasium.com/bestiejs/punycode.js.png)](https://gemnasium.com/bestiejs/punycode.js)\n\nA robust Punycode converter that fully complies to [RFC 3492](http://tools.ietf.org/html/rfc3492) and [RFC 5891](http://tools.ietf.org/html/rfc5891), and works on nearly all JavaScript platforms.\n\nThis JavaScript library is the result of comparing, optimizing and documenting different open-source implementations of the Punycode algorithm:\n\n* [The C example code from RFC 3492](http://tools.ietf.org/html/rfc3492#appendix-C)\n* [`punycode.c` by _Markus W. Scherer_ (IBM)](http://opensource.apple.com/source/ICU/ICU-400.42/icuSources/common/punycode.c)\n* [`punycode.c` by _Ben Noordhuis_](https://github.com/bnoordhuis/punycode/blob/master/punycode.c)\n* [JavaScript implementation by _some_](http://stackoverflow.com/questions/183485/can-anyone-recommend-a-good-free-javascript-for-punycode-to-unicode-conversion/301287#301287)\n* [`punycode.js` by _Ben Noordhuis_](https://github.com/joyent/node/blob/426298c8c1c0d5b5224ac3658c41e7c2a3fe9377/lib/punycode.js) (note: [not fully compliant](https://github.com/joyent/node/issues/2072))\n\nThis project is [bundled](https://github.com/joyent/node/blob/master/lib/punycode.js) with [Node.js v0.6.2+](https://github.com/joyent/node/compare/975f1930b1...61e796decc).\n\n## Installation\n\nVia [npm](http://npmjs.org/) (only required for Node.js releases older than v0.6.2):\n\n```bash\nnpm install punycode\n```\n\nVia [Bower](http://bower.io/):\n\n```bash\nbower install punycode\n```\n\nVia [Component](https://github.com/component/component):\n\n```bash\ncomponent install bestiejs/punycode.js\n```\n\nIn a browser:\n\n```html\n<script src=\"punycode.js\"></script>\n```\n\nIn [Narwhal](http://narwhaljs.org/), [Node.js](http://nodejs.org/), and [RingoJS](http://ringojs.org/):\n\n```js\nvar punycode = require('punycode');\n```\n\nIn [Rhino](http://www.mozilla.org/rhino/):\n\n```js\nload('punycode.js');\n```\n\nUsing an AMD loader like [RequireJS](http://requirejs.org/):\n\n```js\nrequire(\n  {\n    'paths': {\n      'punycode': 'path/to/punycode'\n    }\n  },\n  ['punycode'],\n  function(punycode) {\n    console.log(punycode);\n  }\n);\n```\n\n## API\n\n### `punycode.decode(string)`\n\nConverts a Punycode string of ASCII symbols to a string of Unicode symbols.\n\n```js\n// decode domain name parts\npunycode.decode('maana-pta'); // 'maÃ±ana'\npunycode.decode('--dqo34k'); // 'â-â'\n```\n\n### `punycode.encode(string)`\n\nConverts a string of Unicode symbols to a Punycode string of ASCII symbols.\n\n```js\n// encode domain name parts\npunycode.encode('maÃ±ana'); // 'maana-pta'\npunycode.encode('â-â'); // '--dqo34k'\n```\n\n### `punycode.toUnicode(domain)`\n\nConverts a Punycode string representing a domain name to Unicode. Only the Punycoded parts of the domain name will be converted, i.e. it doesnât matter if you call it on a string that has already been converted to Unicode.\n\n```js\n// decode domain names\npunycode.toUnicode('xn--maana-pta.com'); // 'maÃ±ana.com'\npunycode.toUnicode('xn----dqo34k.com'); // 'â-â.com'\n```\n\n### `punycode.toASCII(domain)`\n\nConverts a Unicode string representing a domain name to Punycode. Only the non-ASCII parts of the domain name will be converted, i.e. it doesnât matter if you call it with a domain that's already in ASCII.\n\n```js\n// encode domain names\npunycode.toASCII('maÃ±ana.com'); // 'xn--maana-pta.com'\npunycode.toASCII('â-â.com'); // 'xn----dqo34k.com'\n```\n\n### `punycode.ucs2`\n\n#### `punycode.ucs2.decode(string)`\n\nCreates an array containing the numeric code point values of each Unicode symbol in the string. While [JavaScript uses UCS-2 internally](http://mathiasbynens.be/notes/javascript-encoding), this function will convert a pair of surrogate halves (each of which UCS-2 exposes as separate characters) into a single code point, matching UTF-16.\n\n```js\npunycode.ucs2.decode('abc'); // [0x61, 0x62, 0x63]\n// surrogate pair for U+1D306 TETRAGRAM FOR CENTRE:\npunycode.ucs2.decode('\\uD834\\uDF06'); // [0x1D306]\n```\n\n#### `punycode.ucs2.encode(codePoints)`\n\nCreates a string based on an array of numeric code point values.\n\n```js\npunycode.ucs2.encode([0x61, 0x62, 0x63]); // 'abc'\npunycode.ucs2.encode([0x1D306]); // '\\uD834\\uDF06'\n```\n\n### `punycode.version`\n\nA string representing the current Punycode.js version number.\n\n[Full API documentation is available.](https://github.com/bestiejs/punycode.js/tree/master/docs#readme)\n\n## Unit tests & code coverage\n\nAfter cloning this repository, run `npm install --dev` to install the dependencies needed for Punycode.js development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.\n\nOnce thatâs done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, PhantomJS, and web browsers as well, use `grunt test`.\n\nTo generate [the code coverage report](http://rawgithub.com/bestiejs/punycode.js/master/coverage/punycode.js/punycode.js.html), use `grunt cover`.\n\nFeel free to fork if you see possible improvements!\n\n## Author\n\n| [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](http://twitter.com/mathias \"Follow @mathias on Twitter\") |\n|---|\n| [Mathias Bynens](http://mathiasbynens.be/) |\n\n## Contributors\n\n| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](http://twitter.com/jdalton \"Follow @jdalton on Twitter\") |\n|---|\n| [John-David Dalton](http://allyoucanleet.com/) |\n\n## License\n\nPunycode.js is dual licensed under the [MIT](http://mths.be/mit) and [GPL](http://mths.be/gpl) licenses.\n",
+  "readmeFilename": "README.md",
+  "_id": "punycode@1.2.4",
+  "_from": "punycode@>=0.2.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/punycode.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/punycode.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/punycode.js	(revision 517)
@@ -0,0 +1,507 @@
+/*! http://mths.be/punycode v1.2.4 by @mathias */
+;(function(root) {
+
+	/** Detect free variables */
+	var freeExports = typeof exports == 'object' && exports;
+	var freeModule = typeof module == 'object' && module &&
+		module.exports == freeExports && module;
+	var freeGlobal = typeof global == 'object' && global;
+	if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+		root = freeGlobal;
+	}
+
+	/**
+	 * The `punycode` object.
+	 * @name punycode
+	 * @type Object
+	 */
+	var punycode,
+
+	/** Highest positive signed 32-bit float value */
+	maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+	/** Bootstring parameters */
+	base = 36,
+	tMin = 1,
+	tMax = 26,
+	skew = 38,
+	damp = 700,
+	initialBias = 72,
+	initialN = 128, // 0x80
+	delimiter = '-', // '\x2D'
+
+	/** Regular expressions */
+	regexPunycode = /^xn--/,
+	regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars
+	regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators
+
+	/** Error messages */
+	errors = {
+		'overflow': 'Overflow: input needs wider integers to process',
+		'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+		'invalid-input': 'Invalid input'
+	},
+
+	/** Convenience shortcuts */
+	baseMinusTMin = base - tMin,
+	floor = Math.floor,
+	stringFromCharCode = String.fromCharCode,
+
+	/** Temporary variable */
+	key;
+
+	/*--------------------------------------------------------------------------*/
+
+	/**
+	 * A generic error utility function.
+	 * @private
+	 * @param {String} type The error type.
+	 * @returns {Error} Throws a `RangeError` with the applicable error message.
+	 */
+	function error(type) {
+		throw RangeError(errors[type]);
+	}
+
+	/**
+	 * A generic `Array#map` utility function.
+	 * @private
+	 * @param {Array} array The array to iterate over.
+	 * @param {Function} callback The function that gets called for every array
+	 * item.
+	 * @returns {Array} A new array of values returned by the callback function.
+	 */
+	function map(array, fn) {
+		var length = array.length;
+		while (length--) {
+			array[length] = fn(array[length]);
+		}
+		return array;
+	}
+
+	/**
+	 * A simple `Array#map`-like wrapper to work with domain name strings.
+	 * @private
+	 * @param {String} domain The domain name.
+	 * @param {Function} callback The function that gets called for every
+	 * character.
+	 * @returns {Array} A new string of characters returned by the callback
+	 * function.
+	 */
+	function mapDomain(string, fn) {
+		return map(string.split(regexSeparators), fn).join('.');
+	}
+
+	/**
+	 * Creates an array containing the numeric code points of each Unicode
+	 * character in the string. While JavaScript uses UCS-2 internally,
+	 * this function will convert a pair of surrogate halves (each of which
+	 * UCS-2 exposes as separate characters) into a single code point,
+	 * matching UTF-16.
+	 * @see `punycode.ucs2.encode`
+	 * @see <http://mathiasbynens.be/notes/javascript-encoding>
+	 * @memberOf punycode.ucs2
+	 * @name decode
+	 * @param {String} string The Unicode input string (UCS-2).
+	 * @returns {Array} The new array of code points.
+	 */
+	function ucs2decode(string) {
+		var output = [],
+		    counter = 0,
+		    length = string.length,
+		    value,
+		    extra;
+		while (counter < length) {
+			value = string.charCodeAt(counter++);
+			if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+				// high surrogate, and there is a next character
+				extra = string.charCodeAt(counter++);
+				if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+					output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+				} else {
+					// unmatched surrogate; only append this code unit, in case the next
+					// code unit is the high surrogate of a surrogate pair
+					output.push(value);
+					counter--;
+				}
+			} else {
+				output.push(value);
+			}
+		}
+		return output;
+	}
+
+	/**
+	 * Creates a string based on an array of numeric code points.
+	 * @see `punycode.ucs2.decode`
+	 * @memberOf punycode.ucs2
+	 * @name encode
+	 * @param {Array} codePoints The array of numeric code points.
+	 * @returns {String} The new Unicode string (UCS-2).
+	 */
+	function ucs2encode(array) {
+		return map(array, function(value) {
+			var output = '';
+			if (value > 0xFFFF) {
+				value -= 0x10000;
+				output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+				value = 0xDC00 | value & 0x3FF;
+			}
+			output += stringFromCharCode(value);
+			return output;
+		}).join('');
+	}
+
+	/**
+	 * Converts a basic code point into a digit/integer.
+	 * @see `digitToBasic()`
+	 * @private
+	 * @param {Number} codePoint The basic numeric code point value.
+	 * @returns {Number} The numeric value of a basic code point (for use in
+	 * representing integers) in the range `0` to `base - 1`, or `base` if
+	 * the code point does not represent a value.
+	 */
+	function basicToDigit(codePoint) {
+		if (codePoint - 48 < 10) {
+			return codePoint - 22;
+		}
+		if (codePoint - 65 < 26) {
+			return codePoint - 65;
+		}
+		if (codePoint - 97 < 26) {
+			return codePoint - 97;
+		}
+		return base;
+	}
+
+	/**
+	 * Converts a digit/integer into a basic code point.
+	 * @see `basicToDigit()`
+	 * @private
+	 * @param {Number} digit The numeric value of a basic code point.
+	 * @returns {Number} The basic code point whose value (when used for
+	 * representing integers) is `digit`, which needs to be in the range
+	 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+	 * used; else, the lowercase form is used. The behavior is undefined
+	 * if `flag` is non-zero and `digit` has no uppercase form.
+	 */
+	function digitToBasic(digit, flag) {
+		//  0..25 map to ASCII a..z or A..Z
+		// 26..35 map to ASCII 0..9
+		return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+	}
+
+	/**
+	 * Bias adaptation function as per section 3.4 of RFC 3492.
+	 * http://tools.ietf.org/html/rfc3492#section-3.4
+	 * @private
+	 */
+	function adapt(delta, numPoints, firstTime) {
+		var k = 0;
+		delta = firstTime ? floor(delta / damp) : delta >> 1;
+		delta += floor(delta / numPoints);
+		for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+			delta = floor(delta / baseMinusTMin);
+		}
+		return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+	}
+
+	/**
+	 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+	 * symbols.
+	 * @memberOf punycode
+	 * @param {String} input The Punycode string of ASCII-only symbols.
+	 * @returns {String} The resulting string of Unicode symbols.
+	 */
+	function decode(input) {
+		// Don't use UCS-2
+		var output = [],
+		    inputLength = input.length,
+		    out,
+		    i = 0,
+		    n = initialN,
+		    bias = initialBias,
+		    basic,
+		    j,
+		    index,
+		    oldi,
+		    w,
+		    k,
+		    digit,
+		    t,
+		    /** Cached calculation results */
+		    baseMinusT;
+
+		// Handle the basic code points: let `basic` be the number of input code
+		// points before the last delimiter, or `0` if there is none, then copy
+		// the first basic code points to the output.
+
+		basic = input.lastIndexOf(delimiter);
+		if (basic < 0) {
+			basic = 0;
+		}
+
+		for (j = 0; j < basic; ++j) {
+			// if it's not a basic code point
+			if (input.charCodeAt(j) >= 0x80) {
+				error('not-basic');
+			}
+			output.push(input.charCodeAt(j));
+		}
+
+		// Main decoding loop: start just after the last delimiter if any basic code
+		// points were copied; start at the beginning otherwise.
+
+		for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+			// `index` is the index of the next character to be consumed.
+			// Decode a generalized variable-length integer into `delta`,
+			// which gets added to `i`. The overflow checking is easier
+			// if we increase `i` as we go, then subtract off its starting
+			// value at the end to obtain `delta`.
+			for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+				if (index >= inputLength) {
+					error('invalid-input');
+				}
+
+				digit = basicToDigit(input.charCodeAt(index++));
+
+				if (digit >= base || digit > floor((maxInt - i) / w)) {
+					error('overflow');
+				}
+
+				i += digit * w;
+				t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+				if (digit < t) {
+					break;
+				}
+
+				baseMinusT = base - t;
+				if (w > floor(maxInt / baseMinusT)) {
+					error('overflow');
+				}
+
+				w *= baseMinusT;
+
+			}
+
+			out = output.length + 1;
+			bias = adapt(i - oldi, out, oldi == 0);
+
+			// `i` was supposed to wrap around from `out` to `0`,
+			// incrementing `n` each time, so we'll fix that now:
+			if (floor(i / out) > maxInt - n) {
+				error('overflow');
+			}
+
+			n += floor(i / out);
+			i %= out;
+
+			// Insert `n` at position `i` of the output
+			output.splice(i++, 0, n);
+
+		}
+
+		return ucs2encode(output);
+	}
+
+	/**
+	 * Converts a string of Unicode symbols to a Punycode string of ASCII-only
+	 * symbols.
+	 * @memberOf punycode
+	 * @param {String} input The string of Unicode symbols.
+	 * @returns {String} The resulting Punycode string of ASCII-only symbols.
+	 */
+	function encode(input) {
+		var n,
+		    delta,
+		    handledCPCount,
+		    basicLength,
+		    bias,
+		    j,
+		    m,
+		    q,
+		    k,
+		    t,
+		    currentValue,
+		    output = [],
+		    /** `inputLength` will hold the number of code points in `input`. */
+		    inputLength,
+		    /** Cached calculation results */
+		    handledCPCountPlusOne,
+		    baseMinusT,
+		    qMinusT;
+
+		// Convert the input in UCS-2 to Unicode
+		input = ucs2decode(input);
+
+		// Cache the length
+		inputLength = input.length;
+
+		// Initialize the state
+		n = initialN;
+		delta = 0;
+		bias = initialBias;
+
+		// Handle the basic code points
+		for (j = 0; j < inputLength; ++j) {
+			currentValue = input[j];
+			if (currentValue < 0x80) {
+				output.push(stringFromCharCode(currentValue));
+			}
+		}
+
+		handledCPCount = basicLength = output.length;
+
+		// `handledCPCount` is the number of code points that have been handled;
+		// `basicLength` is the number of basic code points.
+
+		// Finish the basic string - if it is not empty - with a delimiter
+		if (basicLength) {
+			output.push(delimiter);
+		}
+
+		// Main encoding loop:
+		while (handledCPCount < inputLength) {
+
+			// All non-basic code points < n have been handled already. Find the next
+			// larger one:
+			for (m = maxInt, j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+				if (currentValue >= n && currentValue < m) {
+					m = currentValue;
+				}
+			}
+
+			// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+			// but guard against overflow
+			handledCPCountPlusOne = handledCPCount + 1;
+			if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+				error('overflow');
+			}
+
+			delta += (m - n) * handledCPCountPlusOne;
+			n = m;
+
+			for (j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+
+				if (currentValue < n && ++delta > maxInt) {
+					error('overflow');
+				}
+
+				if (currentValue == n) {
+					// Represent delta as a generalized variable-length integer
+					for (q = delta, k = base; /* no condition */; k += base) {
+						t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+						if (q < t) {
+							break;
+						}
+						qMinusT = q - t;
+						baseMinusT = base - t;
+						output.push(
+							stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+						);
+						q = floor(qMinusT / baseMinusT);
+					}
+
+					output.push(stringFromCharCode(digitToBasic(q, 0)));
+					bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+					delta = 0;
+					++handledCPCount;
+				}
+			}
+
+			++delta;
+			++n;
+
+		}
+		return output.join('');
+	}
+
+	/**
+	 * Converts a Punycode string representing a domain name to Unicode. Only the
+	 * Punycoded parts of the domain name will be converted, i.e. it doesn't
+	 * matter if you call it on a string that has already been converted to
+	 * Unicode.
+	 * @memberOf punycode
+	 * @param {String} domain The Punycode domain name to convert to Unicode.
+	 * @returns {String} The Unicode representation of the given Punycode
+	 * string.
+	 */
+	function toUnicode(domain) {
+		return mapDomain(domain, function(string) {
+			return regexPunycode.test(string)
+				? decode(string.slice(4).toLowerCase())
+				: string;
+		});
+	}
+
+	/**
+	 * Converts a Unicode string representing a domain name to Punycode. Only the
+	 * non-ASCII parts of the domain name will be converted, i.e. it doesn't
+	 * matter if you call it with a domain that's already in ASCII.
+	 * @memberOf punycode
+	 * @param {String} domain The domain name to convert, as a Unicode string.
+	 * @returns {String} The Punycode representation of the given domain name.
+	 */
+	function toASCII(domain) {
+		return mapDomain(domain, function(string) {
+			return regexNonASCII.test(string)
+				? 'xn--' + encode(string)
+				: string;
+		});
+	}
+
+	/*--------------------------------------------------------------------------*/
+
+	/** Define the public API */
+	punycode = {
+		/**
+		 * A string representing the current Punycode.js version number.
+		 * @memberOf punycode
+		 * @type String
+		 */
+		'version': '1.2.4',
+		/**
+		 * An object of methods to convert from JavaScript's internal character
+		 * representation (UCS-2) to Unicode code points, and back.
+		 * @see <http://mathiasbynens.be/notes/javascript-encoding>
+		 * @memberOf punycode
+		 * @type Object
+		 */
+		'ucs2': {
+			'decode': ucs2decode,
+			'encode': ucs2encode
+		},
+		'decode': decode,
+		'encode': encode,
+		'toASCII': toASCII,
+		'toUnicode': toUnicode
+	};
+
+	/** Expose `punycode` */
+	// Some AMD build optimizers, like r.js, check for specific condition patterns
+	// like the following:
+	if (
+		typeof define == 'function' &&
+		typeof define.amd == 'object' &&
+		define.amd
+	) {
+		define('punycode', function() {
+			return punycode;
+		});
+	} else if (freeExports && !freeExports.nodeType) {
+		if (freeModule) { // in Node.js or RingoJS v0.8.0+
+			freeModule.exports = punycode;
+		} else { // in Narwhal or RingoJS v0.7.0-
+			for (key in punycode) {
+				punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+			}
+		}
+	} else { // in Rhino or a web browser
+		root.punycode = punycode;
+	}
+
+}(this));
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/punycode.min.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/punycode.min.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/node_modules/punycode/punycode.min.js	(revision 517)
@@ -0,0 +1,2 @@
+/*! http://mths.be/punycode v1.2.4 by @mathias */
+!function(a){function b(a){throw RangeError(E[a])}function c(a,b){for(var c=a.length;c--;)a[c]=b(a[c]);return a}function d(a,b){return c(a.split(D),b).join(".")}function e(a){for(var b,c,d=[],e=0,f=a.length;f>e;)b=a.charCodeAt(e++),b>=55296&&56319>=b&&f>e?(c=a.charCodeAt(e++),56320==(64512&c)?d.push(((1023&b)<<10)+(1023&c)+65536):(d.push(b),e--)):d.push(b);return d}function f(a){return c(a,function(a){var b="";return a>65535&&(a-=65536,b+=H(a>>>10&1023|55296),a=56320|1023&a),b+=H(a)}).join("")}function g(a){return 10>a-48?a-22:26>a-65?a-65:26>a-97?a-97:t}function h(a,b){return a+22+75*(26>a)-((0!=b)<<5)}function i(a,b,c){var d=0;for(a=c?G(a/x):a>>1,a+=G(a/b);a>F*v>>1;d+=t)a=G(a/F);return G(d+(F+1)*a/(a+w))}function j(a){var c,d,e,h,j,k,l,m,n,o,p=[],q=a.length,r=0,w=z,x=y;for(d=a.lastIndexOf(A),0>d&&(d=0),e=0;d>e;++e)a.charCodeAt(e)>=128&&b("not-basic"),p.push(a.charCodeAt(e));for(h=d>0?d+1:0;q>h;){for(j=r,k=1,l=t;h>=q&&b("invalid-input"),m=g(a.charCodeAt(h++)),(m>=t||m>G((s-r)/k))&&b("overflow"),r+=m*k,n=x>=l?u:l>=x+v?v:l-x,!(n>m);l+=t)o=t-n,k>G(s/o)&&b("overflow"),k*=o;c=p.length+1,x=i(r-j,c,0==j),G(r/c)>s-w&&b("overflow"),w+=G(r/c),r%=c,p.splice(r++,0,w)}return f(p)}function k(a){var c,d,f,g,j,k,l,m,n,o,p,q,r,w,x,B=[];for(a=e(a),q=a.length,c=z,d=0,j=y,k=0;q>k;++k)p=a[k],128>p&&B.push(H(p));for(f=g=B.length,g&&B.push(A);q>f;){for(l=s,k=0;q>k;++k)p=a[k],p>=c&&l>p&&(l=p);for(r=f+1,l-c>G((s-d)/r)&&b("overflow"),d+=(l-c)*r,c=l,k=0;q>k;++k)if(p=a[k],c>p&&++d>s&&b("overflow"),p==c){for(m=d,n=t;o=j>=n?u:n>=j+v?v:n-j,!(o>m);n+=t)x=m-o,w=t-o,B.push(H(h(o+x%w,0))),m=G(x/w);B.push(H(h(m,0))),j=i(d,r,f==g),d=0,++f}++d,++c}return B.join("")}function l(a){return d(a,function(a){return B.test(a)?j(a.slice(4).toLowerCase()):a})}function m(a){return d(a,function(a){return C.test(a)?"xn--"+k(a):a})}var n="object"==typeof exports&&exports,o="object"==typeof module&&module&&module.exports==n&&module,p="object"==typeof global&&global;(p.global===p||p.window===p)&&(a=p);var q,r,s=2147483647,t=36,u=1,v=26,w=38,x=700,y=72,z=128,A="-",B=/^xn--/,C=/[^ -~]/,D=/\x2E|\u3002|\uFF0E|\uFF61/g,E={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},F=t-u,G=Math.floor,H=String.fromCharCode;if(q={version:"1.2.4",ucs2:{decode:e,encode:f},decode:j,encode:k,toASCII:m,toUnicode:l},"function"==typeof define&&"object"==typeof define.amd&&define.amd)define("punycode",function(){return q});else if(n&&!n.nodeType)if(o)o.exports=q;else for(r in q)q.hasOwnProperty(r)&&(n[r]=q[r]);else a.punycode=q}(this);
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/package.json	(revision 517)
@@ -0,0 +1,45 @@
+{
+  "author": {
+    "name": "GoInstant Inc., a salesforce.com company"
+  },
+  "license": "MIT",
+  "name": "tough-cookie",
+  "description": "RFC6265 Cookies and Cookie Jar for node.js",
+  "keywords": [
+    "HTTP",
+    "cookie",
+    "cookies",
+    "set-cookie",
+    "cookiejar",
+    "jar",
+    "RFC6265",
+    "RFC2965"
+  ],
+  "version": "0.12.1",
+  "homepage": "https://github.com/goinstant/tough-cookie",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/goinstant/tough-cookie.git"
+  },
+  "bugs": {
+    "url": "https://github.com/goinstant/tough-cookie/issues"
+  },
+  "main": "./lib/cookie",
+  "scripts": {
+    "test": "vows test.js"
+  },
+  "engines": {
+    "node": ">=0.4.12"
+  },
+  "dependencies": {
+    "punycode": ">=0.2.0"
+  },
+  "devDependencies": {
+    "vows": "0.7.0",
+    "async": ">=0.1.12"
+  },
+  "readme": "[RFC6265](http://tools.ietf.org/html/rfc6265) Cookies and CookieJar for Node.js\n\n![Tough Cookie](http://www.goinstant.com.s3.amazonaws.com/tough-cookie.jpg)\n\n[![Build Status](https://travis-ci.org/goinstant/node-cookie.png?branch=master)](https://travis-ci.org/goinstant/node-cookie)\n\n[![NPM Stats](https://nodei.co/npm/tough-cookie.png?downloads=true&stars=true)](https://npmjs.org/package/tough-cookie)\n![NPM Downloads](https://nodei.co/npm-dl/tough-cookie.png?months=9)\n\n# Synopsis\n\n``` javascript\nvar tough = require('tough-cookie'); // note: not 'cookie', 'cookies' or 'node-cookie'\nvar Cookie = tough.Cookie;\nvar cookie = Cookie.parse(header);\ncookie.value = 'somethingdifferent';\nheader = cookie.toString();\n\nvar cookiejar = new tough.CookieJar();\ncookiejar.setCookie(cookie, 'http://currentdomain.example.com/path', cb);\n// ...\ncookiejar.getCookies('http://example.com/otherpath',function(err,cookies) {\n  res.headers['cookie'] = cookies.join('; ');\n});\n```\n\n# Installation\n\nIt's _so_ easy!\n\n`npm install tough-cookie`\n\nRequires `punycode`, which should get installed automatically for you.  Note that node.js v0.6.2+ bundles punycode by default.\n\nWhy the name?  NPM modules `cookie`, `cookies` and `cookiejar` were already taken.\n\n# API\n\ntough\n=====\n\nFunctions on the module you get from `require('tough-cookie')`.  All can be used as pure functions and don't need to be \"bound\".\n\nparseDate(string[,strict])\n-----------------\n\nParse a cookie date string into a `Date`.  Parses according to RFC6265 Section 5.1.1, not `Date.parse()`.  If strict is set to true then leading/trailing non-seperator characters around the time part will cause the parsing to fail (e.g. \"Thu, 01 Jan 1970 00:00:010 GMT\" has an extra trailing zero but Chrome, an assumedly RFC-compliant browser, treats this as valid).\n\nformatDate(date)\n----------------\n\nFormat a Date into a RFC1123 string (the RFC6265-recommended format).\n\ncanonicalDomain(str)\n--------------------\n\nTransforms a domain-name into a canonical domain-name.  The canonical domain-name is a trimmed, lowercased, stripped-of-leading-dot and optionally punycode-encoded domain-name (Section 5.1.2 of RFC6265).  For the most part, this function is idempotent (can be run again on its output without ill effects).\n\ndomainMatch(str,domStr[,canonicalize=true])\n-------------------------------------------\n\nAnswers \"does this real domain match the domain in a cookie?\".  The `str` is the \"current\" domain-name and the `domStr` is the \"cookie\" domain-name.  Matches according to RFC6265 Section 5.1.3, but it helps to think of it as a \"suffix match\".\n\nThe `canonicalize` parameter will run the other two paramters through `canonicalDomain` or not.\n\ndefaultPath(path)\n-----------------\n\nGiven a current request/response path, gives the Path apropriate for storing in a cookie.  This is basically the \"directory\" of a \"file\" in the path, but is specified by Section 5.1.4 of the RFC.\n\nThe `path` parameter MUST be _only_ the pathname part of a URI (i.e. excludes the hostname, query, fragment, etc.).  This is the `.pathname` property of node's `uri.parse()` output.\n\npathMatch(reqPath,cookiePath)\n-----------------------------\n\nAnswers \"does the request-path path-match a given cookie-path?\" as per RFC6265 Section 5.1.4.  Returns a boolean.\n\nThis is essentially a prefix-match where `cookiePath` is a prefix of `reqPath`.\n\nparse(header[,strict=false])\n----------------------------\n\nalias for `Cookie.parse(header[,strict])`\n\nfromJSON(string)\n----------------\n\nalias for `Cookie.fromJSON(string)`\n\ngetPublicSuffix(hostname)\n-------------------------\n\nReturns the public suffix of this hostname.  The public suffix is the shortest domain-name upon which a cookie can be set.  Returns `null` if the hostname cannot have cookies set for it.\n\nFor example: `www.example.com` and `www.subdomain.example.com` both have public suffix `example.com`.\n\nFor further information, see http://publicsuffix.org/.  This module derives its list from that site.\n\ncookieCompare(a,b)\n------------------\n\nFor use with `.sort()`, sorts a list of cookies into the recommended order given in the RFC (Section 5.4 step 2).  Longest `.path`s go first, then sorted oldest to youngest.\n\n``` javascript\nvar cookies = [ /* unsorted array of Cookie objects */ ];\ncookies = cookies.sort(cookieCompare);\n```\n\npermuteDomain(domain)\n---------------------\n\nGenerates a list of all possible domains that `domainMatch()` the parameter.  May be handy for implementing cookie stores.\n\n\npermutePath(path)\n-----------------\n\nGenerates a list of all possible paths that `pathMatch()` the parameter.  May be handy for implementing cookie stores.\n\nCookie\n======\n\nCookie.parse(header[,strict=false])\n-----------------------------------\n\nParses a single Cookie or Set-Cookie HTTP header into a `Cookie` object.  Returns `undefined` if the string can't be parsed.  If in strict mode, returns `undefined` if the cookie doesn't follow the guidelines in section 4 of RFC6265.  Generally speaking, strict mode can be used to validate your own generated Set-Cookie headers, but acting as a client you want to be lenient and leave strict mode off.\n\nHere's how to process the Set-Cookie header(s) on a node HTTP/HTTPS response:\n\n``` javascript\nif (res.headers['set-cookie'] instanceof Array)\n  cookies = res.headers['set-cookie'].map(function (c) { return (Cookie.parse(c)); });\nelse\n  cookies = [Cookie.parse(res.headers['set-cookie'])];\n```\n\nCookie.fromJSON(string)\n-----------------------\n\nConvert a JSON string to a `Cookie` object.  Does a `JSON.parse()` and converts the `.created`, `.lastAccessed` and `.expires` properties into `Date` objects.\n\nProperties\n==========\n\n  * _key_ - string - the name or key of the cookie (default \"\")\n  * _value_ - string - the value of the cookie (default \"\")\n  * _expires_ - `Date` - if set, the `Expires=` attribute of the cookie (defaults to the string `\"Infinity\"`). See `setExpires()`\n  * _maxAge_ - seconds - if set, the `Max-Age=` attribute _in seconds_ of the cookie.  May also be set to strings `\"Infinity\"` and `\"-Infinity\"` for non-expiry and immediate-expiry, respectively.  See `setMaxAge()`\n  * _domain_ - string - the `Domain=` attribute of the cookie\n  * _path_ - string - the `Path=` of the cookie\n  * _secure_ - boolean - the `Secure` cookie flag\n  * _httpOnly_ - boolean - the `HttpOnly` cookie flag\n  * _extensions_ - `Array` - any unrecognized cookie attributes as strings (even if equal-signs inside)\n\nAfter a cookie has been passed through `CookieJar.setCookie()` it will have the following additional attributes:\n\n  * _hostOnly_ - boolean - is this a host-only cookie (i.e. no Domain field was set, but was instead implied)\n  * _pathIsDefault_ - boolean - if true, there was no Path field on the cookie and `defaultPath()` was used to derive one.\n  * _created_ - `Date` - when this cookie was added to the jar\n  * _lastAccessed_ - `Date` - last time the cookie got accessed. Will affect cookie cleaning once implemented.  Using `cookiejar.getCookies(...)` will update this attribute.\n\nConstruction([{options}])\n------------\n\nReceives an options object that can contain any Cookie properties, uses the default for unspecified properties.\n\n.toString()\n-----------\n\nencode to a Set-Cookie header value.  The Expires cookie field is set using `formatDate()`, but is omitted entirely if `.expires` is `Infinity`.\n\n.cookieString()\n---------------\n\nencode to a Cookie header value (i.e. the `.key` and `.value` properties joined with '=').\n\n.setExpires(String)\n-------------------\n\nsets the expiry based on a date-string passed through `parseDate()`.  If parseDate returns `null` (i.e. can't parse this date string), `.expires` is set to `\"Infinity\"` (a string) is set.\n\n.setMaxAge(number)\n-------------------\n\nsets the maxAge in seconds.  Coerces `-Infinity` to `\"-Infinity\"` and `Infinity` to `\"Infinity\"` so it JSON serializes correctly.\n\n.expiryTime([now=Date.now()])\n-----------------------------\n\n.expiryDate([now=Date.now()])\n-----------------------------\n\nexpiryTime() Computes the absolute unix-epoch milliseconds that this cookie expires. expiryDate() works similarly, except it returns a `Date` object.  Note that in both cases the `now` parameter should be milliseconds.\n\nMax-Age takes precedence over Expires (as per the RFC). The `.created` attribute -- or, by default, the `now` paramter -- is used to offset the `.maxAge` attribute.\n\nIf Expires (`.expires`) is set, that's returned.\n\nOtherwise, `expiryTime()` returns `Infinity` and `expiryDate()` returns a `Date` object for \"Tue, 19 Jan 2038 03:14:07 GMT\" (latest date that can be expressed by a 32-bit `time_t`; the common limit for most user-agents).\n\n.TTL([now=Date.now()])\n---------\n\ncompute the TTL relative to `now` (milliseconds).  The same precedence rules as for `expiryTime`/`expiryDate` apply.\n\nThe \"number\" `Infinity` is returned for cookies without an explicit expiry and `0` is returned if the cookie is expired.  Otherwise a time-to-live in milliseconds is returned.\n\n.canonicalizedDoman()\n---------------------\n\n.cdomain()\n----------\n\nreturn the canonicalized `.domain` field.  This is lower-cased and punycode (RFC3490) encoded if the domain has any non-ASCII characters.\n\n.validate()\n-----------\n\nStatus: *IN PROGRESS*. Works for a few things, but is by no means comprehensive.\n\nvalidates cookie attributes for semantic correctness.  Useful for \"lint\" checking any Set-Cookie headers you generate.  For now, it returns a boolean, but eventually could return a reason string -- you can future-proof with this construct:\n\n``` javascript\nif (cookie.validate() === true) {\n  // it's tasty\n} else {\n  // yuck!\n}\n```\n\nCookieJar\n=========\n\nConstruction([store = new MemoryCookieStore()][, rejectPublicSuffixes])\n------------\n\nSimply use `new CookieJar()`.  If you'd like to use a custom store, pass that to the constructor otherwise a `MemoryCookieStore` will be created and used.\n\n\nAttributes\n----------\n\n  * _rejectPublicSuffixes_ - boolean - reject cookies with domains like \"com\" and \"co.uk\" (default: `true`)\n\nSince eventually this module would like to support database/remote/etc. CookieJars, continuation passing style is used for CookieJar methods.\n\n.setCookie(cookieOrString, currentUrl, [{options},] cb(err,cookie))\n-------------------------------------------------------------------\n\nAttempt to set the cookie in the cookie jar.  If the operation fails, an error will be given to the callback `cb`, otherwise the cookie is passed through.  The cookie will have updated `.created`, `.lastAccessed` and `.hostOnly` properties.\n\nThe `options` object can be omitted and can have the following properties:\n\n  * _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API.  Affects HttpOnly cookies.\n  * _secure_ - boolean - autodetect from url - indicates if this is a \"Secure\" API.  If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.\n  * _now_ - Date - default `new Date()` - what to use for the creation/access time of cookies\n  * _strict_ - boolean - default `false` - perform extra checks\n  * _ignoreError_ - boolean - default `false` - silently ignore things like parse errors and invalid domains.  CookieStore errors aren't ignored by this option.\n\nAs per the RFC, the `.hostOnly` property is set if there was no \"Domain=\" parameter in the cookie string (or `.domain` was null on the Cookie object).  The `.domain` property is set to the fully-qualified hostname of `currentUrl` in this case.  Matching this cookie requires an exact hostname match (not a `domainMatch` as per usual).\n\n.setCookieSync(cookieOrString, currentUrl, [{options}])\n-------------------------------------------------------\n\nSynchronous version of `setCookie`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).\n\n.storeCookie(cookie, [{options},] cb(err,cookie))\n-------------------------------------------------\n\n__REMOVED__ removed in lieu of the CookieStore API below\n\n.getCookies(currentUrl, [{options},] cb(err,cookies))\n-----------------------------------------------------\n\nRetrieve the list of cookies that can be sent in a Cookie header for the current url.\n\nIf an error is encountered, that's passed as `err` to the callback, otherwise an `Array` of `Cookie` objects is passed.  The array is sorted with `cookieCompare()` unless the `{sort:false}` option is given.\n\nThe `options` object can be omitted and can have the following properties:\n\n  * _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API.  Affects HttpOnly cookies.\n  * _secure_ - boolean - autodetect from url - indicates if this is a \"Secure\" API.  If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.\n  * _now_ - Date - default `new Date()` - what to use for the creation/access time of cookies\n  * _expire_ - boolean - default `true` - perform expiry-time checking of cookies and asynchronously remove expired cookies from the store.  Using `false` will return expired cookies and **not** remove them from the store (which is useful for replaying Set-Cookie headers, potentially).\n  * _allPaths_ - boolean - default `false` - if `true`, do not scope cookies by path. The default uses RFC-compliant path scoping. **Note**: may not be supported by the CookieStore `fetchCookies` function (the default MemoryCookieStore supports it).\n\nThe `.lastAccessed` property of the returned cookies will have been updated.\n\n.getCookiesSync(currentUrl, [{options}])\n----------------------------------------\n\nSynchronous version of `getCookies`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).\n\n.getCookieString(...)\n---------------------\n\nAccepts the same options as `.getCookies()` but passes a string suitable for a Cookie header rather than an array to the callback.  Simply maps the `Cookie` array via `.cookieString()`.\n\n.getCookieStringSync(...)\n-------------------------\n\nSynchronous version of `getCookieString`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).\n\n.getSetCookieStrings(...)\n-------------------------\n\nReturns an array of strings suitable for **Set-Cookie** headers. Accepts the same options as `.getCookies()`.  Simply maps the cookie array via `.toString()`.\n\n.getSetCookieStringsSync(...)\n-----------------------------\n\nSynchronous version of `getSetCookieStrings`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).\n\nStore\n=====\n\nBase class for CookieJar stores.\n\n# CookieStore API\n\nThe storage model for each `CookieJar` instance can be replaced with a custom implementation.  The default is `MemoryCookieStore` which can be found in the `lib/memstore.js` file.  The API uses continuation-passing-style to allow for asynchronous stores.\n\nStores should inherit from the base `Store` class, which is available as `require('tough-cookie').Store`.  Stores are asynchronous by default, but if `store.synchronous` is set, then the `*Sync` methods on the CookieJar can be used.\n\nAll `domain` parameters will have been normalized before calling.\n\nThe Cookie store must have all of the following methods.\n\nstore.findCookie(domain, path, key, cb(err,cookie))\n---------------------------------------------------\n\nRetrieve a cookie with the given domain, path and key (a.k.a. name).  The RFC maintains that exactly one of these cookies should exist in a store.  If the store is using versioning, this means that the latest/newest such cookie should be returned.\n\nCallback takes an error and the resulting `Cookie` object.  If no cookie is found then `null` MUST be passed instead (i.e. not an error).\n\nstore.findCookies(domain, path, cb(err,cookies))\n------------------------------------------------\n\nLocates cookies matching the given domain and path.  This is most often called in the context of `cookiejar.getCookies()` above.\n\nIf no cookies are found, the callback MUST be passed an empty array.\n\nThe resulting list will be checked for applicability to the current request according to the RFC (domain-match, path-match, http-only-flag, secure-flag, expiry, etc.), so it's OK to use an optimistic search algorithm when implementing this method.  However, the search algorithm used SHOULD try to find cookies that `domainMatch()` the domain and `pathMatch()` the path in order to limit the amount of checking that needs to be done.\n\nAs of version 0.9.12, the `allPaths` option to `cookiejar.getCookies()` above will cause the path here to be `null`.  If the path is `null`, path-matching MUST NOT be performed (i.e. domain-matching only).\n\nstore.putCookie(cookie, cb(err))\n--------------------------------\n\nAdds a new cookie to the store.  The implementation SHOULD replace any existing cookie with the same `.domain`, `.path`, and `.key` properties -- depending on the nature of the implementation, it's possible that between the call to `fetchCookie` and `putCookie` that a duplicate `putCookie` can occur.\n\nThe `cookie` object MUST NOT be modified; the caller will have already updated the `.creation` and `.lastAccessed` properties.\n\nPass an error if the cookie cannot be stored.\n\nstore.updateCookie(oldCookie, newCookie, cb(err))\n-------------------------------------------------\n\nUpdate an existing cookie.  The implementation MUST update the `.value` for a cookie with the same `domain`, `.path` and `.key`.  The implementation SHOULD check that the old value in the store is equivalent to `oldCookie` - how the conflict is resolved is up to the store.\n\nThe `.lastAccessed` property will always be different between the two objects and `.created` will always be the same.  Stores MAY ignore or defer the `.lastAccessed` change at the cost of affecting how cookies are sorted (or selected for deletion).\n\nStores may wish to optimize changing the `.value` of the cookie in the store versus storing a new cookie.  If the implementation doesn't define this method a stub that calls `putCookie(newCookie,cb)` will be added to the store object.\n\nThe `newCookie` and `oldCookie` objects MUST NOT be modified.\n\nPass an error if the newCookie cannot be stored.\n\nstore.removeCookie(domain, path, key, cb(err))\n----------------------------------------------\n\nRemove a cookie from the store (see notes on `findCookie` about the uniqueness constraint).\n\nThe implementation MUST NOT pass an error if the cookie doesn't exist; only pass an error due to the failure to remove an existing cookie.\n\nstore.removeCookies(domain, path, cb(err))\n------------------------------------------\n\nRemoves matching cookies from the store.  The `path` paramter is optional, and if missing means all paths in a domain should be removed.\n\nPass an error ONLY if removing any existing cookies failed.\n\n# TODO\n\n  * _full_ RFC5890/RFC5891 canonicalization for domains in `cdomain()`\n    * the optional `punycode` requirement implements RFC3492, but RFC6265 requires RFC5891\n  * better tests for `validate()`?\n\n# Copyright and License\n\n(tl;dr: MIT with some MPL/1.1)\n\nCopyright 2012- GoInstant, Inc. and other contributors. All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\nPortions may be licensed under different licenses (in particular public-suffix.txt is MPL/1.1); please read the LICENSE file for full details.\n",
+  "readmeFilename": "README.md",
+  "_id": "tough-cookie@0.12.1",
+  "_from": "tough-cookie@>=0.12.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/public-suffix.txt
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/public-suffix.txt	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/public-suffix.txt	(revision 517)
@@ -0,0 +1,5236 @@
+// ***** BEGIN LICENSE BLOCK *****
+// Version: MPL 1.1/GPL 2.0/LGPL 2.1
+// 
+// The contents of this file are subject to the Mozilla Public License Version 
+// 1.1 (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.mozilla.org/MPL/
+// 
+// Software distributed under the License is distributed on an "AS IS" basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+// for the specific language governing rights and limitations under the
+// License.
+// 
+// The Original Code is the Public Suffix List.
+// 
+// The Initial Developer of the Original Code is
+// Jo Hermans <jo.hermans@gmail.com>.
+// Portions created by the Initial Developer are Copyright (C) 2007
+// the Initial Developer. All Rights Reserved.
+// 
+// Contributor(s):
+//   Ruben Arakelyan <ruben@rubenarakelyan.com>
+//   Gervase Markham <gerv@gerv.net>
+//   Pamela Greene <pamg.bugs@gmail.com>
+//   David Triendl <david@triendl.name>
+//   Jothan Frakes <jothan@gmail.com>
+//   The kind representatives of many TLD registries
+// 
+// Alternatively, the contents of this file may be used under the terms of
+// either the GNU General Public License Version 2 or later (the "GPL"), or
+// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+// in which case the provisions of the GPL or the LGPL are applicable instead
+// of those above. If you wish to allow use of your version of this file only
+// under the terms of either the GPL or the LGPL, and not to allow others to
+// use your version of this file under the terms of the MPL, indicate your
+// decision by deleting the provisions above and replace them with the notice
+// and other provisions required by the GPL or the LGPL. If you do not delete
+// the provisions above, a recipient may use your version of this file under
+// the terms of any one of the MPL, the GPL or the LGPL.
+// 
+// ***** END LICENSE BLOCK *****
+
+// ===BEGIN ICANN DOMAINS===
+
+// ac : http://en.wikipedia.org/wiki/.ac
+ac
+com.ac
+edu.ac
+gov.ac
+net.ac
+mil.ac
+org.ac
+
+// ad : http://en.wikipedia.org/wiki/.ad
+ad
+nom.ad
+
+// ae : http://en.wikipedia.org/wiki/.ae
+// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php
+ae
+co.ae
+net.ae
+org.ae
+sch.ae
+ac.ae
+gov.ae
+mil.ae
+
+// aero : see http://www.information.aero/index.php?id=66
+aero
+accident-investigation.aero
+accident-prevention.aero
+aerobatic.aero
+aeroclub.aero
+aerodrome.aero
+agents.aero
+aircraft.aero
+airline.aero
+airport.aero
+air-surveillance.aero
+airtraffic.aero
+air-traffic-control.aero
+ambulance.aero
+amusement.aero
+association.aero
+author.aero
+ballooning.aero
+broker.aero
+caa.aero
+cargo.aero
+catering.aero
+certification.aero
+championship.aero
+charter.aero
+civilaviation.aero
+club.aero
+conference.aero
+consultant.aero
+consulting.aero
+control.aero
+council.aero
+crew.aero
+design.aero
+dgca.aero
+educator.aero
+emergency.aero
+engine.aero
+engineer.aero
+entertainment.aero
+equipment.aero
+exchange.aero
+express.aero
+federation.aero
+flight.aero
+freight.aero
+fuel.aero
+gliding.aero
+government.aero
+groundhandling.aero
+group.aero
+hanggliding.aero
+homebuilt.aero
+insurance.aero
+journal.aero
+journalist.aero
+leasing.aero
+logistics.aero
+magazine.aero
+maintenance.aero
+marketplace.aero
+media.aero
+microlight.aero
+modelling.aero
+navigation.aero
+parachuting.aero
+paragliding.aero
+passenger-association.aero
+pilot.aero
+press.aero
+production.aero
+recreation.aero
+repbody.aero
+res.aero
+research.aero
+rotorcraft.aero
+safety.aero
+scientist.aero
+services.aero
+show.aero
+skydiving.aero
+software.aero
+student.aero
+taxi.aero
+trader.aero
+trading.aero
+trainer.aero
+union.aero
+workinggroup.aero
+works.aero
+
+// af : http://www.nic.af/help.jsp
+af
+gov.af
+com.af
+org.af
+net.af
+edu.af
+
+// ag : http://www.nic.ag/prices.htm
+ag
+com.ag
+org.ag
+net.ag
+co.ag
+nom.ag
+
+// ai : http://nic.com.ai/
+ai
+off.ai
+com.ai
+net.ai
+org.ai
+
+// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31
+al
+com.al
+edu.al
+gov.al
+mil.al
+net.al
+org.al
+
+// am : http://en.wikipedia.org/wiki/.am
+am
+
+// an : http://www.una.an/an_domreg/default.asp
+an
+com.an
+net.an
+org.an
+edu.an
+
+// ao : http://en.wikipedia.org/wiki/.ao
+// http://www.dns.ao/REGISTR.DOC
+ao
+ed.ao
+gv.ao
+og.ao
+co.ao
+pb.ao
+it.ao
+
+// aq : http://en.wikipedia.org/wiki/.aq
+aq
+
+// ar : http://en.wikipedia.org/wiki/.ar
+*.ar
+!congresodelalengua3.ar
+!educ.ar
+!gobiernoelectronico.ar
+!mecon.ar
+!nacion.ar
+!nic.ar
+!promocion.ar
+!retina.ar
+!uba.ar
+
+// arpa : http://en.wikipedia.org/wiki/.arpa
+// Confirmed by registry <iana-questions@icann.org> 2008-06-18
+e164.arpa
+in-addr.arpa
+ip6.arpa
+iris.arpa
+uri.arpa
+urn.arpa
+
+// as : http://en.wikipedia.org/wiki/.as
+as
+gov.as
+
+// asia : http://en.wikipedia.org/wiki/.asia
+asia
+
+// at : http://en.wikipedia.org/wiki/.at
+// Confirmed by registry <it@nic.at> 2008-06-17
+at
+ac.at
+co.at
+gv.at
+or.at
+
+// au : http://en.wikipedia.org/wiki/.au
+// http://www.auda.org.au/
+// 2LDs
+com.au
+net.au
+org.au
+edu.au
+gov.au
+csiro.au
+asn.au
+id.au
+// Historic 2LDs (closed to new registration, but sites still exist)
+info.au
+conf.au
+oz.au
+// CGDNs - http://www.cgdn.org.au/
+act.au
+nsw.au
+nt.au
+qld.au
+sa.au
+tas.au
+vic.au
+wa.au
+// 3LDs
+act.edu.au
+nsw.edu.au
+nt.edu.au
+qld.edu.au
+sa.edu.au
+tas.edu.au
+vic.edu.au
+wa.edu.au
+act.gov.au
+// Removed at request of Shae.Donelan@services.nsw.gov.au, 2010-03-04
+// nsw.gov.au
+nt.gov.au
+qld.gov.au
+sa.gov.au
+tas.gov.au
+vic.gov.au
+wa.gov.au
+
+// aw : http://en.wikipedia.org/wiki/.aw
+aw
+com.aw
+
+// ax : http://en.wikipedia.org/wiki/.ax
+ax
+
+// az : http://en.wikipedia.org/wiki/.az
+az
+com.az
+net.az
+int.az
+gov.az
+org.az
+edu.az
+info.az
+pp.az
+mil.az
+name.az
+pro.az
+biz.az
+
+// ba : http://en.wikipedia.org/wiki/.ba
+ba
+org.ba
+net.ba
+edu.ba
+gov.ba
+mil.ba
+unsa.ba
+unbi.ba
+co.ba
+com.ba
+rs.ba
+
+// bb : http://en.wikipedia.org/wiki/.bb
+bb
+biz.bb
+com.bb
+edu.bb
+gov.bb
+info.bb
+net.bb
+org.bb
+store.bb
+
+// bd : http://en.wikipedia.org/wiki/.bd
+*.bd
+
+// be : http://en.wikipedia.org/wiki/.be
+// Confirmed by registry <tech@dns.be> 2008-06-08
+be
+ac.be
+
+// bf : http://en.wikipedia.org/wiki/.bf
+bf
+gov.bf
+
+// bg : http://en.wikipedia.org/wiki/.bg
+// https://www.register.bg/user/static/rules/en/index.html
+bg
+a.bg
+b.bg
+c.bg
+d.bg
+e.bg
+f.bg
+g.bg
+h.bg
+i.bg
+j.bg
+k.bg
+l.bg
+m.bg
+n.bg
+o.bg
+p.bg
+q.bg
+r.bg
+s.bg
+t.bg
+u.bg
+v.bg
+w.bg
+x.bg
+y.bg
+z.bg
+0.bg
+1.bg
+2.bg
+3.bg
+4.bg
+5.bg
+6.bg
+7.bg
+8.bg
+9.bg	 	 	
+
+// bh : http://en.wikipedia.org/wiki/.bh
+bh
+com.bh
+edu.bh
+net.bh
+org.bh
+gov.bh
+
+// bi : http://en.wikipedia.org/wiki/.bi
+// http://whois.nic.bi/
+bi
+co.bi
+com.bi
+edu.bi
+or.bi
+org.bi
+
+// biz : http://en.wikipedia.org/wiki/.biz
+biz
+
+// bj : http://en.wikipedia.org/wiki/.bj
+bj
+asso.bj
+barreau.bj
+gouv.bj
+
+// bm : http://www.bermudanic.bm/dnr-text.txt
+bm
+com.bm
+edu.bm
+gov.bm
+net.bm
+org.bm
+
+// bn : http://en.wikipedia.org/wiki/.bn
+*.bn
+
+// bo : http://www.nic.bo/
+bo
+com.bo
+edu.bo
+gov.bo
+gob.bo
+int.bo
+org.bo
+net.bo
+mil.bo
+tv.bo
+
+// br : http://registro.br/dominio/dpn.html
+// Updated by registry <fneves@registro.br> 2011-03-01
+br
+adm.br
+adv.br
+agr.br
+am.br
+arq.br
+art.br
+ato.br
+b.br
+bio.br
+blog.br
+bmd.br
+can.br
+cim.br
+cng.br
+cnt.br
+com.br
+coop.br
+ecn.br
+edu.br
+emp.br
+eng.br
+esp.br
+etc.br
+eti.br
+far.br
+flog.br
+fm.br
+fnd.br
+fot.br
+fst.br
+g12.br
+ggf.br
+gov.br
+imb.br
+ind.br
+inf.br
+jor.br
+jus.br
+lel.br
+mat.br
+med.br
+mil.br
+mus.br
+net.br
+nom.br
+not.br
+ntr.br
+odo.br
+org.br
+ppg.br
+pro.br
+psc.br
+psi.br
+qsl.br
+radio.br
+rec.br
+slg.br
+srv.br
+taxi.br
+teo.br
+tmp.br
+trd.br
+tur.br
+tv.br
+vet.br
+vlog.br
+wiki.br
+zlg.br
+
+// bs : http://www.nic.bs/rules.html
+bs
+com.bs
+net.bs
+org.bs
+edu.bs
+gov.bs
+
+// bt : http://en.wikipedia.org/wiki/.bt
+bt
+com.bt
+edu.bt
+gov.bt
+net.bt
+org.bt
+
+// bv : No registrations at this time.
+// Submitted by registry <jarle@uninett.no> 2006-06-16
+
+// bw : http://en.wikipedia.org/wiki/.bw
+// http://www.gobin.info/domainname/bw.doc
+// list of other 2nd level tlds ?
+bw
+co.bw
+org.bw
+
+// by : http://en.wikipedia.org/wiki/.by
+// http://tld.by/rules_2006_en.html
+// list of other 2nd level tlds ?
+by
+gov.by
+mil.by
+// Official information does not indicate that com.by is a reserved
+// second-level domain, but it's being used as one (see www.google.com.by and
+// www.yahoo.com.by, for example), so we list it here for safety's sake.
+com.by
+
+// http://hoster.by/
+of.by
+
+// bz : http://en.wikipedia.org/wiki/.bz
+// http://www.belizenic.bz/
+bz
+com.bz
+net.bz
+org.bz
+edu.bz
+gov.bz
+
+// ca : http://en.wikipedia.org/wiki/.ca
+ca
+// ca geographical names
+ab.ca
+bc.ca
+mb.ca
+nb.ca
+nf.ca
+nl.ca
+ns.ca
+nt.ca
+nu.ca
+on.ca
+pe.ca
+qc.ca
+sk.ca
+yk.ca
+// gc.ca: http://en.wikipedia.org/wiki/.gc.ca
+// see also: http://registry.gc.ca/en/SubdomainFAQ
+gc.ca
+
+// cat : http://en.wikipedia.org/wiki/.cat
+cat
+
+// cc : http://en.wikipedia.org/wiki/.cc
+cc
+
+// cd : http://en.wikipedia.org/wiki/.cd
+// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1
+cd
+gov.cd
+
+// cf : http://en.wikipedia.org/wiki/.cf
+cf
+
+// cg : http://en.wikipedia.org/wiki/.cg
+cg
+
+// ch : http://en.wikipedia.org/wiki/.ch
+ch
+
+// ci : http://en.wikipedia.org/wiki/.ci
+// http://www.nic.ci/index.php?page=charte
+ci
+org.ci
+or.ci
+com.ci
+co.ci
+edu.ci
+ed.ci
+ac.ci
+net.ci
+go.ci
+asso.ci
+aÃ©roport.ci
+int.ci
+presse.ci
+md.ci
+gouv.ci
+
+// ck : http://en.wikipedia.org/wiki/.ck
+*.ck
+!www.ck
+
+// cl : http://en.wikipedia.org/wiki/.cl
+cl
+gov.cl
+gob.cl
+co.cl
+mil.cl
+
+// cm : http://en.wikipedia.org/wiki/.cm
+cm
+gov.cm
+
+// cn : http://en.wikipedia.org/wiki/.cn
+// Submitted by registry <tanyaling@cnnic.cn> 2008-06-11
+cn
+ac.cn
+com.cn
+edu.cn
+gov.cn
+net.cn
+org.cn
+mil.cn
+å
+¬åž.cn
+çœç».cn
+ç¶²çµ¡.cn
+// cn geographic names
+ah.cn
+bj.cn
+cq.cn
+fj.cn
+gd.cn
+gs.cn
+gz.cn
+gx.cn
+ha.cn
+hb.cn
+he.cn
+hi.cn
+hl.cn
+hn.cn
+jl.cn
+js.cn
+jx.cn
+ln.cn
+nm.cn
+nx.cn
+qh.cn
+sc.cn
+sd.cn
+sh.cn
+sn.cn
+sx.cn
+tj.cn
+xj.cn
+xz.cn
+yn.cn
+zj.cn
+hk.cn
+mo.cn
+tw.cn
+
+// co : http://en.wikipedia.org/wiki/.co
+// Submitted by registry <tecnico@uniandes.edu.co> 2008-06-11
+co
+arts.co
+com.co
+edu.co
+firm.co
+gov.co
+info.co
+int.co
+mil.co
+net.co
+nom.co
+org.co
+rec.co
+web.co
+
+// com : http://en.wikipedia.org/wiki/.com
+com
+
+// coop : http://en.wikipedia.org/wiki/.coop
+coop
+
+// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do
+cr
+ac.cr
+co.cr
+ed.cr
+fi.cr
+go.cr
+or.cr
+sa.cr
+
+// cu : http://en.wikipedia.org/wiki/.cu
+cu
+com.cu
+edu.cu
+org.cu
+net.cu
+gov.cu
+inf.cu
+
+// cv : http://en.wikipedia.org/wiki/.cv
+cv
+
+// cx : http://en.wikipedia.org/wiki/.cx
+// list of other 2nd level tlds ?
+cx
+gov.cx
+
+// cy : http://en.wikipedia.org/wiki/.cy
+*.cy
+
+// cz : http://en.wikipedia.org/wiki/.cz
+cz
+
+// de : http://en.wikipedia.org/wiki/.de
+// Confirmed by registry <ops@denic.de> (with technical
+// reservations) 2008-07-01
+de
+
+// dj : http://en.wikipedia.org/wiki/.dj
+dj
+
+// dk : http://en.wikipedia.org/wiki/.dk
+// Confirmed by registry <robert@dk-hostmaster.dk> 2008-06-17
+dk
+
+// dm : http://en.wikipedia.org/wiki/.dm
+dm
+com.dm
+net.dm
+org.dm
+edu.dm
+gov.dm
+
+// do : http://en.wikipedia.org/wiki/.do
+do
+art.do
+com.do
+edu.do
+gob.do
+gov.do
+mil.do
+net.do
+org.do
+sld.do
+web.do
+
+// dz : http://en.wikipedia.org/wiki/.dz
+dz
+com.dz
+org.dz
+net.dz
+gov.dz
+edu.dz
+asso.dz
+pol.dz
+art.dz
+
+// ec : http://www.nic.ec/reg/paso1.asp
+// Submitted by registry <vabboud@nic.ec> 2008-07-04
+ec
+com.ec
+info.ec
+net.ec
+fin.ec
+k12.ec
+med.ec
+pro.ec
+org.ec
+edu.ec
+gov.ec
+gob.ec
+mil.ec
+
+// edu : http://en.wikipedia.org/wiki/.edu
+edu
+
+// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B
+ee
+edu.ee
+gov.ee
+riik.ee
+lib.ee
+med.ee
+com.ee
+pri.ee
+aip.ee
+org.ee
+fie.ee
+
+// eg : http://en.wikipedia.org/wiki/.eg
+eg  
+com.eg
+edu.eg
+eun.eg
+gov.eg
+mil.eg
+name.eg
+net.eg
+org.eg
+sci.eg
+
+// er : http://en.wikipedia.org/wiki/.er
+*.er
+
+// es : https://www.nic.es/site_ingles/ingles/dominios/index.html
+es
+com.es
+nom.es
+org.es
+gob.es
+edu.es
+
+// et : http://en.wikipedia.org/wiki/.et
+*.et
+
+// eu : http://en.wikipedia.org/wiki/.eu
+eu
+
+// fi : http://en.wikipedia.org/wiki/.fi
+fi
+// aland.fi : http://en.wikipedia.org/wiki/.ax
+// This domain is being phased out in favor of .ax. As there are still many
+// domains under aland.fi, we still keep it on the list until aland.fi is
+// completely removed.
+// TODO: Check for updates (expected to be phased out around Q1/2009)
+aland.fi
+
+// fj : http://en.wikipedia.org/wiki/.fj
+*.fj
+
+// fk : http://en.wikipedia.org/wiki/.fk
+*.fk
+
+// fm : http://en.wikipedia.org/wiki/.fm
+fm
+
+// fo : http://en.wikipedia.org/wiki/.fo
+fo
+
+// fr : http://www.afnic.fr/
+// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs
+fr
+com.fr
+asso.fr
+nom.fr
+prd.fr
+presse.fr
+tm.fr
+// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels
+aeroport.fr
+assedic.fr
+avocat.fr
+avoues.fr
+cci.fr
+chambagri.fr
+chirurgiens-dentistes.fr
+experts-comptables.fr
+geometre-expert.fr
+gouv.fr
+greta.fr
+huissier-justice.fr
+medecin.fr
+notaires.fr
+pharmacien.fr
+port.fr
+veterinaire.fr
+
+// ga : http://en.wikipedia.org/wiki/.ga
+ga
+
+// gb : This registry is effectively dormant
+// Submitted by registry <Damien.Shaw@ja.net> 2008-06-12
+
+// gd : http://en.wikipedia.org/wiki/.gd
+gd
+
+// ge : http://www.nic.net.ge/policy_en.pdf
+ge
+com.ge
+edu.ge
+gov.ge
+org.ge
+mil.ge
+net.ge
+pvt.ge
+
+// gf : http://en.wikipedia.org/wiki/.gf
+gf
+
+// gg : http://www.channelisles.net/applic/avextn.shtml
+gg
+co.gg
+org.gg
+net.gg
+sch.gg
+gov.gg
+
+// gh : http://en.wikipedia.org/wiki/.gh
+// see also: http://www.nic.gh/reg_now.php
+// Although domains directly at second level are not possible at the moment,
+// they have been possible for some time and may come back.
+gh
+com.gh
+edu.gh
+gov.gh
+org.gh
+mil.gh
+
+// gi : http://www.nic.gi/rules.html
+gi
+com.gi
+ltd.gi
+gov.gi
+mod.gi
+edu.gi
+org.gi
+
+// gl : http://en.wikipedia.org/wiki/.gl
+// http://nic.gl
+gl
+
+// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm
+gm
+
+// gn : http://psg.com/dns/gn/gn.txt
+// Submitted by registry <randy@psg.com> 2008-06-17
+ac.gn
+com.gn
+edu.gn
+gov.gn
+org.gn
+net.gn
+
+// gov : http://en.wikipedia.org/wiki/.gov
+gov
+
+// gp : http://www.nic.gp/index.php?lang=en
+gp
+com.gp
+net.gp
+mobi.gp
+edu.gp
+org.gp
+asso.gp
+
+// gq : http://en.wikipedia.org/wiki/.gq
+gq
+
+// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html
+// Submitted by registry <segred@ics.forth.gr> 2008-06-09
+gr
+com.gr
+edu.gr
+net.gr
+org.gr
+gov.gr
+
+// gs : http://en.wikipedia.org/wiki/.gs
+gs
+
+// gt : http://www.gt/politicas.html
+*.gt
+!www.gt
+
+// gu : http://gadao.gov.gu/registration.txt
+*.gu
+
+// gw : http://en.wikipedia.org/wiki/.gw
+gw
+
+// gy : http://en.wikipedia.org/wiki/.gy
+// http://registry.gy/
+gy
+co.gy
+com.gy
+net.gy
+
+// hk : https://www.hkdnr.hk
+// Submitted by registry <hk.tech@hkirc.hk> 2008-06-11
+hk
+com.hk
+edu.hk
+gov.hk
+idv.hk
+net.hk
+org.hk
+å
+¬åž.hk
+æè².hk
+æè².hk
+æ¿åº.hk
+åäºº.hk
+äžªäºº.hk
+ç®äºº.hk
+ç¶²ç».hk
+çœç».hk
+ç»ç¹.hk
+ç¶²çµ¡.hk
+çœçµ¡.hk
+ç»ç».hk
+çµç¹.hk
+çµç».hk 
+
+// hm : http://en.wikipedia.org/wiki/.hm
+hm
+
+// hn : http://www.nic.hn/politicas/ps02,,05.html
+hn
+com.hn
+edu.hn
+org.hn
+net.hn
+mil.hn
+gob.hn
+
+// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf
+hr
+iz.hr
+from.hr
+name.hr
+com.hr
+
+// ht : http://www.nic.ht/info/charte.cfm
+ht
+com.ht
+shop.ht
+firm.ht
+info.ht
+adult.ht
+net.ht
+pro.ht
+org.ht
+med.ht
+art.ht
+coop.ht
+pol.ht
+asso.ht
+edu.ht
+rel.ht
+gouv.ht
+perso.ht
+
+// hu : http://www.domain.hu/domain/English/sld.html
+// Confirmed by registry <pasztor@iszt.hu> 2008-06-12
+hu
+co.hu
+info.hu
+org.hu
+priv.hu
+sport.hu
+tm.hu
+2000.hu
+agrar.hu
+bolt.hu
+casino.hu
+city.hu
+erotica.hu
+erotika.hu
+film.hu
+forum.hu
+games.hu
+hotel.hu
+ingatlan.hu
+jogasz.hu
+konyvelo.hu
+lakas.hu
+media.hu
+news.hu
+reklam.hu
+sex.hu
+shop.hu
+suli.hu
+szex.hu
+tozsde.hu
+utazas.hu
+video.hu
+
+// id : http://en.wikipedia.org/wiki/.id
+// see also: https://register.pandi.or.id/
+id
+ac.id
+co.id
+go.id
+mil.id
+net.id
+or.id
+sch.id
+web.id
+
+// ie : http://en.wikipedia.org/wiki/.ie
+ie
+gov.ie
+
+// il : http://en.wikipedia.org/wiki/.il
+*.il
+
+// im : https://www.nic.im/pdfs/imfaqs.pdf
+im
+co.im
+ltd.co.im
+plc.co.im
+net.im
+gov.im
+org.im
+nic.im
+ac.im
+
+// in : http://en.wikipedia.org/wiki/.in
+// see also: http://www.inregistry.in/policies/
+// Please note, that nic.in is not an offical eTLD, but used by most
+// government institutions.
+in
+co.in
+firm.in
+net.in
+org.in
+gen.in
+ind.in
+nic.in
+ac.in
+edu.in
+res.in
+gov.in
+mil.in
+
+// info : http://en.wikipedia.org/wiki/.info
+info
+
+// int : http://en.wikipedia.org/wiki/.int
+// Confirmed by registry <iana-questions@icann.org> 2008-06-18
+int
+eu.int
+
+// io : http://www.nic.io/rules.html
+// list of other 2nd level tlds ?
+io
+com.io
+
+// iq : http://www.cmc.iq/english/iq/iqregister1.htm
+iq
+gov.iq
+edu.iq
+mil.iq
+com.iq
+org.iq
+net.iq
+
+// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules
+// Also see http://www.nic.ir/Internationalized_Domain_Names
+// Two <iran>.ir entries added at request of <tech-team@nic.ir>, 2010-04-16
+ir
+ac.ir
+co.ir
+gov.ir
+id.ir
+net.ir
+org.ir
+sch.ir
+// xn--mgba3a4f16a.ir (<iran>.ir, Persian YEH)
+Ø§ÛØ±Ø§Ù.ir
+// xn--mgba3a4fra.ir (<iran>.ir, Arabic YEH)
+Ø§ÙØ±Ø§Ù.ir
+
+// is : http://www.isnic.is/domain/rules.php
+// Confirmed by registry <marius@isgate.is> 2008-12-06
+is
+net.is
+com.is
+edu.is
+gov.is
+org.is
+int.is
+
+// it : http://en.wikipedia.org/wiki/.it
+it
+gov.it
+edu.it
+// list of reserved geo-names : 
+// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf
+// (There is also a list of reserved geo-names corresponding to Italian 
+// municipalities : http://www.nic.it/documenti/appendice-c.pdf , but it is
+// not included here.)
+agrigento.it
+ag.it
+alessandria.it
+al.it
+ancona.it
+an.it
+aosta.it
+aoste.it
+ao.it
+arezzo.it
+ar.it
+ascoli-piceno.it
+ascolipiceno.it
+ap.it
+asti.it
+at.it
+avellino.it
+av.it
+bari.it
+ba.it
+andria-barletta-trani.it
+andriabarlettatrani.it
+trani-barletta-andria.it
+tranibarlettaandria.it
+barletta-trani-andria.it
+barlettatraniandria.it
+andria-trani-barletta.it
+andriatranibarletta.it
+trani-andria-barletta.it
+traniandriabarletta.it
+bt.it
+belluno.it
+bl.it
+benevento.it
+bn.it
+bergamo.it
+bg.it
+biella.it
+bi.it
+bologna.it
+bo.it
+bolzano.it
+bozen.it
+balsan.it
+alto-adige.it
+altoadige.it
+suedtirol.it
+bz.it
+brescia.it
+bs.it
+brindisi.it
+br.it
+cagliari.it
+ca.it
+caltanissetta.it
+cl.it
+campobasso.it
+cb.it
+carboniaiglesias.it
+carbonia-iglesias.it
+iglesias-carbonia.it
+iglesiascarbonia.it
+ci.it
+caserta.it
+ce.it
+catania.it
+ct.it
+catanzaro.it
+cz.it
+chieti.it
+ch.it
+como.it
+co.it
+cosenza.it
+cs.it
+cremona.it
+cr.it
+crotone.it
+kr.it
+cuneo.it
+cn.it
+dell-ogliastra.it
+dellogliastra.it
+ogliastra.it
+og.it
+enna.it
+en.it
+ferrara.it
+fe.it
+fermo.it
+fm.it
+firenze.it
+florence.it
+fi.it
+foggia.it
+fg.it
+forli-cesena.it
+forlicesena.it
+cesena-forli.it
+cesenaforli.it
+fc.it
+frosinone.it
+fr.it
+genova.it
+genoa.it
+ge.it
+gorizia.it
+go.it
+grosseto.it
+gr.it
+imperia.it
+im.it
+isernia.it
+is.it
+laquila.it
+aquila.it
+aq.it
+la-spezia.it
+laspezia.it
+sp.it
+latina.it
+lt.it
+lecce.it
+le.it
+lecco.it
+lc.it
+livorno.it
+li.it
+lodi.it
+lo.it
+lucca.it
+lu.it
+macerata.it
+mc.it
+mantova.it
+mn.it
+massa-carrara.it
+massacarrara.it
+carrara-massa.it
+carraramassa.it
+ms.it
+matera.it
+mt.it
+medio-campidano.it
+mediocampidano.it
+campidano-medio.it
+campidanomedio.it
+vs.it
+messina.it
+me.it
+milano.it
+milan.it
+mi.it
+modena.it
+mo.it
+monza.it
+monza-brianza.it
+monzabrianza.it
+monzaebrianza.it
+monzaedellabrianza.it
+monza-e-della-brianza.it
+mb.it
+napoli.it
+naples.it
+na.it
+novara.it
+no.it
+nuoro.it
+nu.it
+oristano.it
+or.it
+padova.it
+padua.it
+pd.it
+palermo.it
+pa.it
+parma.it
+pr.it
+pavia.it
+pv.it
+perugia.it
+pg.it
+pescara.it
+pe.it
+pesaro-urbino.it
+pesarourbino.it
+urbino-pesaro.it
+urbinopesaro.it
+pu.it
+piacenza.it
+pc.it
+pisa.it
+pi.it
+pistoia.it
+pt.it
+pordenone.it
+pn.it
+potenza.it
+pz.it
+prato.it
+po.it
+ragusa.it
+rg.it
+ravenna.it
+ra.it
+reggio-calabria.it
+reggiocalabria.it
+rc.it
+reggio-emilia.it
+reggioemilia.it
+re.it
+rieti.it
+ri.it
+rimini.it
+rn.it
+roma.it
+rome.it
+rm.it
+rovigo.it
+ro.it
+salerno.it
+sa.it
+sassari.it
+ss.it
+savona.it
+sv.it
+siena.it
+si.it
+siracusa.it
+sr.it
+sondrio.it
+so.it
+taranto.it
+ta.it
+tempio-olbia.it
+tempioolbia.it
+olbia-tempio.it
+olbiatempio.it
+ot.it
+teramo.it
+te.it
+terni.it
+tr.it
+torino.it
+turin.it
+to.it
+trapani.it
+tp.it
+trento.it
+trentino.it
+tn.it
+treviso.it
+tv.it
+trieste.it
+ts.it
+udine.it
+ud.it
+varese.it
+va.it
+venezia.it
+venice.it
+ve.it
+verbania.it
+vb.it
+vercelli.it
+vc.it
+verona.it
+vr.it
+vibo-valentia.it
+vibovalentia.it
+vv.it
+vicenza.it
+vi.it
+viterbo.it
+vt.it
+
+// je : http://www.channelisles.net/applic/avextn.shtml
+je
+co.je
+org.je
+net.je
+sch.je
+gov.je
+
+// jm : http://www.com.jm/register.html
+*.jm
+
+// jo : http://www.dns.jo/Registration_policy.aspx
+jo
+com.jo
+org.jo
+net.jo
+edu.jo
+sch.jo
+gov.jo
+mil.jo
+name.jo
+
+// jobs : http://en.wikipedia.org/wiki/.jobs
+jobs
+
+// jp : http://en.wikipedia.org/wiki/.jp
+// http://jprs.co.jp/en/jpdomain.html
+// Submitted by registry <yone@jprs.co.jp> 2008-06-11
+// Updated by registry <yone@jprs.co.jp> 2008-12-04
+jp
+// jp organizational type names 
+ac.jp
+ad.jp
+co.jp
+ed.jp
+go.jp
+gr.jp
+lg.jp
+ne.jp
+or.jp
+// jp geographic type names
+// http://jprs.jp/doc/rule/saisoku-1.html
+*.aichi.jp
+*.akita.jp
+*.aomori.jp
+*.chiba.jp
+*.ehime.jp
+*.fukui.jp
+*.fukuoka.jp
+*.fukushima.jp
+*.gifu.jp
+*.gunma.jp
+*.hiroshima.jp
+*.hokkaido.jp
+*.hyogo.jp
+*.ibaraki.jp
+*.ishikawa.jp
+*.iwate.jp
+*.kagawa.jp
+*.kagoshima.jp
+*.kanagawa.jp
+*.kawasaki.jp
+*.kitakyushu.jp
+*.kobe.jp
+*.kochi.jp
+*.kumamoto.jp
+*.kyoto.jp
+*.mie.jp
+*.miyagi.jp
+*.miyazaki.jp
+*.nagano.jp
+*.nagasaki.jp
+*.nagoya.jp
+*.nara.jp
+*.niigata.jp
+*.oita.jp
+*.okayama.jp
+*.okinawa.jp
+*.osaka.jp
+*.saga.jp
+*.saitama.jp
+*.sapporo.jp
+*.sendai.jp
+*.shiga.jp
+*.shimane.jp
+*.shizuoka.jp
+*.tochigi.jp
+*.tokushima.jp
+*.tokyo.jp
+*.tottori.jp
+*.toyama.jp
+*.wakayama.jp
+*.yamagata.jp
+*.yamaguchi.jp
+*.yamanashi.jp
+*.yokohama.jp
+!metro.tokyo.jp
+!pref.aichi.jp
+!pref.akita.jp
+!pref.aomori.jp
+!pref.chiba.jp
+!pref.ehime.jp
+!pref.fukui.jp
+!pref.fukuoka.jp
+!pref.fukushima.jp
+!pref.gifu.jp
+!pref.gunma.jp
+!pref.hiroshima.jp
+!pref.hokkaido.jp
+!pref.hyogo.jp
+!pref.ibaraki.jp
+!pref.ishikawa.jp
+!pref.iwate.jp
+!pref.kagawa.jp
+!pref.kagoshima.jp
+!pref.kanagawa.jp
+!pref.kochi.jp
+!pref.kumamoto.jp
+!pref.kyoto.jp
+!pref.mie.jp
+!pref.miyagi.jp
+!pref.miyazaki.jp
+!pref.nagano.jp
+!pref.nagasaki.jp
+!pref.nara.jp
+!pref.niigata.jp
+!pref.oita.jp
+!pref.okayama.jp
+!pref.okinawa.jp
+!pref.osaka.jp
+!pref.saga.jp
+!pref.saitama.jp
+!pref.shiga.jp
+!pref.shimane.jp
+!pref.shizuoka.jp
+!pref.tochigi.jp
+!pref.tokushima.jp
+!pref.tottori.jp
+!pref.toyama.jp
+!pref.wakayama.jp
+!pref.yamagata.jp
+!pref.yamaguchi.jp
+!pref.yamanashi.jp
+!city.chiba.jp
+!city.fukuoka.jp
+!city.hiroshima.jp
+!city.kawasaki.jp
+!city.kitakyushu.jp
+!city.kobe.jp
+!city.kyoto.jp
+!city.nagoya.jp
+!city.niigata.jp
+!city.okayama.jp
+!city.osaka.jp
+!city.saitama.jp
+!city.sapporo.jp
+!city.sendai.jp
+!city.shizuoka.jp
+!city.yokohama.jp
+
+// ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145
+*.ke
+
+// kg : http://www.domain.kg/dmn_n.html
+kg
+org.kg
+net.kg
+com.kg
+edu.kg
+gov.kg
+mil.kg
+
+// kh : http://www.mptc.gov.kh/dns_registration.htm
+*.kh
+
+// ki : http://www.ki/dns/index.html
+ki
+edu.ki
+biz.ki
+net.ki
+org.ki
+gov.ki
+info.ki
+com.ki
+
+// km : http://en.wikipedia.org/wiki/.km
+// http://www.domaine.km/documents/charte.doc
+km
+org.km
+nom.km
+gov.km
+prd.km
+tm.km
+edu.km
+mil.km
+ass.km
+com.km
+// These are only mentioned as proposed suggestions at domaine.km, but
+// http://en.wikipedia.org/wiki/.km says they're available for registration:
+coop.km
+asso.km
+presse.km
+medecin.km
+notaires.km
+pharmaciens.km
+veterinaire.km
+gouv.km
+
+// kn : http://en.wikipedia.org/wiki/.kn
+// http://www.dot.kn/domainRules.html
+kn
+net.kn
+org.kn
+edu.kn
+gov.kn
+
+// kp : http://www.kcce.kp/en_index.php
+com.kp
+edu.kp
+gov.kp
+org.kp
+rep.kp
+tra.kp
+
+// kr : http://en.wikipedia.org/wiki/.kr
+// see also: http://domain.nida.or.kr/eng/registration.jsp
+kr
+ac.kr
+co.kr
+es.kr
+go.kr
+hs.kr
+kg.kr
+mil.kr
+ms.kr
+ne.kr
+or.kr
+pe.kr
+re.kr
+sc.kr
+// kr geographical names
+busan.kr
+chungbuk.kr
+chungnam.kr
+daegu.kr
+daejeon.kr
+gangwon.kr
+gwangju.kr
+gyeongbuk.kr
+gyeonggi.kr
+gyeongnam.kr
+incheon.kr
+jeju.kr
+jeonbuk.kr
+jeonnam.kr
+seoul.kr
+ulsan.kr
+
+// kw : http://en.wikipedia.org/wiki/.kw
+*.kw
+
+// ky : http://www.icta.ky/da_ky_reg_dom.php
+// Confirmed by registry <kysupport@perimeterusa.com> 2008-06-17
+ky
+edu.ky
+gov.ky
+com.ky
+org.ky
+net.ky
+
+// kz : http://en.wikipedia.org/wiki/.kz
+// see also: http://www.nic.kz/rules/index.jsp
+kz
+org.kz
+edu.kz
+net.kz
+gov.kz
+mil.kz
+com.kz
+
+// la : http://en.wikipedia.org/wiki/.la
+// Submitted by registry <gavin.brown@nic.la> 2008-06-10
+la
+int.la
+net.la
+info.la
+edu.la
+gov.la
+per.la
+com.la
+org.la
+
+// lb : http://en.wikipedia.org/wiki/.lb
+// Submitted by registry <randy@psg.com> 2008-06-17
+com.lb
+edu.lb
+gov.lb
+net.lb
+org.lb
+
+// lc : http://en.wikipedia.org/wiki/.lc
+// see also: http://www.nic.lc/rules.htm
+lc
+com.lc
+net.lc
+co.lc
+org.lc
+edu.lc
+gov.lc
+
+// li : http://en.wikipedia.org/wiki/.li
+li
+
+// lk : http://www.nic.lk/seclevpr.html
+lk
+gov.lk
+sch.lk
+net.lk
+int.lk
+com.lk
+org.lk
+edu.lk
+ngo.lk
+soc.lk
+web.lk
+ltd.lk
+assn.lk
+grp.lk
+hotel.lk
+
+// lr : http://psg.com/dns/lr/lr.txt
+// Submitted by registry <randy@psg.com> 2008-06-17
+com.lr
+edu.lr
+gov.lr
+org.lr
+net.lr
+
+// ls : http://en.wikipedia.org/wiki/.ls
+ls
+co.ls
+org.ls
+
+// lt : http://en.wikipedia.org/wiki/.lt
+lt
+// gov.lt : http://www.gov.lt/index_en.php
+gov.lt
+
+// lu : http://www.dns.lu/en/
+lu
+
+// lv : http://www.nic.lv/DNS/En/generic.php
+lv
+com.lv
+edu.lv
+gov.lv
+org.lv
+mil.lv
+id.lv
+net.lv
+asn.lv
+conf.lv
+
+// ly : http://www.nic.ly/regulations.php
+ly
+com.ly
+net.ly
+gov.ly
+plc.ly
+edu.ly
+sch.ly
+med.ly
+org.ly
+id.ly
+
+// ma : http://en.wikipedia.org/wiki/.ma
+// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf
+ma
+co.ma
+net.ma
+gov.ma
+org.ma
+ac.ma
+press.ma
+
+// mc : http://www.nic.mc/
+mc
+tm.mc
+asso.mc
+
+// md : http://en.wikipedia.org/wiki/.md
+md
+
+// me : http://en.wikipedia.org/wiki/.me
+me
+co.me
+net.me
+org.me
+edu.me
+ac.me
+gov.me
+its.me
+priv.me
+
+// mg : http://www.nic.mg/tarif.htm
+mg
+org.mg
+nom.mg
+gov.mg
+prd.mg
+tm.mg
+edu.mg
+mil.mg
+com.mg
+
+// mh : http://en.wikipedia.org/wiki/.mh
+mh
+
+// mil : http://en.wikipedia.org/wiki/.mil
+mil
+
+// mk : http://en.wikipedia.org/wiki/.mk
+// see also: http://dns.marnet.net.mk/postapka.php
+mk
+com.mk
+org.mk
+net.mk
+edu.mk
+gov.mk
+inf.mk
+name.mk
+
+// ml : http://www.gobin.info/domainname/ml-template.doc
+// see also: http://en.wikipedia.org/wiki/.ml
+ml
+com.ml
+edu.ml
+gouv.ml
+gov.ml
+net.ml
+org.ml
+presse.ml
+
+// mm : http://en.wikipedia.org/wiki/.mm
+*.mm
+
+// mn : http://en.wikipedia.org/wiki/.mn
+mn
+gov.mn
+edu.mn
+org.mn
+
+// mo : http://www.monic.net.mo/
+mo
+com.mo
+net.mo
+org.mo
+edu.mo
+gov.mo
+
+// mobi : http://en.wikipedia.org/wiki/.mobi
+mobi
+
+// mp : http://www.dot.mp/
+// Confirmed by registry <dcamacho@saipan.com> 2008-06-17
+mp
+
+// mq : http://en.wikipedia.org/wiki/.mq
+mq
+
+// mr : http://en.wikipedia.org/wiki/.mr
+mr
+gov.mr
+
+// ms : http://en.wikipedia.org/wiki/.ms
+ms
+
+// mt : https://www.nic.org.mt/dotmt/
+*.mt
+
+// mu : http://en.wikipedia.org/wiki/.mu
+mu
+com.mu
+net.mu
+org.mu
+gov.mu
+ac.mu
+co.mu
+or.mu
+
+// museum : http://about.museum/naming/
+// http://index.museum/
+museum
+academy.museum
+agriculture.museum
+air.museum
+airguard.museum
+alabama.museum
+alaska.museum
+amber.museum
+ambulance.museum
+american.museum
+americana.museum
+americanantiques.museum
+americanart.museum
+amsterdam.museum
+and.museum
+annefrank.museum
+anthro.museum
+anthropology.museum
+antiques.museum
+aquarium.museum
+arboretum.museum
+archaeological.museum
+archaeology.museum
+architecture.museum
+art.museum
+artanddesign.museum
+artcenter.museum
+artdeco.museum
+arteducation.museum
+artgallery.museum
+arts.museum
+artsandcrafts.museum
+asmatart.museum
+assassination.museum
+assisi.museum
+association.museum
+astronomy.museum
+atlanta.museum
+austin.museum
+australia.museum
+automotive.museum
+aviation.museum
+axis.museum
+badajoz.museum
+baghdad.museum
+bahn.museum
+bale.museum
+baltimore.museum
+barcelona.museum
+baseball.museum
+basel.museum
+baths.museum
+bauern.museum
+beauxarts.museum
+beeldengeluid.museum
+bellevue.museum
+bergbau.museum
+berkeley.museum
+berlin.museum
+bern.museum
+bible.museum
+bilbao.museum
+bill.museum
+birdart.museum
+birthplace.museum
+bonn.museum
+boston.museum
+botanical.museum
+botanicalgarden.museum
+botanicgarden.museum
+botany.museum
+brandywinevalley.museum
+brasil.museum
+bristol.museum
+british.museum
+britishcolumbia.museum
+broadcast.museum
+brunel.museum
+brussel.museum
+brussels.museum
+bruxelles.museum
+building.museum
+burghof.museum
+bus.museum
+bushey.museum
+cadaques.museum
+california.museum
+cambridge.museum
+can.museum
+canada.museum
+capebreton.museum
+carrier.museum
+cartoonart.museum
+casadelamoneda.museum
+castle.museum
+castres.museum
+celtic.museum
+center.museum
+chattanooga.museum
+cheltenham.museum
+chesapeakebay.museum
+chicago.museum
+children.museum
+childrens.museum
+childrensgarden.museum
+chiropractic.museum
+chocolate.museum
+christiansburg.museum
+cincinnati.museum
+cinema.museum
+circus.museum
+civilisation.museum
+civilization.museum
+civilwar.museum
+clinton.museum
+clock.museum
+coal.museum
+coastaldefence.museum
+cody.museum
+coldwar.museum
+collection.museum
+colonialwilliamsburg.museum
+coloradoplateau.museum
+columbia.museum
+columbus.museum
+communication.museum
+communications.museum
+community.museum
+computer.museum
+computerhistory.museum
+comunicaÃ§Ãµes.museum
+contemporary.museum
+contemporaryart.museum
+convent.museum
+copenhagen.museum
+corporation.museum
+correios-e-telecomunicaÃ§Ãµes.museum
+corvette.museum
+costume.museum
+countryestate.museum
+county.museum
+crafts.museum
+cranbrook.museum
+creation.museum
+cultural.museum
+culturalcenter.museum
+culture.museum
+cyber.museum
+cymru.museum
+dali.museum
+dallas.museum
+database.museum
+ddr.museum
+decorativearts.museum
+delaware.museum
+delmenhorst.museum
+denmark.museum
+depot.museum
+design.museum
+detroit.museum
+dinosaur.museum
+discovery.museum
+dolls.museum
+donostia.museum
+durham.museum
+eastafrica.museum
+eastcoast.museum
+education.museum
+educational.museum
+egyptian.museum
+eisenbahn.museum
+elburg.museum
+elvendrell.museum
+embroidery.museum
+encyclopedic.museum
+england.museum
+entomology.museum
+environment.museum
+environmentalconservation.museum
+epilepsy.museum
+essex.museum
+estate.museum
+ethnology.museum
+exeter.museum
+exhibition.museum
+family.museum
+farm.museum
+farmequipment.museum
+farmers.museum
+farmstead.museum
+field.museum
+figueres.museum
+filatelia.museum
+film.museum
+fineart.museum
+finearts.museum
+finland.museum
+flanders.museum
+florida.museum
+force.museum
+fortmissoula.museum
+fortworth.museum
+foundation.museum
+francaise.museum
+frankfurt.museum
+franziskaner.museum
+freemasonry.museum
+freiburg.museum
+fribourg.museum
+frog.museum
+fundacio.museum
+furniture.museum
+gallery.museum
+garden.museum
+gateway.museum
+geelvinck.museum
+gemological.museum
+geology.museum
+georgia.museum
+giessen.museum
+glas.museum
+glass.museum
+gorge.museum
+grandrapids.museum
+graz.museum
+guernsey.museum
+halloffame.museum
+hamburg.museum
+handson.museum
+harvestcelebration.museum
+hawaii.museum
+health.museum
+heimatunduhren.museum
+hellas.museum
+helsinki.museum
+hembygdsforbund.museum
+heritage.museum
+histoire.museum
+historical.museum
+historicalsociety.museum
+historichouses.museum
+historisch.museum
+historisches.museum
+history.museum
+historyofscience.museum
+horology.museum
+house.museum
+humanities.museum
+illustration.museum
+imageandsound.museum
+indian.museum
+indiana.museum
+indianapolis.museum
+indianmarket.museum
+intelligence.museum
+interactive.museum
+iraq.museum
+iron.museum
+isleofman.museum
+jamison.museum
+jefferson.museum
+jerusalem.museum
+jewelry.museum
+jewish.museum
+jewishart.museum
+jfk.museum
+journalism.museum
+judaica.museum
+judygarland.museum
+juedisches.museum
+juif.museum
+karate.museum
+karikatur.museum
+kids.museum
+koebenhavn.museum
+koeln.museum
+kunst.museum
+kunstsammlung.museum
+kunstunddesign.museum
+labor.museum
+labour.museum
+lajolla.museum
+lancashire.museum
+landes.museum
+lans.museum
+lÃ€ns.museum
+larsson.museum
+lewismiller.museum
+lincoln.museum
+linz.museum
+living.museum
+livinghistory.museum
+localhistory.museum
+london.museum
+losangeles.museum
+louvre.museum
+loyalist.museum
+lucerne.museum
+luxembourg.museum
+luzern.museum
+mad.museum
+madrid.museum
+mallorca.museum
+manchester.museum
+mansion.museum
+mansions.museum
+manx.museum
+marburg.museum
+maritime.museum
+maritimo.museum
+maryland.museum
+marylhurst.museum
+media.museum
+medical.museum
+medizinhistorisches.museum
+meeres.museum
+memorial.museum
+mesaverde.museum
+michigan.museum
+midatlantic.museum
+military.museum
+mill.museum
+miners.museum
+mining.museum
+minnesota.museum
+missile.museum
+missoula.museum
+modern.museum
+moma.museum
+money.museum
+monmouth.museum
+monticello.museum
+montreal.museum
+moscow.museum
+motorcycle.museum
+muenchen.museum
+muenster.museum
+mulhouse.museum
+muncie.museum
+museet.museum
+museumcenter.museum
+museumvereniging.museum
+music.museum
+national.museum
+nationalfirearms.museum
+nationalheritage.museum
+nativeamerican.museum
+naturalhistory.museum
+naturalhistorymuseum.museum
+naturalsciences.museum
+nature.museum
+naturhistorisches.museum
+natuurwetenschappen.museum
+naumburg.museum
+naval.museum
+nebraska.museum
+neues.museum
+newhampshire.museum
+newjersey.museum
+newmexico.museum
+newport.museum
+newspaper.museum
+newyork.museum
+niepce.museum
+norfolk.museum
+north.museum
+nrw.museum
+nuernberg.museum
+nuremberg.museum
+nyc.museum
+nyny.museum
+oceanographic.museum
+oceanographique.museum
+omaha.museum
+online.museum
+ontario.museum
+openair.museum
+oregon.museum
+oregontrail.museum
+otago.museum
+oxford.museum
+pacific.museum
+paderborn.museum
+palace.museum
+paleo.museum
+palmsprings.museum
+panama.museum
+paris.museum
+pasadena.museum
+pharmacy.museum
+philadelphia.museum
+philadelphiaarea.museum
+philately.museum
+phoenix.museum
+photography.museum
+pilots.museum
+pittsburgh.museum
+planetarium.museum
+plantation.museum
+plants.museum
+plaza.museum
+portal.museum
+portland.museum
+portlligat.museum
+posts-and-telecommunications.museum
+preservation.museum
+presidio.museum
+press.museum
+project.museum
+public.museum
+pubol.museum
+quebec.museum
+railroad.museum
+railway.museum
+research.museum
+resistance.museum
+riodejaneiro.museum
+rochester.museum
+rockart.museum
+roma.museum
+russia.museum
+saintlouis.museum
+salem.museum
+salvadordali.museum
+salzburg.museum
+sandiego.museum
+sanfrancisco.museum
+santabarbara.museum
+santacruz.museum
+santafe.museum
+saskatchewan.museum
+satx.museum
+savannahga.museum
+schlesisches.museum
+schoenbrunn.museum
+schokoladen.museum
+school.museum
+schweiz.museum
+science.museum
+scienceandhistory.museum
+scienceandindustry.museum
+sciencecenter.museum
+sciencecenters.museum
+science-fiction.museum
+sciencehistory.museum
+sciences.museum
+sciencesnaturelles.museum
+scotland.museum
+seaport.museum
+settlement.museum
+settlers.museum
+shell.museum
+sherbrooke.museum
+sibenik.museum
+silk.museum
+ski.museum
+skole.museum
+society.museum
+sologne.museum
+soundandvision.museum
+southcarolina.museum
+southwest.museum
+space.museum
+spy.museum
+square.museum
+stadt.museum
+stalbans.museum
+starnberg.museum
+state.museum
+stateofdelaware.museum
+station.museum
+steam.museum
+steiermark.museum
+stjohn.museum
+stockholm.museum
+stpetersburg.museum
+stuttgart.museum
+suisse.museum
+surgeonshall.museum
+surrey.museum
+svizzera.museum
+sweden.museum
+sydney.museum
+tank.museum
+tcm.museum
+technology.museum
+telekommunikation.museum
+television.museum
+texas.museum
+textile.museum
+theater.museum
+time.museum
+timekeeping.museum
+topology.museum
+torino.museum
+touch.museum
+town.museum
+transport.museum
+tree.museum
+trolley.museum
+trust.museum
+trustee.museum
+uhren.museum
+ulm.museum
+undersea.museum
+university.museum
+usa.museum
+usantiques.museum
+usarts.museum
+uscountryestate.museum
+usculture.museum
+usdecorativearts.museum
+usgarden.museum
+ushistory.museum
+ushuaia.museum
+uslivinghistory.museum
+utah.museum
+uvic.museum
+valley.museum
+vantaa.museum
+versailles.museum
+viking.museum
+village.museum
+virginia.museum
+virtual.museum
+virtuel.museum
+vlaanderen.museum
+volkenkunde.museum
+wales.museum
+wallonie.museum
+war.museum
+washingtondc.museum
+watchandclock.museum
+watch-and-clock.museum
+western.museum
+westfalen.museum
+whaling.museum
+wildlife.museum
+williamsburg.museum
+windmill.museum
+workshop.museum
+york.museum
+yorkshire.museum
+yosemite.museum
+youth.museum
+zoological.museum
+zoology.museum
+××š××©×××.museum
+ÐžÐºÐŸÐŒ.museum
+
+// mv : http://en.wikipedia.org/wiki/.mv
+// "mv" included because, contra Wikipedia, google.mv exists.
+mv
+aero.mv
+biz.mv
+com.mv
+coop.mv
+edu.mv
+gov.mv
+info.mv
+int.mv
+mil.mv
+museum.mv
+name.mv
+net.mv
+org.mv
+pro.mv
+
+// mw : http://www.registrar.mw/
+mw
+ac.mw
+biz.mw
+co.mw
+com.mw
+coop.mw
+edu.mw
+gov.mw
+int.mw
+museum.mw
+net.mw
+org.mw
+
+// mx : http://www.nic.mx/
+// Submitted by registry <farias@nic.mx> 2008-06-19
+mx
+com.mx
+org.mx
+gob.mx
+edu.mx
+net.mx
+
+// my : http://www.mynic.net.my/
+my
+com.my
+net.my
+org.my
+gov.my
+edu.my
+mil.my
+name.my
+
+// mz : http://www.gobin.info/domainname/mz-template.doc
+*.mz
+
+// na : http://www.na-nic.com.na/
+// http://www.info.na/domain/
+na
+info.na
+pro.na
+name.na
+school.na
+or.na
+dr.na
+us.na
+mx.na
+ca.na
+in.na
+cc.na
+tv.na
+ws.na
+mobi.na
+co.na
+com.na
+org.na
+
+// name : has 2nd-level tlds, but there's no list of them
+name
+
+// nc : http://www.cctld.nc/
+nc
+asso.nc
+
+// ne : http://en.wikipedia.org/wiki/.ne
+ne
+
+// net : http://en.wikipedia.org/wiki/.net
+net
+
+// nf : http://en.wikipedia.org/wiki/.nf
+nf
+com.nf
+net.nf
+per.nf
+rec.nf
+web.nf
+arts.nf
+firm.nf
+info.nf
+other.nf
+store.nf
+
+// ng : http://psg.com/dns/ng/
+// Submitted by registry <randy@psg.com> 2008-06-17
+ac.ng
+com.ng
+edu.ng
+gov.ng
+net.ng
+org.ng
+
+// ni : http://www.nic.ni/dominios.htm
+*.ni
+
+// nl : http://www.domain-registry.nl/ace.php/c,728,122,,,,Home.html
+// Confirmed by registry <Antoin.Verschuren@sidn.nl> (with technical
+// reservations) 2008-06-08
+nl
+
+// BV.nl will be a registry for dutch BV's (besloten vennootschap)
+bv.nl
+
+// no : http://www.norid.no/regelverk/index.en.html
+// The Norwegian registry has declined to notify us of updates. The web pages
+// referenced below are the official source of the data. There is also an
+// announce mailing list: 
+// https://postlister.uninett.no/sympa/info/norid-diskusjon
+no
+// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html
+fhs.no
+vgs.no
+fylkesbibl.no
+folkebibl.no
+museum.no
+idrett.no
+priv.no
+// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html
+mil.no
+stat.no
+dep.no
+kommune.no
+herad.no
+// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html
+// counties
+aa.no
+ah.no
+bu.no
+fm.no
+hl.no
+hm.no
+jan-mayen.no
+mr.no
+nl.no
+nt.no
+of.no
+ol.no
+oslo.no
+rl.no
+sf.no
+st.no
+svalbard.no
+tm.no
+tr.no
+va.no
+vf.no
+// primary and lower secondary schools per county
+gs.aa.no
+gs.ah.no
+gs.bu.no
+gs.fm.no
+gs.hl.no
+gs.hm.no
+gs.jan-mayen.no
+gs.mr.no
+gs.nl.no
+gs.nt.no
+gs.of.no
+gs.ol.no
+gs.oslo.no
+gs.rl.no
+gs.sf.no
+gs.st.no
+gs.svalbard.no
+gs.tm.no
+gs.tr.no
+gs.va.no
+gs.vf.no
+// cities
+akrehamn.no
+Ã¥krehamn.no
+algard.no
+Ã¥lgÃ¥rd.no
+arna.no
+brumunddal.no
+bryne.no
+bronnoysund.no
+brÃžnnÃžysund.no
+drobak.no
+drÃžbak.no
+egersund.no
+fetsund.no
+floro.no
+florÃž.no
+fredrikstad.no
+hokksund.no
+honefoss.no
+hÃžnefoss.no
+jessheim.no
+jorpeland.no
+jÃžrpeland.no
+kirkenes.no
+kopervik.no
+krokstadelva.no
+langevag.no
+langevÃ¥g.no
+leirvik.no
+mjondalen.no
+mjÃžndalen.no
+mo-i-rana.no
+mosjoen.no
+mosjÃžen.no
+nesoddtangen.no
+orkanger.no
+osoyro.no
+osÃžyro.no
+raholt.no
+rÃ¥holt.no
+sandnessjoen.no
+sandnessjÃžen.no
+skedsmokorset.no
+slattum.no
+spjelkavik.no
+stathelle.no
+stavern.no
+stjordalshalsen.no
+stjÃžrdalshalsen.no
+tananger.no
+tranby.no
+vossevangen.no
+// communities
+afjord.no
+Ã¥fjord.no
+agdenes.no
+al.no
+Ã¥l.no
+alesund.no
+Ã¥lesund.no
+alstahaug.no
+alta.no
+Ã¡ltÃ¡.no
+alaheadju.no
+Ã¡laheadju.no
+alvdal.no
+amli.no
+Ã¥mli.no
+amot.no
+Ã¥mot.no
+andebu.no
+andoy.no
+andÃžy.no
+andasuolo.no
+ardal.no
+Ã¥rdal.no
+aremark.no
+arendal.no
+Ã¥s.no
+aseral.no
+Ã¥seral.no
+asker.no
+askim.no
+askvoll.no
+askoy.no
+askÃžy.no
+asnes.no
+Ã¥snes.no
+audnedaln.no
+aukra.no
+aure.no
+aurland.no
+aurskog-holand.no
+aurskog-hÃžland.no
+austevoll.no
+austrheim.no
+averoy.no
+averÃžy.no
+balestrand.no
+ballangen.no
+balat.no
+bÃ¡lÃ¡t.no
+balsfjord.no
+bahccavuotna.no
+bÃ¡hccavuotna.no
+bamble.no
+bardu.no
+beardu.no
+beiarn.no
+bajddar.no
+bÃ¡jddar.no
+baidar.no
+bÃ¡idÃ¡r.no
+berg.no
+bergen.no
+berlevag.no
+berlevÃ¥g.no
+bearalvahki.no
+bearalvÃ¡hki.no
+bindal.no
+birkenes.no
+bjarkoy.no
+bjarkÃžy.no
+bjerkreim.no
+bjugn.no
+bodo.no
+bodÃž.no
+badaddja.no
+bÃ¥dÃ¥ddjÃ¥.no
+budejju.no
+bokn.no
+bremanger.no
+bronnoy.no
+brÃžnnÃžy.no
+bygland.no
+bykle.no
+barum.no
+bÃŠrum.no
+bo.telemark.no
+bÃž.telemark.no
+bo.nordland.no
+bÃž.nordland.no
+bievat.no
+bievÃ¡t.no
+bomlo.no
+bÃžmlo.no
+batsfjord.no
+bÃ¥tsfjord.no
+bahcavuotna.no
+bÃ¡hcavuotna.no
+dovre.no
+drammen.no
+drangedal.no
+dyroy.no
+dyrÃžy.no
+donna.no
+dÃžnna.no
+eid.no
+eidfjord.no
+eidsberg.no
+eidskog.no
+eidsvoll.no
+eigersund.no
+elverum.no
+enebakk.no
+engerdal.no
+etne.no
+etnedal.no
+evenes.no
+evenassi.no
+evenÃ¡Å¡Å¡i.no
+evje-og-hornnes.no
+farsund.no
+fauske.no
+fuossko.no
+fuoisku.no
+fedje.no
+fet.no
+finnoy.no
+finnÃžy.no
+fitjar.no
+fjaler.no
+fjell.no
+flakstad.no
+flatanger.no
+flekkefjord.no
+flesberg.no
+flora.no
+fla.no
+flÃ¥.no
+folldal.no
+forsand.no
+fosnes.no
+frei.no
+frogn.no
+froland.no
+frosta.no
+frana.no
+frÃŠna.no
+froya.no
+frÃžya.no
+fusa.no
+fyresdal.no
+forde.no
+fÃžrde.no
+gamvik.no
+gangaviika.no
+gÃ¡Ågaviika.no
+gaular.no
+gausdal.no
+gildeskal.no
+gildeskÃ¥l.no
+giske.no
+gjemnes.no
+gjerdrum.no
+gjerstad.no
+gjesdal.no
+gjovik.no
+gjÃžvik.no
+gloppen.no
+gol.no
+gran.no
+grane.no
+granvin.no
+gratangen.no
+grimstad.no
+grong.no
+kraanghke.no
+krÃ¥anghke.no
+grue.no
+gulen.no
+hadsel.no
+halden.no
+halsa.no
+hamar.no
+hamaroy.no
+habmer.no
+hÃ¡bmer.no
+hapmir.no
+hÃ¡pmir.no
+hammerfest.no
+hammarfeasta.no
+hÃ¡mmÃ¡rfeasta.no
+haram.no
+hareid.no
+harstad.no
+hasvik.no
+aknoluokta.no
+Ã¡kÅoluokta.no
+hattfjelldal.no
+aarborte.no
+haugesund.no
+hemne.no
+hemnes.no
+hemsedal.no
+heroy.more-og-romsdal.no
+herÃžy.mÃžre-og-romsdal.no
+heroy.nordland.no
+herÃžy.nordland.no
+hitra.no
+hjartdal.no
+hjelmeland.no
+hobol.no
+hobÃžl.no
+hof.no
+hol.no
+hole.no
+holmestrand.no
+holtalen.no
+holtÃ¥len.no
+hornindal.no
+horten.no
+hurdal.no
+hurum.no
+hvaler.no
+hyllestad.no
+hagebostad.no
+hÃŠgebostad.no
+hoyanger.no
+hÃžyanger.no
+hoylandet.no
+hÃžylandet.no
+ha.no
+hÃ¥.no
+ibestad.no
+inderoy.no
+inderÃžy.no
+iveland.no
+jevnaker.no
+jondal.no
+jolster.no
+jÃžlster.no
+karasjok.no
+karasjohka.no
+kÃ¡rÃ¡Å¡johka.no
+karlsoy.no
+galsa.no
+gÃ¡lsÃ¡.no
+karmoy.no
+karmÃžy.no
+kautokeino.no
+guovdageaidnu.no
+klepp.no
+klabu.no
+klÃŠbu.no
+kongsberg.no
+kongsvinger.no
+kragero.no
+kragerÃž.no
+kristiansand.no
+kristiansund.no
+krodsherad.no
+krÃždsherad.no
+kvalsund.no
+rahkkeravju.no
+rÃ¡hkkerÃ¡vju.no
+kvam.no
+kvinesdal.no
+kvinnherad.no
+kviteseid.no
+kvitsoy.no
+kvitsÃžy.no
+kvafjord.no
+kvÃŠfjord.no
+giehtavuoatna.no
+kvanangen.no
+kvÃŠnangen.no
+navuotna.no
+nÃ¡vuotna.no
+kafjord.no
+kÃ¥fjord.no
+gaivuotna.no
+gÃ¡ivuotna.no
+larvik.no
+lavangen.no
+lavagis.no
+loabat.no
+loabÃ¡t.no
+lebesby.no
+davvesiida.no
+leikanger.no
+leirfjord.no
+leka.no
+leksvik.no
+lenvik.no
+leangaviika.no
+leaÅgaviika.no
+lesja.no
+levanger.no
+lier.no
+lierne.no
+lillehammer.no
+lillesand.no
+lindesnes.no
+lindas.no
+lindÃ¥s.no
+lom.no
+loppa.no
+lahppi.no
+lÃ¡hppi.no
+lund.no
+lunner.no
+luroy.no
+lurÃžy.no
+luster.no
+lyngdal.no
+lyngen.no
+ivgu.no
+lardal.no
+lerdal.no
+lÃŠrdal.no
+lodingen.no
+lÃždingen.no
+lorenskog.no
+lÃžrenskog.no
+loten.no
+lÃžten.no
+malvik.no
+masoy.no
+mÃ¥sÃžy.no
+muosat.no
+muosÃ¡t.no
+mandal.no
+marker.no
+marnardal.no
+masfjorden.no
+meland.no
+meldal.no
+melhus.no
+meloy.no
+melÃžy.no
+meraker.no
+merÃ¥ker.no
+moareke.no
+moÃ¥reke.no
+midsund.no
+midtre-gauldal.no
+modalen.no
+modum.no
+molde.no
+moskenes.no
+moss.no
+mosvik.no
+malselv.no
+mÃ¥lselv.no
+malatvuopmi.no
+mÃ¡latvuopmi.no
+namdalseid.no
+aejrie.no
+namsos.no
+namsskogan.no
+naamesjevuemie.no
+nÃ¥Ã¥mesjevuemie.no
+laakesvuemie.no
+nannestad.no
+narvik.no
+narviika.no
+naustdal.no
+nedre-eiker.no
+nes.akershus.no
+nes.buskerud.no
+nesna.no
+nesodden.no
+nesseby.no
+unjarga.no
+unjÃ¡rga.no
+nesset.no
+nissedal.no
+nittedal.no
+nord-aurdal.no
+nord-fron.no
+nord-odal.no
+norddal.no
+nordkapp.no
+davvenjarga.no
+davvenjÃ¡rga.no
+nordre-land.no
+nordreisa.no
+raisa.no
+rÃ¡isa.no
+nore-og-uvdal.no
+notodden.no
+naroy.no
+nÃŠrÃžy.no
+notteroy.no
+nÃžtterÃžy.no
+odda.no
+oksnes.no
+Ãžksnes.no
+oppdal.no
+oppegard.no
+oppegÃ¥rd.no
+orkdal.no
+orland.no
+Ãžrland.no
+orskog.no
+Ãžrskog.no
+orsta.no
+Ãžrsta.no
+os.hedmark.no
+os.hordaland.no
+osen.no
+osteroy.no
+osterÃžy.no
+ostre-toten.no
+Ãžstre-toten.no
+overhalla.no
+ovre-eiker.no
+Ãžvre-eiker.no
+oyer.no
+Ãžyer.no
+oygarden.no
+Ãžygarden.no
+oystre-slidre.no
+Ãžystre-slidre.no
+porsanger.no
+porsangu.no
+porsÃ¡Ågu.no
+porsgrunn.no
+radoy.no
+radÃžy.no
+rakkestad.no
+rana.no
+ruovat.no
+randaberg.no
+rauma.no
+rendalen.no
+rennebu.no
+rennesoy.no
+rennesÃžy.no
+rindal.no
+ringebu.no
+ringerike.no
+ringsaker.no
+rissa.no
+risor.no
+risÃžr.no
+roan.no
+rollag.no
+rygge.no
+ralingen.no
+rÃŠlingen.no
+rodoy.no
+rÃždÃžy.no
+romskog.no
+rÃžmskog.no
+roros.no
+rÃžros.no
+rost.no
+rÃžst.no
+royken.no
+rÃžyken.no
+royrvik.no
+rÃžyrvik.no
+rade.no
+rÃ¥de.no
+salangen.no
+siellak.no
+saltdal.no
+salat.no
+sÃ¡lÃ¡t.no
+sÃ¡lat.no
+samnanger.no
+sande.more-og-romsdal.no
+sande.mÃžre-og-romsdal.no
+sande.vestfold.no
+sandefjord.no
+sandnes.no
+sandoy.no
+sandÃžy.no
+sarpsborg.no
+sauda.no
+sauherad.no
+sel.no
+selbu.no
+selje.no
+seljord.no
+sigdal.no
+siljan.no
+sirdal.no
+skaun.no
+skedsmo.no
+ski.no
+skien.no
+skiptvet.no
+skjervoy.no
+skjervÃžy.no
+skierva.no
+skiervÃ¡.no
+skjak.no
+skjÃ¥k.no
+skodje.no
+skanland.no
+skÃ¥nland.no
+skanit.no
+skÃ¡nit.no
+smola.no
+smÃžla.no
+snillfjord.no
+snasa.no
+snÃ¥sa.no
+snoasa.no
+snaase.no
+snÃ¥ase.no
+sogndal.no
+sokndal.no
+sola.no
+solund.no
+songdalen.no
+sortland.no
+spydeberg.no
+stange.no
+stavanger.no
+steigen.no
+steinkjer.no
+stjordal.no
+stjÃžrdal.no
+stokke.no
+stor-elvdal.no
+stord.no
+stordal.no
+storfjord.no
+omasvuotna.no
+strand.no
+stranda.no
+stryn.no
+sula.no
+suldal.no
+sund.no
+sunndal.no
+surnadal.no
+sveio.no
+svelvik.no
+sykkylven.no
+sogne.no
+sÃžgne.no
+somna.no
+sÃžmna.no
+sondre-land.no
+sÃžndre-land.no
+sor-aurdal.no
+sÃžr-aurdal.no
+sor-fron.no
+sÃžr-fron.no
+sor-odal.no
+sÃžr-odal.no
+sor-varanger.no
+sÃžr-varanger.no
+matta-varjjat.no
+mÃ¡tta-vÃ¡rjjat.no
+sorfold.no
+sÃžrfold.no
+sorreisa.no
+sÃžrreisa.no
+sorum.no
+sÃžrum.no
+tana.no
+deatnu.no
+time.no
+tingvoll.no
+tinn.no
+tjeldsund.no
+dielddanuorri.no
+tjome.no
+tjÃžme.no
+tokke.no
+tolga.no
+torsken.no
+tranoy.no
+tranÃžy.no
+tromso.no
+tromsÃž.no
+tromsa.no
+romsa.no
+trondheim.no
+troandin.no
+trysil.no
+trana.no
+trÃŠna.no
+trogstad.no
+trÃžgstad.no
+tvedestrand.no
+tydal.no
+tynset.no
+tysfjord.no
+divtasvuodna.no
+divttasvuotna.no
+tysnes.no
+tysvar.no
+tysvÃŠr.no
+tonsberg.no
+tÃžnsberg.no
+ullensaker.no
+ullensvang.no
+ulvik.no
+utsira.no
+vadso.no
+vadsÃž.no
+cahcesuolo.no
+ÄÃ¡hcesuolo.no
+vaksdal.no
+valle.no
+vang.no
+vanylven.no
+vardo.no
+vardÃž.no
+varggat.no
+vÃ¡rggÃ¡t.no
+vefsn.no
+vaapste.no
+vega.no
+vegarshei.no
+vegÃ¥rshei.no
+vennesla.no
+verdal.no
+verran.no
+vestby.no
+vestnes.no
+vestre-slidre.no
+vestre-toten.no
+vestvagoy.no
+vestvÃ¥gÃžy.no
+vevelstad.no
+vik.no
+vikna.no
+vindafjord.no
+volda.no
+voss.no
+varoy.no
+vÃŠrÃžy.no
+vagan.no
+vÃ¥gan.no
+voagat.no
+vagsoy.no
+vÃ¥gsÃžy.no
+vaga.no
+vÃ¥gÃ¥.no
+valer.ostfold.no
+vÃ¥ler.Ãžstfold.no
+valer.hedmark.no
+vÃ¥ler.hedmark.no
+
+// np : http://www.mos.com.np/register.html
+*.np
+
+// nr : http://cenpac.net.nr/dns/index.html
+// Confirmed by registry <technician@cenpac.net.nr> 2008-06-17
+nr
+biz.nr
+info.nr
+gov.nr
+edu.nr
+org.nr
+net.nr
+com.nr
+
+// nu : http://en.wikipedia.org/wiki/.nu
+nu
+
+// nz : http://en.wikipedia.org/wiki/.nz
+*.nz
+
+// om : http://en.wikipedia.org/wiki/.om
+*.om
+!mediaphone.om
+!nawrastelecom.om
+!nawras.om
+!omanmobile.om
+!omanpost.om
+!omantel.om
+!rakpetroleum.om
+!siemens.om
+!songfest.om
+!statecouncil.om
+
+// org : http://en.wikipedia.org/wiki/.org
+org
+
+// pa : http://www.nic.pa/
+// Some additional second level "domains" resolve directly as hostnames, such as
+// pannet.pa, so we add a rule for "pa".
+pa
+ac.pa
+gob.pa
+com.pa
+org.pa
+sld.pa
+edu.pa
+net.pa
+ing.pa
+abo.pa
+med.pa
+nom.pa
+
+// pe : https://www.nic.pe/InformeFinalComision.pdf
+pe
+edu.pe
+gob.pe
+nom.pe
+mil.pe
+org.pe
+com.pe
+net.pe
+
+// pf : http://www.gobin.info/domainname/formulaire-pf.pdf
+pf
+com.pf
+org.pf
+edu.pf
+
+// pg : http://en.wikipedia.org/wiki/.pg
+*.pg
+
+// ph : http://www.domains.ph/FAQ2.asp
+// Submitted by registry <jed@email.com.ph> 2008-06-13
+ph
+com.ph
+net.ph
+org.ph
+gov.ph
+edu.ph
+ngo.ph
+mil.ph
+i.ph
+
+// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK
+pk
+com.pk
+net.pk
+edu.pk
+org.pk
+fam.pk
+biz.pk
+web.pk
+gov.pk
+gob.pk
+gok.pk
+gon.pk
+gop.pk
+gos.pk
+info.pk
+
+// pl : http://www.dns.pl/english/
+pl
+// NASK functional domains (nask.pl / dns.pl) : http://www.dns.pl/english/dns-funk.html
+aid.pl
+agro.pl
+atm.pl
+auto.pl
+biz.pl
+com.pl
+edu.pl
+gmina.pl
+gsm.pl
+info.pl
+mail.pl
+miasta.pl
+media.pl
+mil.pl
+net.pl
+nieruchomosci.pl
+nom.pl
+org.pl
+pc.pl
+powiat.pl
+priv.pl
+realestate.pl
+rel.pl
+sex.pl
+shop.pl
+sklep.pl
+sos.pl
+szkola.pl
+targi.pl
+tm.pl
+tourism.pl
+travel.pl
+turystyka.pl
+// ICM functional domains (icm.edu.pl)
+6bone.pl
+art.pl
+mbone.pl
+// Government domains (administred by ippt.gov.pl)
+gov.pl
+uw.gov.pl
+um.gov.pl
+ug.gov.pl
+upow.gov.pl
+starostwo.gov.pl
+so.gov.pl
+sr.gov.pl
+po.gov.pl
+pa.gov.pl
+// other functional domains
+ngo.pl
+irc.pl
+usenet.pl
+// NASK geographical domains : http://www.dns.pl/english/dns-regiony.html
+augustow.pl
+babia-gora.pl
+bedzin.pl
+beskidy.pl
+bialowieza.pl
+bialystok.pl
+bielawa.pl
+bieszczady.pl
+boleslawiec.pl
+bydgoszcz.pl
+bytom.pl
+cieszyn.pl
+czeladz.pl
+czest.pl
+dlugoleka.pl
+elblag.pl
+elk.pl
+glogow.pl
+gniezno.pl
+gorlice.pl
+grajewo.pl
+ilawa.pl
+jaworzno.pl
+jelenia-gora.pl
+jgora.pl
+kalisz.pl
+kazimierz-dolny.pl
+karpacz.pl
+kartuzy.pl
+kaszuby.pl
+katowice.pl
+kepno.pl
+ketrzyn.pl
+klodzko.pl
+kobierzyce.pl
+kolobrzeg.pl
+konin.pl
+konskowola.pl
+kutno.pl
+lapy.pl
+lebork.pl
+legnica.pl
+lezajsk.pl
+limanowa.pl
+lomza.pl
+lowicz.pl
+lubin.pl
+lukow.pl
+malbork.pl
+malopolska.pl
+mazowsze.pl
+mazury.pl
+mielec.pl
+mielno.pl
+mragowo.pl
+naklo.pl
+nowaruda.pl
+nysa.pl
+olawa.pl
+olecko.pl
+olkusz.pl
+olsztyn.pl
+opoczno.pl
+opole.pl
+ostroda.pl
+ostroleka.pl
+ostrowiec.pl
+ostrowwlkp.pl
+pila.pl
+pisz.pl
+podhale.pl
+podlasie.pl
+polkowice.pl
+pomorze.pl
+pomorskie.pl
+prochowice.pl
+pruszkow.pl
+przeworsk.pl
+pulawy.pl
+radom.pl
+rawa-maz.pl
+rybnik.pl
+rzeszow.pl
+sanok.pl
+sejny.pl
+siedlce.pl
+slask.pl
+slupsk.pl
+sosnowiec.pl
+stalowa-wola.pl
+skoczow.pl
+starachowice.pl
+stargard.pl
+suwalki.pl
+swidnica.pl
+swiebodzin.pl
+swinoujscie.pl
+szczecin.pl
+szczytno.pl
+tarnobrzeg.pl
+tgory.pl
+turek.pl
+tychy.pl
+ustka.pl
+walbrzych.pl
+warmia.pl
+warszawa.pl
+waw.pl
+wegrow.pl
+wielun.pl
+wlocl.pl
+wloclawek.pl
+wodzislaw.pl
+wolomin.pl
+wroclaw.pl
+zachpomor.pl
+zagan.pl
+zarow.pl
+zgora.pl
+zgorzelec.pl
+// TASK geographical domains (www.task.gda.pl/uslugi/dns)
+gda.pl
+gdansk.pl
+gdynia.pl
+med.pl
+sopot.pl
+// other geographical domains
+gliwice.pl
+krakow.pl
+poznan.pl
+wroc.pl
+zakopane.pl
+
+// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+pm
+
+// pn : http://www.government.pn/PnRegistry/policies.htm
+pn
+gov.pn
+co.pn
+org.pn
+edu.pn
+net.pn
+
+// pr : http://www.nic.pr/index.asp?f=1
+pr
+com.pr
+net.pr
+org.pr
+gov.pr
+edu.pr
+isla.pr
+pro.pr
+biz.pr
+info.pr
+name.pr
+// these aren't mentioned on nic.pr, but on http://en.wikipedia.org/wiki/.pr
+est.pr
+prof.pr
+ac.pr
+
+// pro : http://www.nic.pro/support_faq.htm
+pro
+aca.pro
+bar.pro
+cpa.pro
+jur.pro
+law.pro
+med.pro
+eng.pro
+
+// ps : http://en.wikipedia.org/wiki/.ps
+// http://www.nic.ps/registration/policy.html#reg
+ps
+edu.ps
+gov.ps
+sec.ps
+plo.ps
+com.ps
+org.ps
+net.ps
+
+// pt : http://online.dns.pt/dns/start_dns
+pt
+net.pt
+gov.pt
+org.pt
+edu.pt
+int.pt
+publ.pt
+com.pt
+nome.pt
+
+// pw : http://en.wikipedia.org/wiki/.pw
+pw
+co.pw
+ne.pw
+or.pw
+ed.pw
+go.pw
+belau.pw
+
+// py : http://www.nic.py/faq_a.html#faq_b
+*.py
+
+// qa : http://domains.qa/en/
+qa
+com.qa
+edu.qa
+gov.qa
+mil.qa
+name.qa
+net.qa
+org.qa
+sch.qa
+
+// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs
+re
+com.re
+asso.re
+nom.re
+
+// ro : http://www.rotld.ro/
+ro
+com.ro
+org.ro
+tm.ro
+nt.ro
+nom.ro
+info.ro
+rec.ro
+arts.ro
+firm.ro
+store.ro
+www.ro
+
+// rs : http://en.wikipedia.org/wiki/.rs
+rs
+co.rs
+org.rs
+edu.rs
+ac.rs
+gov.rs
+in.rs
+
+// ru : http://www.cctld.ru/ru/docs/aktiv_8.php
+// Industry domains
+ru
+ac.ru
+com.ru
+edu.ru
+int.ru
+net.ru
+org.ru
+pp.ru
+// Geographical domains
+adygeya.ru
+altai.ru
+amur.ru
+arkhangelsk.ru
+astrakhan.ru
+bashkiria.ru
+belgorod.ru
+bir.ru
+bryansk.ru
+buryatia.ru
+cbg.ru
+chel.ru
+chelyabinsk.ru
+chita.ru
+chukotka.ru
+chuvashia.ru
+dagestan.ru
+dudinka.ru
+e-burg.ru
+grozny.ru
+irkutsk.ru
+ivanovo.ru
+izhevsk.ru
+jar.ru
+joshkar-ola.ru
+kalmykia.ru
+kaluga.ru
+kamchatka.ru
+karelia.ru
+kazan.ru
+kchr.ru
+kemerovo.ru
+khabarovsk.ru
+khakassia.ru
+khv.ru
+kirov.ru
+koenig.ru
+komi.ru
+kostroma.ru
+krasnoyarsk.ru
+kuban.ru
+kurgan.ru
+kursk.ru
+lipetsk.ru
+magadan.ru
+mari.ru
+mari-el.ru
+marine.ru
+mordovia.ru
+mosreg.ru
+msk.ru
+murmansk.ru
+nalchik.ru
+nnov.ru
+nov.ru
+novosibirsk.ru
+nsk.ru
+omsk.ru
+orenburg.ru
+oryol.ru
+palana.ru
+penza.ru
+perm.ru
+pskov.ru
+ptz.ru
+rnd.ru
+ryazan.ru
+sakhalin.ru
+samara.ru
+saratov.ru
+simbirsk.ru
+smolensk.ru
+spb.ru
+stavropol.ru
+stv.ru
+surgut.ru
+tambov.ru
+tatarstan.ru
+tom.ru
+tomsk.ru
+tsaritsyn.ru
+tsk.ru
+tula.ru
+tuva.ru
+tver.ru
+tyumen.ru
+udm.ru
+udmurtia.ru
+ulan-ude.ru
+vladikavkaz.ru
+vladimir.ru
+vladivostok.ru
+volgograd.ru
+vologda.ru
+voronezh.ru
+vrn.ru
+vyatka.ru
+yakutia.ru
+yamal.ru
+yaroslavl.ru
+yekaterinburg.ru
+yuzhno-sakhalinsk.ru
+// More geographical domains
+amursk.ru
+baikal.ru
+cmw.ru
+fareast.ru
+jamal.ru
+kms.ru
+k-uralsk.ru
+kustanai.ru
+kuzbass.ru
+magnitka.ru
+mytis.ru
+nakhodka.ru
+nkz.ru
+norilsk.ru
+oskol.ru
+pyatigorsk.ru
+rubtsovsk.ru
+snz.ru
+syzran.ru
+vdonsk.ru
+zgrad.ru
+// State domains
+gov.ru
+mil.ru
+// Technical domains
+test.ru
+
+// rw : http://www.nic.rw/cgi-bin/policy.pl
+rw
+gov.rw
+net.rw
+edu.rw
+ac.rw
+com.rw
+co.rw
+int.rw
+mil.rw
+gouv.rw
+
+// sa : http://www.nic.net.sa/
+sa
+com.sa
+net.sa
+org.sa
+gov.sa
+med.sa
+pub.sa
+edu.sa
+sch.sa
+
+// sb : http://www.sbnic.net.sb/
+// Submitted by registry <lee.humphries@telekom.com.sb> 2008-06-08
+sb
+com.sb
+edu.sb
+gov.sb
+net.sb
+org.sb
+
+// sc : http://www.nic.sc/
+sc
+com.sc
+gov.sc
+net.sc
+org.sc
+edu.sc
+
+// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm
+// Submitted by registry <admin@isoc.sd> 2008-06-17
+sd
+com.sd
+net.sd
+org.sd
+edu.sd
+med.sd
+gov.sd
+info.sd
+
+// se : http://en.wikipedia.org/wiki/.se
+// Submitted by registry <Patrik.Wallstrom@iis.se> 2008-06-24
+se
+a.se
+ac.se
+b.se
+bd.se
+brand.se
+c.se
+d.se
+e.se
+f.se
+fh.se
+fhsk.se
+fhv.se
+g.se
+h.se
+i.se
+k.se
+komforb.se
+kommunalforbund.se
+komvux.se
+l.se
+lanbib.se
+m.se
+n.se
+naturbruksgymn.se
+o.se
+org.se
+p.se
+parti.se
+pp.se
+press.se
+r.se
+s.se
+sshn.se
+t.se
+tm.se
+u.se
+w.se
+x.se
+y.se
+z.se
+
+// sg : http://www.nic.net.sg/sub_policies_agreement/2ld.html
+sg
+com.sg
+net.sg
+org.sg
+gov.sg
+edu.sg
+per.sg
+
+// sh : http://www.nic.sh/rules.html
+// list of 2nd level domains ?
+sh
+
+// si : http://en.wikipedia.org/wiki/.si
+si
+
+// sj : No registrations at this time.
+// Submitted by registry <jarle@uninett.no> 2008-06-16
+
+// sk : http://en.wikipedia.org/wiki/.sk
+// list of 2nd level domains ?
+sk
+
+// sl : http://www.nic.sl
+// Submitted by registry <adam@neoip.com> 2008-06-12
+sl
+com.sl
+net.sl
+edu.sl
+gov.sl
+org.sl
+
+// sm : http://en.wikipedia.org/wiki/.sm
+sm
+
+// sn : http://en.wikipedia.org/wiki/.sn
+sn
+art.sn
+com.sn
+edu.sn
+gouv.sn
+org.sn
+perso.sn
+univ.sn
+
+// so : http://www.soregistry.com/
+so
+com.so
+net.so
+org.so
+
+// sr : http://en.wikipedia.org/wiki/.sr
+sr
+
+// st : http://www.nic.st/html/policyrules/
+st
+co.st
+com.st
+consulado.st
+edu.st
+embaixada.st
+gov.st
+mil.st
+net.st
+org.st
+principe.st
+saotome.st
+store.st
+
+// su : http://en.wikipedia.org/wiki/.su
+su
+
+// sv : http://www.svnet.org.sv/svpolicy.html
+*.sv
+
+// sy : http://en.wikipedia.org/wiki/.sy
+// see also: http://www.gobin.info/domainname/sy.doc
+sy
+edu.sy
+gov.sy
+net.sy
+mil.sy
+com.sy
+org.sy
+
+// sz : http://en.wikipedia.org/wiki/.sz
+// http://www.sispa.org.sz/
+sz
+co.sz
+ac.sz
+org.sz
+
+// tc : http://en.wikipedia.org/wiki/.tc
+tc
+
+// td : http://en.wikipedia.org/wiki/.td
+td
+
+// tel: http://en.wikipedia.org/wiki/.tel
+// http://www.telnic.org/
+tel
+
+// tf : http://en.wikipedia.org/wiki/.tf
+tf
+
+// tg : http://en.wikipedia.org/wiki/.tg
+// http://www.nic.tg/nictg/index.php implies no reserved 2nd-level domains,
+// although this contradicts wikipedia.
+tg
+
+// th : http://en.wikipedia.org/wiki/.th
+// Submitted by registry <krit@thains.co.th> 2008-06-17
+th
+ac.th
+co.th
+go.th
+in.th
+mi.th
+net.th
+or.th
+
+// tj : http://www.nic.tj/policy.htm
+tj
+ac.tj
+biz.tj
+co.tj
+com.tj
+edu.tj
+go.tj
+gov.tj
+int.tj
+mil.tj
+name.tj
+net.tj
+nic.tj
+org.tj
+test.tj
+web.tj
+
+// tk : http://en.wikipedia.org/wiki/.tk
+tk
+
+// tl : http://en.wikipedia.org/wiki/.tl
+tl
+gov.tl
+
+// tm : http://www.nic.tm/rules.html
+// list of 2nd level tlds ?
+tm
+
+// tn : http://en.wikipedia.org/wiki/.tn
+// http://whois.ati.tn/
+tn
+com.tn
+ens.tn
+fin.tn
+gov.tn
+ind.tn
+intl.tn
+nat.tn
+net.tn
+org.tn
+info.tn
+perso.tn
+tourism.tn
+edunet.tn
+rnrt.tn
+rns.tn
+rnu.tn
+mincom.tn
+agrinet.tn
+defense.tn
+turen.tn
+
+// to : http://en.wikipedia.org/wiki/.to
+// Submitted by registry <egullich@colo.to> 2008-06-17
+to
+com.to
+gov.to
+net.to
+org.to
+edu.to
+mil.to
+
+// tr : http://en.wikipedia.org/wiki/.tr
+*.tr
+!nic.tr
+// Used by government in the TRNC
+// http://en.wikipedia.org/wiki/.nc.tr
+gov.nc.tr
+
+// travel : http://en.wikipedia.org/wiki/.travel
+travel
+
+// tt : http://www.nic.tt/
+tt
+co.tt
+com.tt
+org.tt
+net.tt
+biz.tt
+info.tt
+pro.tt
+int.tt
+coop.tt
+jobs.tt
+mobi.tt
+travel.tt
+museum.tt
+aero.tt
+name.tt
+gov.tt
+edu.tt
+
+// tv : http://en.wikipedia.org/wiki/.tv
+// Not listing any 2LDs as reserved since none seem to exist in practice,
+// Wikipedia notwithstanding.
+tv
+
+// tw : http://en.wikipedia.org/wiki/.tw
+tw
+edu.tw
+gov.tw
+mil.tw
+com.tw
+net.tw
+org.tw
+idv.tw
+game.tw
+ebiz.tw
+club.tw
+ç¶²è·¯.tw
+çµç¹.tw
+åæ¥­.tw
+
+// tz : http://en.wikipedia.org/wiki/.tz
+// Submitted by registry <randy@psg.com> 2008-06-17
+// Updated from http://www.tznic.or.tz/index.php/domains.html 2010-10-25
+ac.tz
+co.tz
+go.tz
+mil.tz
+ne.tz
+or.tz
+sc.tz
+
+// ua : http://www.nic.net.ua/
+ua
+com.ua
+edu.ua
+gov.ua
+in.ua
+net.ua
+org.ua
+// ua geo-names
+cherkassy.ua
+chernigov.ua
+chernovtsy.ua
+ck.ua
+cn.ua
+crimea.ua
+cv.ua
+dn.ua
+dnepropetrovsk.ua
+donetsk.ua
+dp.ua
+if.ua
+ivano-frankivsk.ua
+kh.ua
+kharkov.ua
+kherson.ua
+khmelnitskiy.ua
+kiev.ua
+kirovograd.ua
+km.ua
+kr.ua
+ks.ua
+kv.ua
+lg.ua
+lugansk.ua
+lutsk.ua
+lviv.ua
+mk.ua
+nikolaev.ua
+od.ua
+odessa.ua
+pl.ua
+poltava.ua
+rovno.ua
+rv.ua
+sebastopol.ua
+sumy.ua
+te.ua
+ternopil.ua
+uzhgorod.ua
+vinnica.ua
+vn.ua
+zaporizhzhe.ua
+zp.ua
+zhitomir.ua
+zt.ua
+
+// Private registries in .ua
+co.ua
+pp.ua
+
+// ug : http://www.registry.co.ug/
+ug
+co.ug
+ac.ug
+sc.ug
+go.ug
+ne.ug
+or.ug
+
+// uk : http://en.wikipedia.org/wiki/.uk
+*.uk
+*.sch.uk
+!bl.uk
+!british-library.uk
+!icnet.uk
+!jet.uk
+!mod.uk
+!nel.uk
+!nhs.uk
+!nic.uk
+!nls.uk
+!national-library-scotland.uk
+!parliament.uk
+!police.uk
+
+// us : http://en.wikipedia.org/wiki/.us
+us
+dni.us
+fed.us
+isa.us
+kids.us
+nsn.us
+// us geographic names
+ak.us
+al.us
+ar.us
+as.us
+az.us
+ca.us
+co.us
+ct.us
+dc.us
+de.us
+fl.us
+ga.us
+gu.us
+hi.us
+ia.us
+id.us
+il.us
+in.us
+ks.us
+ky.us
+la.us
+ma.us
+md.us
+me.us
+mi.us
+mn.us
+mo.us
+ms.us
+mt.us
+nc.us
+nd.us
+ne.us
+nh.us
+nj.us
+nm.us
+nv.us
+ny.us
+oh.us
+ok.us
+or.us
+pa.us
+pr.us
+ri.us
+sc.us
+sd.us
+tn.us
+tx.us
+ut.us
+vi.us
+vt.us
+va.us
+wa.us
+wi.us
+wv.us
+wy.us
+// The registrar notes several more specific domains available in each state,
+// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat
+// haphazard; in some states these domains resolve as addresses, while in others
+// only subdomains are available, or even nothing at all. We include the
+// most common ones where it's clear that different sites are different
+// entities.
+k12.ak.us
+k12.al.us
+k12.ar.us
+k12.as.us
+k12.az.us
+k12.ca.us
+k12.co.us
+k12.ct.us
+k12.dc.us
+k12.de.us
+k12.fl.us
+k12.ga.us
+k12.gu.us
+// k12.hi.us  Hawaii has a state-wide DOE login: bug 614565
+k12.ia.us
+k12.id.us
+k12.il.us
+k12.in.us
+k12.ks.us
+k12.ky.us
+k12.la.us
+k12.ma.us
+k12.md.us
+k12.me.us
+k12.mi.us
+k12.mn.us
+k12.mo.us
+k12.ms.us
+k12.mt.us
+k12.nc.us
+k12.nd.us
+k12.ne.us
+k12.nh.us
+k12.nj.us
+k12.nm.us
+k12.nv.us
+k12.ny.us
+k12.oh.us
+k12.ok.us
+k12.or.us
+k12.pa.us
+k12.pr.us
+k12.ri.us
+k12.sc.us
+k12.sd.us
+k12.tn.us
+k12.tx.us
+k12.ut.us
+k12.vi.us
+k12.vt.us
+k12.va.us
+k12.wa.us
+k12.wi.us
+k12.wv.us
+k12.wy.us
+
+cc.ak.us
+cc.al.us
+cc.ar.us
+cc.as.us
+cc.az.us
+cc.ca.us
+cc.co.us
+cc.ct.us
+cc.dc.us
+cc.de.us
+cc.fl.us
+cc.ga.us
+cc.gu.us
+cc.hi.us
+cc.ia.us
+cc.id.us
+cc.il.us
+cc.in.us
+cc.ks.us
+cc.ky.us
+cc.la.us
+cc.ma.us
+cc.md.us
+cc.me.us
+cc.mi.us
+cc.mn.us
+cc.mo.us
+cc.ms.us
+cc.mt.us
+cc.nc.us
+cc.nd.us
+cc.ne.us
+cc.nh.us
+cc.nj.us
+cc.nm.us
+cc.nv.us
+cc.ny.us
+cc.oh.us
+cc.ok.us
+cc.or.us
+cc.pa.us
+cc.pr.us
+cc.ri.us
+cc.sc.us
+cc.sd.us
+cc.tn.us
+cc.tx.us
+cc.ut.us
+cc.vi.us
+cc.vt.us
+cc.va.us
+cc.wa.us
+cc.wi.us
+cc.wv.us
+cc.wy.us
+
+lib.ak.us
+lib.al.us
+lib.ar.us
+lib.as.us
+lib.az.us
+lib.ca.us
+lib.co.us
+lib.ct.us
+lib.dc.us
+lib.de.us
+lib.fl.us
+lib.ga.us
+lib.gu.us
+lib.hi.us
+lib.ia.us
+lib.id.us
+lib.il.us
+lib.in.us
+lib.ks.us
+lib.ky.us
+lib.la.us
+lib.ma.us
+lib.md.us
+lib.me.us
+lib.mi.us
+lib.mn.us
+lib.mo.us
+lib.ms.us
+lib.mt.us
+lib.nc.us
+lib.nd.us
+lib.ne.us
+lib.nh.us
+lib.nj.us
+lib.nm.us
+lib.nv.us
+lib.ny.us
+lib.oh.us
+lib.ok.us
+lib.or.us
+lib.pa.us
+lib.pr.us
+lib.ri.us
+lib.sc.us
+lib.sd.us
+lib.tn.us
+lib.tx.us
+lib.ut.us
+lib.vi.us
+lib.vt.us
+lib.va.us
+lib.wa.us
+lib.wi.us
+lib.wv.us
+lib.wy.us
+
+// k12.ma.us contains school districts in Massachusetts. The 4LDs are 
+//  managed indepedently except for private (PVT), charter (CHTR) and
+//  parochial (PAROCH) schools.  Those are delegated dorectly to the 
+//  5LD operators.   <k12-ma-hostmaster _ at _ rsuc.gweep.net>
+pvt.k12.ma.us
+chtr.k12.ma.us
+paroch.k12.ma.us
+
+// uy : http://www.antel.com.uy/
+*.uy
+
+// uz : http://www.reg.uz/registerr.html
+// are there other 2nd level tlds ?
+uz
+com.uz
+co.uz
+
+// va : http://en.wikipedia.org/wiki/.va
+va
+
+// vc : http://en.wikipedia.org/wiki/.vc
+// Submitted by registry <kshah@ca.afilias.info> 2008-06-13
+vc
+com.vc
+net.vc
+org.vc
+gov.vc
+mil.vc
+edu.vc
+
+// ve : http://registro.nic.ve/nicve/registro/index.html
+*.ve
+
+// vg : http://en.wikipedia.org/wiki/.vg
+vg
+
+// vi : http://www.nic.vi/newdomainform.htm
+// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other
+// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they
+// are available for registration (which they do not seem to be).
+vi
+co.vi
+com.vi
+k12.vi
+net.vi
+org.vi
+
+// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp
+vn
+com.vn
+net.vn
+org.vn
+edu.vn
+gov.vn
+int.vn
+ac.vn
+biz.vn
+info.vn
+name.vn
+pro.vn
+health.vn
+
+// vu : http://en.wikipedia.org/wiki/.vu
+// list of 2nd level tlds ?
+vu
+
+// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+wf
+
+// ws : http://en.wikipedia.org/wiki/.ws
+// http://samoanic.ws/index.dhtml
+ws
+com.ws
+net.ws
+org.ws
+gov.ws
+edu.ws
+
+// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+yt
+
+// IDN ccTLDs
+// Please sort by ISO 3166 ccTLD, then punicode string
+// when submitting patches and follow this format:
+// <Punicode> ("<english word>" <language>) : <ISO 3166 ccTLD>
+// [optional sponsoring org]
+// <URL>
+
+// xn--mgbaam7a8h ("Emerat" Arabic) : AE
+//http://nic.ae/english/arabicdomain/rules.jsp
+Ø§Ù
+Ø§Ø±Ø§Øª
+
+// xn--54b7fta0cc ("Bangla" Bangla) : BD  
+àŠ¬àŠŸàŠàŠ²àŠŸ
+
+// xn--fiqs8s ("China" Chinese-Han-Simplified <.Zhonggou>) : CN 
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+äž­åœ
+
+// xn--fiqz9s ("China" Chinese-Han-Traditional <.Zhonggou>) : CN
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+äž­å
+
+// xn--lgbbat1ad8j ("Algeria / Al Jazair" Arabic) : DZ  
+Ø§ÙØ¬Ø²Ø§ØŠØ±
+
+// xn--wgbh1c ("Egypt" Arabic .masr) : EG
+// http://www.dotmasr.eg/
+Ù
+ØµØ±
+
+// xn--node ("ge" Georgian (Mkhedruli)) : GE  
+áá
+
+// xn--j6w193g ("Hong Kong" Chinese-Han) : HK
+// https://www2.hkirc.hk/register/rules.jsp
+éŠæž¯
+
+// xn--h2brj9c ("Bharat" Devanagari) : IN  
+// India
+à€­à€Ÿà€°à€€
+
+// xn--mgbbh1a71e ("Bharat" Arabic) : IN  
+// India
+ØšÚŸØ§Ø±Øª
+
+// xn--fpcrj9c3d ("Bharat" Telugu) : IN  
+// India
+à°­à°Ÿà°°à°€à±
+
+// xn--gecrj9c ("Bharat" Gujarati) : IN  
+// India
+àª­àªŸàª°àª€
+
+// xn--s9brj9c ("Bharat" Gurmukhi) : IN  
+// India
+àš­àšŸàš°àš€
+
+// xn--45brj9c ("Bharat" Bengali) : IN  
+// India
+àŠ­àŠŸàŠ°àŠ€
+
+// xn--xkc2dl3a5ee0h ("India" Tamil) : IN  
+// India
+à®à®šà¯à®€à®¿à®¯à®Ÿ
+
+// xn--mgba3a4f16a ("Iran" Persian) : IR  
+Ø§ÛØ±Ø§Ù
+
+// xn--mgba3a4fra ("Iran" Arabic) : IR  
+Ø§ÙØ±Ø§Ù
+
+//xn--mgbayh7gpa ("al-Ordon" Arabic) JO
+//National Information Technology Center (NITC) 
+//Royal Scientific Society, Al-Jubeiha
+Ø§ÙØ§Ø±Ø¯Ù
+
+// xn--3e0b707e ("Republic of Korea" Hangul) : KR  
+íêµ­
+
+// xn--fzc2c9e2c ("Lanka" Sinhalese-Sinhala) : LK
+// http://nic.lk
+à¶œà¶à¶à·
+
+// xn--xkc2al3hye2a ("Ilangai" Tamil) : LK
+// http://nic.lk
+à®à®²à®à¯à®à¯
+
+// xn--mgbc0a9azcg ("Morocco / al-Maghrib" Arabic) : MA  
+Ø§ÙÙ
+ØºØ±Øš
+
+// xn--mgb9awbf ("Oman" Arabic) : OM  
+Ø¹Ù
+Ø§Ù
+
+// xn--ygbi2ammx ("Falasteen" Arabic) : PS
+// The Palestinian National Internet Naming Authority (PNINA)
+// http://www.pnina.ps
+ÙÙØ³Ø·ÙÙ
+
+// xn--90a3ac ("srb" Cyrillic) : RS  
+ÑÑÐ±
+
+// xn--p1ai ("rf" Russian-Cyrillic) : RU
+// http://www.cctld.ru/en/docs/rulesrf.php
+ÑÑ
+
+// xn--wgbl6a ("Qatar" Arabic) : QA
+// http://www.ict.gov.qa/
+ÙØ·Ø±
+
+// xn--mgberp4a5d4ar ("AlSaudiah" Arabic) : SA
+// http://www.nic.net.sa/
+Ø§ÙØ³Ø¹ÙØ¯ÙØ©
+
+// xn--mgberp4a5d4a87g ("AlSaudiah" Arabic) variant : SA  
+Ø§ÙØ³Ø¹ÙØ¯ÛØ©
+
+// xn--mgbqly7c0a67fbc ("AlSaudiah" Arabic) variant : SA  
+Ø§ÙØ³Ø¹ÙØ¯ÛÛ
+
+// xn--mgbqly7cvafr ("AlSaudiah" Arabic) variant : SA  
+Ø§ÙØ³Ø¹ÙØ¯ÙÙ
+
+// xn--ogbpf8fl ("Syria" Arabic) : SY  
+Ø³ÙØ±ÙØ©
+
+// xn--mgbtf8fl ("Syria" Arabic) variant : SY  
+Ø³ÙØ±ÙØ§
+
+// xn--yfro4i67o Singapore ("Singapore" Chinese-Han) : SG
+æ°å å¡
+
+// xn--clchc0ea0b2g2a9gcd ("Singapore" Tamil) : SG
+à®à®¿à®à¯à®à®ªà¯à®ªà¯à®°à¯
+
+// xn--o3cw4h ("Thai" Thai) : TH
+// http://www.thnic.co.th
+à¹àžàž¢
+
+// xn--pgbs0dh ("Tunis") : TN
+// http://nic.tn
+ØªÙÙØ³
+
+// xn--kpry57d ("Taiwan" Chinese-Han-Traditional) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+å°ç£
+
+// xn--kprw13d ("Taiwan" Chinese-Han-Simplified) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+å°æ¹Ÿ
+
+// xn--nnx388a ("Taiwan") variant : TW  
+èºç£
+
+// xn--j1amh ("ukr" Cyrillic) : UA  
+ÑÐºÑ
+
+// xn--mgb2ddes ("AlYemen" Arabic) : YE  
+Ø§ÙÙÙ
+Ù
+
+// xxx : http://icmregistry.com
+xxx
+
+// ye : http://www.y.net.ye/services/domain_name.htm
+*.ye
+
+// za : http://www.zadna.org.za/slds.html
+*.za
+
+// zm : http://en.wikipedia.org/wiki/.zm
+*.zm
+
+// zw : http://en.wikipedia.org/wiki/.zw
+*.zw
+
+// ===END ICANN DOMAINS===
+// ===BEGIN PRIVATE DOMAINS===
+
+// info.at : http://www.info.at/
+biz.at
+info.at
+
+// priv.at : http://www.nic.priv.at/
+// Submitted by registry <lendl@nic.at> 2008-06-09
+priv.at
+
+// co.ca : http://registry.co.ca
+co.ca
+
+// CentralNic : http://www.centralnic.com/names/domains
+// Confirmed by registry <gavin.brown@centralnic.com> 2008-06-09
+ar.com
+br.com
+cn.com
+de.com
+eu.com
+gb.com
+gr.com
+hu.com
+jpn.com
+kr.com
+no.com
+qc.com
+ru.com
+sa.com
+se.com
+uk.com
+us.com
+uy.com
+za.com
+gb.net
+jp.net
+se.net
+uk.net
+ae.org
+us.org
+com.de
+
+// Opera Software, A.S.A.
+// Requested by Yngve Pettersen <yngve@opera.com> 2009-11-26
+operaunite.com
+
+// Google, Inc.
+// Requested by Eduardo Vela <evn@google.com> 2010-09-06
+appspot.com
+
+// iki.fi : Submitted by Hannu Aronsson <haa@iki.fi> 2009-11-05
+iki.fi
+
+// c.la : http://www.c.la/
+c.la
+
+// ZaNiC : http://www.za.net/
+// Confirmed by registry <hostmaster@nic.za.net> 2009-10-03
+za.net
+za.org
+
+// CoDNS B.V.
+// Added 2010-05-23.
+co.nl
+co.no
+
+// Mainseek Sp. z o.o. : http://www.co.pl/
+co.pl
+
+// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/
+dyndns-at-home.com
+dyndns-at-work.com
+dyndns-blog.com
+dyndns-free.com
+dyndns-home.com
+dyndns-ip.com
+dyndns-mail.com
+dyndns-office.com
+dyndns-pics.com
+dyndns-remote.com
+dyndns-server.com
+dyndns-web.com
+dyndns-wiki.com
+dyndns-work.com
+dyndns.biz
+dyndns.info
+dyndns.org
+dyndns.tv
+at-band-camp.net
+ath.cx
+barrel-of-knowledge.info
+barrell-of-knowledge.info
+better-than.tv
+blogdns.com
+blogdns.net
+blogdns.org
+blogsite.org
+boldlygoingnowhere.org
+broke-it.net
+buyshouses.net
+cechire.com
+dnsalias.com
+dnsalias.net
+dnsalias.org
+dnsdojo.com
+dnsdojo.net
+dnsdojo.org
+does-it.net
+doesntexist.com
+doesntexist.org
+dontexist.com
+dontexist.net
+dontexist.org
+doomdns.com
+doomdns.org
+dvrdns.org
+dyn-o-saur.com
+dynalias.com
+dynalias.net
+dynalias.org
+dynathome.net
+dyndns.ws
+endofinternet.net
+endofinternet.org
+endoftheinternet.org
+est-a-la-maison.com
+est-a-la-masion.com
+est-le-patron.com
+est-mon-blogueur.com
+for-better.biz
+for-more.biz
+for-our.info
+for-some.biz
+for-the.biz
+forgot.her.name
+forgot.his.name
+from-ak.com
+from-al.com
+from-ar.com
+from-az.net
+from-ca.com
+from-co.net
+from-ct.com
+from-dc.com
+from-de.com
+from-fl.com
+from-ga.com
+from-hi.com
+from-ia.com
+from-id.com
+from-il.com
+from-in.com
+from-ks.com
+from-ky.com
+from-la.net
+from-ma.com
+from-md.com
+from-me.org
+from-mi.com
+from-mn.com
+from-mo.com
+from-ms.com
+from-mt.com
+from-nc.com
+from-nd.com
+from-ne.com
+from-nh.com
+from-nj.com
+from-nm.com
+from-nv.com
+from-ny.net
+from-oh.com
+from-ok.com
+from-or.com
+from-pa.com
+from-pr.com
+from-ri.com
+from-sc.com
+from-sd.com
+from-tn.com
+from-tx.com
+from-ut.com
+from-va.com
+from-vt.com
+from-wa.com
+from-wi.com
+from-wv.com
+from-wy.com
+ftpaccess.cc
+fuettertdasnetz.de
+game-host.org
+game-server.cc
+getmyip.com
+gets-it.net
+go.dyndns.org
+gotdns.com
+gotdns.org
+groks-the.info
+groks-this.info
+ham-radio-op.net
+here-for-more.info
+hobby-site.com
+hobby-site.org
+home.dyndns.org
+homedns.org
+homeftp.net
+homeftp.org
+homeip.net
+homelinux.com
+homelinux.net
+homelinux.org
+homeunix.com
+homeunix.net
+homeunix.org
+iamallama.com
+in-the-band.net
+is-a-anarchist.com
+is-a-blogger.com
+is-a-bookkeeper.com
+is-a-bruinsfan.org
+is-a-bulls-fan.com
+is-a-candidate.org
+is-a-caterer.com
+is-a-celticsfan.org
+is-a-chef.com
+is-a-chef.net
+is-a-chef.org
+is-a-conservative.com
+is-a-cpa.com
+is-a-cubicle-slave.com
+is-a-democrat.com
+is-a-designer.com
+is-a-doctor.com
+is-a-financialadvisor.com
+is-a-geek.com
+is-a-geek.net
+is-a-geek.org
+is-a-green.com
+is-a-guru.com
+is-a-hard-worker.com
+is-a-hunter.com
+is-a-knight.org
+is-a-landscaper.com
+is-a-lawyer.com
+is-a-liberal.com
+is-a-libertarian.com
+is-a-linux-user.org
+is-a-llama.com
+is-a-musician.com
+is-a-nascarfan.com
+is-a-nurse.com
+is-a-painter.com
+is-a-patsfan.org
+is-a-personaltrainer.com
+is-a-photographer.com
+is-a-player.com
+is-a-republican.com
+is-a-rockstar.com
+is-a-socialist.com
+is-a-soxfan.org
+is-a-student.com
+is-a-teacher.com
+is-a-techie.com
+is-a-therapist.com
+is-an-accountant.com
+is-an-actor.com
+is-an-actress.com
+is-an-anarchist.com
+is-an-artist.com
+is-an-engineer.com
+is-an-entertainer.com
+is-by.us
+is-certified.com
+is-found.org
+is-gone.com
+is-into-anime.com
+is-into-cars.com
+is-into-cartoons.com
+is-into-games.com
+is-leet.com
+is-lost.org
+is-not-certified.com
+is-saved.org
+is-slick.com
+is-uberleet.com
+is-very-bad.org
+is-very-evil.org
+is-very-good.org
+is-very-nice.org
+is-very-sweet.org
+is-with-theband.com
+isa-geek.com
+isa-geek.net
+isa-geek.org
+isa-hockeynut.com
+issmarterthanyou.com
+isteingeek.de
+istmein.de
+kicks-ass.net
+kicks-ass.org
+knowsitall.info
+land-4-sale.us
+lebtimnetz.de
+leitungsen.de
+likes-pie.com
+likescandy.com
+merseine.nu
+mine.nu
+misconfused.org
+mypets.ws
+myphotos.cc
+neat-url.com
+office-on-the.net
+on-the-web.tv
+podzone.net
+podzone.org
+readmyblog.org
+saves-the-whales.com
+scrapper-site.net
+scrapping.cc
+selfip.biz
+selfip.com
+selfip.info
+selfip.net
+selfip.org
+sells-for-less.com
+sells-for-u.com
+sells-it.net
+sellsyourhome.org
+servebbs.com
+servebbs.net
+servebbs.org
+serveftp.net
+serveftp.org
+servegame.org
+shacknet.nu
+simple-url.com
+space-to-rent.com
+stuff-4-sale.org
+stuff-4-sale.us
+teaches-yoga.com
+thruhere.net
+traeumtgerade.de
+webhop.biz
+webhop.info
+webhop.net
+webhop.org
+worse-than.tv
+writesthisblog.com
+
+// ===END PRIVATE DOMAINS===
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tough-cookie/test.js	(revision 517)
@@ -0,0 +1,1625 @@
+/*
+ * Copyright GoInstant, Inc. and other contributors. All rights reserved.
+ * 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.
+ */
+'use strict';
+var vows = require('vows');
+var assert = require('assert');
+var async = require('async');
+
+// NOTE use require("tough-cookie") in your own code:
+var tough = require('./lib/cookie');
+var Cookie = tough.Cookie;
+var CookieJar = tough.CookieJar;
+
+
+function dateVows(table) {
+  var theVows = { };
+  Object.keys(table).forEach(function(date) {
+    var expect = table[date];
+    theVows[date] = function() {
+      var got = tough.parseDate(date) ? 'valid' : 'invalid';
+      assert.equal(got, expect ? 'valid' : 'invalid');
+    };
+  });
+  return { "date parsing": theVows };
+}
+
+function matchVows(func,table) {
+  var theVows = {};
+  table.forEach(function(item) {
+    var str = item[0];
+    var dom = item[1];
+    var expect = item[2];
+    var label = str+(expect?" matches ":" doesn't match ")+dom;
+    theVows[label] = function() {
+      assert.equal(func(str,dom),expect);
+    };
+  });
+  return theVows;
+}
+
+function defaultPathVows(table) {
+  var theVows = {};
+  table.forEach(function(item) {
+    var str = item[0];
+    var expect = item[1];
+    var label = str+" gives "+expect;
+    theVows[label] = function() {
+      assert.equal(tough.defaultPath(str),expect);
+    };
+  });
+  return theVows;
+}
+
+var atNow = Date.now();
+function at(offset) { return {now: new Date(atNow+offset)}; }
+
+vows.describe('Cookie Jar')
+.addBatch({
+  "all defined": function() {
+    assert.ok(Cookie);
+    assert.ok(CookieJar);
+  },
+})
+.addBatch(
+  dateVows({
+    "Wed, 09 Jun 2021 10:18:14 GMT": true,
+    "Wed, 09 Jun 2021 22:18:14 GMT": true,
+    "Tue, 18 Oct 2011 07:42:42.123 GMT": true,
+    "18 Oct 2011 07:42:42 GMT": true,
+    "8 Oct 2011 7:42:42 GMT": true,
+    "8 Oct 2011 7:2:42 GMT": false,
+    "Oct 18 2011 07:42:42 GMT": true,
+    "Tue Oct 18 2011 07:05:03 GMT+0000 (GMT)": true,
+    "09 Jun 2021 10:18:14 GMT": true,
+    "99 Jix 3038 48:86:72 ZMT": false,
+    '01 Jan 1970 00:00:00 GMT': true,
+    '01 Jan 1600 00:00:00 GMT': false, // before 1601
+    '01 Jan 1601 00:00:00 GMT': true,
+    '10 Feb 81 13:00:00 GMT': true, // implicit year
+    'Thu, 01 Jan 1970 00:00:010 GMT': true, // strange time, non-strict OK
+    'Thu, 17-Apr-2014 02:12:29 GMT': true, // dashes
+    'Thu, 17-Apr-2014 02:12:29 UTC': true, // dashes and UTC
+  })
+)
+.addBatch({
+  "strict date parse of Thu, 01 Jan 1970 00:00:010 GMT": {
+    topic: function() {
+      return tough.parseDate('Thu, 01 Jan 1970 00:00:010 GMT', true) ? true : false;
+    },
+    "invalid": function(date) {
+      assert.equal(date,false);
+    },
+  }
+})
+.addBatch({
+  "formatting": {
+    "a simple cookie": {
+      topic: function() {
+        var c = new Cookie();
+        c.key = 'a';
+        c.value = 'b';
+        return c;
+      },
+      "validates": function(c) {
+        assert.ok(c.validate());
+      },
+      "to string": function(c) {
+        assert.equal(c.toString(), 'a=b');
+      },
+    },
+    "a cookie with spaces in the value": {
+      topic: function() {
+        var c = new Cookie();
+        c.key = 'a';
+        c.value = 'beta gamma';
+        return c;
+      },
+      "doesn't validate": function(c) {
+        assert.ok(!c.validate());
+      },
+      "'garbage in, garbage out'": function(c) {
+        assert.equal(c.toString(), 'a=beta gamma');
+      },
+    },
+    "with an empty value and HttpOnly": {
+      topic: function() {
+        var c = new Cookie();
+        c.key = 'a';
+        c.httpOnly = true;
+        return c;
+      },
+      "to string": function(c) {
+        assert.equal(c.toString(), 'a=; HttpOnly');
+      }
+    },
+    "with an expiry": {
+      topic: function() {
+        var c = new Cookie();
+        c.key = 'a';
+        c.value = 'b';
+        c.setExpires("Oct 18 2011 07:05:03 GMT");
+        return c;
+      },
+      "validates": function(c) {
+        assert.ok(c.validate());
+      },
+      "to string": function(c) {
+        assert.equal(c.toString(), 'a=b; Expires=Tue, 18 Oct 2011 07:05:03 GMT');
+      },
+      "to short string": function(c) {
+        assert.equal(c.cookieString(), 'a=b');
+      },
+    },
+    "with a max-age": {
+      topic: function() {
+        var c = new Cookie();
+        c.key = 'a';
+        c.value = 'b';
+        c.setExpires("Oct 18 2011 07:05:03 GMT");
+        c.maxAge = 12345;
+        return c;
+      },
+      "validates": function(c) {
+        assert.ok(c.validate()); // mabe this one *shouldn't*?
+      },
+      "to string": function(c) {
+        assert.equal(c.toString(), 'a=b; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Max-Age=12345');
+      },
+    },
+    "with a bunch of things": function() {
+      var c = new Cookie();
+      c.key = 'a';
+      c.value = 'b';
+      c.setExpires("Oct 18 2011 07:05:03 GMT");
+      c.maxAge = 12345;
+      c.domain = 'example.com';
+      c.path = '/foo';
+      c.secure = true;
+      c.httpOnly = true;
+      c.extensions = ['MyExtension'];
+      assert.equal(c.toString(), 'a=b; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Max-Age=12345; Domain=example.com; Path=/foo; Secure; HttpOnly; MyExtension');
+    },
+    "a host-only cookie": {
+      topic: function() {
+        var c = new Cookie();
+        c.key = 'a';
+        c.value = 'b';
+        c.hostOnly = true;
+        c.domain = 'shouldnt-stringify.example.com';
+        c.path = '/should-stringify';
+        return c;
+      },
+      "validates": function(c) {
+        assert.ok(c.validate());
+      },
+      "to string": function(c) {
+        assert.equal(c.toString(), 'a=b; Path=/should-stringify');
+      },
+    },
+    "minutes are '10'": {
+      topic: function() {
+        var c = new Cookie();
+        c.key = 'a';
+        c.value = 'b';
+        c.expires = new Date(1284113410000);
+        return c;
+      },
+      "validates": function(c) {
+        assert.ok(c.validate());
+      },
+      "to string": function(c) {
+        var str = c.toString();
+        assert.notEqual(str, 'a=b; Expires=Fri, 010 Sep 2010 010:010:010 GMT');
+        assert.equal(str, 'a=b; Expires=Fri, 10 Sep 2010 10:10:10 GMT');
+      },
+    }
+  }
+})
+.addBatch({
+  "TTL with max-age": function() {
+    var c = new Cookie();
+    c.maxAge = 123;
+    assert.equal(c.TTL(), 123000);
+    assert.equal(c.expiryTime(new Date(9000000)), 9123000);
+  },
+  "TTL with zero max-age": function() {
+    var c = new Cookie();
+    c.key = 'a'; c.value = 'b';
+    c.maxAge = 0; // should be treated as "earliest representable"
+    assert.equal(c.TTL(), 0);
+    assert.equal(c.expiryTime(new Date(9000000)), -Infinity);
+    assert.ok(!c.validate()); // not valid, really: non-zero-digit *DIGIT
+  },
+  "TTL with negative max-age": function() {
+    var c = new Cookie();
+    c.key = 'a'; c.value = 'b';
+    c.maxAge = -1; // should be treated as "earliest representable"
+    assert.equal(c.TTL(), 0);
+    assert.equal(c.expiryTime(new Date(9000000)), -Infinity);
+    assert.ok(!c.validate()); // not valid, really: non-zero-digit *DIGIT
+  },
+  "TTL with max-age and expires": function() {
+    var c = new Cookie();
+    c.maxAge = 123;
+    c.expires = new Date(Date.now()+9000);
+    assert.equal(c.TTL(), 123000);
+    assert.ok(c.isPersistent());
+  },
+  "TTL with expires": function() {
+    var c = new Cookie();
+    var now = Date.now();
+    c.expires = new Date(now+9000);
+    assert.equal(c.TTL(now), 9000);
+    assert.equal(c.expiryTime(), c.expires.getTime());
+  },
+  "TTL with old expires": function() {
+    var c = new Cookie();
+    c.setExpires('17 Oct 2010 00:00:00 GMT');
+    assert.ok(c.TTL() < 0);
+    assert.ok(c.isPersistent());
+  },
+  "default TTL": {
+    topic: function() { return new Cookie(); },
+    "is Infinite-future": function(c) { assert.equal(c.TTL(), Infinity) },
+    "is a 'session' cookie": function(c) { assert.ok(!c.isPersistent()) },
+  },
+}).addBatch({
+  "Parsing": {
+    "simple": {
+      topic: function() {
+        return Cookie.parse('a=bcd',true) || null;
+      },
+      "parsed": function(c) { assert.ok(c) },
+      "key": function(c) { assert.equal(c.key, 'a') },
+      "value": function(c) { assert.equal(c.value, 'bcd') },
+      "no path": function(c) { assert.equal(c.path, null) },
+      "no domain": function(c) { assert.equal(c.domain, null) },
+      "no extensions": function(c) { assert.ok(!c.extensions) },
+    },
+    "with expiry": {
+      topic: function() {
+        return Cookie.parse('a=bcd; Expires=Tue, 18 Oct 2011 07:05:03 GMT',true) || null;
+      },
+      "parsed": function(c) { assert.ok(c) },
+      "key": function(c) { assert.equal(c.key, 'a') },
+      "value": function(c) { assert.equal(c.value, 'bcd') },
+      "has expires": function(c) {
+        assert.ok(c.expires !== Infinity, 'expiry is infinite when it shouldn\'t be');
+        assert.equal(c.expires.getTime(), 1318921503000);
+      },
+    },
+    "with expiry and path": {
+      topic: function() {
+        return Cookie.parse('abc="xyzzy!"; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Path=/aBc',true) || null;
+      },
+      "parsed": function(c) { assert.ok(c) },
+      "key": function(c) { assert.equal(c.key, 'abc') },
+      "value": function(c) { assert.equal(c.value, 'xyzzy!') },
+      "has expires": function(c) {
+        assert.ok(c.expires !== Infinity, 'expiry is infinite when it shouldn\'t be');
+        assert.equal(c.expires.getTime(), 1318921503000);
+      },
+      "has path": function(c) { assert.equal(c.path, '/aBc'); },
+      "no httponly or secure": function(c) {
+        assert.ok(!c.httpOnly);
+        assert.ok(!c.secure);
+      },
+    },
+    "with everything": {
+      topic: function() {
+        return Cookie.parse('abc="xyzzy!"; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Path=/aBc; Domain=example.com; Secure; HTTPOnly; Max-Age=1234; Foo=Bar; Baz', true) || null;
+      },
+      "parsed": function(c) { assert.ok(c) },
+      "key": function(c) { assert.equal(c.key, 'abc') },
+      "value": function(c) { assert.equal(c.value, 'xyzzy!') },
+      "has expires": function(c) {
+        assert.ok(c.expires !== Infinity, 'expiry is infinite when it shouldn\'t be');
+        assert.equal(c.expires.getTime(), 1318921503000);
+      },
+      "has path": function(c) { assert.equal(c.path, '/aBc'); },
+      "has domain": function(c) { assert.equal(c.domain, 'example.com'); },
+      "has httponly": function(c) { assert.equal(c.httpOnly, true); },
+      "has secure": function(c) { assert.equal(c.secure, true); },
+      "has max-age": function(c) { assert.equal(c.maxAge, 1234); },
+      "has extensions": function(c) {
+        assert.ok(c.extensions);
+        assert.equal(c.extensions[0], 'Foo=Bar');
+        assert.equal(c.extensions[1], 'Baz');
+      },
+    },
+    "invalid expires": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; Expires=xyzzy", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; Expires=xyzzy");
+        assert.ok(c);
+        assert.equal(c.expires, Infinity);
+      },
+    },
+    "zero max-age": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; Max-Age=0", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; Max-Age=0");
+        assert.ok(c);
+        assert.equal(c.maxAge, 0);
+      },
+    },
+    "negative max-age": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; Max-Age=-1", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; Max-Age=-1");
+        assert.ok(c);
+        assert.equal(c.maxAge, -1);
+      },
+    },
+    "empty domain": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; domain=", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; domain=");
+        assert.ok(c);
+        assert.equal(c.domain, null);
+      },
+    },
+    "dot domain": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; domain=.", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; domain=.");
+        assert.ok(c);
+        assert.equal(c.domain, null);
+      },
+    },
+    "uppercase domain": {
+      "strict lowercases": function() {
+        var c = Cookie.parse("a=b; domain=EXAMPLE.COM");
+        assert.ok(c);
+        assert.equal(c.domain, 'example.com');
+      },
+      "non-strict lowercases": function() {
+        var c = Cookie.parse("a=b; domain=EXAMPLE.COM");
+        assert.ok(c);
+        assert.equal(c.domain, 'example.com');
+      },
+    },
+    "trailing dot in domain": {
+      topic: function() {
+        return Cookie.parse("a=b; Domain=example.com.", true) || null;
+      },
+      "has the domain": function(c) { assert.equal(c.domain,"example.com.") },
+      "but doesn't validate": function(c) { assert.equal(c.validate(),false) },
+    },
+    "empty path": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; path=", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; path=");
+        assert.ok(c);
+        assert.equal(c.path, null);
+      },
+    },
+    "no-slash path": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; path=xyzzy", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; path=xyzzy");
+        assert.ok(c);
+        assert.equal(c.path, null);
+      },
+    },
+    "trailing semi-colons after path": {
+      topic: function () {
+        return [
+          "a=b; path=/;",
+          "c=d;;;;"
+        ];
+      },
+      "strict": function (t) {
+        assert.ok(!Cookie.parse(t[0], true));
+        assert.ok(!Cookie.parse(t[1], true));
+      },
+      "non-strict": function (t) {
+        var c1 = Cookie.parse(t[0]);
+        var c2 = Cookie.parse(t[1]);
+        assert.ok(c1);
+        assert.ok(c2);
+        assert.equal(c1.path, '/');
+      }
+    },
+    "secure-with-value": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; Secure=xyzzy", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; Secure=xyzzy");
+        assert.ok(c);
+        assert.equal(c.secure, true);
+      },
+    },
+    "httponly-with-value": {
+      "strict": function() { assert.ok(!Cookie.parse("a=b; HttpOnly=xyzzy", true)) },
+      "non-strict": function() {
+        var c = Cookie.parse("a=b; HttpOnly=xyzzy");
+        assert.ok(c);
+        assert.equal(c.httpOnly, true);
+      },
+    },
+    "garbage": {
+      topic: function() {
+        return Cookie.parse("\x08", true) || null;
+      },
+      "doesn't parse": function(c) { assert.equal(c,null) },
+    },
+    "public suffix domain": {
+      topic: function() {
+        return Cookie.parse("a=b; domain=kyoto.jp", true) || null;
+      },
+      "parses fine": function(c) {
+        assert.ok(c);
+        assert.equal(c.domain, 'kyoto.jp');
+      },
+      "but fails validation": function(c) {
+        assert.ok(c);
+        assert.ok(!c.validate());
+      },
+    },
+    "Ironically, Google 'GAPS' cookie has very little whitespace": {
+      topic: function() {
+        return Cookie.parse("GAPS=1:A1aaaaAaAAa1aaAaAaaAAAaaa1a11a:aaaAaAaAa-aaaA1-;Path=/;Expires=Thu, 17-Apr-2014 02:12:29 GMT;Secure;HttpOnly");
+      },
+      "parsed": function(c) { assert.ok(c) },
+      "key": function(c) { assert.equal(c.key, 'GAPS') },
+      "value": function(c) { assert.equal(c.value, '1:A1aaaaAaAAa1aaAaAaaAAAaaa1a11a:aaaAaAaAa-aaaA1-') },
+      "path": function(c) {
+        assert.notEqual(c.path, '/;Expires'); // BUG
+        assert.equal(c.path, '/');
+      },
+      "expires": function(c) {
+        assert.notEqual(c.expires, Infinity);
+        assert.equal(c.expires.getTime(), 1397700749000);
+      },
+      "secure": function(c) { assert.ok(c.secure) },
+      "httponly": function(c) { assert.ok(c.httpOnly) },
+    },
+    "lots of equal signs": {
+      topic: function() {
+        return Cookie.parse("queryPref=b=c&d=e; Path=/f=g; Expires=Thu, 17 Apr 2014 02:12:29 GMT; HttpOnly");
+      },
+      "parsed": function(c) { assert.ok(c) },
+      "key": function(c) { assert.equal(c.key, 'queryPref') },
+      "value": function(c) { assert.equal(c.value, 'b=c&d=e') },
+      "path": function(c) {
+        assert.equal(c.path, '/f=g');
+      },
+      "expires": function(c) {
+        assert.notEqual(c.expires, Infinity);
+        assert.equal(c.expires.getTime(), 1397700749000);
+      },
+      "httponly": function(c) { assert.ok(c.httpOnly) },
+    },
+    "spaces in value": {
+      "strict": {
+        topic: function() {
+          return Cookie.parse('a=one two three',true) || null;
+        },
+        "did not parse": function(c) { assert.isNull(c) },
+      },
+      "non-strict": {
+        topic: function() {
+          return Cookie.parse('a=one two three',false) || null;
+        },
+        "parsed": function(c) { assert.ok(c) },
+        "key": function(c) { assert.equal(c.key, 'a') },
+        "value": function(c) { assert.equal(c.value, 'one two three') },
+        "no path": function(c) { assert.equal(c.path, null) },
+        "no domain": function(c) { assert.equal(c.domain, null) },
+        "no extensions": function(c) { assert.ok(!c.extensions) },
+      },
+    },
+    "quoted spaces in value": {
+      "strict": {
+        topic: function() {
+          return Cookie.parse('a="one two three"',true) || null;
+        },
+        "did not parse": function(c) { assert.isNull(c) },
+      },
+      "non-strict": {
+        topic: function() {
+          return Cookie.parse('a="one two three"',false) || null;
+        },
+        "parsed": function(c) { assert.ok(c) },
+        "key": function(c) { assert.equal(c.key, 'a') },
+        "value": function(c) { assert.equal(c.value, 'one two three') },
+        "no path": function(c) { assert.equal(c.path, null) },
+        "no domain": function(c) { assert.equal(c.domain, null) },
+        "no extensions": function(c) { assert.ok(!c.extensions) },
+      }
+    },
+    "non-ASCII in value": {
+      "strict": {
+        topic: function() {
+          return Cookie.parse('farbe=weiÃ',true) || null;
+        },
+        "did not parse": function(c) { assert.isNull(c) },
+      },
+      "non-strict": {
+        topic: function() {
+          return Cookie.parse('farbe=weiÃ',false) || null;
+        },
+        "parsed": function(c) { assert.ok(c) },
+        "key": function(c) { assert.equal(c.key, 'farbe') },
+        "value": function(c) { assert.equal(c.value, 'weiÃ') },
+        "no path": function(c) { assert.equal(c.path, null) },
+        "no domain": function(c) { assert.equal(c.domain, null) },
+        "no extensions": function(c) { assert.ok(!c.extensions) },
+      },
+    },
+  }
+})
+.addBatch({
+  "domain normalization": {
+    "simple": function() {
+      var c = new Cookie();
+      c.domain = "EXAMPLE.com";
+      assert.equal(c.canonicalizedDomain(), "example.com");
+    },
+    "extra dots": function() {
+      var c = new Cookie();
+      c.domain = ".EXAMPLE.com";
+      assert.equal(c.cdomain(), "example.com");
+    },
+    "weird trailing dot": function() {
+      var c = new Cookie();
+      c.domain = "EXAMPLE.ca.";
+      assert.equal(c.canonicalizedDomain(), "example.ca.");
+    },
+    "weird internal dots": function() {
+      var c = new Cookie();
+      c.domain = "EXAMPLE...ca.";
+      assert.equal(c.canonicalizedDomain(), "example...ca.");
+    },
+    "IDN": function() {
+      var c = new Cookie();
+      c.domain = "ÎŽÎ¿ÎºÎ¹ÎŒÎ®.ÎŽÎ¿ÎºÎ¹ÎŒÎ®"; // "test.test" in greek
+      assert.equal(c.canonicalizedDomain(), "xn--jxalpdlp.xn--jxalpdlp");
+    }
+  }
+})
+.addBatch({
+  "Domain Match":matchVows(tough.domainMatch, [
+    // str,          dom,          expect
+    ["example.com", "example.com", true],
+    ["eXaMpLe.cOm", "ExAmPlE.CoM", true],
+    ["no.ca", "yes.ca", false],
+    ["wwwexample.com", "example.com", false],
+    ["www.example.com", "example.com", true],
+    ["example.com", "www.example.com", false],
+    ["www.subdom.example.com", "example.com", true],
+    ["www.subdom.example.com", "subdom.example.com", true],
+    ["example.com", "example.com.", false], // RFC6265 S4.1.2.3
+    ["192.168.0.1", "168.0.1", false], // S5.1.3 "The string is a host name"
+    [null, "example.com", null],
+    ["example.com", null, null],
+    [null, null, null],
+    [undefined, undefined, null],
+  ])
+})
+.addBatch({
+  "default-path": defaultPathVows([
+    [null,"/"],
+    ["/","/"],
+    ["/file","/"],
+    ["/dir/file","/dir"],
+    ["noslash","/"],
+  ])
+})
+.addBatch({
+  "Path-Match": matchVows(tough.pathMatch, [
+    // request, cookie, match
+    ["/","/",true],
+    ["/dir","/",true],
+    ["/","/dir",false],
+    ["/dir/","/dir/", true],
+    ["/dir/file","/dir/",true],
+    ["/dir/file","/dir",true],
+    ["/directory","/dir",false],
+  ])
+})
+.addBatch({
+  "Cookie Sorting": {
+    topic: function() {
+      var cookies = [];
+      var now = Date.now();
+      cookies.push(Cookie.parse("a=0; Domain=example.com"));
+      cookies.push(Cookie.parse("b=1; Domain=www.example.com"));
+      cookies.push(Cookie.parse("c=2; Domain=example.com; Path=/pathA"));
+      cookies.push(Cookie.parse("d=3; Domain=www.example.com; Path=/pathA"));
+      cookies.push(Cookie.parse("e=4; Domain=example.com; Path=/pathA/pathB"));
+      cookies.push(Cookie.parse("f=5; Domain=www.example.com; Path=/pathA/pathB"));
+
+      // force a stable creation time consistent with the order above since
+      // some may have been created at now + 1ms.
+      var i = cookies.length;
+      cookies.forEach(function(cookie) {
+        cookie.creation = new Date(now - 100*(i--));
+      });
+
+      // weak shuffle:
+      cookies = cookies.sort(function(){return Math.random()-0.5});
+
+      cookies = cookies.sort(tough.cookieCompare);
+      return cookies;
+    },
+    "got": function(cookies) {
+      assert.lengthOf(cookies, 6);
+      var names = cookies.map(function(c) {return c.key});
+      assert.deepEqual(names, ['e','f','c','d','a','b']);
+    },
+  }
+})
+.addBatch({
+  "CookieJar": {
+    "Setting a basic cookie": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=example.com; Path=/");
+        assert.strictEqual(c.hostOnly, null);
+        assert.instanceOf(c.creation, Date);
+        assert.strictEqual(c.lastAccessed, null);
+        c.creation = new Date(Date.now()-10000);
+        cj.setCookie(c, 'http://example.com/index.html', this.callback);
+      },
+      "works": function(c) { assert.instanceOf(c,Cookie) }, // C is for Cookie, good enough for me
+      "gets timestamped": function(c) {
+        assert.ok(c.creation);
+        assert.ok(Date.now() - c.creation.getTime() < 5000); // recently stamped
+        assert.ok(c.lastAccessed);
+        assert.equal(c.creation, c.lastAccessed);
+        assert.equal(c.TTL(), Infinity);
+        assert.ok(!c.isPersistent());
+      },
+    },
+    "Setting a no-path cookie": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=example.com");
+        assert.strictEqual(c.hostOnly, null);
+        assert.instanceOf(c.creation, Date);
+        assert.strictEqual(c.lastAccessed, null);
+        c.creation = new Date(Date.now()-10000);
+        cj.setCookie(c, 'http://example.com/index.html', this.callback);
+      },
+      "domain": function(c) { assert.equal(c.domain, 'example.com') },
+      "path is /": function(c) { assert.equal(c.path, '/') },
+      "path was derived": function(c) { assert.strictEqual(c.pathIsDefault, true) },
+    },
+    "Setting a cookie already marked as host-only": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=example.com");
+        assert.strictEqual(c.hostOnly, null);
+        assert.instanceOf(c.creation, Date);
+        assert.strictEqual(c.lastAccessed, null);
+        c.creation = new Date(Date.now()-10000);
+        c.hostOnly = true;
+        cj.setCookie(c, 'http://example.com/index.html', this.callback);
+      },
+      "domain": function(c) { assert.equal(c.domain, 'example.com') },
+      "still hostOnly": function(c) { assert.strictEqual(c.hostOnly, true) },
+    },
+    "Setting a session cookie": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b");
+        assert.strictEqual(c.path, null);
+        cj.setCookie(c, 'http://www.example.com/dir/index.html', this.callback);
+      },
+      "works": function(c) { assert.instanceOf(c,Cookie) },
+      "gets the domain": function(c) { assert.equal(c.domain, 'www.example.com') },
+      "gets the default path": function(c) { assert.equal(c.path, '/dir') },
+      "is 'hostOnly'": function(c) { assert.ok(c.hostOnly) },
+    },
+    "Setting wrong domain cookie": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=fooxample.com; Path=/");
+        cj.setCookie(c, 'http://example.com/index.html', this.callback);
+      },
+      "fails": function(err,c) {
+        assert.ok(err.message.match(/domain/i));
+        assert.ok(!c);
+      },
+    },
+    "Setting sub-domain cookie": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=www.example.com; Path=/");
+        cj.setCookie(c, 'http://example.com/index.html', this.callback);
+      },
+      "fails": function(err,c) {
+        assert.ok(err.message.match(/domain/i));
+        assert.ok(!c);
+      },
+    },
+    "Setting super-domain cookie": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=example.com; Path=/");
+        cj.setCookie(c, 'http://www.app.example.com/index.html', this.callback);
+      },
+      "success": function(err,c) {
+        assert.ok(!err);
+        assert.equal(c.domain, 'example.com');
+      },
+    },
+    "Setting a sub-path cookie on a super-domain": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=example.com; Path=/subpath");
+        assert.strictEqual(c.hostOnly, null);
+        assert.instanceOf(c.creation, Date);
+        assert.strictEqual(c.lastAccessed, null);
+        c.creation = new Date(Date.now()-10000);
+        cj.setCookie(c, 'http://www.example.com/index.html', this.callback);
+      },
+      "domain is super-domain": function(c) { assert.equal(c.domain, 'example.com') },
+      "path is /subpath": function(c) { assert.equal(c.path, '/subpath') },
+      "path was NOT derived": function(c) { assert.strictEqual(c.pathIsDefault, null) },
+    },
+    "Setting HttpOnly cookie over non-HTTP API": {
+      topic: function() {
+        var cj = new CookieJar();
+        var c = Cookie.parse("a=b; Domain=example.com; Path=/; HttpOnly");
+        cj.setCookie(c, 'http://example.com/index.html', {http:false}, this.callback);
+      },
+      "fails": function(err,c) {
+        assert.match(err.message, /HttpOnly/i);
+        assert.ok(!c);
+      },
+    },
+  },
+  "Cookie Jar store eight cookies": {
+    topic: function() {
+      var cj = new CookieJar();
+      var ex = 'http://example.com/index.html';
+      var tasks = [];
+      tasks.push(function(next) {
+        cj.setCookie('a=1; Domain=example.com; Path=/',ex,at(0),next);
+      });
+      tasks.push(function(next) {
+        cj.setCookie('b=2; Domain=example.com; Path=/; HttpOnly',ex,at(1000),next);
+      });
+      tasks.push(function(next) {
+        cj.setCookie('c=3; Domain=example.com; Path=/; Secure',ex,at(2000),next);
+      });
+      tasks.push(function(next) { // path
+        cj.setCookie('d=4; Domain=example.com; Path=/foo',ex,at(3000),next);
+      });
+      tasks.push(function(next) { // host only
+        cj.setCookie('e=5',ex,at(4000),next);
+      });
+      tasks.push(function(next) { // other domain
+        cj.setCookie('f=6; Domain=nodejs.org; Path=/','http://nodejs.org',at(5000),next);
+      });
+      tasks.push(function(next) { // expired
+        cj.setCookie('g=7; Domain=example.com; Path=/; Expires=Tue, 18 Oct 2011 00:00:00 GMT',ex,at(6000),next);
+      });
+      tasks.push(function(next) { // expired via Max-Age
+        cj.setCookie('h=8; Domain=example.com; Path=/; Max-Age=1',ex,next);
+      });
+      var cb = this.callback;
+      async.parallel(tasks, function(err,results){
+        setTimeout(function() {
+          cb(err,cj,results);
+        }, 2000); // so that 'h=8' expires
+      });
+    },
+    "setup ok": function(err,cj,results) {
+      assert.ok(!err);
+      assert.ok(cj);
+      assert.ok(results);
+    },
+    "then retrieving for http://nodejs.org": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('http://nodejs.org',this.callback);
+      },
+      "get a nodejs cookie": function(cookies) {
+        assert.lengthOf(cookies, 1);
+        var cookie = cookies[0];
+        assert.equal(cookie.domain, 'nodejs.org');
+      },
+    },
+    "then retrieving for https://example.com": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('https://example.com',{secure:true},this.callback);
+      },
+      "get a secure example cookie with others": function(cookies) {
+        var names = cookies.map(function(c) {return c.key});
+        assert.deepEqual(names, ['a','b','c','e']);
+      },
+    },
+    "then retrieving for https://example.com (missing options)": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('https://example.com',this.callback);
+      },
+      "get a secure example cookie with others": function(cookies) {
+        var names = cookies.map(function(c) {return c.key});
+        assert.deepEqual(names, ['a','b','c','e']);
+      },
+    },
+    "then retrieving for http://example.com": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('http://example.com',this.callback);
+      },
+      "get a bunch of cookies": function(cookies) {
+        var names = cookies.map(function(c) {return c.key});
+        assert.deepEqual(names, ['a','b','e']);
+      },
+    },
+    "then retrieving for http://EXAMPlE.com": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('http://EXAMPlE.com',this.callback);
+      },
+      "get a bunch of cookies": function(cookies) {
+        var names = cookies.map(function(c) {return c.key});
+        assert.deepEqual(names, ['a','b','e']);
+      },
+    },
+    "then retrieving for http://example.com, non-HTTP": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('http://example.com',{http:false},this.callback);
+      },
+      "get a bunch of cookies": function(cookies) {
+        var names = cookies.map(function(c) {return c.key});
+        assert.deepEqual(names, ['a','e']);
+      },
+    },
+    "then retrieving for http://example.com/foo/bar": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('http://example.com/foo/bar',this.callback);
+      },
+      "get a bunch of cookies": function(cookies) {
+        var names = cookies.map(function(c) {return c.key});
+        assert.deepEqual(names, ['d','a','b','e']);
+      },
+    },
+    "then retrieving for http://example.com as a string": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookieString('http://example.com',this.callback);
+      },
+      "get a single string": function(cookieHeader) {
+        assert.equal(cookieHeader, "a=1; b=2; e=5");
+      },
+    },
+    "then retrieving for http://example.com as a set-cookie header": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getSetCookieStrings('http://example.com',this.callback);
+      },
+      "get a single string": function(cookieHeaders) {
+        assert.lengthOf(cookieHeaders, 3);
+        assert.equal(cookieHeaders[0], "a=1; Domain=example.com; Path=/");
+        assert.equal(cookieHeaders[1], "b=2; Domain=example.com; Path=/; HttpOnly");
+        assert.equal(cookieHeaders[2], "e=5; Path=/");
+      },
+    },
+    "then retrieving for http://www.example.com/": {
+      topic: function(cj,oldResults) {
+        assert.ok(oldResults);
+        cj.getCookies('http://www.example.com/foo/bar',this.callback);
+      },
+      "get a bunch of cookies": function(cookies) {
+        var names = cookies.map(function(c) {return c.key});
+        assert.deepEqual(names, ['d','a','b']); // note lack of 'e'
+      },
+    },
+  },
+  "Repeated names": {
+    topic: function() {
+      var cb = this.callback;
+      var cj = new CookieJar();
+      var ex = 'http://www.example.com/';
+      var sc = cj.setCookie;
+      var tasks = [];
+      var now = Date.now();
+      tasks.push(sc.bind(cj,'aaaa=xxxx',ex,at(0)));
+      tasks.push(sc.bind(cj,'aaaa=1111; Domain=www.example.com',ex,at(1000)));
+      tasks.push(sc.bind(cj,'aaaa=2222; Domain=example.com',ex,at(2000)));
+      tasks.push(sc.bind(cj,'aaaa=3333; Domain=www.example.com; Path=/pathA',ex,at(3000)));
+      async.series(tasks,function(err,results) {
+        results = results.filter(function(e) {return e !== undefined});
+        cb(err,{cj:cj, cookies:results, now:now});
+      });
+    },
+    "all got set": function(err,t) {
+      assert.lengthOf(t.cookies,4);
+    },
+    "then getting 'em back": {
+      topic: function(t) {
+        var cj = t.cj;
+        cj.getCookies('http://www.example.com/pathA',this.callback);
+      },
+      "there's just three": function (err,cookies) {
+        var vals = cookies.map(function(c) {return c.value});
+        // may break with sorting; sorting should put 3333 first due to longest path:
+        assert.deepEqual(vals, ['3333','1111','2222']);
+      }
+    },
+  },
+  "CookieJar setCookie errors": {
+    "public-suffix domain": {
+      topic: function() {
+        var cj = new CookieJar();
+        cj.setCookie('i=9; Domain=kyoto.jp; Path=/','kyoto.jp',this.callback);
+      },
+      "errors": function(err,cookie) {
+        assert.ok(err);
+        assert.ok(!cookie);
+        assert.match(err.message, /public suffix/i);
+      },
+    },
+    "wrong domain": {
+      topic: function() {
+        var cj = new CookieJar();
+        cj.setCookie('j=10; Domain=google.com; Path=/','google.ca',this.callback);
+      },
+      "errors": function(err,cookie) {
+        assert.ok(err);
+        assert.ok(!cookie);
+        assert.match(err.message, /not in this host's domain/i);
+      },
+    },
+    "old cookie is HttpOnly": {
+      topic: function() {
+        var cb = this.callback;
+        var next = function (err,c) {
+          c = null;
+          return cb(err,cj);
+        };
+        var cj = new CookieJar();
+        cj.setCookie('k=11; Domain=example.ca; Path=/; HttpOnly','http://example.ca',{http:true},next);
+      },
+      "initial cookie is set": function(err,cj) {
+        assert.ok(!err);
+        assert.ok(cj);
+      },
+      "but when trying to overwrite": {
+        topic: function(cj) {
+          var cb = this.callback;
+          var next = function(err,c) {
+            c = null;
+            cb(null,err);
+          };
+          cj.setCookie('k=12; Domain=example.ca; Path=/','http://example.ca',{http:false},next);
+        },
+        "it's an error": function(err) {
+          assert.ok(err);
+        },
+        "then, checking the original": {
+          topic: function(ignored,cj) {
+            assert.ok(cj instanceof CookieJar);
+            cj.getCookies('http://example.ca',{http:true},this.callback);
+          },
+          "cookie has original value": function(err,cookies) {
+            assert.equal(err,null);
+            assert.lengthOf(cookies, 1);
+            assert.equal(cookies[0].value,11);
+          },
+        },
+      },
+    },
+  },
+})
+.addBatch({
+  "JSON": {
+    "serialization": {
+      topic: function() {
+        var c = Cookie.parse('alpha=beta; Domain=example.com; Path=/foo; Expires=Tue, 19 Jan 2038 03:14:07 GMT; HttpOnly');
+        return JSON.stringify(c);
+      },
+      "gives a string": function(str) {
+        assert.equal(typeof str, "string");
+      },
+      "date is in ISO format": function(str) {
+        assert.match(str, /"expires":"2038-01-19T03:14:07\.000Z"/, 'expires is in ISO format');
+      },
+    },
+    "deserialization": {
+      topic: function() {
+        var json = '{"key":"alpha","value":"beta","domain":"example.com","path":"/foo","expires":"2038-01-19T03:14:07.000Z","httpOnly":true,"lastAccessed":2000000000123}';
+        return Cookie.fromJSON(json);
+      },
+      "works": function(c) {
+        assert.ok(c);
+      },
+      "key": function(c) { assert.equal(c.key, "alpha") },
+      "value": function(c) { assert.equal(c.value, "beta") },
+      "domain": function(c) { assert.equal(c.domain, "example.com") },
+      "path": function(c) { assert.equal(c.path, "/foo") },
+      "httpOnly": function(c) { assert.strictEqual(c.httpOnly, true) },
+      "secure": function(c) { assert.strictEqual(c.secure, false) },
+      "hostOnly": function(c) { assert.strictEqual(c.hostOnly, null) },
+      "expires is a date object": function(c) {
+        assert.equal(c.expires.getTime(), 2147483647000);
+      },
+      "lastAccessed is a date object": function(c) {
+        assert.equal(c.lastAccessed.getTime(), 2000000000123);
+      },
+      "creation defaulted": function(c) {
+        assert.ok(c.creation.getTime());
+      }
+    },
+    "null deserialization": {
+      topic: function() {
+        return Cookie.fromJSON(null);
+      },
+      "is null": function(cookie) {
+        assert.equal(cookie,null);
+      },
+    },
+  },
+  "expiry deserialization": {
+    "Infinity": {
+      topic: Cookie.fromJSON.bind(null, '{"expires":"Infinity"}'),
+      "is infinite": function(c) {
+        assert.strictEqual(c.expires, "Infinity");
+        assert.equal(c.expires, Infinity);
+      },
+    },
+  },
+  "maxAge serialization": {
+    topic: function() {
+      return function(toSet) {
+        var c = new Cookie();
+        c.key = 'foo'; c.value = 'bar';
+        c.setMaxAge(toSet);
+        return JSON.stringify(c);
+      };
+    },
+    "zero": {
+      topic: function(f) { return f(0) },
+      "looks good": function(str) {
+        assert.match(str, /"maxAge":0/);
+      },
+    },
+    "Infinity": {
+      topic: function(f) { return f(Infinity) },
+      "looks good": function(str) {
+        assert.match(str, /"maxAge":"Infinity"/);
+      },
+    },
+    "-Infinity": {
+      topic: function(f) { return f(-Infinity) },
+      "looks good": function(str) {
+        assert.match(str, /"maxAge":"-Infinity"/);
+      },
+    },
+    "null": {
+      topic: function(f) { return f(null) },
+      "looks good": function(str) {
+        assert.match(str, /"maxAge":null/);
+      },
+    },
+  },
+  "maxAge deserialization": {
+    "number": {
+      topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":123}'),
+      "is the number": function(c) {
+        assert.strictEqual(c.maxAge, 123);
+      },
+    },
+    "null": {
+      topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":null}'),
+      "is null": function(c) {
+        assert.strictEqual(c.maxAge, null);
+      },
+    },
+    "less than zero": {
+      topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":-123}'),
+      "is -123": function(c) {
+        assert.strictEqual(c.maxAge, -123);
+      },
+    },
+    "Infinity": {
+      topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":"Infinity"}'),
+      "is inf-as-string": function(c) {
+        assert.strictEqual(c.maxAge, "Infinity");
+      },
+    },
+    "-Infinity": {
+      topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":"-Infinity"}'),
+      "is inf-as-string": function(c) {
+        assert.strictEqual(c.maxAge, "-Infinity");
+      },
+    },
+  }
+})
+.addBatch({
+  "permuteDomain": {
+    "base case": {
+      topic: tough.permuteDomain.bind(null,'example.com'),
+      "got the domain": function(list) {
+        assert.deepEqual(list, ['example.com']);
+      },
+    },
+    "two levels": {
+      topic: tough.permuteDomain.bind(null,'foo.bar.example.com'),
+      "got three things": function(list) {
+        assert.deepEqual(list, ['example.com','bar.example.com','foo.bar.example.com']);
+      },
+    },
+    "invalid domain": {
+      topic: tough.permuteDomain.bind(null,'foo.bar.example.localduhmain'),
+      "got three things": function(list) {
+        assert.equal(list, null);
+      },
+    },
+  },
+  "permutePath": {
+    "base case": {
+      topic: tough.permutePath.bind(null,'/'),
+      "just slash": function(list) {
+        assert.deepEqual(list,['/']);
+      },
+    },
+    "single case": {
+      topic: tough.permutePath.bind(null,'/foo'),
+      "two things": function(list) {
+        assert.deepEqual(list,['/foo','/']);
+      },
+      "path matching": function(list) {
+        list.forEach(function(e) {
+          assert.ok(tough.pathMatch('/foo',e));
+        });
+      },
+    },
+    "double case": {
+      topic: tough.permutePath.bind(null,'/foo/bar'),
+      "four things": function(list) {
+        assert.deepEqual(list,['/foo/bar','/foo','/']);
+      },
+      "path matching": function(list) {
+        list.forEach(function(e) {
+          assert.ok(tough.pathMatch('/foo/bar',e));
+        });
+      },
+    },
+    "trailing slash": {
+      topic: tough.permutePath.bind(null,'/foo/bar/'),
+      "three things": function(list) {
+        assert.deepEqual(list,['/foo/bar','/foo','/']);
+      },
+      "path matching": function(list) {
+        list.forEach(function(e) {
+          assert.ok(tough.pathMatch('/foo/bar/',e));
+        });
+      },
+    },
+  }
+})
+.addBatch({
+  "Issue 1": {
+    topic: function() {
+      var cj = new CookieJar();
+      cj.setCookie('hello=world; path=/some/path/', 'http://domain/some/path/file', function(err,cookie) {
+        this.callback(err,{cj:cj, cookie:cookie});
+      }.bind(this));
+    },
+    "stored a cookie": function(t) {
+      assert.ok(t.cookie);
+    },
+    "cookie's path was modified to remove unnecessary slash": function(t) {
+      assert.equal(t.cookie.path, '/some/path');
+    },
+    "getting it back": {
+      topic: function(t) {
+        t.cj.getCookies('http://domain/some/path/file', function(err,cookies) {
+          this.callback(err, {cj:t.cj, cookies:cookies||[]});
+        }.bind(this));
+      },
+      "got one cookie": function(t) {
+        assert.lengthOf(t.cookies, 1);
+      },
+      "it's the right one": function(t) {
+        var c = t.cookies[0];
+        assert.equal(c.key, 'hello');
+        assert.equal(c.value, 'world');
+      },
+    }
+  }
+})
+.addBatch({
+  "expiry option": {
+    topic: function() {
+      var cb = this.callback;
+      var cj = new CookieJar();
+      cj.setCookie('near=expiry; Domain=example.com; Path=/; Max-Age=1','http://www.example.com',at(-1), function(err,cookie) {
+
+        cb(err, {cj:cj, cookie:cookie});
+      });
+    },
+    "set the cookie": function(t) {
+      assert.ok(t.cookie, "didn't set?!");
+      assert.equal(t.cookie.key, 'near');
+    },
+    "then, retrieving": {
+      topic: function(t) {
+        var cb = this.callback;
+        setTimeout(function() {
+          t.cj.getCookies('http://www.example.com', {http:true, expire:false}, function(err,cookies) {
+            t.cookies = cookies;
+            cb(err,t);
+          });
+        },2000);
+      },
+      "got the cookie": function(t) {
+        assert.lengthOf(t.cookies, 1);
+        assert.equal(t.cookies[0].key, 'near');
+      },
+    }
+  }
+})
+.addBatch({
+  "trailing semi-colon set into cj": {
+    topic: function () {
+      var cb = this.callback;
+      var cj = new CookieJar();
+      var ex = 'http://www.example.com';
+      var tasks = [];
+      tasks.push(function(next) {
+        cj.setCookie('broken_path=testme; path=/;',ex,at(-1),next);
+      });
+      tasks.push(function(next) {
+        cj.setCookie('b=2; Path=/;;;;',ex,at(-1),next);
+      });
+      async.parallel(tasks, function (err, cookies) {
+        cb(null, {
+          cj: cj,
+          cookies: cookies
+        });
+      });
+    },
+    "check number of cookies": function (t) {
+      assert.lengthOf(t.cookies, 2, "didn't set");
+    },
+    "check *broken_path* was set properly": function (t) {
+      assert.equal(t.cookies[0].key, "broken_path");
+      assert.equal(t.cookies[0].value, "testme");
+      assert.equal(t.cookies[0].path, "/");
+    },
+    "check *b* was set properly": function (t) {
+      assert.equal(t.cookies[1].key, "b");
+      assert.equal(t.cookies[1].value, "2");
+      assert.equal(t.cookies[1].path, "/");
+    },
+    "retrieve the cookie": {
+      topic: function (t) {
+        var cb = this.callback;
+        t.cj.getCookies('http://www.example.com', {}, function (err, cookies) {
+          t.cookies = cookies;
+          cb(err, t);
+        });
+      },
+      "get the cookie": function(t) {
+        assert.lengthOf(t.cookies, 2);
+        assert.equal(t.cookies[0].key, 'broken_path');
+        assert.equal(t.cookies[0].value, 'testme');
+        assert.equal(t.cookies[1].key, "b");
+        assert.equal(t.cookies[1].value, "2");
+        assert.equal(t.cookies[1].path, "/");
+      },
+    },
+  }
+})
+.addBatch({
+  "Constructor":{
+    topic: function () {
+      return new Cookie({
+        key: 'test',
+        value: 'b',
+        maxAge: 60
+      });
+    },
+    'check for key property': function (c) {
+      assert.ok(c);
+      assert.equal(c.key, 'test');
+    },
+    'check for value property': function (c) {
+      assert.equal(c.value, 'b');
+    },
+    'check for maxAge': function (c) {
+      assert.equal(c.maxAge, 60);
+    },
+    'check for default values for unspecified properties': function (c) {
+      assert.equal(c.expires, "Infinity");
+      assert.equal(c.secure, false);
+      assert.equal(c.httpOnly, false);
+    }
+  }
+})
+.addBatch({
+  "allPaths option": {
+    topic: function() {
+      var cj = new CookieJar();
+      var tasks = [];
+      tasks.push(cj.setCookie.bind(cj, 'nopath_dom=qq; Path=/; Domain=example.com', 'http://example.com', {}));
+      tasks.push(cj.setCookie.bind(cj, 'path_dom=qq; Path=/foo; Domain=example.com', 'http://example.com', {}));
+      tasks.push(cj.setCookie.bind(cj, 'nopath_host=qq; Path=/', 'http://www.example.com', {}));
+      tasks.push(cj.setCookie.bind(cj, 'path_host=qq; Path=/foo', 'http://www.example.com', {}));
+      tasks.push(cj.setCookie.bind(cj, 'other=qq; Path=/', 'http://other.example.com/', {}));
+      tasks.push(cj.setCookie.bind(cj, 'other2=qq; Path=/foo', 'http://other.example.com/foo', {}));
+      var cb = this.callback;
+      async.parallel(tasks, function(err,results) {
+        cb(err, {cj:cj, cookies: results});
+      });
+    },
+    "all set": function(t) {
+      assert.equal(t.cookies.length, 6);
+      assert.ok(t.cookies.every(function(c) { return !!c }));
+    },
+    "getting without allPaths": {
+      topic: function(t) {
+        var cb = this.callback;
+        var cj = t.cj;
+        cj.getCookies('http://www.example.com/', {}, function(err,cookies) {
+          cb(err, {cj:cj, cookies:cookies});
+        });
+      },
+      "found just two cookies": function(t) {
+        assert.equal(t.cookies.length, 2);
+      },
+      "all are path=/": function(t) {
+        assert.ok(t.cookies.every(function(c) { return c.path === '/' }));
+      },
+      "no 'other' cookies": function(t) {
+        assert.ok(!t.cookies.some(function(c) { return (/^other/).test(c.name) }));
+      },
+    },
+    "getting without allPaths for /foo": {
+      topic: function(t) {
+        var cb = this.callback;
+        var cj = t.cj;
+        cj.getCookies('http://www.example.com/foo', {}, function(err,cookies) {
+          cb(err, {cj:cj, cookies:cookies});
+        });
+      },
+      "found four cookies": function(t) {
+        assert.equal(t.cookies.length, 4);
+      },
+      "no 'other' cookies": function(t) {
+        assert.ok(!t.cookies.some(function(c) { return (/^other/).test(c.name) }));
+      },
+    },
+    "getting with allPaths:true": {
+      topic: function(t) {
+        var cb = this.callback;
+        var cj = t.cj;
+        cj.getCookies('http://www.example.com/', {allPaths:true}, function(err,cookies) {
+          cb(err, {cj:cj, cookies:cookies});
+        });
+      },
+      "found four cookies": function(t) {
+        assert.equal(t.cookies.length, 4);
+      },
+      "no 'other' cookies": function(t) {
+        assert.ok(!t.cookies.some(function(c) { return (/^other/).test(c.name) }));
+      },
+    },
+  }
+})
+.addBatch({
+  "remove cookies": {
+    topic: function() {
+      var jar = new CookieJar();
+      var cookie = Cookie.parse("a=b; Domain=example.com; Path=/");
+      var cookie2 = Cookie.parse("a=b; Domain=foo.com; Path=/");
+      var cookie3 = Cookie.parse("foo=bar; Domain=foo.com; Path=/");
+      jar.setCookie(cookie, 'http://example.com/index.html', function(){});
+      jar.setCookie(cookie2, 'http://foo.com/index.html', function(){});
+      jar.setCookie(cookie3, 'http://foo.com/index.html', function(){});
+      return jar;
+    },
+    "all from matching domain": function(jar){
+      jar.store.removeCookies('example.com',null, function(err) {
+        assert(err == null);
+
+        jar.store.findCookies('example.com', null, function(err, cookies){
+          assert(err == null);
+          assert(cookies != null);
+          assert(cookies.length === 0, 'cookie was not removed');
+        });
+
+        jar.store.findCookies('foo.com', null, function(err, cookies){
+          assert(err == null);
+          assert(cookies != null);
+          assert(cookies.length === 2, 'cookies should not have been removed');
+        });
+      });
+    },
+    "from cookie store matching domain and key": function(jar){
+      jar.store.removeCookie('foo.com', '/', 'foo', function(err) {
+        assert(err == null);
+
+        jar.store.findCookies('foo.com', null, function(err, cookies){
+          assert(err == null);
+          assert(cookies != null);
+          assert(cookies.length === 1, 'cookie was not removed correctly');
+          assert(cookies[0].key === 'a', 'wrong cookie was removed');
+        });
+      });
+    }
+  }
+})
+.addBatch({
+  "Synchronous CookieJar": {
+    "setCookieSync": {
+      topic: function() {
+        var jar = new CookieJar();
+        var cookie = Cookie.parse("a=b; Domain=example.com; Path=/");
+        cookie = jar.setCookieSync(cookie, 'http://example.com/index.html');
+        return cookie;
+      },
+      "returns a copy of the cookie": function(cookie) {
+        assert.instanceOf(cookie, Cookie);
+      }
+    },
+
+    "setCookieSync strict parse error": {
+      topic: function() {
+        var jar = new CookieJar();
+        var opts = { strict: true };
+        try {
+          jar.setCookieSync("farbe=weiÃ", 'http://example.com/index.html', opts);
+          return false;
+        } catch (e) {
+          return e;
+        }
+      },
+      "throws the error": function(err) {
+        assert.instanceOf(err, Error);
+        assert.equal(err.message, "Cookie failed to parse");
+      }
+    },
+
+    "getCookiesSync": {
+      topic: function() {
+        var jar = new CookieJar();
+        var url = 'http://example.com/index.html';
+        jar.setCookieSync("a=b; Domain=example.com; Path=/", url);
+        jar.setCookieSync("c=d; Domain=example.com; Path=/", url);
+        return jar.getCookiesSync(url);
+      },
+      "returns the cookie array": function(err, cookies) {
+        assert.ok(!err);
+        assert.ok(Array.isArray(cookies));
+        assert.lengthOf(cookies, 2);
+        cookies.forEach(function(cookie) {
+          assert.instanceOf(cookie, Cookie);
+        });
+      }
+    },
+
+    "getCookieStringSync": {
+      topic: function() {
+        var jar = new CookieJar();
+        var url = 'http://example.com/index.html';
+        jar.setCookieSync("a=b; Domain=example.com; Path=/", url);
+        jar.setCookieSync("c=d; Domain=example.com; Path=/", url);
+        return jar.getCookieStringSync(url);
+      },
+      "returns the cookie header string": function(err, str) {
+        assert.ok(!err);
+        assert.typeOf(str, 'string');
+      }
+    },
+
+    "getSetCookieStringsSync": {
+      topic: function() {
+        var jar = new CookieJar();
+        var url = 'http://example.com/index.html';
+        jar.setCookieSync("a=b; Domain=example.com; Path=/", url);
+        jar.setCookieSync("c=d; Domain=example.com; Path=/", url);
+        return jar.getSetCookieStringsSync(url);
+      },
+      "returns the cookie header string": function(err, headers) {
+        assert.ok(!err);
+        assert.ok(Array.isArray(headers));
+        assert.lengthOf(headers, 2);
+        headers.forEach(function(header) {
+          assert.typeOf(header, 'string');
+        });
+      }
+    },
+  }
+})
+.addBatch({
+  "Synchronous API on async CookieJar": {
+    topic: function() {
+      return new tough.Store();
+    },
+    "setCookieSync": {
+      topic: function(store) {
+        var jar = new CookieJar(store);
+        try {
+          jar.setCookieSync("a=b", 'http://example.com/index.html');
+          return false;
+        } catch(e) {
+          return e;
+        }
+      },
+      "fails": function(err) {
+        assert.instanceOf(err, Error);
+        assert.equal(err.message,
+                     'CookieJar store is not synchronous; use async API instead.');
+      }
+    },
+    "getCookiesSync": {
+      topic: function(store) {
+        var jar = new CookieJar(store);
+        try {
+          jar.getCookiesSync('http://example.com/index.html');
+          return false;
+        } catch(e) {
+          return e;
+        }
+      },
+      "fails": function(err) {
+        assert.instanceOf(err, Error);
+        assert.equal(err.message,
+                     'CookieJar store is not synchronous; use async API instead.');
+      }
+    },
+    "getCookieStringSync": {
+      topic: function(store) {
+        var jar = new CookieJar(store);
+        try {
+          jar.getCookieStringSync('http://example.com/index.html');
+          return false;
+        } catch(e) {
+          return e;
+        }
+      },
+      "fails": function(err) {
+        assert.instanceOf(err, Error);
+        assert.equal(err.message,
+                     'CookieJar store is not synchronous; use async API instead.');
+      }
+    },
+    "getSetCookieStringsSync": {
+      topic: function(store) {
+        var jar = new CookieJar(store);
+        try {
+          jar.getSetCookieStringsSync('http://example.com/index.html');
+          return false;
+        } catch(e) {
+          return e;
+        }
+      },
+      "fails": function(err) {
+        assert.instanceOf(err, Error);
+        assert.equal(err.message,
+                     'CookieJar store is not synchronous; use async API instead.');
+      }
+    },
+  }
+})
+.export(module);
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/LICENSE
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/LICENSE	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/LICENSE	(revision 517)
@@ -0,0 +1,55 @@
+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:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+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
+
+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
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/README.md
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/README.md	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/README.md	(revision 517)
@@ -0,0 +1,4 @@
+tunnel-agent
+============
+
+HTTP proxy tunneling agent. Formerly part of mikeal/request, now a standalone module.
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/index.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/index.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/index.js	(revision 517)
@@ -0,0 +1,227 @@
+'use strict'
+
+var net = require('net')
+  , tls = require('tls')
+  , http = require('http')
+  , https = require('https')
+  , events = require('events')
+  , assert = require('assert')
+  , util = require('util')
+  ;
+
+exports.httpOverHttp = httpOverHttp
+exports.httpsOverHttp = httpsOverHttp
+exports.httpOverHttps = httpOverHttps
+exports.httpsOverHttps = httpsOverHttps
+
+
+function httpOverHttp(options) {
+  var agent = new TunnelingAgent(options)
+  agent.request = http.request
+  return agent
+}
+
+function httpsOverHttp(options) {
+  var agent = new TunnelingAgent(options)
+  agent.request = http.request
+  agent.createSocket = createSecureSocket
+  return agent
+}
+
+function httpOverHttps(options) {
+  var agent = new TunnelingAgent(options)
+  agent.request = https.request
+  return agent
+}
+
+function httpsOverHttps(options) {
+  var agent = new TunnelingAgent(options)
+  agent.request = https.request
+  agent.createSocket = createSecureSocket
+  return agent
+}
+
+
+function TunnelingAgent(options) {
+  var self = this
+  self.options = options || {}
+  self.proxyOptions = self.options.proxy || {}
+  self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets
+  self.requests = []
+  self.sockets = []
+
+  self.on('free', function onFree(socket, host, port) {
+    for (var i = 0, len = self.requests.length; i < len; ++i) {
+      var pending = self.requests[i]
+      if (pending.host === host && pending.port === port) {
+        // Detect the request to connect same origin server,
+        // reuse the connection.
+        self.requests.splice(i, 1)
+        pending.request.onSocket(socket)
+        return
+      }
+    }
+    socket.destroy()
+    self.removeSocket(socket)
+  })
+}
+util.inherits(TunnelingAgent, events.EventEmitter)
+
+TunnelingAgent.prototype.addRequest = function addRequest(req, host, port) {
+  var self = this
+
+  if (self.sockets.length >= this.maxSockets) {
+    // We are over limit so we'll add it to the queue.
+    self.requests.push({host: host, port: port, request: req})
+    return
+  }
+
+  // If we are under maxSockets create a new one.
+  self.createSocket({host: host, port: port, request: req}, function(socket) {
+    socket.on('free', onFree)
+    socket.on('close', onCloseOrRemove)
+    socket.on('agentRemove', onCloseOrRemove)
+    req.onSocket(socket)
+
+    function onFree() {
+      self.emit('free', socket, host, port)
+    }
+
+    function onCloseOrRemove(err) {
+      self.removeSocket()
+      socket.removeListener('free', onFree)
+      socket.removeListener('close', onCloseOrRemove)
+      socket.removeListener('agentRemove', onCloseOrRemove)
+    }
+  })
+}
+
+TunnelingAgent.prototype.createSocket = function createSocket(options, cb) {
+  var self = this
+  var placeholder = {}
+  self.sockets.push(placeholder)
+
+  var connectOptions = mergeOptions({}, self.proxyOptions, 
+    { method: 'CONNECT'
+    , path: options.host + ':' + options.port
+    , agent: false
+    }
+  )
+  if (connectOptions.proxyAuth) {
+    connectOptions.headers = connectOptions.headers || {}
+    connectOptions.headers['Proxy-Authorization'] = 'Basic ' +
+        new Buffer(connectOptions.proxyAuth).toString('base64')
+  }
+
+  debug('making CONNECT request')
+  var connectReq = self.request(connectOptions)
+  connectReq.useChunkedEncodingByDefault = false // for v0.6
+  connectReq.once('response', onResponse) // for v0.6
+  connectReq.once('upgrade', onUpgrade)   // for v0.6
+  connectReq.once('connect', onConnect)   // for v0.7 or later
+  connectReq.once('error', onError)
+  connectReq.end()
+
+  function onResponse(res) {
+    // Very hacky. This is necessary to avoid http-parser leaks.
+    res.upgrade = true
+  }
+
+  function onUpgrade(res, socket, head) {
+    // Hacky.
+    process.nextTick(function() {
+      onConnect(res, socket, head)
+    })
+  }
+
+  function onConnect(res, socket, head) {
+    connectReq.removeAllListeners()
+    socket.removeAllListeners()
+
+    if (res.statusCode === 200) {
+      assert.equal(head.length, 0)
+      debug('tunneling connection has established')
+      self.sockets[self.sockets.indexOf(placeholder)] = socket
+      cb(socket)
+    } else {
+      debug('tunneling socket could not be established, statusCode=%d', res.statusCode)
+      var error = new Error('tunneling socket could not be established, ' + 'statusCode=' + res.statusCode)
+      error.code = 'ECONNRESET'
+      options.request.emit('error', error)
+      self.removeSocket(placeholder)
+    }
+  }
+
+  function onError(cause) {
+    connectReq.removeAllListeners()
+
+    debug('tunneling socket could not be established, cause=%s\n', cause.message, cause.stack)
+    var error = new Error('tunneling socket could not be established, ' + 'cause=' + cause.message)
+    error.code = 'ECONNRESET'
+    options.request.emit('error', error)
+    self.removeSocket(placeholder)
+  }
+}
+
+TunnelingAgent.prototype.removeSocket = function removeSocket(socket) {
+  var pos = this.sockets.indexOf(socket)
+  if (pos === -1) return
+  
+  this.sockets.splice(pos, 1)
+
+  var pending = this.requests.shift()
+  if (pending) {
+    // If we have pending requests and a socket gets closed a new one
+    // needs to be created to take over in the pool for the one that closed.
+    this.createSocket(pending, function(socket) {
+      pending.request.onSocket(socket)
+    })
+  }
+}
+
+function createSecureSocket(options, cb) {
+  var self = this
+  TunnelingAgent.prototype.createSocket.call(self, options, function(socket) {
+    // 0 is dummy port for v0.6
+    var secureSocket = tls.connect(0, mergeOptions({}, self.options, 
+      { servername: options.host
+      , socket: socket
+      }
+    ))
+    cb(secureSocket)
+  })
+}
+
+
+function mergeOptions(target) {
+  for (var i = 1, len = arguments.length; i < len; ++i) {
+    var overrides = arguments[i]
+    if (typeof overrides === 'object') {
+      var keys = Object.keys(overrides)
+      for (var j = 0, keyLen = keys.length; j < keyLen; ++j) {
+        var k = keys[j]
+        if (overrides[k] !== undefined) {
+          target[k] = overrides[k]
+        }
+      }
+    }
+  }
+  return target
+}
+
+
+var debug
+if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) {
+  debug = function() {
+    var args = Array.prototype.slice.call(arguments)
+    if (typeof args[0] === 'string') {
+      args[0] = 'TUNNEL: ' + args[0]
+    } else {
+      args.unshift('TUNNEL:')
+    }
+    console.error.apply(console, args)
+  }
+} else {
+  debug = function() {}
+}
+exports.debug = debug // for test
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/node_modules/tunnel-agent/package.json	(revision 517)
@@ -0,0 +1,28 @@
+{
+  "author": {
+    "name": "Mikeal Rogers",
+    "email": "mikeal.rogers@gmail.com",
+    "url": "http://www.futurealoof.com"
+  },
+  "name": "tunnel-agent",
+  "description": "HTTP proxy tunneling agent. Formerly part of mikeal/request, now a standalone module.",
+  "version": "0.3.0",
+  "repository": {
+    "url": "https://github.com/mikeal/tunnel-agent"
+  },
+  "main": "index.js",
+  "dependencies": {},
+  "devDependencies": {},
+  "optionalDependencies": {},
+  "engines": {
+    "node": "*"
+  },
+  "readme": "tunnel-agent\n============\n\nHTTP proxy tunneling agent. Formerly part of mikeal/request, now a standalone module.\n",
+  "readmeFilename": "README.md",
+  "bugs": {
+    "url": "https://github.com/mikeal/tunnel-agent/issues"
+  },
+  "homepage": "https://github.com/mikeal/tunnel-agent",
+  "_id": "tunnel-agent@0.3.0",
+  "_from": "tunnel-agent@~0.3.0"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/package.json	(revision 517)
@@ -0,0 +1,61 @@
+{
+  "name": "request",
+  "description": "Simplified HTTP request client.",
+  "tags": [
+    "http",
+    "simple",
+    "util",
+    "utility"
+  ],
+  "version": "2.33.0",
+  "author": {
+    "name": "Mikeal Rogers",
+    "email": "mikeal.rogers@gmail.com"
+  },
+  "repository": {
+    "type": "git",
+    "url": "http://github.com/mikeal/request.git"
+  },
+  "bugs": {
+    "url": "http://github.com/mikeal/request/issues"
+  },
+  "engines": [
+    "node >= 0.8.0"
+  ],
+  "main": "index.js",
+  "dependencies": {
+    "qs": "~0.6.0",
+    "json-stringify-safe": "~5.0.0",
+    "forever-agent": "~0.5.0",
+    "node-uuid": "~1.4.0",
+    "mime": "~1.2.9",
+    "tough-cookie": ">=0.12.0",
+    "form-data": "~0.1.0",
+    "tunnel-agent": "~0.3.0",
+    "http-signature": "~0.10.0",
+    "oauth-sign": "~0.3.0",
+    "hawk": "~1.0.0",
+    "aws-sign2": "~0.5.0"
+  },
+  "optionalDependencies": {
+    "tough-cookie": ">=0.12.0",
+    "form-data": "~0.1.0",
+    "tunnel-agent": "~0.3.0",
+    "http-signature": "~0.10.0",
+    "oauth-sign": "~0.3.0",
+    "hawk": "~1.0.0",
+    "aws-sign2": "~0.5.0"
+  },
+  "scripts": {
+    "test": "node tests/run.js"
+  },
+  "readme": "# Request -- Simplified HTTP client\n\n[![NPM](https://nodei.co/npm/request.png)](https://nodei.co/npm/request/)\n\n## Super simple to use\n\nRequest is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.\n\n```javascript\nvar request = require('request');\nrequest('http://www.google.com', function (error, response, body) {\n  if (!error && response.statusCode == 200) {\n    console.log(body) // Print the google web page.\n  }\n})\n```\n\n## Streaming\n\nYou can stream any response to a file stream.\n\n```javascript\nrequest('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))\n```\n\nYou can also stream a file to a PUT or POST request. This method will also check the file extension against a mapping of file extensions to content-types (in this case `application/json`) and use the proper `content-type` in the PUT request (if the headers donât already provide one).\n\n```javascript\nfs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))\n```\n\nRequest can also `pipe` to itself. When doing so, `content-type` and `content-length` are preserved in the PUT headers.\n\n```javascript\nrequest.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))\n```\n\nNow letâs get fancy.\n\n```javascript\nhttp.createServer(function (req, resp) {\n  if (req.url === '/doodle.png') {\n    if (req.method === 'PUT') {\n      req.pipe(request.put('http://mysite.com/doodle.png'))\n    } else if (req.method === 'GET' || req.method === 'HEAD') {\n      request.get('http://mysite.com/doodle.png').pipe(resp)\n    }\n  }\n})\n```\n\nYou can also `pipe()` from `http.ServerRequest` instances, as well as to `http.ServerResponse` instances. The HTTP method, headers, and entity-body data will be sent. Which means that, if you don't really care about security, you can do:\n\n```javascript\nhttp.createServer(function (req, resp) {\n  if (req.url === '/doodle.png') {\n    var x = request('http://mysite.com/doodle.png')\n    req.pipe(x)\n    x.pipe(resp)\n  }\n})\n```\n\nAnd since `pipe()` returns the destination stream in â¥ Node 0.5.x you can do one line proxying. :)\n\n```javascript\nreq.pipe(request('http://mysite.com/doodle.png')).pipe(resp)\n```\n\nAlso, none of this new functionality conflicts with requests previous features, it just expands them.\n\n```javascript\nvar r = request.defaults({'proxy':'http://localproxy.com'})\n\nhttp.createServer(function (req, resp) {\n  if (req.url === '/doodle.png') {\n    r.get('http://google.com/doodle.png').pipe(resp)\n  }\n})\n```\n\nYou can still use intermediate proxies, the requests will still follow HTTP forwards, etc.\n\n## Forms\n\n`request` supports `application/x-www-form-urlencoded` and `multipart/form-data` form uploads. For `multipart/related` refer to the `multipart` API.\n\nURL-encoded forms are simple.\n\n```javascript\nrequest.post('http://service.com/upload', {form:{key:'value'}})\n// or\nrequest.post('http://service.com/upload').form({key:'value'})\n```\n\nFor `multipart/form-data` we use the [form-data](https://github.com/felixge/node-form-data) library by [@felixge](https://github.com/felixge). You donât need to worry about piping the form object or setting the headers, `request` will handle that for you.\n\n```javascript\nvar r = request.post('http://service.com/upload')\nvar form = r.form()\nform.append('my_field', 'my_value')\nform.append('my_buffer', new Buffer([1, 2, 3]))\nform.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png'))\nform.append('remote_file', request('http://google.com/doodle.png'))\n```\n\n## HTTP Authentication\n\n```javascript\nrequest.get('http://some.server.com/').auth('username', 'password', false);\n// or\nrequest.get('http://some.server.com/', {\n  'auth': {\n    'user': 'username',\n    'pass': 'password',\n    'sendImmediately': false\n  }\n});\n```\n\nIf passed as an option, `auth` should be a hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional).  The method form takes parameters `auth(username, password, sendImmediately)`.\n\n`sendImmediately` defaults to `true`, which causes a basic authentication header to be sent.  If `sendImmediately` is `false`, then `request` will retry with a proper authentication header after receiving a `401` response from the server (which must contain a `WWW-Authenticate` header indicating the required authentication method).\n\nDigest authentication is supported, but it only works with `sendImmediately` set to `false`; otherwise `request` will send basic authentication on the initial request, which will probably cause the request to fail.\n\n## OAuth Signing\n\n```javascript\n// Twitter OAuth\nvar qs = require('querystring')\n  , oauth =\n    { callback: 'http://mysite.com/callback/'\n    , consumer_key: CONSUMER_KEY\n    , consumer_secret: CONSUMER_SECRET\n    }\n  , url = 'https://api.twitter.com/oauth/request_token'\n  ;\nrequest.post({url:url, oauth:oauth}, function (e, r, body) {\n  // Ideally, you would take the body in the response\n  // and construct a URL that a user clicks on (like a sign in button).\n  // The verifier is only available in the response after a user has\n  // verified with twitter that they are authorizing your app.\n  var access_token = qs.parse(body)\n    , oauth =\n      { consumer_key: CONSUMER_KEY\n      , consumer_secret: CONSUMER_SECRET\n      , token: access_token.oauth_token\n      , verifier: access_token.oauth_verifier\n      }\n    , url = 'https://api.twitter.com/oauth/access_token'\n    ;\n  request.post({url:url, oauth:oauth}, function (e, r, body) {\n    var perm_token = qs.parse(body)\n      , oauth =\n        { consumer_key: CONSUMER_KEY\n        , consumer_secret: CONSUMER_SECRET\n        , token: perm_token.oauth_token\n        , token_secret: perm_token.oauth_token_secret\n        }\n      , url = 'https://api.twitter.com/1.1/users/show.json?'\n      , params =\n        { screen_name: perm_token.screen_name\n        , user_id: perm_token.user_id\n        }\n      ;\n    url += qs.stringify(params)\n    request.get({url:url, oauth:oauth, json:true}, function (e, r, user) {\n      console.log(user)\n    })\n  })\n})\n```\n\n### Custom HTTP Headers\n\nHTTP Headers, such as `User-Agent`, can be set in the `options` object.\nIn the example below, we call the github API to find out the number\nof stars and forks for the request repository. This requires a\ncustom `User-Agent` header as well as https.\n\n```javascript\nvar request = require('request');\n\nvar options = {\n\turl: 'https://api.github.com/repos/mikeal/request',\n\theaders: {\n\t\t'User-Agent': 'request'\n\t}\n};\n\nfunction callback(error, response, body) {\n\tif (!error && response.statusCode == 200) {\n\t\tvar info = JSON.parse(body);\n\t\tconsole.log(info.stargazers_count + \" Stars\");\n\t\tconsole.log(info.forks_count + \" Forks\");\n\t}\n}\n\nrequest(options, callback);\n```\n\n### request(options, callback)\n\nThe first argument can be either a `url` or an `options` object. The only required option is `uri`; all others are optional.\n\n* `uri` || `url` - fully qualified uri or a parsed url object from `url.parse()`\n* `qs` - object containing querystring values to be appended to the `uri`\n* `method` - http method (default: `\"GET\"`)\n* `headers` - http headers (default: `{}`)\n* `body` - entity body for PATCH, POST and PUT requests. Must be a `Buffer` or `String`.\n* `form` - when passed an object, this sets `body` to a querystring representation of value, and adds `Content-type: application/x-www-form-urlencoded; charset=utf-8` header. When passed no options, a `FormData` instance is returned (and is piped to request).\n* `auth` - A hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional).  See documentation above.\n* `json` - sets `body` but to JSON representation of value and adds `Content-type: application/json` header.  Additionally, parses the response body as JSON.\n* `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below.\n* `followRedirect` - follow HTTP 3xx responses as redirects (default: `true`)\n* `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects (default: `false`)\n* `maxRedirects` - the maximum number of redirects to follow (default: `10`)\n* `encoding` - Encoding to be used on `setEncoding` of response data. If `null`, the `body` is returned as a `Buffer`.\n* `pool` - A hash object containing the agents for these requests. If omitted, the request will use the global pool (which is set to node's default `maxSockets`)\n* `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.\n* `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request\n* `proxy` - An HTTP proxy to be used. Supports proxy Auth with Basic Auth, identical to support for the `url` parameter (by embedding the auth info in the `uri`)\n* `oauth` - Options for OAuth HMAC-SHA1 signing. See documentation above.\n* `hawk` - Options for [Hawk signing](https://github.com/hueniverse/hawk). The `credentials` key must contain the necessary signing info, [see hawk docs for details](https://github.com/hueniverse/hawk#usage-example).\n* `strictSSL` - If `true`, requires SSL certificates be valid. **Note:** to use your own certificate authority, you need to specify an agent that was created with that CA as an option.\n* `jar` - If `true`, remember cookies for future use (or define your custom cookie jar; see examples section)\n* `aws` - `object` containing AWS signing information. Should have the properties `key`, `secret`. Also requires the property `bucket`, unless youâre specifying your `bucket` as part of the path, or the request doesnât use a bucket (i.e. GET Services)\n* `httpSignature` - Options for the [HTTP Signature Scheme](https://github.com/joyent/node-http-signature/blob/master/http_signing.md) using [Joyent's library](https://github.com/joyent/node-http-signature). The `keyId` and `key` properties must be specified. See the docs for other options.\n* `localAddress` - Local interface to bind for network connections.\n\n\nThe callback argument gets 3 arguments: \n\n1. An `error` when applicable (usually from [`http.ClientRequest`](http://nodejs.org/api/http.html#http_class_http_clientrequest) object)\n2. An [`http.IncomingMessage`](http://nodejs.org/api/http.html#http_http_incomingmessage) object\n3. The third is the `response` body (`String` or `Buffer`, or JSON object if the `json` option is supplied)\n\n## Convenience methods\n\nThere are also shorthand methods for different HTTP METHODs and some other conveniences.\n\n### request.defaults(options)\n\nThis method returns a wrapper around the normal request API that defaults to whatever options you pass in to it.\n\n### request.put\n\nSame as `request()`, but defaults to `method: \"PUT\"`.\n\n```javascript\nrequest.put(url)\n```\n\n### request.patch\n\nSame as `request()`, but defaults to `method: \"PATCH\"`.\n\n```javascript\nrequest.patch(url)\n```\n\n### request.post\n\nSame as `request()`, but defaults to `method: \"POST\"`.\n\n```javascript\nrequest.post(url)\n```\n\n### request.head\n\nSame as request() but defaults to `method: \"HEAD\"`.\n\n```javascript\nrequest.head(url)\n```\n\n### request.del\n\nSame as `request()`, but defaults to `method: \"DELETE\"`.\n\n```javascript\nrequest.del(url)\n```\n\n### request.get\n\nSame as `request()` (for uniformity).\n\n```javascript\nrequest.get(url)\n```\n### request.cookie\n\nFunction that creates a new cookie.\n\n```javascript\nrequest.cookie('cookie_string_here')\n```\n### request.jar\n\nFunction that creates a new cookie jar.\n\n```javascript\nrequest.jar()\n```\n\n\n## Examples:\n\n```javascript\n  var request = require('request')\n    , rand = Math.floor(Math.random()*100000000).toString()\n    ;\n  request(\n    { method: 'PUT'\n    , uri: 'http://mikeal.iriscouch.com/testjs/' + rand\n    , multipart:\n      [ { 'content-type': 'application/json'\n        ,  body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})\n        }\n      , { body: 'I am an attachment' }\n      ]\n    }\n  , function (error, response, body) {\n      if(response.statusCode == 201){\n        console.log('document saved as: http://mikeal.iriscouch.com/testjs/'+ rand)\n      } else {\n        console.log('error: '+ response.statusCode)\n        console.log(body)\n      }\n    }\n  )\n```\n\nCookies are disabled by default (else, they would be used in subsequent requests). To enable cookies, set `jar` to `true` (either in `defaults` or `options`).\n\n```javascript\nvar request = request.defaults({jar: true})\nrequest('http://www.google.com', function () {\n  request('http://images.google.com')\n})\n```\n\nTo use a custom cookie jar (instead `request`âs global cookie jar), set `jar` to an instance of `request.jar()` (either in `defaults` or `options`)\n\n```javascript\nvar j = request.jar()\nvar request = request.defaults({jar:j})\nrequest('http://www.google.com', function () {\n  request('http://images.google.com')\n})\n```\n\nOR\n\n```javascript\nvar j = request.jar()\nvar cookie = request.cookie('your_cookie_here')\nj.setCookie(cookie, uri);\nrequest({url: 'http://www.google.com', jar: j}, function () {\n  request('http://images.google.com')\n})\n```\n",
+  "readmeFilename": "README.md",
+  "homepage": "https://github.com/mikeal/request",
+  "_id": "request@2.33.0",
+  "dist": {
+    "shasum": "c7d6ffd589542aee5ef456175ffcd21330cf0a2a"
+  },
+  "_from": "request@~2.33.0",
+  "_resolved": "https://registry.npmjs.org/request/-/request-2.33.0.tgz"
+}
Index: Dev/trunk/node_modules/grunt-http/node_modules/request/request.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/node_modules/request/request.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/node_modules/request/request.js	(revision 517)
@@ -0,0 +1,1249 @@
+var optional = require('./lib/optional')
+  , http = require('http')
+  , https = optional('https')
+  , tls = optional('tls')
+  , url = require('url')
+  , util = require('util')
+  , stream = require('stream')
+  , qs = require('qs')
+  , querystring = require('querystring')
+  , crypto = require('crypto')
+
+  , oauth = optional('oauth-sign')
+  , hawk = optional('hawk')
+  , aws = optional('aws-sign2')
+  , httpSignature = optional('http-signature')
+  , uuid = require('node-uuid')
+  , mime = require('mime')
+  , tunnel = optional('tunnel-agent')
+  , _safeStringify = require('json-stringify-safe')
+
+  , ForeverAgent = require('forever-agent')
+  , FormData = optional('form-data')
+
+  , cookies = require('./lib/cookies')
+  , globalCookieJar = cookies.jar()
+
+  , copy = require('./lib/copy')
+  , debug = require('./lib/debug')
+  , getSafe = require('./lib/getSafe')
+  ;
+
+function safeStringify (obj) {
+  var ret
+  try { ret = JSON.stringify(obj) }
+  catch (e) { ret = _safeStringify(obj) }
+  return ret
+}
+
+var globalPool = {}
+var isUrl = /^https?:/i
+
+
+// Hacky fix for pre-0.4.4 https
+if (https && !https.Agent) {
+  https.Agent = function (options) {
+    http.Agent.call(this, options)
+  }
+  util.inherits(https.Agent, http.Agent)
+  https.Agent.prototype._getConnection = function (host, port, cb) {
+    var s = tls.connect(port, host, this.options, function () {
+      // do other checks here?
+      if (cb) cb()
+    })
+    return s
+  }
+}
+
+function isReadStream (rs) {
+  if (rs.readable && rs.path && rs.mode) {
+    return true
+  }
+}
+
+function toBase64 (str) {
+  return (new Buffer(str || "", "ascii")).toString("base64")
+}
+
+function md5 (str) {
+  return crypto.createHash('md5').update(str).digest('hex')
+}
+
+function Request (options) {
+  stream.Stream.call(this)
+  this.readable = true
+  this.writable = true
+
+  if (typeof options === 'string') {
+    options = {uri:options}
+  }
+
+  var reserved = Object.keys(Request.prototype)
+  for (var i in options) {
+    if (reserved.indexOf(i) === -1) {
+      this[i] = options[i]
+    } else {
+      if (typeof options[i] === 'function') {
+        delete options[i]
+      }
+    }
+  }
+
+  if (options.method) {
+    this.explicitMethod = true
+  }
+
+  this.canTunnel = options.tunnel !== false && tunnel;
+
+  this.init(options)
+}
+util.inherits(Request, stream.Stream)
+Request.prototype.init = function (options) {
+  // init() contains all the code to setup the request object.
+  // the actual outgoing request is not started until start() is called
+  // this function is called from both the constructor and on redirect.
+  var self = this
+  if (!options) options = {}
+
+  if (!self.method) self.method = options.method || 'GET'
+  self.localAddress = options.localAddress
+
+  debug(options)
+  if (!self.pool && self.pool !== false) self.pool = globalPool
+  self.dests = self.dests || []
+  self.__isRequestRequest = true
+
+  // Protect against double callback
+  if (!self._callback && self.callback) {
+    self._callback = self.callback
+    self.callback = function () {
+      if (self._callbackCalled) return // Print a warning maybe?
+      self._callbackCalled = true
+      self._callback.apply(self, arguments)
+    }
+    self.on('error', self.callback.bind())
+    self.on('complete', self.callback.bind(self, null))
+  }
+
+  if (self.url && !self.uri) {
+    // People use this property instead all the time so why not just support it.
+    self.uri = self.url
+    delete self.url
+  }
+
+  if (!self.uri) {
+    // this will throw if unhandled but is handleable when in a redirect
+    return self.emit('error', new Error("options.uri is a required argument"))
+  } else {
+    if (typeof self.uri == "string") self.uri = url.parse(self.uri)
+  }
+
+  if (self.strictSSL === false) {
+    self.rejectUnauthorized = false
+  }
+
+  if (self.proxy) {
+    if (typeof self.proxy == 'string') self.proxy = url.parse(self.proxy)
+
+    // do the HTTP CONNECT dance using koichik/node-tunnel
+    if (http.globalAgent && self.uri.protocol === "https:" && self.canTunnel) {
+      var tunnelFn = self.proxy.protocol === "http:"
+                   ? tunnel.httpsOverHttp : tunnel.httpsOverHttps
+
+      var tunnelOptions = { proxy: { host: self.proxy.hostname
+                                   , port: +self.proxy.port
+                                   , proxyAuth: self.proxy.auth
+                                   , headers: { Host: self.uri.hostname + ':' +
+                                        (self.uri.port || self.uri.protocol === 'https:' ? 443 : 80) }}
+                          , rejectUnauthorized: self.rejectUnauthorized
+                          , ca: this.ca }
+
+      self.agent = tunnelFn(tunnelOptions)
+      self.tunnel = true
+    }
+  }
+
+  if (!self.uri.pathname) {self.uri.pathname = '/'}
+
+  if (!self.uri.host) {
+    // Invalid URI: it may generate lot of bad errors, like "TypeError: Cannot call method 'indexOf' of undefined" in CookieJar
+    // Detect and reject it as soon as possible
+    var faultyUri = url.format(self.uri)
+    var message = 'Invalid URI "' + faultyUri + '"'
+    if (Object.keys(options).length === 0) {
+      // No option ? This can be the sign of a redirect
+      // As this is a case where the user cannot do anything (they didn't call request directly with this URL)
+      // they should be warned that it can be caused by a redirection (can save some hair)
+      message += '. This can be caused by a crappy redirection.'
+    }
+    self.emit('error', new Error(message))
+    return // This error was fatal
+  }
+
+  self._redirectsFollowed = self._redirectsFollowed || 0
+  self.maxRedirects = (self.maxRedirects !== undefined) ? self.maxRedirects : 10
+  self.followRedirect = (self.followRedirect !== undefined) ? self.followRedirect : true
+  self.followAllRedirects = (self.followAllRedirects !== undefined) ? self.followAllRedirects : false
+  if (self.followRedirect || self.followAllRedirects)
+    self.redirects = self.redirects || []
+
+  self.headers = self.headers ? copy(self.headers) : {}
+
+  self.setHost = false
+  if (!self.hasHeader('host')) {
+    self.setHeader('host', self.uri.hostname)
+    if (self.uri.port) {
+      if ( !(self.uri.port === 80 && self.uri.protocol === 'http:') &&
+           !(self.uri.port === 443 && self.uri.protocol === 'https:') )
+      self.setHeader('host', self.getHeader('host') + (':'+self.uri.port) )
+    }
+    self.setHost = true
+  }
+
+  self.jar(self._jar || options.jar)
+
+  if (!self.uri.port) {
+    if (self.uri.protocol == 'http:') {self.uri.port = 80}
+    else if (self.uri.protocol == 'https:') {self.uri.port = 443}
+  }
+
+  if (self.proxy && !self.tunnel) {
+    self.port = self.proxy.port
+    self.host = self.proxy.hostname
+  } else {
+    self.port = self.uri.port
+    self.host = self.uri.hostname
+  }
+
+  self.clientErrorHandler = function (error) {
+    if (self._aborted) return
+    if (self.req && self.req._reusedSocket && error.code === 'ECONNRESET'
+        && self.agent.addRequestNoreuse) {
+      self.agent = { addRequest: self.agent.addRequestNoreuse.bind(self.agent) }
+      self.start()
+      self.req.end()
+      return
+    }
+    if (self.timeout && self.timeoutTimer) {
+      clearTimeout(self.timeoutTimer)
+      self.timeoutTimer = null
+    }
+    self.emit('error', error)
+  }
+
+  self._parserErrorHandler = function (error) {
+    if (this.res) {
+      if (this.res.request) {
+        this.res.request.emit('error', error)
+      } else {
+        this.res.emit('error', error)
+      }
+    } else {
+      this._httpMessage.emit('error', error)
+    }
+  }
+
+  if (options.form) {
+    self.form(options.form)
+  }
+
+  if (options.qs) self.qs(options.qs)
+
+  if (self.uri.path) {
+    self.path = self.uri.path
+  } else {
+    self.path = self.uri.pathname + (self.uri.search || "")
+  }
+
+  if (self.path.length === 0) self.path = '/'
+
+
+  // Auth must happen last in case signing is dependent on other headers
+  if (options.oauth) {
+    self.oauth(options.oauth)
+  }
+
+  if (options.aws) {
+    self.aws(options.aws)
+  }
+
+  if (options.hawk) {
+    self.hawk(options.hawk)
+  }
+
+  if (options.httpSignature) {
+    self.httpSignature(options.httpSignature)
+  }
+
+  if (options.auth) {
+    if (Object.prototype.hasOwnProperty.call(options.auth, 'username')) options.auth.user = options.auth.username
+    if (Object.prototype.hasOwnProperty.call(options.auth, 'password')) options.auth.pass = options.auth.password
+
+    self.auth(
+      options.auth.user,
+      options.auth.pass,
+      options.auth.sendImmediately
+    )
+  }
+
+  if (self.uri.auth && !self.hasHeader('authorization')) {
+    var authPieces = self.uri.auth.split(':').map(function(item){ return querystring.unescape(item) })
+    self.auth(authPieces[0], authPieces.slice(1).join(':'), true)
+  }
+  if (self.proxy && self.proxy.auth && !self.hasHeader('proxy-authorization') && !self.tunnel) {
+    self.setHeader('proxy-authorization', "Basic " + toBase64(self.proxy.auth.split(':').map(function(item){ return querystring.unescape(item)}).join(':')))
+  }
+
+
+  if (self.proxy && !self.tunnel) self.path = (self.uri.protocol + '//' + self.uri.host + self.path)
+
+  if (options.json) {
+    self.json(options.json)
+  } else if (options.multipart) {
+    self.boundary = uuid()
+    self.multipart(options.multipart)
+  }
+
+  if (self.body) {
+    var length = 0
+    if (!Buffer.isBuffer(self.body)) {
+      if (Array.isArray(self.body)) {
+        for (var i = 0; i < self.body.length; i++) {
+          length += self.body[i].length
+        }
+      } else {
+        self.body = new Buffer(self.body)
+        length = self.body.length
+      }
+    } else {
+      length = self.body.length
+    }
+    if (length) {
+      if (!self.hasHeader('content-length')) self.setHeader('content-length', length)
+    } else {
+      throw new Error('Argument error, options.body.')
+    }
+  }
+
+  var protocol = self.proxy && !self.tunnel ? self.proxy.protocol : self.uri.protocol
+    , defaultModules = {'http:':http, 'https:':https}
+    , httpModules = self.httpModules || {}
+    ;
+  self.httpModule = httpModules[protocol] || defaultModules[protocol]
+
+  if (!self.httpModule) return this.emit('error', new Error("Invalid protocol"))
+
+  if (options.ca) self.ca = options.ca
+
+  if (!self.agent) {
+    if (options.agentOptions) self.agentOptions = options.agentOptions
+
+    if (options.agentClass) {
+      self.agentClass = options.agentClass
+    } else if (options.forever) {
+      self.agentClass = protocol === 'http:' ? ForeverAgent : ForeverAgent.SSL
+    } else {
+      self.agentClass = self.httpModule.Agent
+    }
+  }
+
+  if (self.pool === false) {
+    self.agent = false
+  } else {
+    self.agent = self.agent || self.getAgent()
+    if (self.maxSockets) {
+      // Don't use our pooling if node has the refactored client
+      self.agent.maxSockets = self.maxSockets
+    }
+    if (self.pool.maxSockets) {
+      // Don't use our pooling if node has the refactored client
+      self.agent.maxSockets = self.pool.maxSockets
+    }
+  }
+
+  self.on('pipe', function (src) {
+    if (self.ntick && self._started) throw new Error("You cannot pipe to this stream after the outbound request has started.")
+    self.src = src
+    if (isReadStream(src)) {
+      if (!self.hasHeader('content-type')) self.setHeader('content-type', mime.lookup(src.path))
+    } else {
+      if (src.headers) {
+        for (var i in src.headers) {
+          if (!self.hasHeader(i)) {
+            self.setHeader(i, src.headers[i])
+          }
+        }
+      }
+      if (self._json && !self.hasHeader('content-type'))
+        self.setHeader('content-type', 'application/json')
+      if (src.method && !self.explicitMethod) {
+        self.method = src.method
+      }
+    }
+
+    // self.on('pipe', function () {
+    //   console.error("You have already piped to this stream. Pipeing twice is likely to break the request.")
+    // })
+  })
+
+  process.nextTick(function () {
+    if (self._aborted) return
+
+    if (self._form) {
+      self.setHeaders(self._form.getHeaders())
+      self._form.pipe(self)
+    }
+    if (self.body) {
+      if (Array.isArray(self.body)) {
+        self.body.forEach(function (part) {
+          self.write(part)
+        })
+      } else {
+        self.write(self.body)
+      }
+      self.end()
+    } else if (self.requestBodyStream) {
+      console.warn("options.requestBodyStream is deprecated, please pass the request object to stream.pipe.")
+      self.requestBodyStream.pipe(self)
+    } else if (!self.src) {
+      if (self.method !== 'GET' && typeof self.method !== 'undefined') {
+        self.setHeader('content-length', 0)
+      }
+      self.end()
+    }
+    self.ntick = true
+  })
+}
+
+// Must call this when following a redirect from https to http or vice versa
+// Attempts to keep everything as identical as possible, but update the
+// httpModule, Tunneling agent, and/or Forever Agent in use.
+Request.prototype._updateProtocol = function () {
+  var self = this
+  var protocol = self.uri.protocol
+
+  if (protocol === 'https:') {
+    // previously was doing http, now doing https
+    // if it's https, then we might need to tunnel now.
+    if (self.proxy && self.canTunnel) {
+      self.tunnel = true
+      var tunnelFn = self.proxy.protocol === 'http:'
+                   ? tunnel.httpsOverHttp : tunnel.httpsOverHttps
+      var tunnelOptions = { proxy: { host: self.proxy.hostname
+                                   , port: +self.proxy.port
+                                   , proxyAuth: self.proxy.auth }
+                          , rejectUnauthorized: self.rejectUnauthorized
+                          , ca: self.ca }
+      self.agent = tunnelFn(tunnelOptions)
+      return
+    }
+
+    self.httpModule = https
+    switch (self.agentClass) {
+      case ForeverAgent:
+        self.agentClass = ForeverAgent.SSL
+        break
+      case http.Agent:
+        self.agentClass = https.Agent
+        break
+      default:
+        // nothing we can do.  Just hope for the best.
+        return
+    }
+
+    // if there's an agent, we need to get a new one.
+    if (self.agent) self.agent = self.getAgent()
+
+  } else {
+    // previously was doing https, now doing http
+    // stop any tunneling.
+    if (self.tunnel) self.tunnel = false
+    self.httpModule = http
+    switch (self.agentClass) {
+      case ForeverAgent.SSL:
+        self.agentClass = ForeverAgent
+        break
+      case https.Agent:
+        self.agentClass = http.Agent
+        break
+      default:
+        // nothing we can do.  just hope for the best
+        return
+    }
+
+    // if there's an agent, then get a new one.
+    if (self.agent) {
+      self.agent = null
+      self.agent = self.getAgent()
+    }
+  }
+}
+
+Request.prototype.getAgent = function () {
+  var Agent = this.agentClass
+  var options = {}
+  if (this.agentOptions) {
+    for (var i in this.agentOptions) {
+      options[i] = this.agentOptions[i]
+    }
+  }
+  if (this.ca) options.ca = this.ca
+  if (this.ciphers) options.ciphers = this.ciphers
+  if (this.secureProtocol) options.secureProtocol = this.secureProtocol
+  if (typeof this.rejectUnauthorized !== 'undefined') options.rejectUnauthorized = this.rejectUnauthorized
+
+  if (this.cert && this.key) {
+    options.key = this.key
+    options.cert = this.cert
+  }
+
+  var poolKey = ''
+
+  // different types of agents are in different pools
+  if (Agent !== this.httpModule.Agent) {
+    poolKey += Agent.name
+  }
+
+  if (!this.httpModule.globalAgent) {
+    // node 0.4.x
+    options.host = this.host
+    options.port = this.port
+    if (poolKey) poolKey += ':'
+    poolKey += this.host + ':' + this.port
+  }
+
+  // ca option is only relevant if proxy or destination are https
+  var proxy = this.proxy
+  if (typeof proxy === 'string') proxy = url.parse(proxy)
+  var isHttps = (proxy && proxy.protocol === 'https:') || this.uri.protocol === 'https:'
+  if (isHttps) {
+    if (options.ca) {
+      if (poolKey) poolKey += ':'
+      poolKey += options.ca
+    }
+
+    if (typeof options.rejectUnauthorized !== 'undefined') {
+      if (poolKey) poolKey += ':'
+      poolKey += options.rejectUnauthorized
+    }
+
+    if (options.cert)
+      poolKey += options.cert.toString('ascii') + options.key.toString('ascii')
+
+    if (options.ciphers) {
+      if (poolKey) poolKey += ':'
+      poolKey += options.ciphers
+    }
+
+    if (options.secureProtocol) {
+      if (poolKey) poolKey += ':'
+      poolKey += options.secureProtocol
+    }
+  }
+
+  if (this.pool === globalPool && !poolKey && Object.keys(options).length === 0 && this.httpModule.globalAgent) {
+    // not doing anything special.  Use the globalAgent
+    return this.httpModule.globalAgent
+  }
+
+  // we're using a stored agent.  Make sure it's protocol-specific
+  poolKey = this.uri.protocol + poolKey
+
+  // already generated an agent for this setting
+  if (this.pool[poolKey]) return this.pool[poolKey]
+
+  return this.pool[poolKey] = new Agent(options)
+}
+
+Request.prototype.start = function () {
+  // start() is called once we are ready to send the outgoing HTTP request.
+  // this is usually called on the first write(), end() or on nextTick()
+  var self = this
+
+  if (self._aborted) return
+
+  self._started = true
+  self.method = self.method || 'GET'
+  self.href = self.uri.href
+
+  if (self.src && self.src.stat && self.src.stat.size && !self.hasHeader('content-length')) {
+    self.setHeader('content-length', self.src.stat.size)
+  }
+  if (self._aws) {
+    self.aws(self._aws, true)
+  }
+
+  // We have a method named auth, which is completely different from the http.request
+  // auth option.  If we don't remove it, we're gonna have a bad time.
+  var reqOptions = copy(self)
+  delete reqOptions.auth
+
+  debug('make request', self.uri.href)
+  self.req = self.httpModule.request(reqOptions, self.onResponse.bind(self))
+
+  if (self.timeout && !self.timeoutTimer) {
+    self.timeoutTimer = setTimeout(function () {
+      self.req.abort()
+      var e = new Error("ETIMEDOUT")
+      e.code = "ETIMEDOUT"
+      self.emit("error", e)
+    }, self.timeout)
+
+    // Set additional timeout on socket - in case if remote
+    // server freeze after sending headers
+    if (self.req.setTimeout) { // only works on node 0.6+
+      self.req.setTimeout(self.timeout, function () {
+        if (self.req) {
+          self.req.abort()
+          var e = new Error("ESOCKETTIMEDOUT")
+          e.code = "ESOCKETTIMEDOUT"
+          self.emit("error", e)
+        }
+      })
+    }
+  }
+
+  self.req.on('error', self.clientErrorHandler)
+  self.req.on('drain', function() {
+    self.emit('drain')
+  })
+  self.on('end', function() {
+    if ( self.req.connection ) self.req.connection.removeListener('error', self._parserErrorHandler)
+  })
+  self.emit('request', self.req)
+}
+Request.prototype.onResponse = function (response) {
+  var self = this
+  debug('onResponse', self.uri.href, response.statusCode, response.headers)
+  response.on('end', function() {
+    debug('response end', self.uri.href, response.statusCode, response.headers)
+  });
+
+  if (response.connection.listeners('error').indexOf(self._parserErrorHandler) === -1) {
+    response.connection.once('error', self._parserErrorHandler)
+  }
+  if (self._aborted) {
+    debug('aborted', self.uri.href)
+    response.resume()
+    return
+  }
+  if (self._paused) response.pause()
+  else response.resume()
+
+  self.response = response
+  response.request = self
+  response.toJSON = toJSON
+
+  // XXX This is different on 0.10, because SSL is strict by default
+  if (self.httpModule === https &&
+      self.strictSSL &&
+      !response.client.authorized) {
+    debug('strict ssl error', self.uri.href)
+    var sslErr = response.client.authorizationError
+    self.emit('error', new Error('SSL Error: '+ sslErr))
+    return
+  }
+
+  if (self.setHost && self.hasHeader('host')) delete self.headers[self.hasHeader('host')]
+  if (self.timeout && self.timeoutTimer) {
+    clearTimeout(self.timeoutTimer)
+    self.timeoutTimer = null
+  }
+
+  var targetCookieJar = (self._jar && self._jar.setCookie)?self._jar:globalCookieJar;
+  var addCookie = function (cookie) {
+    //set the cookie if it's domain in the href's domain.
+    try {
+      targetCookieJar.setCookie(cookie, self.uri.href);
+    } catch (e) {
+      self.emit('error', e);
+    }
+  }
+
+  if (hasHeader('set-cookie', response.headers) && (!self._disableCookies)) {
+    var headerName = hasHeader('set-cookie', response.headers)
+    if (Array.isArray(response.headers[headerName])) response.headers[headerName].forEach(addCookie)
+    else addCookie(response.headers[headerName])
+  }
+
+  var redirectTo = null
+  if (response.statusCode >= 300 && response.statusCode < 400 && hasHeader('location', response.headers)) {
+    var location = response.headers[hasHeader('location', response.headers)]
+    debug('redirect', location)
+
+    if (self.followAllRedirects) {
+      redirectTo = location
+    } else if (self.followRedirect) {
+      switch (self.method) {
+        case 'PATCH':
+        case 'PUT':
+        case 'POST':
+        case 'DELETE':
+          // Do not follow redirects
+          break
+        default:
+          redirectTo = location
+          break
+      }
+    }
+  } else if (response.statusCode == 401 && self._hasAuth && !self._sentAuth) {
+    var authHeader = response.headers[hasHeader('www-authenticate', response.headers)]
+    var authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()
+    debug('reauth', authVerb)
+
+    switch (authVerb) {
+      case 'basic':
+        self.auth(self._user, self._pass, true)
+        redirectTo = self.uri
+        break
+
+      case 'digest':
+        // TODO: More complete implementation of RFC 2617.
+        //   - check challenge.algorithm
+        //   - support algorithm="MD5-sess"
+        //   - handle challenge.domain
+        //   - support qop="auth-int" only
+        //   - handle Authentication-Info (not necessarily?)
+        //   - check challenge.stale (not necessarily?)
+        //   - increase nc (not necessarily?)
+        // For reference:
+        // http://tools.ietf.org/html/rfc2617#section-3
+        // https://github.com/bagder/curl/blob/master/lib/http_digest.c
+
+        var challenge = {}
+        var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
+        for (;;) {
+          var match = re.exec(authHeader)
+          if (!match) break
+          challenge[match[1]] = match[2] || match[3];
+        }
+
+        var ha1 = md5(self._user + ':' + challenge.realm + ':' + self._pass)
+        var ha2 = md5(self.method + ':' + self.uri.path)
+        var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
+        var nc = qop && '00000001'
+        var cnonce = qop && uuid().replace(/-/g, '')
+        var digestResponse = qop ? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2) : md5(ha1 + ':' + challenge.nonce + ':' + ha2)
+        var authValues = {
+          username: self._user,
+          realm: challenge.realm,
+          nonce: challenge.nonce,
+          uri: self.uri.path,
+          qop: qop,
+          response: digestResponse,
+          nc: nc,
+          cnonce: cnonce,
+          algorithm: challenge.algorithm,
+          opaque: challenge.opaque
+        }
+
+        authHeader = []
+        for (var k in authValues) {
+          if (!authValues[k]) {
+            //ignore
+          } else if (k === 'qop' || k === 'nc' || k === 'algorithm') {
+            authHeader.push(k + '=' + authValues[k])
+          } else {
+            authHeader.push(k + '="' + authValues[k] + '"')
+          }
+        }
+        authHeader = 'Digest ' + authHeader.join(', ')
+        self.setHeader('authorization', authHeader)
+        self._sentAuth = true
+
+        redirectTo = self.uri
+        break
+    }
+  }
+
+  if (redirectTo) {
+    debug('redirect to', redirectTo)
+
+    // ignore any potential response body.  it cannot possibly be useful
+    // to us at this point.
+    if (self._paused) response.resume()
+
+    if (self._redirectsFollowed >= self.maxRedirects) {
+      self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop "+self.uri.href))
+      return
+    }
+    self._redirectsFollowed += 1
+
+    if (!isUrl.test(redirectTo)) {
+      redirectTo = url.resolve(self.uri.href, redirectTo)
+    }
+
+    var uriPrev = self.uri
+    self.uri = url.parse(redirectTo)
+
+    // handle the case where we change protocol from https to http or vice versa
+    if (self.uri.protocol !== uriPrev.protocol) {
+      self._updateProtocol()
+    }
+
+    self.redirects.push(
+      { statusCode : response.statusCode
+      , redirectUri: redirectTo
+      }
+    )
+    if (self.followAllRedirects && response.statusCode != 401) self.method = 'GET'
+    // self.method = 'GET' // Force all redirects to use GET || commented out fixes #215
+    delete self.src
+    delete self.req
+    delete self.agent
+    delete self._started
+    if (response.statusCode != 401) {
+      // Remove parameters from the previous response, unless this is the second request
+      // for a server that requires digest authentication.
+      delete self.body
+      delete self._form
+      if (self.headers) {
+        if (self.hasHeader('host')) delete self.headers[self.hasHeader('host')]
+        if (self.hasHeader('content-type')) delete self.headers[self.hasHeader('content-type')]
+        if (self.hasHeader('content-length')) delete self.headers[self.hasHeader('content-length')]
+      }
+    }
+
+    self.emit('redirect');
+
+    self.init()
+    return // Ignore the rest of the response
+  } else {
+    self._redirectsFollowed = self._redirectsFollowed || 0
+    // Be a good stream and emit end when the response is finished.
+    // Hack to emit end on close because of a core bug that never fires end
+    response.on('close', function () {
+      if (!self._ended) self.response.emit('end')
+    })
+
+    if (self.encoding) {
+      if (self.dests.length !== 0) {
+        console.error("Ignoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid.")
+      } else {
+        response.setEncoding(self.encoding)
+      }
+    }
+
+    self.emit('response', response)
+
+    self.dests.forEach(function (dest) {
+      self.pipeDest(dest)
+    })
+
+    response.on("data", function (chunk) {
+      self._destdata = true
+      self.emit("data", chunk)
+    })
+    response.on("end", function (chunk) {
+      self._ended = true
+      self.emit("end", chunk)
+    })
+    response.on("close", function () {self.emit("close")})
+
+    if (self.callback) {
+      var buffer = []
+      var bodyLen = 0
+      self.on("data", function (chunk) {
+        buffer.push(chunk)
+        bodyLen += chunk.length
+      })
+      self.on("end", function () {
+        debug('end event', self.uri.href)
+        if (self._aborted) {
+          debug('aborted', self.uri.href)
+          return
+        }
+
+        if (buffer.length && Buffer.isBuffer(buffer[0])) {
+          debug('has body', self.uri.href, bodyLen)
+          var body = new Buffer(bodyLen)
+          var i = 0
+          buffer.forEach(function (chunk) {
+            chunk.copy(body, i, 0, chunk.length)
+            i += chunk.length
+          })
+          if (self.encoding === null) {
+            response.body = body
+          } else {
+            response.body = body.toString(self.encoding)
+          }
+        } else if (buffer.length) {
+          // The UTF8 BOM [0xEF,0xBB,0xBF] is converted to [0xFE,0xFF] in the JS UTC16/UCS2 representation.
+          // Strip this value out when the encoding is set to 'utf8', as upstream consumers won't expect it and it breaks JSON.parse().
+          if (self.encoding === 'utf8' && buffer[0].length > 0 && buffer[0][0] === "\uFEFF") {
+            buffer[0] = buffer[0].substring(1)
+          }
+          response.body = buffer.join('')
+        }
+
+        if (self._json) {
+          try {
+            response.body = JSON.parse(response.body)
+          } catch (e) {}
+        }
+        debug('emitting complete', self.uri.href)
+        if(response.body == undefined && !self._json) {
+          response.body = "";
+        }
+        self.emit('complete', response, response.body)
+      })
+    }
+    //if no callback
+    else{
+      self.on("end", function () {
+        if (self._aborted) {
+          debug('aborted', self.uri.href)
+          return
+        }
+        self.emit('complete', response);
+      });
+    }
+  }
+  debug('finish init function', self.uri.href)
+}
+
+Request.prototype.abort = function () {
+  this._aborted = true
+
+  if (this.req) {
+    this.req.abort()
+  }
+  else if (this.response) {
+    this.response.abort()
+  }
+
+  this.emit("abort")
+}
+
+Request.prototype.pipeDest = function (dest) {
+  var response = this.response
+  // Called after the response is received
+  if (dest.headers && !dest.headersSent) {
+    if (hasHeader('content-type', response.headers)) {
+      var ctname = hasHeader('content-type', response.headers)
+      if (dest.setHeader) dest.setHeader(ctname, response.headers[ctname])
+      else dest.headers[ctname] = response.headers[ctname]
+    }
+
+    if (hasHeader('content-length', response.headers)) {
+      var clname = hasHeader('content-length', response.headers)
+      if (dest.setHeader) dest.setHeader(clname, response.headers[clname])
+      else dest.headers[clname] = response.headers[clname]
+    }
+  }
+  if (dest.setHeader && !dest.headersSent) {
+    for (var i in response.headers) {
+      dest.setHeader(i, response.headers[i])
+    }
+    dest.statusCode = response.statusCode
+  }
+  if (this.pipefilter) this.pipefilter(response, dest)
+}
+
+// Composable API
+Request.prototype.setHeader = function (name, value, clobber) {
+  if (clobber === undefined) clobber = true
+  if (clobber || !this.hasHeader(name)) this.headers[name] = value
+  else this.headers[this.hasHeader(name)] += ',' + value
+  return this
+}
+Request.prototype.setHeaders = function (headers) {
+  for (var i in headers) {this.setHeader(i, headers[i])}
+  return this
+}
+Request.prototype.hasHeader = function (header, headers) {
+  var headers = Object.keys(headers || this.headers)
+    , lheaders = headers.map(function (h) {return h.toLowerCase()})
+    ;
+  header = header.toLowerCase()
+  for (var i=0;i<lheaders.length;i++) {
+    if (lheaders[i] === header) return headers[i]
+  }
+  return false
+}
+
+var hasHeader = Request.prototype.hasHeader
+
+Request.prototype.qs = function (q, clobber) {
+  var base
+  if (!clobber && this.uri.query) base = qs.parse(this.uri.query)
+  else base = {}
+
+  for (var i in q) {
+    base[i] = q[i]
+  }
+
+  if (qs.stringify(base) === ''){
+    return this
+  }
+
+  this.uri = url.parse(this.uri.href.split('?')[0] + '?' + qs.stringify(base))
+  this.url = this.uri
+  this.path = this.uri.path
+
+  return this
+}
+Request.prototype.form = function (form) {
+  if (form) {
+    this.setHeader('content-type', 'application/x-www-form-urlencoded; charset=utf-8')
+    this.body = qs.stringify(form).toString('utf8')
+    return this
+  }
+  // create form-data object
+  this._form = new FormData()
+  return this._form
+}
+Request.prototype.multipart = function (multipart) {
+  var self = this
+  self.body = []
+
+  if (!self.hasHeader('content-type')) {
+    self.setHeader('content-type', 'multipart/related; boundary=' + self.boundary)
+  } else {
+    var headerName = self.hasHeader('content-type');
+    self.setHeader(headerName, self.headers[headerName].split(';')[0] + '; boundary=' + self.boundary)
+  }
+
+  if (!multipart.forEach) throw new Error('Argument error, options.multipart.')
+
+  if (self.preambleCRLF) {
+    self.body.push(new Buffer('\r\n'))
+  }
+
+  multipart.forEach(function (part) {
+    var body = part.body
+    if(body == null) throw Error('Body attribute missing in multipart.')
+    delete part.body
+    var preamble = '--' + self.boundary + '\r\n'
+    Object.keys(part).forEach(function (key) {
+      preamble += key + ': ' + part[key] + '\r\n'
+    })
+    preamble += '\r\n'
+    self.body.push(new Buffer(preamble))
+    self.body.push(new Buffer(body))
+    self.body.push(new Buffer('\r\n'))
+  })
+  self.body.push(new Buffer('--' + self.boundary + '--'))
+  return self
+}
+Request.prototype.json = function (val) {
+  var self = this
+
+  if (!self.hasHeader('accept')) self.setHeader('accept', 'application/json')
+
+  this._json = true
+  if (typeof val === 'boolean') {
+    if (typeof this.body === 'object') {
+      this.body = safeStringify(this.body)
+      self.setHeader('content-type', 'application/json')
+    }
+  } else {
+    this.body = safeStringify(val)
+    self.setHeader('content-type', 'application/json')
+  }
+  return this
+}
+Request.prototype.getHeader = function (name, headers) {
+  var result, re, match
+  if (!headers) headers = this.headers
+  Object.keys(headers).forEach(function (key) {
+    re = new RegExp(name, 'i')
+    match = key.match(re)
+    if (match) result = headers[key]
+  })
+  return result
+}
+var getHeader = Request.prototype.getHeader
+
+Request.prototype.auth = function (user, pass, sendImmediately) {
+  if (typeof user !== 'string' || (pass !== undefined && typeof pass !== 'string')) {
+    throw new Error('auth() received invalid user or password')
+  }
+  this._user = user
+  this._pass = pass
+  this._hasAuth = true
+  var header = typeof pass !== 'undefined' ? user + ':' + pass : user
+  if (sendImmediately || typeof sendImmediately == 'undefined') {
+    this.setHeader('authorization', 'Basic ' + toBase64(header))
+    this._sentAuth = true
+  }
+  return this
+}
+Request.prototype.aws = function (opts, now) {
+  if (!now) {
+    this._aws = opts
+    return this
+  }
+  var date = new Date()
+  this.setHeader('date', date.toUTCString())
+  var auth =
+    { key: opts.key
+    , secret: opts.secret
+    , verb: this.method.toUpperCase()
+    , date: date
+    , contentType: this.getHeader('content-type') || ''
+    , md5: this.getHeader('content-md5') || ''
+    , amazonHeaders: aws.canonicalizeHeaders(this.headers)
+    }
+  if (opts.bucket && this.path) {
+    auth.resource = '/' + opts.bucket + this.path
+  } else if (opts.bucket && !this.path) {
+    auth.resource = '/' + opts.bucket
+  } else if (!opts.bucket && this.path) {
+    auth.resource = this.path
+  } else if (!opts.bucket && !this.path) {
+    auth.resource = '/'
+  }
+  auth.resource = aws.canonicalizeResource(auth.resource)
+  this.setHeader('authorization', aws.authorization(auth))
+
+  return this
+}
+Request.prototype.httpSignature = function (opts) {
+  var req = this
+  httpSignature.signRequest({
+    getHeader: function(header) {
+      return getHeader(header, req.headers)
+    },
+    setHeader: function(header, value) {
+      req.setHeader(header, value)
+    },
+    method: this.method,
+    path: this.path
+  }, opts)
+  debug('httpSignature authorization', this.getHeader('authorization'))
+
+  return this
+}
+
+Request.prototype.hawk = function (opts) {
+  this.setHeader('Authorization', hawk.client.header(this.uri, this.method, opts).field)
+}
+
+Request.prototype.oauth = function (_oauth) {
+  var form
+  if (this.hasHeader('content-type') &&
+      this.getHeader('content-type').slice(0, 'application/x-www-form-urlencoded'.length) ===
+        'application/x-www-form-urlencoded'
+     ) {
+    form = qs.parse(this.body)
+  }
+  if (this.uri.query) {
+    form = qs.parse(this.uri.query)
+  }
+  if (!form) form = {}
+  var oa = {}
+  for (var i in form) oa[i] = form[i]
+  for (var i in _oauth) oa['oauth_'+i] = _oauth[i]
+  if (!oa.oauth_version) oa.oauth_version = '1.0'
+  if (!oa.oauth_timestamp) oa.oauth_timestamp = Math.floor( Date.now() / 1000 ).toString()
+  if (!oa.oauth_nonce) oa.oauth_nonce = uuid().replace(/-/g, '')
+
+  oa.oauth_signature_method = 'HMAC-SHA1'
+
+  var consumer_secret = oa.oauth_consumer_secret
+  delete oa.oauth_consumer_secret
+  var token_secret = oa.oauth_token_secret
+  delete oa.oauth_token_secret
+  var timestamp = oa.oauth_timestamp
+
+  var baseurl = this.uri.protocol + '//' + this.uri.host + this.uri.pathname
+  var signature = oauth.hmacsign(this.method, baseurl, oa, consumer_secret, token_secret)
+
+  // oa.oauth_signature = signature
+  for (var i in form) {
+    if ( i.slice(0, 'oauth_') in _oauth) {
+      // skip
+    } else {
+      delete oa['oauth_'+i]
+      if (i !== 'x_auth_mode') delete oa[i]
+    }
+  }
+  oa.oauth_timestamp = timestamp
+  var authHeader = 'OAuth '+Object.keys(oa).sort().map(function (i) {return i+'="'+oauth.rfc3986(oa[i])+'"'}).join(',')
+  authHeader += ',oauth_signature="' + oauth.rfc3986(signature) + '"'
+  this.setHeader('Authorization', authHeader)
+  return this
+}
+Request.prototype.jar = function (jar) {
+  var cookies
+
+  if (this._redirectsFollowed === 0) {
+    this.originalCookieHeader = this.getHeader('cookie')
+  }
+
+  if (!jar) {
+    // disable cookies
+    cookies = false
+    this._disableCookies = true
+  } else {
+    var targetCookieJar = (jar && jar.getCookieString)?jar:globalCookieJar;
+    var urihref = this.uri.href
+    //fetch cookie in the Specified host
+    if (targetCookieJar) {
+      cookies = targetCookieJar.getCookieString(urihref);
+    }
+  }
+
+  //if need cookie and cookie is not empty
+  if (cookies && cookies.length) {
+    if (this.originalCookieHeader) {
+      // Don't overwrite existing Cookie header
+      this.setHeader('cookie', this.originalCookieHeader + '; ' + cookies)
+    } else {
+      this.setHeader('cookie', cookies)
+    }
+  }
+  this._jar = jar
+  return this
+}
+
+
+// Stream API
+Request.prototype.pipe = function (dest, opts) {
+  if (this.response) {
+    if (this._destdata) {
+      throw new Error("You cannot pipe after data has been emitted from the response.")
+    } else if (this._ended) {
+      throw new Error("You cannot pipe after the response has been ended.")
+    } else {
+      stream.Stream.prototype.pipe.call(this, dest, opts)
+      this.pipeDest(dest)
+      return dest
+    }
+  } else {
+    this.dests.push(dest)
+    stream.Stream.prototype.pipe.call(this, dest, opts)
+    return dest
+  }
+}
+Request.prototype.write = function () {
+  if (!this._started) this.start()
+  return this.req.write.apply(this.req, arguments)
+}
+Request.prototype.end = function (chunk) {
+  if (chunk) this.write(chunk)
+  if (!this._started) this.start()
+  this.req.end()
+}
+Request.prototype.pause = function () {
+  if (!this.response) this._paused = true
+  else this.response.pause.apply(this.response, arguments)
+}
+Request.prototype.resume = function () {
+  if (!this.response) this._paused = false
+  else this.response.resume.apply(this.response, arguments)
+}
+Request.prototype.destroy = function () {
+  if (!this._ended) this.end()
+  else if (this.response) this.response.destroy()
+}
+
+function toJSON () {
+  return getSafe(this, '__' + (((1+Math.random())*0x10000)|0).toString(16))
+}
+
+Request.prototype.toJSON = toJSON
+
+
+module.exports = Request
Index: Dev/trunk/node_modules/grunt-http/package.json
===================================================================
--- Dev/trunk/node_modules/grunt-http/package.json	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/package.json	(revision 517)
@@ -0,0 +1,56 @@
+{
+  "name": "grunt-http",
+  "description": "Sends a HTTP request and deals with the response.",
+  "version": "1.1.0",
+  "homepage": "https://github.com/johngeorgewright/grunt-http",
+  "author": {
+    "name": "John Wright",
+    "email": "johngeorge.wright@gmail.com"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/johngeorgewright/grunt-http.git"
+  },
+  "bugs": {
+    "url": "https://github.com/johngeorgewright/grunt-http/issues"
+  },
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://github.com/johngeorgewright/grunt-http/blob/master/LICENSE-MIT"
+    }
+  ],
+  "main": "Gruntfile.js",
+  "engines": {
+    "node": ">= 0.8.0"
+  },
+  "scripts": {
+    "test": "grunt test"
+  },
+  "devDependencies": {
+    "grunt-contrib-jshint": "~0.1.1",
+    "grunt-contrib-clean": "~0.4.0",
+    "grunt-contrib-nodeunit": "~0.1.2",
+    "grunt": "~0.4.1",
+    "sinon": "~1.7.2"
+  },
+  "peerDependencies": {
+    "grunt": "~0.4.1"
+  },
+  "keywords": [
+    "gruntplugin",
+    "request",
+    "http"
+  ],
+  "dependencies": {
+    "request": "~2.33.0"
+  },
+  "readme": "# grunt-http\n\n> Sends a HTTP request and deals with the response.\n\n[![NPM](https://nodei.co/npm/grunt-http.png)](https://nodei.co/npm/grunt-http)\n\n## Getting Started\nThis plugin requires Grunt `~0.4.1`\n\nIf you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:\n\n```shell\nnpm install grunt-http --save-dev\n```\n\nOnce the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:\n\n```js\ngrunt.loadNpmTasks('grunt-http');\n```\n\n## The \"http\" task\n\n### Overview\nIn your project's Gruntfile, add a section named `http` to the data object passed into `grunt.initConfig()`.\n\n```js\ngrunt.initConfig({\n  http: {\n    your_service: {\n      options: {\n        url: 'your/url.com',\n      },\n      dest: 'optional/file/to/save/response'\n    }\n  }\n})\n```\n\nIf you add a source file, the contents will be added to the `body` option unless another field is specified in the `sourceField` option.\n\n### Options\n\ngrunt-http uses the [request](https://github.com/mikeal/request) module under the hood, and apart from a couple specific to grunt-http options, the rest get passed straight to it. Here's a copy of the of the module's option docs. Otherwise, [go to the repo](https://github.com/mikeal/request) and have a look at what's it's capable of.\n\n- `uri || url` - fully qualified uri or a parsed url object from url.parse(). REQUIRED.\n- `qs` - object containing querystring values to be appended to the uri\n- `method` - http method, defaults to GET\n- `headers` - http headers, defaults to {}\n- `body` - entity body for PATCH, POST and PUT requests. Must be buffer or string.\n- `sourceField` - A field in the body or form to add the source files' contents to. Can contain full stops to separate object path. Ie \"form.js\\_code\".\n- `form` - when passed an object this will set body but to a querystring representation of value and adds Content-type: application/x-www-form-urlencoded; charset=utf-8 header. When passed no option a FormData instance is returned that will be piped to request.\n- `auth` - A hash containing values user || username, password || pass, and sendImmediately (optional). [See more info here](https://github.com/mikeal/request#http-authentication).\n- `json` - sets body but to JSON representation of value and adds Content-type: application/json header. Additionally, parses the response body as json.\n- `multipart` - (experimental) array of objects which contains their own headers and body attribute. Sends multipart/related request. See example below.\n- `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true.\n- `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects. defaults to false.\n- `maxRedirects` - the maximum number of redirects to follow, defaults to 10.\n- `encoding` - Encoding to be used on setEncoding of response data. If set to null, the body is returned as a Buffer.\n- `pool` - A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets.\n- `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.\n- `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request\n- `proxy` - An HTTP proxy to be used. Support proxy Auth with Basic Auth the same way it's supported with the url parameter by embedding the auth info in the uri.\n- `oauth` - Options for OAuth HMAC-SHA1 signing. [See more info here](https://github.com/mikeal/request#oauth-signing).\n- `hawk` - Options for [Hawk signing](https://github.com/hueniverse/hawk). The credentials key must contain the necessary signing info, [see hawk docs for details](https://github.com/hueniverse/hawk#usage-example).\n- `strictSSL` - Set to true to require that SSL certificates be valid. Note: to use your own certificate authority, you need to specify an agent that was created with that ca as an option.\n- `jar` - Set to false if you don't want cookies to be remembered for future use or define your custom cookie jar ([see mikeal/request's examples section](https://github.com/mikeal/request#examples))\n- `aws` - object containing aws signing information, should have the properties key and secret as well as bucket unless you're specifying your bucket as part of the path, or you are making a request that doesn't use a bucket (i.e. GET Services)\n- `httpSignature` - Options for the [HTTP Signature Scheme](https://github.com/joyent/node-http-signature/blob/master/http_signing.md) using [Joyent's library](https://github.com/joyent/node-http-signature). The keyId and key properties must be specified. See the docs for other options.\n- `localAddress` - Local interface to bind for network connections.\n- `ignoreErrors` - Ignore the status code returned (if any).\n\n### Usage Examples\n\n#### Google Closure\nIn this example, we're using google's closure service to compile a JS file.\n\n```js\ngrunt.initConfig({\n  http: {\n    closure: {\n      options: {\n        url: 'http://closure-compiler.appspot.com/compile',\n        method: 'POST',\n        form: {\n          output_info: 'compiled_code',\n          output_format: 'text',\n          compilation_level: 'SIMPLE_OPTIMIZATIONS',\n          warning_level: 'default'\n        },\n        sourceField: 'form.js_code'\n      },\n      files: {\n        'build/main.js': 'src/main.js'\n      }\n    }\n  }\n});\n```\n\n## Contributing\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).\n\n## [Release History](/johngeorgewright/grunt-http/releases)\n\n",
+  "readmeFilename": "README.md",
+  "_id": "grunt-http@1.1.0",
+  "dist": {
+    "shasum": "469e11c742532140e45476e87fd7bf7be9fe7a54"
+  },
+  "_from": "grunt-http@",
+  "_resolved": "https://registry.npmjs.org/grunt-http/-/grunt-http-1.1.0.tgz"
+}
Index: Dev/trunk/node_modules/grunt-http/tasks/http.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/tasks/http.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/tasks/http.js	(revision 517)
@@ -0,0 +1,83 @@
+/*
+ * grunt-http
+ * https://github.com/johngeorgewright/grunt-contrib-http
+ *
+ * Copyright (c) 2013 John Wright
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var request = require('request');
+
+module.exports = function (grunt) {
+
+  function responseHandler (done, dest, ignoreErrors) {
+    return function (error, response, body) {
+
+      response = response || { statusCode: 0 };
+
+      grunt.verbose.subhead('Response');
+
+      if (error && !ignoreErrors) {
+        grunt.fail.fatal(error);
+        return done(error);
+      } else if (!ignoreErrors && (response.statusCode < 200 || response.statusCode > 299)) {
+        grunt.fail.fatal(response.statusCode);
+        return done(response.statusCode);
+      }
+
+      grunt.log.ok(response.statusCode);
+      grunt.verbose.writeln(body);
+
+      if (dest) {
+        grunt.file.write(dest, body);
+      }
+
+      done();
+    };
+  }
+
+  function readFile(filepath) {
+    return grunt.file.read(filepath);
+  }
+
+  grunt.registerMultiTask('http', 'Sends a HTTP request and deals with the response.', function () {
+
+    var options = this.options({
+          ignoreErrors: false,
+          sourceField: 'body'
+        }),
+        done = this.async(),
+        sourceField = options.sourceField,
+        sourcePath = sourceField.split('.'),
+        sourceKey = sourcePath.pop(),
+        sourceObj = options;
+
+    sourcePath.forEach(function (key) {
+      sourceObj = sourceObj[key];
+    });
+
+    if (this.files.length) {
+      this.files.forEach(function (file) {
+        var dest = file.dest,
+            contents;
+
+        if (file.src) {
+          contents = file.src.map(readFile).join('\n');
+          sourceObj[sourceKey] = contents;
+        }
+
+        grunt.verbose.subhead('Request');
+        grunt.verbose.writeln(JSON.stringify(options, null, 2));
+
+        request(options, responseHandler(done, dest, options.ignoreErrors));
+      });
+    } else {
+      request(options, responseHandler(done, null, options.ignoreErrors));
+    }
+
+  });
+
+};
+
Index: Dev/trunk/node_modules/grunt-http/test/fixtures/basic.html
===================================================================
--- Dev/trunk/node_modules/grunt-http/test/fixtures/basic.html	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/test/fixtures/basic.html	(revision 517)
@@ -0,0 +1,3 @@
+<!DOCTYPE html><html><head><meta encoding="utf8"><meta name="robots" content="index, follow"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>John Wright | Web Developer | SEO Webmaster | UX Designer</title><link rel="stylesheet" href="/stylesheets/base.css"><script>document.getElementsByTagName('html')[0].className+='js-enabled js-loading'
+</script></head><body><ul class="ah"><li><a href="#body">Skip to content</a></li></ul><div class="navbar navbar-fixed-top navbar-inverse"><div class="navbar-inner"><div class="container"><a data-toggle="collapse" data-target=".nav-collapse" href="#main-nav" class="btn btn-navbar">Menu</a><nav id="main-nav"><a href="/" class="brand"><abbr title="John Wright"><span class="jw-logo-tag-delim">&lt;</span>j<span class="jw-logo-tag-delim">&gt;&lt;/</span>w<span class="jw-logo-tag-delim">&gt;</span></abbr></a><div class="nav-collapse collapse"><ul class="nav pull-right"><!--mixin navItem('/professional-background', 'Professional Background')--><li class=""><a href="/portfolio">Portfolio</a></li><li class=""><a href="/technologies">Technologies</a></li><li class=""><a href="/prices">Prices</a></li><li class=""><a href="https://github.com/johngeorgewright">Find me on GitHub</a></li><li class=""><a href="/docs/CV.pdf">Download CV</a></li><li class=""><a href="mailto:johngeorge.wright@gmail.com">Contact</a></li></ul></div></nav></div></div></div><div id="body" class="container"><article><header><div class="media header-media"><img src="http://www.gravatar.com/avatar/2ad6ebafae880b4bedcadb214c558caa.png" alt="Wee Mee" class="img-rounded pull-left"><div class="media-body"><h1>Web Developer</h1><p class="lead">Specialising in profitable, commercial and communication solutions for you unique business requirements.</p></div></div></header><p>Hi there,</p><p>My name is John Wright and I'm a freelance Web Developer. I've had over 5 years experience with web sites large and small. I'm senior in both backend and frontend development and I'm highly skilled in search engine optimisation helping you get the customers to your site.</p><p>If you'd like to hire me, have any enquiries or just fancy a chat, please don't hesitate to&nbsp;<a href="mailto:johngeorge.wright@gmail.com">contact me</a></p></article></div><script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script><script src="/javascripts/bootstrap-min.js"></script><script>jQuery(function(){jQuery('html').addClass('js-loaded').removeClass('js-loading')})
+</script></body></html>
Index: Dev/trunk/node_modules/grunt-http/test/fixtures/compiled.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/test/fixtures/compiled.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/test/fixtures/compiled.js	(revision 517)
@@ -0,0 +1,1 @@
+function hello(a){alert("Hello, "+a)}hello("New user");
Index: Dev/trunk/node_modules/grunt-http/test/fixtures/not-compiled.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/test/fixtures/not-compiled.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/test/fixtures/not-compiled.js	(revision 517)
@@ -0,0 +1,10 @@
+// ==ClosureCompiler==
+// @compilation_level SIMPLE_OPTIMIZATIONS
+// @output_file_name default.js
+// ==/ClosureCompiler==
+
+// ADD YOUR CODE HERE
+function hello(name) {
+  alert('Hello, ' + name);
+}
+hello('New user');
Index: Dev/trunk/node_modules/grunt-http/test/http_test.js
===================================================================
--- Dev/trunk/node_modules/grunt-http/test/http_test.js	(revision 517)
+++ Dev/trunk/node_modules/grunt-http/test/http_test.js	(revision 517)
@@ -0,0 +1,29 @@
+'use strict';
+
+var request = require('request'),
+    grunt = require('grunt');
+
+exports.http = {
+
+  'it can fetch something just using a destination': function (test) {
+    test.expect(1);
+    test.equal(
+      grunt.file.read('tmp/basic.html'),
+      grunt.file.read('test/fixtures/basic.html'),
+      'different content to what\'s been downloaded'
+    );
+    test.done();
+  },
+
+  'it should have downloaded compiled code from the closure service': function (test) {
+    test.expect(1);
+    test.equal(
+      grunt.file.read('tmp/compiled.js'),
+      grunt.file.read('test/fixtures/compiled.js'),
+      'different content to what\'s been downloaded'
+    );
+    test.done();
+  }
+
+};
+
Index: Dev/trunk/package.json
===================================================================
--- Dev/trunk/package.json	(revision 516)
+++ Dev/trunk/package.json	(revision 517)
@@ -23,5 +23,6 @@
     "grunt-path-check": "~0.9.3",
     "grunt-git-deploy": "~0.1.1",
-    "grunt-svninfo": "~0.1.4"
+    "grunt-svninfo": "~0.1.4",
+    "grunt-http": "^1.1.0"
   },
   "dependencies": {}
