Mitch Garnaat

Adding an initial S3 sample and code to register for event notification on an S3 bucket.

Showing 56 changed files with 2343 additions and 2 deletions
...@@ -170,7 +170,20 @@ class Kappa(object): ...@@ -170,7 +170,20 @@ class Kappa(object):
170 for log_event in response['events']: 170 for log_event in response['events']:
171 print(log_event['message']) 171 print(log_event['message'])
172 172
173 - def add_event_source(self): 173 + def _get_function_arn(self):
174 + name = self.config['lambda']['name']
175 + arn = None
176 + lambda_svc = self.session.create_client('lambda', self.region)
177 + try:
178 + response = lambda_svc.get_function_configuration(
179 + FunctionName=name)
180 + LOG.debug(response)
181 + arn = response['FunctionARN']
182 + except Exception:
183 + LOG.debug('Unable to find ARN for function: %s' % name)
184 + return arn
185 +
186 + def _add_kinesis_event_source(self, event_source_arn):
174 lambda_svc = self.session.create_client('lambda', self.region) 187 lambda_svc = self.session.create_client('lambda', self.region)
175 try: 188 try:
176 invoke_role = self.get_role_arn( 189 invoke_role = self.get_role_arn(
...@@ -178,12 +191,38 @@ class Kappa(object): ...@@ -178,12 +191,38 @@ class Kappa(object):
178 response = lambda_svc.add_event_source( 191 response = lambda_svc.add_event_source(
179 FunctionName=self.config['lambda']['name'], 192 FunctionName=self.config['lambda']['name'],
180 Role=invoke_role, 193 Role=invoke_role,
181 - EventSource=self.config['lambda']['event_source'], 194 + EventSource=event_source_arn,
182 BatchSize=self.config['lambda'].get('batch_size', 100)) 195 BatchSize=self.config['lambda'].get('batch_size', 100))
183 LOG.debug(response) 196 LOG.debug(response)
184 except Exception: 197 except Exception:
185 LOG.exception('Unable to add event source') 198 LOG.exception('Unable to add event source')
186 199
200 + def _add_s3_event_source(self, event_source_arn):
201 + s3_svc = self.session.create_client('s3', self.region)
202 + bucket_name = event_source_arn.split(':')[-1]
203 + invoke_role = self.get_role_arn(
204 + self.config['cloudformation']['invoke_role'])
205 + notification_spec = {
206 + 'CloudFunctionConfiguration': {
207 + 'Id': 'Kappa-%s-notification' % self.config['lambda']['name'],
208 + 'Events': [e for e in self.config['lambda']['s3_events']],
209 + 'CloudFunction': self._get_function_arn(),
210 + 'InvocationRole': invoke_role}}
211 + response = s3_svc.put_bucket_notification(
212 + Bucket=bucket_name,
213 + NotificationConfiguration=notification_spec)
214 + LOG.debug(response)
215 +
216 + def add_event_source(self):
217 + event_source_arn = self.config['lambda']['event_source']
218 + _, _, svc, _ = event_source_arn.split(':', 3)
219 + if svc == 'kinesis':
220 + self._add_kinesis_event_source(event_source_arn)
221 + elif svc == 's3':
222 + self._add_s3_event_source(event_source_arn)
223 + else:
224 + raise ValueError('Unsupported event source: %s' % event_source_arn)
225 +
187 def deploy(self): 226 def deploy(self):
188 self.create_update_roles( 227 self.create_update_roles(
189 self.config['cloudformation']['stack_name'], 228 self.config['cloudformation']['stack_name'],
......
1 +---
2 +profile: personal
3 +region: us-east-1
4 +cloudformation:
5 + template: roles.cf
6 + stack_name: TestS3
7 + exec_role: ExecRole
8 + invoke_role: InvokeRole
9 +lambda:
10 + name: S3Sample
11 + zipfile_name: S3Sample.zip
12 + description: Testing S3 Lambda handler
13 + path: examplefolder
14 + handler: CreateThumbnail.handler
15 + runtime: nodejs
16 + memory_size: 128
17 + timeout: 3
18 + mode: event
19 + test_data: input.json
20 + event_source: arn:aws:s3:::garnaat_pub
21 + s3_events:
22 + - s3:ObjectCreated:*
...\ No newline at end of file ...\ No newline at end of file
1 +// dependencies
2 +var async = require('async');
3 +var AWS = require('aws-sdk');
4 +var gm = require('gm')
5 + .subClass({ imageMagick: true }); // Enable ImageMagick integration.
6 +var util = require('util');
7 +
8 +// constants
9 +var MAX_WIDTH = 100;
10 +var MAX_HEIGHT = 100;
11 +
12 +// get reference to S3 client
13 +var s3 = new AWS.S3();
14 +
15 +exports.handler = function(event, context) {
16 + // Read options from the event.
17 + console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
18 + var srcBucket = event.Records[0].s3.bucket.name;
19 + var srcKey = event.Records[0].s3.object.key;
20 + var dstBucket = srcBucket + "resized";
21 + var dstKey = "resized-" + srcKey;
22 +
23 + // Sanity check: validate that source and destination are different buckets.
24 + if (srcBucket == dstBucket) {
25 + console.error("Destination bucket must not match source bucket.");
26 + return;
27 + }
28 +
29 + // Infer the image type.
30 + var typeMatch = srcKey.match(/\.([^.]*)$/);
31 + if (!typeMatch) {
32 + console.error('unable to infer image type for key ' + srcKey);
33 + return;
34 + }
35 + var imageType = typeMatch[1];
36 + if (imageType != "jpg" && imageType != "png") {
37 + console.log('skipping non-image ' + srcKey);
38 + return;
39 + }
40 +
41 + // Download the image from S3, transform, and upload to a different S3 bucket.
42 + async.waterfall([
43 + function download(next) {
44 + // Download the image from S3 into a buffer.
45 + s3.getObject({
46 + Bucket: srcBucket,
47 + Key: srcKey
48 + },
49 + next);
50 + },
51 + function tranform(response, next) {
52 + gm(response.Body).size(function(err, size) {
53 + // Infer the scaling factor to avoid stretching the image unnaturally.
54 + var scalingFactor = Math.min(
55 + MAX_WIDTH / size.width,
56 + MAX_HEIGHT / size.height
57 + );
58 + var width = scalingFactor * size.width;
59 + var height = scalingFactor * size.height;
60 +
61 + // Transform the image buffer in memory.
62 + this.resize(width, height)
63 + .toBuffer(imageType, function(err, buffer) {
64 + if (err) {
65 + next(err);
66 + } else {
67 + next(null, response.ContentType, buffer);
68 + }
69 + });
70 + });
71 + },
72 + function upload(contentType, data, next) {
73 + // Stream the transformed image to a different S3 bucket.
74 + s3.putObject({
75 + Bucket: dstBucket,
76 + Key: dstKey,
77 + Body: data,
78 + ContentType: contentType
79 + },
80 + next);
81 + }
82 + ], function (err) {
83 + if (err) {
84 + console.error(
85 + 'Unable to resize ' + srcBucket + '/' + srcKey +
86 + ' and upload to ' + dstBucket + '/' + dstKey +
87 + ' due to an error: ' + err
88 + );
89 + } else {
90 + console.log(
91 + 'Successfully resized ' + srcBucket + '/' + srcKey +
92 + ' and uploaded to ' + dstBucket + '/' + dstKey
93 + );
94 + }
95 +
96 + context.done();
97 + }
98 + );
99 +};
1 +language: node_js
2 +node_js:
3 + - "0.10"
1 +Copyright (c) 2010-2014 Caolan McMahon
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining a copy
4 +of this software and associated documentation files (the "Software"), to deal
5 +in the Software without restriction, including without limitation the rights
6 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +copies of the Software, and to permit persons to whom the Software is
8 +furnished to do so, subject to the following conditions:
9 +
10 +The above copyright notice and this permission notice shall be included in
11 +all copies or substantial portions of the Software.
12 +
13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 +THE SOFTWARE.
This diff is collapsed. Click to expand it.
1 +{
2 + "name": "async",
3 + "repo": "caolan/async",
4 + "description": "Higher-order functions and common patterns for asynchronous code",
5 + "version": "0.1.23",
6 + "keywords": [],
7 + "dependencies": {},
8 + "development": {},
9 + "main": "lib/async.js",
10 + "scripts": [ "lib/async.js" ]
11 +}
1 +{
2 + "name": "async",
3 + "description": "Higher-order functions and common patterns for asynchronous code",
4 + "main": "./lib/async",
5 + "author": {
6 + "name": "Caolan McMahon"
7 + },
8 + "version": "0.9.0",
9 + "repository": {
10 + "type": "git",
11 + "url": "https://github.com/caolan/async.git"
12 + },
13 + "bugs": {
14 + "url": "https://github.com/caolan/async/issues"
15 + },
16 + "licenses": [
17 + {
18 + "type": "MIT",
19 + "url": "https://github.com/caolan/async/raw/master/LICENSE"
20 + }
21 + ],
22 + "devDependencies": {
23 + "nodeunit": ">0.0.0",
24 + "uglify-js": "1.2.x",
25 + "nodelint": ">0.0.0"
26 + },
27 + "jam": {
28 + "main": "lib/async.js",
29 + "include": [
30 + "lib/async.js",
31 + "README.md",
32 + "LICENSE"
33 + ]
34 + },
35 + "scripts": {
36 + "test": "nodeunit test/test-async.js"
37 + },
38 + "homepage": "https://github.com/caolan/async",
39 + "_id": "async@0.9.0",
40 + "dist": {
41 + "shasum": "ac3613b1da9bed1b47510bb4651b8931e47146c7",
42 + "tarball": "http://registry.npmjs.org/async/-/async-0.9.0.tgz"
43 + },
44 + "_from": "async@",
45 + "_npmVersion": "1.4.3",
46 + "_npmUser": {
47 + "name": "caolan",
48 + "email": "caolan.mcmahon@gmail.com"
49 + },
50 + "maintainers": [
51 + {
52 + "name": "caolan",
53 + "email": "caolan@caolanmcmahon.com"
54 + }
55 + ],
56 + "directories": {},
57 + "_shasum": "ac3613b1da9bed1b47510bb4651b8931e47146c7",
58 + "_resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz",
59 + "readme": "ERROR: No README data found!"
60 +}
1 +before_install:
2 + - sudo apt-get update
3 + - sudo apt-get install imagemagick graphicsmagick
4 +language: node_js
5 +node_js:
6 + - "0.8"
7 + - "0.10"
This diff is collapsed. Click to expand it.
1 +
2 +test:
3 + @node test/ --integration $(TESTS)
4 +
5 +test-unit:
6 + @node test/ $(TESTS)
7 +
8 +.PHONY: test test-unit
This diff is collapsed. Click to expand it.
1 +
2 +/**
3 + * Module dependencies.
4 + */
5 +
6 +var Stream = require('stream').Stream;
7 +var EventEmitter = require('events').EventEmitter;
8 +var util = require('util');
9 +
10 +util.inherits(gm, EventEmitter);
11 +
12 +/**
13 + * Constructor.
14 + *
15 + * @param {String|Number} path - path to img source or ReadableStream or width of img to create
16 + * @param {Number} [height] - optional filename of ReadableStream or height of img to create
17 + * @param {String} [color] - optional hex background color of created img
18 + */
19 +
20 +function gm (source, height, color) {
21 + var width;
22 +
23 + if (!(this instanceof gm)) {
24 + return new gm(source, height, color);
25 + }
26 +
27 + EventEmitter.call(this);
28 +
29 + this._options = {};
30 + this.options(this.__proto__._options);
31 +
32 + this.data = {};
33 + this._in = [];
34 + this._out = [];
35 + this._outputFormat = null;
36 + this._subCommand = 'convert';
37 +
38 + if (source instanceof Stream) {
39 + this.sourceStream = source;
40 + source = height || 'unknown.jpg';
41 + } else if (Buffer.isBuffer(source)) {
42 + this.sourceBuffer = source;
43 + source = height || 'unknown.jpg';
44 + } else if (height) {
45 + // new images
46 + width = source;
47 + source = "";
48 +
49 + this.in("-size", width + "x" + height);
50 +
51 + if (color) {
52 + this.in("xc:"+ color);
53 + }
54 + }
55 +
56 + if (typeof source === "string") {
57 + // then source is a path
58 +
59 + // parse out gif frame brackets from filename
60 + // since stream doesn't use source path
61 + // eg. "filename.gif[0]"
62 + var frames = source.match(/(\[.+\])$/);
63 + if (frames) {
64 + this.sourceFrames = source.substr(frames.index, frames[0].length);
65 + source = source.substr(0, frames.index);
66 + }
67 + }
68 +
69 + this.source = source;
70 +
71 + this.addSrcFormatter(function (src) {
72 + // must be first source formatter
73 +
74 + var inputFromStdin = this.sourceStream || this.sourceBuffer;
75 + var ret = inputFromStdin ? '-' : this.source;
76 +
77 + if (ret && this.sourceFrames) ret += this.sourceFrames;
78 +
79 + src.length = 0;
80 + src[0] = ret;
81 + });
82 +}
83 +
84 +/**
85 + * Subclasses the gm constructor with custom options.
86 + *
87 + * @param {options} options
88 + * @return {gm} the subclasses gm constructor
89 + */
90 +
91 +var parent = gm;
92 +gm.subClass = function subClass (options) {
93 + function gm (source, height, color) {
94 + if (!(this instanceof parent)) {
95 + return new gm(source, height, color);
96 + }
97 +
98 + parent.call(this, source, height, color);
99 + }
100 +
101 + gm.prototype.__proto__ = parent.prototype;
102 + gm.prototype._options = {};
103 + gm.prototype.options(options);
104 +
105 + return gm;
106 +}
107 +
108 +/**
109 + * Augment the prototype.
110 + */
111 +
112 +require("./lib/options")(gm.prototype);
113 +require("./lib/getters")(gm);
114 +require("./lib/args")(gm.prototype);
115 +require("./lib/drawing")(gm.prototype);
116 +require("./lib/convenience")(gm.prototype);
117 +require("./lib/command")(gm.prototype);
118 +require("./lib/compare")(gm.prototype);
119 +require("./lib/composite")(gm.prototype);
120 +
121 +/**
122 + * Expose.
123 + */
124 +
125 +module.exports = exports = gm;
126 +module.exports.utils = require('./lib/utils');
127 +module.exports.compare = require('./lib/compare')();
128 +module.exports.version = JSON.parse(
129 + require('fs').readFileSync(__dirname + '/package.json', 'utf8')
130 +).version;
131 +
1 +# Compiled source #
2 +###################
3 +*.com
4 +*.class
5 +*.dll
6 +*.exe
7 +*.o
8 +*.so
9 +
10 +# Packages #
11 +############
12 +# it's better to unpack these files and commit the raw source
13 +# git has its own built in compression methods
14 +*.7z
15 +*.dmg
16 +*.gz
17 +*.iso
18 +*.jar
19 +*.rar
20 +*.tar
21 +*.zip
22 +
23 +# Logs and databases #
24 +######################
25 +*.log
26 +*.sql
27 +*.sqlite
28 +
29 +# OS generated files #
30 +######################
31 +.DS_Store*
32 +ehthumbs.db
33 +Icon?
34 +Thumbs.db
35 +
36 +# Node.js #
37 +###########
38 +lib-cov
39 +*.seed
40 +*.log
41 +*.csv
42 +*.dat
43 +*.out
44 +*.pid
45 +*.gz
46 +
47 +pids
48 +logs
49 +results
50 +
51 +node_modules
52 +npm-debug.log
53 +
54 +# Components #
55 +##############
56 +
57 +/build
58 +/components
...\ No newline at end of file ...\ No newline at end of file
1 +language: node_js
2 +node_js:
3 + - "0.4"
4 + - "0.6"
5 + - "0.8"
6 + - "0.10"
...\ No newline at end of file ...\ No newline at end of file
1 +# Array Series [![Build Status](https://travis-ci.org/component/array-parallel.png)](https://travis-ci.org/component/array-parallel)
2 +
3 +Call an array of asynchronous functions in parallel
4 +
5 +### API
6 +
7 +#### parallel(fns[, context[, callback]])
8 +
9 +```js
10 +var parallel = require('array-parallel')
11 +
12 +parallel([
13 + function (done) {
14 + done()
15 + }
16 +], this, function (err) {
17 +
18 +})
19 +```
20 +
21 +#### fns
22 +
23 +`fns` is an array of functions to call in parallel.
24 +The argument signature should be:
25 +
26 +```js
27 +function (done) {
28 + done(new Error())
29 + // or
30 + done(null, result)
31 +}
32 +```
33 +
34 +That is, each function should only take a `done` as an argument.
35 +Each callback should only take an `Error` as the first argument,
36 +or a value as the second.
37 +
38 +#### context
39 +
40 +Optional context to pass to each `fn`.
41 +Basically `fn.call(context, done)`.
42 +
43 +#### callback(err, results)
44 +
45 +```js
46 +function (err, results) {
47 +
48 +}
49 +```
50 +
51 +Only argument is an `Error` argument.
52 +It will be the first error retrieved from all the `fns`.
53 +`results` will be an array of results from each `fn`,
54 +thus this could be considered an asynchronous version of `[].map`.
55 +
56 +### License
57 +
58 +The MIT License (MIT)
59 +
60 +Copyright (c) 2013 Jonathan Ong me@jongleberry.com
61 +
62 +Permission is hereby granted, free of charge, to any person obtaining a copy
63 +of this software and associated documentation files (the "Software"), to deal
64 +in the Software without restriction, including without limitation the rights
65 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
66 +copies of the Software, and to permit persons to whom the Software is
67 +furnished to do so, subject to the following conditions:
68 +
69 +The above copyright notice and this permission notice shall be included in
70 +all copies or substantial portions of the Software.
71 +
72 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
75 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
76 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
77 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
78 +THE SOFTWARE.
1 +{
2 + "name": "array-parallel",
3 + "description": "Call an array of asynchronous functions in parallel",
4 + "repo": "array-parallel",
5 + "version": "0.1.3",
6 + "main": "index.js",
7 + "scripts": [
8 + "index.js"
9 + ],
10 + "license": "MIT"
11 +}
...\ No newline at end of file ...\ No newline at end of file
1 +module.exports = function parallel(fns, context, callback) {
2 + if (!callback) {
3 + if (typeof context === 'function') {
4 + callback = context
5 + context = null
6 + } else {
7 + callback = noop
8 + }
9 + }
10 +
11 + var pending = fns && fns.length
12 + if (!pending) return callback(null, []);
13 +
14 + var finished = false
15 + var results = new Array(pending)
16 +
17 + fns.forEach(context ? function (fn, i) {
18 + fn.call(context, maybeDone(i))
19 + } : function (fn, i) {
20 + fn(maybeDone(i))
21 + })
22 +
23 + function maybeDone(i) {
24 + return function (err, result) {
25 + if (finished) return;
26 +
27 + if (err) {
28 + callback(err, results)
29 + finished = true
30 + return
31 + }
32 +
33 + results[i] = result
34 +
35 + if (!--pending) callback(null, results);
36 + }
37 + }
38 +}
39 +
40 +function noop() {}
1 +{
2 + "name": "array-parallel",
3 + "description": "Call an array of asynchronous functions in parallel",
4 + "version": "0.1.3",
5 + "scripts": {
6 + "test": "node test"
7 + },
8 + "author": {
9 + "name": "Jonathan Ong",
10 + "email": "me@jongleberry.com",
11 + "url": "http://jongleberry.com"
12 + },
13 + "repository": {
14 + "type": "git",
15 + "url": "https://github.com/component/array-parallel.git"
16 + },
17 + "bugs": {
18 + "url": "https://github.com/component/array-parallel/issues",
19 + "email": "me@jongleberry.com"
20 + },
21 + "license": "MIT",
22 + "homepage": "https://github.com/component/array-parallel",
23 + "_id": "array-parallel@0.1.3",
24 + "dist": {
25 + "shasum": "8f785308926ed5aa478c47e64d1b334b6c0c947d",
26 + "tarball": "http://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz"
27 + },
28 + "_from": "array-parallel@~0.1.0",
29 + "_npmVersion": "1.3.17",
30 + "_npmUser": {
31 + "name": "jongleberry",
32 + "email": "jonathanrichardong@gmail.com"
33 + },
34 + "maintainers": [
35 + {
36 + "name": "jongleberry",
37 + "email": "jonathanrichardong@gmail.com"
38 + }
39 + ],
40 + "directories": {},
41 + "_shasum": "8f785308926ed5aa478c47e64d1b334b6c0c947d",
42 + "_resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz"
43 +}
1 +var assert = require('assert')
2 +var parallel = require('./')
3 +
4 +var a, b, c
5 +parallel([
6 + function (done) {
7 + setTimeout(function () {
8 + done(null, a = 0)
9 + }, 5)
10 + },
11 + function (done) {
12 + setTimeout(function () {
13 + done(null, b = 1)
14 + }, 10)
15 + },
16 + function (done) {
17 + setTimeout(function () {
18 + done(null, c = 2)
19 + }, 15)
20 + }
21 +], function (err, results) {
22 + assert.equal(a, 0)
23 + assert.equal(b, 1)
24 + assert.equal(c, 2)
25 +
26 + assert.deepEqual(results, [0, 1, 2])
27 +})
28 +
29 +var d, e
30 +parallel([
31 + function (done) {
32 + setTimeout(function () {
33 + d = 1
34 + done(new Error('message'))
35 + }, 5)
36 + },
37 + function (done) {
38 + setTimeout(function () {
39 + e = 2
40 + done()
41 + }, 10)
42 + }
43 +], function (err) {
44 + assert.equal(err.message, 'message')
45 + assert.equal(d, 1)
46 + assert.equal(e, undefined)
47 +})
48 +
49 +var context = 'hello'
50 +parallel([function (done) {
51 + assert.equal(this, context)
52 +}], context)
53 +
54 +var f
55 +parallel([function (done) {
56 + f = true
57 + done()
58 +}])
59 +
60 +process.nextTick(function () {
61 + assert.equal(f, true)
62 +})
...\ No newline at end of file ...\ No newline at end of file
1 +# Compiled source #
2 +###################
3 +*.com
4 +*.class
5 +*.dll
6 +*.exe
7 +*.o
8 +*.so
9 +
10 +# Packages #
11 +############
12 +# it's better to unpack these files and commit the raw source
13 +# git has its own built in compression methods
14 +*.7z
15 +*.dmg
16 +*.gz
17 +*.iso
18 +*.jar
19 +*.rar
20 +*.tar
21 +*.zip
22 +
23 +# Logs and databases #
24 +######################
25 +*.log
26 +*.sql
27 +*.sqlite
28 +
29 +# OS generated files #
30 +######################
31 +.DS_Store*
32 +ehthumbs.db
33 +Icon?
34 +Thumbs.db
35 +
36 +# Node.js #
37 +###########
38 +lib-cov
39 +*.seed
40 +*.log
41 +*.csv
42 +*.dat
43 +*.out
44 +*.pid
45 +*.gz
46 +
47 +pids
48 +logs
49 +results
50 +
51 +node_modules
52 +npm-debug.log
53 +
54 +# Components #
55 +##############
56 +
57 +/build
58 +/components
...\ No newline at end of file ...\ No newline at end of file
1 +language: node_js
2 +node_js:
3 + - "0.8"
4 + - "0.10"
...\ No newline at end of file ...\ No newline at end of file
1 +# Array Series [![Build Status](https://travis-ci.org/component/array-series.png)](https://travis-ci.org/component/array-series)
2 +
3 +Call an array of asynchronous functions in series
4 +
5 +### API
6 +
7 +#### series(fns[, context[, callback]])
8 +
9 +```js
10 +var series = require('array-series')
11 +
12 +series([
13 + function (done) {
14 + done()
15 + }
16 +], this, function (err) {
17 +
18 +})
19 +```
20 +
21 +#### fns
22 +
23 +`fns` is an array of functions to call in series.
24 +The argument signature should be:
25 +
26 +```js
27 +function (done) {
28 + done(new Error())
29 + // or
30 + done()
31 +}
32 +```
33 +
34 +That is, each function should only take a `done` as an argument.
35 +Each callback should only take an optional `Error` as an argument.
36 +
37 +#### context
38 +
39 +Optional context to pass to each `fn`.
40 +Basically `fn.call(context, done)`.
41 +
42 +#### callback(err)
43 +
44 +```js
45 +function (err) {
46 +
47 +}
48 +```
49 +
50 +Only argument is an `Error` argument.
51 +It will return the first error in the series of functions that returns an error,
52 +and no function after will be called.
53 +
54 +### License
55 +
56 +The MIT License (MIT)
57 +
58 +Copyright (c) 2013 Jonathan Ong me@jongleberry.com
59 +
60 +Permission is hereby granted, free of charge, to any person obtaining a copy
61 +of this software and associated documentation files (the "Software"), to deal
62 +in the Software without restriction, including without limitation the rights
63 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
64 +copies of the Software, and to permit persons to whom the Software is
65 +furnished to do so, subject to the following conditions:
66 +
67 +The above copyright notice and this permission notice shall be included in
68 +all copies or substantial portions of the Software.
69 +
70 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
75 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
76 +THE SOFTWARE.
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "name": "array-series",
3 + "description": "Call an array of asynchronous functions in series",
4 + "repo": "component/array-series",
5 + "version": "0.1.5",
6 + "main": "index.js",
7 + "scripts": [
8 + "index.js"
9 + ],
10 + "license": "MIT"
11 +}
...\ No newline at end of file ...\ No newline at end of file
1 +module.exports = function series(fns, context, callback) {
2 + if (!callback) {
3 + if (typeof context === 'function') {
4 + callback = context
5 + context = null
6 + } else {
7 + callback = noop
8 + }
9 + }
10 +
11 + if (!(fns && fns.length)) return callback();
12 +
13 + fns = fns.slice(0)
14 +
15 + var call = context
16 + ? function () {
17 + fns.length
18 + ? fns.shift().call(context, next)
19 + : callback()
20 + }
21 + : function () {
22 + fns.length
23 + ? fns.shift()(next)
24 + : callback()
25 + }
26 +
27 + call()
28 +
29 + function next(err) {
30 + err ? callback(err) : call()
31 + }
32 +}
33 +
34 +function noop() {}
1 +{
2 + "name": "array-series",
3 + "description": "Call an array of asynchronous functions in series",
4 + "version": "0.1.5",
5 + "scripts": {
6 + "test": "node test"
7 + },
8 + "author": {
9 + "name": "Jonathan Ong",
10 + "email": "me@jongleberry.com",
11 + "url": "http://jongleberry.com"
12 + },
13 + "repository": {
14 + "type": "git",
15 + "url": "https://github.com/component/array-series.git"
16 + },
17 + "bugs": {
18 + "url": "https://github.com/component/array-series/issues",
19 + "email": "me@jongleberry.com"
20 + },
21 + "license": "MIT",
22 + "homepage": "https://github.com/component/array-series",
23 + "_id": "array-series@0.1.5",
24 + "dist": {
25 + "shasum": "df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f",
26 + "tarball": "http://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz"
27 + },
28 + "_from": "array-series@~0.1.0",
29 + "_npmVersion": "1.3.17",
30 + "_npmUser": {
31 + "name": "jongleberry",
32 + "email": "jonathanrichardong@gmail.com"
33 + },
34 + "maintainers": [
35 + {
36 + "name": "jongleberry",
37 + "email": "jonathanrichardong@gmail.com"
38 + }
39 + ],
40 + "directories": {},
41 + "_shasum": "df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f",
42 + "_resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz"
43 +}
1 +var assert = require('assert')
2 +var series = require('./')
3 +
4 +var a, b, c
5 +
6 +series([
7 + function (done) {
8 + a = 1
9 + process.nextTick(done)
10 + check('a')
11 + },
12 + function (done) {
13 + b = 2
14 + process.nextTick(done)
15 + check('b')
16 + },
17 + function (done) {
18 + c = 3
19 + process.nextTick(done)
20 + check('c')
21 + }
22 +], function (err) {
23 + assert.ifError(err)
24 + assert.equal(a, 1)
25 + assert.equal(b, 2)
26 + assert.equal(c, 3)
27 +})
28 +
29 +function check(x) {
30 + switch (x) {
31 + case 'a':
32 + assert.equal(a, 1)
33 + assert.equal(b, undefined)
34 + assert.equal(c, undefined)
35 + break
36 + case 'b':
37 + assert.equal(a, 1)
38 + assert.equal(b, 2)
39 + assert.equal(c, undefined)
40 + break
41 + case 'c':
42 + assert.equal(a, 1)
43 + assert.equal(b, 2)
44 + assert.equal(c, 3)
45 + break
46 + }
47 +}
48 +
49 +var context = 'hello'
50 +series([function (done) {
51 + assert.equal(this, context)
52 + done()
53 +}], context)
54 +
55 +var finished
56 +series([], function (err) {
57 + finished = true
58 +})
59 +
60 +process.nextTick(function () {
61 + if (!finished)
62 + throw new Error('Failed with no functions.');
63 +})
64 +
65 +var r, d, o
66 +series([
67 + function (done) {
68 + r = 1
69 + process.nextTick(done)
70 + },
71 + function (done) {
72 + d = 0
73 + process.nextTick(function () {
74 + done(new Error('message'))
75 + })
76 + },
77 + function (done) {
78 + o = 0
79 + process.nextTick(done)
80 + }
81 +], function (err) {
82 + assert.equal(err.message, 'message')
83 + assert.equal(r, 1)
84 + assert.equal(d, 0)
85 + assert.equal(o, undefined)
86 +})
87 +
88 +console.log('Array series tests pass!')
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +0.7.0 / 2012-05-04
3 +==================
4 +
5 + * Added .component to package.json
6 + * Added debug.component.js build
7 +
8 +0.6.0 / 2012-03-16
9 +==================
10 +
11 + * Added support for "-" prefix in DEBUG [Vinay Pulim]
12 + * Added `.enabled` flag to the node version [TooTallNate]
13 +
14 +0.5.0 / 2012-02-02
15 +==================
16 +
17 + * Added: humanize diffs. Closes #8
18 + * Added `debug.disable()` to the CS variant
19 + * Removed padding. Closes #10
20 + * Fixed: persist client-side variant again. Closes #9
21 +
22 +0.4.0 / 2012-02-01
23 +==================
24 +
25 + * Added browser variant support for older browsers [TooTallNate]
26 + * Added `debug.enable('project:*')` to browser variant [TooTallNate]
27 + * Added padding to diff (moved it to the right)
28 +
29 +0.3.0 / 2012-01-26
30 +==================
31 +
32 + * Added millisecond diff when isatty, otherwise UTC string
33 +
34 +0.2.0 / 2012-01-22
35 +==================
36 +
37 + * Added wildcard support
38 +
39 +0.1.0 / 2011-12-02
40 +==================
41 +
42 + * Added: remove colors unless stderr isatty [TooTallNate]
43 +
44 +0.0.1 / 2010-01-03
45 +==================
46 +
47 + * Initial release
1 +
2 +debug.component.js: head.js debug.js tail.js
3 + cat $^ > $@
4 +
1 +
2 +# debug
3 +
4 + tiny node.js debugging utility.
5 +
6 +## Installation
7 +
8 +```
9 +$ npm install debug
10 +```
11 +
12 +## Example
13 +
14 + This module is modelled after node core's debugging technique, allowing you to enable one or more topic-specific debugging functions, for example core does the following within many modules:
15 +
16 +```js
17 +var debug;
18 +if (process.env.NODE_DEBUG && /cluster/.test(process.env.NODE_DEBUG)) {
19 + debug = function(x) {
20 + var prefix = process.pid + ',' +
21 + (process.env.NODE_WORKER_ID ? 'Worker' : 'Master');
22 + console.error(prefix, x);
23 + };
24 +} else {
25 + debug = function() { };
26 +}
27 +```
28 +
29 + This concept is extremely simple but it works well. With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.
30 +
31 +Example _app.js_:
32 +
33 +```js
34 +var debug = require('debug')('http')
35 + , http = require('http')
36 + , name = 'My App';
37 +
38 +// fake app
39 +
40 +debug('booting %s', name);
41 +
42 +http.createServer(function(req, res){
43 + debug(req.method + ' ' + req.url);
44 + res.end('hello\n');
45 +}).listen(3000, function(){
46 + debug('listening');
47 +});
48 +
49 +// fake worker of some kind
50 +
51 +require('./worker');
52 +```
53 +
54 +Example _worker.js_:
55 +
56 +```js
57 +var debug = require('debug')('worker');
58 +
59 +setInterval(function(){
60 + debug('doing some work');
61 +}, 1000);
62 +```
63 +
64 + The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:
65 +
66 + ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)
67 +
68 + ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)
69 +
70 +## Millisecond diff
71 +
72 + When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
73 +
74 + ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)
75 +
76 + When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
77 +
78 + ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)
79 +
80 +## Conventions
81 +
82 + If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
83 +
84 +## Wildcards
85 +
86 + The "*" character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
87 +
88 + You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with "connect:".
89 +
90 +## Browser support
91 +
92 + Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`.
93 +
94 +```js
95 +a = debug('worker:a');
96 +b = debug('worker:b');
97 +
98 +setInterval(function(){
99 + a('doing some work');
100 +}, 1000);
101 +
102 +setInterval(function(){
103 + a('doing some work');
104 +}, 1200);
105 +```
106 +
107 +## License
108 +
109 +(The MIT License)
110 +
111 +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
112 +
113 +Permission is hereby granted, free of charge, to any person obtaining
114 +a copy of this software and associated documentation files (the
115 +'Software'), to deal in the Software without restriction, including
116 +without limitation the rights to use, copy, modify, merge, publish,
117 +distribute, sublicense, and/or sell copies of the Software, and to
118 +permit persons to whom the Software is furnished to do so, subject to
119 +the following conditions:
120 +
121 +The above copyright notice and this permission notice shall be
122 +included in all copies or substantial portions of the Software.
123 +
124 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
125 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
126 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
127 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
128 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
129 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
130 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
...\ No newline at end of file ...\ No newline at end of file
1 +;(function(){
2 +
3 +/**
4 + * Create a debugger with the given `name`.
5 + *
6 + * @param {String} name
7 + * @return {Type}
8 + * @api public
9 + */
10 +
11 +function debug(name) {
12 + if (!debug.enabled(name)) return function(){};
13 +
14 + return function(fmt){
15 + var curr = new Date;
16 + var ms = curr - (debug[name] || curr);
17 + debug[name] = curr;
18 +
19 + fmt = name
20 + + ' '
21 + + fmt
22 + + ' +' + debug.humanize(ms);
23 +
24 + // This hackery is required for IE8
25 + // where `console.log` doesn't have 'apply'
26 + window.console
27 + && console.log
28 + && Function.prototype.apply.call(console.log, console, arguments);
29 + }
30 +}
31 +
32 +/**
33 + * The currently active debug mode names.
34 + */
35 +
36 +debug.names = [];
37 +debug.skips = [];
38 +
39 +/**
40 + * Enables a debug mode by name. This can include modes
41 + * separated by a colon and wildcards.
42 + *
43 + * @param {String} name
44 + * @api public
45 + */
46 +
47 +debug.enable = function(name) {
48 + localStorage.debug = name;
49 +
50 + var split = (name || '').split(/[\s,]+/)
51 + , len = split.length;
52 +
53 + for (var i = 0; i < len; i++) {
54 + name = split[i].replace('*', '.*?');
55 + if (name[0] === '-') {
56 + debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
57 + }
58 + else {
59 + debug.names.push(new RegExp('^' + name + '$'));
60 + }
61 + }
62 +};
63 +
64 +/**
65 + * Disable debug output.
66 + *
67 + * @api public
68 + */
69 +
70 +debug.disable = function(){
71 + debug.enable('');
72 +};
73 +
74 +/**
75 + * Humanize the given `ms`.
76 + *
77 + * @param {Number} m
78 + * @return {String}
79 + * @api private
80 + */
81 +
82 +debug.humanize = function(ms) {
83 + var sec = 1000
84 + , min = 60 * 1000
85 + , hour = 60 * min;
86 +
87 + if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
88 + if (ms >= min) return (ms / min).toFixed(1) + 'm';
89 + if (ms >= sec) return (ms / sec | 0) + 's';
90 + return ms + 'ms';
91 +};
92 +
93 +/**
94 + * Returns true if the given mode name is enabled, false otherwise.
95 + *
96 + * @param {String} name
97 + * @return {Boolean}
98 + * @api public
99 + */
100 +
101 +debug.enabled = function(name) {
102 + for (var i = 0, len = debug.skips.length; i < len; i++) {
103 + if (debug.skips[i].test(name)) {
104 + return false;
105 + }
106 + }
107 + for (var i = 0, len = debug.names.length; i < len; i++) {
108 + if (debug.names[i].test(name)) {
109 + return true;
110 + }
111 + }
112 + return false;
113 +};
114 +
115 +// persist
116 +
117 +if (window.localStorage) debug.enable(localStorage.debug);
118 + module.exports = debug;
119 +
120 +})();
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +/**
3 + * Create a debugger with the given `name`.
4 + *
5 + * @param {String} name
6 + * @return {Type}
7 + * @api public
8 + */
9 +
10 +function debug(name) {
11 + if (!debug.enabled(name)) return function(){};
12 +
13 + return function(fmt){
14 + var curr = new Date;
15 + var ms = curr - (debug[name] || curr);
16 + debug[name] = curr;
17 +
18 + fmt = name
19 + + ' '
20 + + fmt
21 + + ' +' + debug.humanize(ms);
22 +
23 + // This hackery is required for IE8
24 + // where `console.log` doesn't have 'apply'
25 + window.console
26 + && console.log
27 + && Function.prototype.apply.call(console.log, console, arguments);
28 + }
29 +}
30 +
31 +/**
32 + * The currently active debug mode names.
33 + */
34 +
35 +debug.names = [];
36 +debug.skips = [];
37 +
38 +/**
39 + * Enables a debug mode by name. This can include modes
40 + * separated by a colon and wildcards.
41 + *
42 + * @param {String} name
43 + * @api public
44 + */
45 +
46 +debug.enable = function(name) {
47 + localStorage.debug = name;
48 +
49 + var split = (name || '').split(/[\s,]+/)
50 + , len = split.length;
51 +
52 + for (var i = 0; i < len; i++) {
53 + name = split[i].replace('*', '.*?');
54 + if (name[0] === '-') {
55 + debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
56 + }
57 + else {
58 + debug.names.push(new RegExp('^' + name + '$'));
59 + }
60 + }
61 +};
62 +
63 +/**
64 + * Disable debug output.
65 + *
66 + * @api public
67 + */
68 +
69 +debug.disable = function(){
70 + debug.enable('');
71 +};
72 +
73 +/**
74 + * Humanize the given `ms`.
75 + *
76 + * @param {Number} m
77 + * @return {String}
78 + * @api private
79 + */
80 +
81 +debug.humanize = function(ms) {
82 + var sec = 1000
83 + , min = 60 * 1000
84 + , hour = 60 * min;
85 +
86 + if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
87 + if (ms >= min) return (ms / min).toFixed(1) + 'm';
88 + if (ms >= sec) return (ms / sec | 0) + 's';
89 + return ms + 'ms';
90 +};
91 +
92 +/**
93 + * Returns true if the given mode name is enabled, false otherwise.
94 + *
95 + * @param {String} name
96 + * @return {Boolean}
97 + * @api public
98 + */
99 +
100 +debug.enabled = function(name) {
101 + for (var i = 0, len = debug.skips.length; i < len; i++) {
102 + if (debug.skips[i].test(name)) {
103 + return false;
104 + }
105 + }
106 + for (var i = 0, len = debug.names.length; i < len; i++) {
107 + if (debug.names[i].test(name)) {
108 + return true;
109 + }
110 + }
111 + return false;
112 +};
113 +
114 +// persist
115 +
116 +if (window.localStorage) debug.enable(localStorage.debug);
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +var debug = require('../')('http')
3 + , http = require('http')
4 + , name = 'My App';
5 +
6 +// fake app
7 +
8 +debug('booting %s', name);
9 +
10 +http.createServer(function(req, res){
11 + debug(req.method + ' ' + req.url);
12 + res.end('hello\n');
13 +}).listen(3000, function(){
14 + debug('listening');
15 +});
16 +
17 +// fake worker of some kind
18 +
19 +require('./worker');
...\ No newline at end of file ...\ No newline at end of file
1 +<html>
2 + <head>
3 + <title>debug()</title>
4 + <script src="../debug.js"></script>
5 + <script>
6 + // type debug.enable('*') in
7 + // the console and refresh :)
8 +
9 + a = debug('worker:a');
10 + b = debug('worker:b');
11 +
12 + setInterval(function(){
13 + a('doing some work');
14 + }, 1000);
15 +
16 + setInterval(function(){
17 + a('doing some work');
18 + }, 1200);
19 + </script>
20 + </head>
21 + <body>
22 +
23 + </body>
24 +</html>
1 +
2 +var debug = {
3 + foo: require('../')('test:foo'),
4 + bar: require('../')('test:bar'),
5 + baz: require('../')('test:baz')
6 +};
7 +
8 +debug.foo('foo')
9 +debug.bar('bar')
10 +debug.baz('baz')
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +// DEBUG=* node example/worker
3 +// DEBUG=worker:* node example/worker
4 +// DEBUG=worker:a node example/worker
5 +// DEBUG=worker:b node example/worker
6 +
7 +var a = require('../')('worker:a')
8 + , b = require('../')('worker:b');
9 +
10 +function work() {
11 + a('doing lots of uninteresting work');
12 + setTimeout(work, Math.random() * 1000);
13 +}
14 +
15 +work();
16 +
17 +function workb() {
18 + b('doing some work');
19 + setTimeout(workb, Math.random() * 2000);
20 +}
21 +
22 +workb();
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +module.exports = require('./lib/debug');
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "name": "debug",
3 + "version": "0.7.0",
4 + "description": "small debugging utility",
5 + "keywords": [
6 + "debug",
7 + "log",
8 + "debugger"
9 + ],
10 + "author": {
11 + "name": "TJ Holowaychuk",
12 + "email": "tj@vision-media.ca"
13 + },
14 + "dependencies": {},
15 + "devDependencies": {
16 + "mocha": "*"
17 + },
18 + "main": "index",
19 + "browserify": "debug.component.js",
20 + "engines": {
21 + "node": "*"
22 + },
23 + "component": {
24 + "scripts": {
25 + "debug": "debug.component.js"
26 + }
27 + },
28 + "_id": "debug@0.7.0",
29 + "dist": {
30 + "shasum": "f5be05ec0434c992d79940e50b2695cfb2e01b08",
31 + "tarball": "http://registry.npmjs.org/debug/-/debug-0.7.0.tgz"
32 + },
33 + "maintainers": [
34 + {
35 + "name": "tjholowaychuk",
36 + "email": "tj@vision-media.ca"
37 + }
38 + ],
39 + "directories": {},
40 + "_shasum": "f5be05ec0434c992d79940e50b2695cfb2e01b08",
41 + "_from": "debug@0.7.0",
42 + "_resolved": "https://registry.npmjs.org/debug/-/debug-0.7.0.tgz"
43 +}
1 +
2 + module.exports = debug;
3 +
4 +})();
...\ No newline at end of file ...\ No newline at end of file
1 +language: node_js
2 +node_js:
3 + - 0.6
4 + - 0.8
5 + - "0.10"
1 +Apache License, Version 2.0
2 +
3 +Copyright (c) 2011 Dominic Tarr
4 +
5 +Licensed under the Apache License, Version 2.0 (the "License");
6 +you may not use this file except in compliance with the License.
7 +You may obtain a copy of the License at
8 +
9 + http://www.apache.org/licenses/LICENSE-2.0
10 +
11 +Unless required by applicable law or agreed to in writing, software
12 +distributed under the License is distributed on an "AS IS" BASIS,
13 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 +See the License for the specific language governing permissions and
15 +limitations under the License.
1 +The MIT License
2 +
3 +Copyright (c) 2011 Dominic Tarr
4 +
5 +Permission is hereby granted, free of charge,
6 +to any person obtaining a copy of this software and
7 +associated documentation files (the "Software"), to
8 +deal in the Software without restriction, including
9 +without limitation the rights to use, copy, modify,
10 +merge, publish, distribute, sublicense, and/or sell
11 +copies of the Software, and to permit persons to whom
12 +the Software is furnished to do so,
13 +subject to the following conditions:
14 +
15 +The above copyright notice and this permission notice
16 +shall be included in all copies or substantial portions of the Software.
17 +
18 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22 +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +var Stream = require('stream')
2 +
3 +// through
4 +//
5 +// a stream that does nothing but re-emit the input.
6 +// useful for aggregating a series of changing but not ending streams into one stream)
7 +
8 +exports = module.exports = through
9 +through.through = through
10 +
11 +//create a readable writable stream.
12 +
13 +function through (write, end, opts) {
14 + write = write || function (data) { this.queue(data) }
15 + end = end || function () { this.queue(null) }
16 +
17 + var ended = false, destroyed = false, buffer = [], _ended = false
18 + var stream = new Stream()
19 + stream.readable = stream.writable = true
20 + stream.paused = false
21 +
22 +// stream.autoPause = !(opts && opts.autoPause === false)
23 + stream.autoDestroy = !(opts && opts.autoDestroy === false)
24 +
25 + stream.write = function (data) {
26 + write.call(this, data)
27 + return !stream.paused
28 + }
29 +
30 + function drain() {
31 + while(buffer.length && !stream.paused) {
32 + var data = buffer.shift()
33 + if(null === data)
34 + return stream.emit('end')
35 + else
36 + stream.emit('data', data)
37 + }
38 + }
39 +
40 + stream.queue = stream.push = function (data) {
41 +// console.error(ended)
42 + if(_ended) return stream
43 + if(data == null) _ended = true
44 + buffer.push(data)
45 + drain()
46 + return stream
47 + }
48 +
49 + //this will be registered as the first 'end' listener
50 + //must call destroy next tick, to make sure we're after any
51 + //stream piped from here.
52 + //this is only a problem if end is not emitted synchronously.
53 + //a nicer way to do this is to make sure this is the last listener for 'end'
54 +
55 + stream.on('end', function () {
56 + stream.readable = false
57 + if(!stream.writable && stream.autoDestroy)
58 + process.nextTick(function () {
59 + stream.destroy()
60 + })
61 + })
62 +
63 + function _end () {
64 + stream.writable = false
65 + end.call(stream)
66 + if(!stream.readable && stream.autoDestroy)
67 + stream.destroy()
68 + }
69 +
70 + stream.end = function (data) {
71 + if(ended) return
72 + ended = true
73 + if(arguments.length) stream.write(data)
74 + _end() // will emit or queue
75 + return stream
76 + }
77 +
78 + stream.destroy = function () {
79 + if(destroyed) return
80 + destroyed = true
81 + ended = true
82 + buffer.length = 0
83 + stream.writable = stream.readable = false
84 + stream.emit('close')
85 + return stream
86 + }
87 +
88 + stream.pause = function () {
89 + if(stream.paused) return
90 + stream.paused = true
91 + return stream
92 + }
93 +
94 + stream.resume = function () {
95 + if(stream.paused) {
96 + stream.paused = false
97 + stream.emit('resume')
98 + }
99 + drain()
100 + //may have become paused again,
101 + //as drain emits 'data'.
102 + if(!stream.paused)
103 + stream.emit('drain')
104 + return stream
105 + }
106 + return stream
107 +}
108 +
1 +{
2 + "name": "through",
3 + "version": "2.3.6",
4 + "description": "simplified stream construction",
5 + "main": "index.js",
6 + "scripts": {
7 + "test": "set -e; for t in test/*.js; do node $t; done"
8 + },
9 + "devDependencies": {
10 + "stream-spec": "~0.3.5",
11 + "tape": "~2.3.2",
12 + "from": "~0.1.3"
13 + },
14 + "keywords": [
15 + "stream",
16 + "streams",
17 + "user-streams",
18 + "pipe"
19 + ],
20 + "author": {
21 + "name": "Dominic Tarr",
22 + "email": "dominic.tarr@gmail.com",
23 + "url": "dominictarr.com"
24 + },
25 + "license": "MIT",
26 + "repository": {
27 + "type": "git",
28 + "url": "https://github.com/dominictarr/through.git"
29 + },
30 + "homepage": "http://github.com/dominictarr/through",
31 + "testling": {
32 + "browsers": [
33 + "ie/8..latest",
34 + "ff/15..latest",
35 + "chrome/20..latest",
36 + "safari/5.1..latest"
37 + ],
38 + "files": "test/*.js"
39 + },
40 + "gitHead": "19ed9b7e84efe7c3e3c8be80f29390b1620e13c0",
41 + "bugs": {
42 + "url": "https://github.com/dominictarr/through/issues"
43 + },
44 + "_id": "through@2.3.6",
45 + "_shasum": "26681c0f524671021d4e29df7c36bce2d0ecf2e8",
46 + "_from": "through@~2.3.1",
47 + "_npmVersion": "1.4.26",
48 + "_npmUser": {
49 + "name": "dominictarr",
50 + "email": "dominic.tarr@gmail.com"
51 + },
52 + "maintainers": [
53 + {
54 + "name": "dominictarr",
55 + "email": "dominic.tarr@gmail.com"
56 + }
57 + ],
58 + "dist": {
59 + "shasum": "26681c0f524671021d4e29df7c36bce2d0ecf2e8",
60 + "tarball": "http://registry.npmjs.org/through/-/through-2.3.6.tgz"
61 + },
62 + "directories": {},
63 + "_resolved": "https://registry.npmjs.org/through/-/through-2.3.6.tgz"
64 +}
1 +#through
2 +
3 +[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through)
4 +[![testling badge](https://ci.testling.com/dominictarr/through.png)](https://ci.testling.com/dominictarr/through)
5 +
6 +Easy way to create a `Stream` that is both `readable` and `writable`.
7 +
8 +* Pass in optional `write` and `end` methods.
9 +* `through` takes care of pause/resume logic if you use `this.queue(data)` instead of `this.emit('data', data)`.
10 +* Use `this.pause()` and `this.resume()` to manage flow.
11 +* Check `this.paused` to see current flow state. (`write` always returns `!this.paused`).
12 +
13 +This function is the basis for most of the synchronous streams in
14 +[event-stream](http://github.com/dominictarr/event-stream).
15 +
16 +``` js
17 +var through = require('through')
18 +
19 +through(function write(data) {
20 + this.queue(data) //data *must* not be null
21 + },
22 + function end () { //optional
23 + this.queue(null)
24 + })
25 +```
26 +
27 +Or, can also be used _without_ buffering on pause, use `this.emit('data', data)`,
28 +and this.emit('end')
29 +
30 +``` js
31 +var through = require('through')
32 +
33 +through(function write(data) {
34 + this.emit('data', data)
35 + //this.pause()
36 + },
37 + function end () { //optional
38 + this.emit('end')
39 + })
40 +```
41 +
42 +## Extended Options
43 +
44 +You will probably not need these 99% of the time.
45 +
46 +### autoDestroy=false
47 +
48 +By default, `through` emits close when the writable
49 +and readable side of the stream has ended.
50 +If that is not desired, set `autoDestroy=false`.
51 +
52 +``` js
53 +var through = require('through')
54 +
55 +//like this
56 +var ts = through(write, end, {autoDestroy: false})
57 +//or like this
58 +var ts = through(write, end)
59 +ts.autoDestroy = false
60 +```
61 +
62 +## License
63 +
64 +MIT / Apache2
1 +var from = require('from')
2 +var through = require('../')
3 +
4 +var tape = require('tape')
5 +
6 +tape('simple async example', function (t) {
7 +
8 + var n = 0, expected = [1,2,3,4,5], actual = []
9 + from(expected)
10 + .pipe(through(function(data) {
11 + this.pause()
12 + n ++
13 + setTimeout(function(){
14 + console.log('pushing data', data)
15 + this.push(data)
16 + this.resume()
17 + }.bind(this), 300)
18 + })).pipe(through(function(data) {
19 + console.log('pushing data second time', data);
20 + this.push(data)
21 + })).on('data', function (d) {
22 + actual.push(d)
23 + }).on('end', function() {
24 + t.deepEqual(actual, expected)
25 + t.end()
26 + })
27 +
28 +})
1 +var test = require('tape')
2 +var through = require('../')
3 +
4 +// must emit end before close.
5 +
6 +test('end before close', function (assert) {
7 + var ts = through()
8 + ts.autoDestroy = false
9 + var ended = false, closed = false
10 +
11 + ts.on('end', function () {
12 + assert.ok(!closed)
13 + ended = true
14 + })
15 + ts.on('close', function () {
16 + assert.ok(ended)
17 + closed = true
18 + })
19 +
20 + ts.write(1)
21 + ts.write(2)
22 + ts.write(3)
23 + ts.end()
24 + assert.ok(ended)
25 + assert.notOk(closed)
26 + ts.destroy()
27 + assert.ok(closed)
28 + assert.end()
29 +})
30 +
1 +var test = require('tape')
2 +var through = require('../')
3 +
4 +// must emit end before close.
5 +
6 +test('buffering', function(assert) {
7 + var ts = through(function (data) {
8 + this.queue(data)
9 + }, function () {
10 + this.queue(null)
11 + })
12 +
13 + var ended = false, actual = []
14 +
15 + ts.on('data', actual.push.bind(actual))
16 + ts.on('end', function () {
17 + ended = true
18 + })
19 +
20 + ts.write(1)
21 + ts.write(2)
22 + ts.write(3)
23 + assert.deepEqual(actual, [1, 2, 3])
24 + ts.pause()
25 + ts.write(4)
26 + ts.write(5)
27 + ts.write(6)
28 + assert.deepEqual(actual, [1, 2, 3])
29 + ts.resume()
30 + assert.deepEqual(actual, [1, 2, 3, 4, 5, 6])
31 + ts.pause()
32 + ts.end()
33 + assert.ok(!ended)
34 + ts.resume()
35 + assert.ok(ended)
36 + assert.end()
37 +})
38 +
39 +test('buffering has data in queue, when ends', function (assert) {
40 +
41 + /*
42 + * If stream ends while paused with data in the queue,
43 + * stream should still emit end after all data is written
44 + * on resume.
45 + */
46 +
47 + var ts = through(function (data) {
48 + this.queue(data)
49 + }, function () {
50 + this.queue(null)
51 + })
52 +
53 + var ended = false, actual = []
54 +
55 + ts.on('data', actual.push.bind(actual))
56 + ts.on('end', function () {
57 + ended = true
58 + })
59 +
60 + ts.pause()
61 + ts.write(1)
62 + ts.write(2)
63 + ts.write(3)
64 + ts.end()
65 + assert.deepEqual(actual, [], 'no data written yet, still paused')
66 + assert.ok(!ended, 'end not emitted yet, still paused')
67 + ts.resume()
68 + assert.deepEqual(actual, [1, 2, 3], 'resumed, all data should be delivered')
69 + assert.ok(ended, 'end should be emitted once all data was delivered')
70 + assert.end();
71 +})
1 +var test = require('tape')
2 +var through = require('../')
3 +
4 +// must emit end before close.
5 +
6 +test('end before close', function (assert) {
7 + var ts = through()
8 + var ended = false, closed = false
9 +
10 + ts.on('end', function () {
11 + assert.ok(!closed)
12 + ended = true
13 + })
14 + ts.on('close', function () {
15 + assert.ok(ended)
16 + closed = true
17 + })
18 +
19 + ts.write(1)
20 + ts.write(2)
21 + ts.write(3)
22 + ts.end()
23 + assert.ok(ended)
24 + assert.ok(closed)
25 + assert.end()
26 +})
27 +
28 +test('end only once', function (t) {
29 +
30 + var ts = through()
31 + var ended = false, closed = false
32 +
33 + ts.on('end', function () {
34 + t.equal(ended, false)
35 + ended = true
36 + })
37 +
38 + ts.queue(null)
39 + ts.queue(null)
40 + ts.queue(null)
41 +
42 + ts.resume()
43 +
44 + t.end()
45 +})
1 +
2 +var test = require('tape')
3 +var spec = require('stream-spec')
4 +var through = require('../')
5 +
6 +/*
7 + I'm using these two functions, and not streams and pipe
8 + so there is less to break. if this test fails it must be
9 + the implementation of _through_
10 +*/
11 +
12 +function write(array, stream) {
13 + array = array.slice()
14 + function next() {
15 + while(array.length)
16 + if(stream.write(array.shift()) === false)
17 + return stream.once('drain', next)
18 +
19 + stream.end()
20 + }
21 +
22 + next()
23 +}
24 +
25 +function read(stream, callback) {
26 + var actual = []
27 + stream.on('data', function (data) {
28 + actual.push(data)
29 + })
30 + stream.once('end', function () {
31 + callback(null, actual)
32 + })
33 + stream.once('error', function (err) {
34 + callback(err)
35 + })
36 +}
37 +
38 +test('simple defaults', function(assert) {
39 +
40 + var l = 1000
41 + , expected = []
42 +
43 + while(l--) expected.push(l * Math.random())
44 +
45 + var t = through()
46 + var s = spec(t).through().pausable()
47 +
48 + read(t, function (err, actual) {
49 + assert.ifError(err)
50 + assert.deepEqual(actual, expected)
51 + assert.end()
52 + })
53 +
54 + t.on('close', s.validate)
55 +
56 + write(expected, t)
57 +});
58 +
59 +test('simple functions', function(assert) {
60 +
61 + var l = 1000
62 + , expected = []
63 +
64 + while(l--) expected.push(l * Math.random())
65 +
66 + var t = through(function (data) {
67 + this.emit('data', data*2)
68 + })
69 + var s = spec(t).through().pausable()
70 +
71 +
72 + read(t, function (err, actual) {
73 + assert.ifError(err)
74 + assert.deepEqual(actual, expected.map(function (data) {
75 + return data*2
76 + }))
77 + assert.end()
78 + })
79 +
80 + t.on('close', s.validate)
81 +
82 + write(expected, t)
83 +})
84 +
85 +test('pauses', function(assert) {
86 +
87 + var l = 1000
88 + , expected = []
89 +
90 + while(l--) expected.push(l) //Math.random())
91 +
92 + var t = through()
93 +
94 + var s = spec(t)
95 + .through()
96 + .pausable()
97 +
98 + t.on('data', function () {
99 + if(Math.random() > 0.1) return
100 + t.pause()
101 + process.nextTick(function () {
102 + t.resume()
103 + })
104 + })
105 +
106 + read(t, function (err, actual) {
107 + assert.ifError(err)
108 + assert.deepEqual(actual, expected)
109 + })
110 +
111 + t.on('close', function () {
112 + s.validate()
113 + assert.end()
114 + })
115 +
116 + write(expected, t)
117 +})
1 +{
2 + "name": "gm",
3 + "description": "GraphicsMagick and ImageMagick for node.js",
4 + "version": "1.17.0",
5 + "author": {
6 + "name": "Aaron Heckmann",
7 + "email": "aaron.heckmann+github@gmail.com"
8 + },
9 + "keywords": [
10 + "graphics",
11 + "magick",
12 + "image",
13 + "graphicsmagick",
14 + "imagemagick",
15 + "gm",
16 + "convert",
17 + "identify",
18 + "compare"
19 + ],
20 + "engines": {
21 + "node": ">= 0.8.0"
22 + },
23 + "bugs": {
24 + "url": "http://github.com/aheckmann/gm/issues"
25 + },
26 + "licenses": [
27 + {
28 + "type": "MIT",
29 + "url": "http://www.opensource.org/licenses/mit-license.php"
30 + }
31 + ],
32 + "main": "./index",
33 + "scripts": {
34 + "test": "make test-unit; make test;"
35 + },
36 + "repository": {
37 + "type": "git",
38 + "url": "https://github.com/aheckmann/gm.git"
39 + },
40 + "license": "MIT",
41 + "devDependencies": {
42 + "gleak": "0.4.0",
43 + "async": "~0.2.7"
44 + },
45 + "dependencies": {
46 + "debug": "0.7.0",
47 + "array-series": "~0.1.0",
48 + "array-parallel": "~0.1.0",
49 + "through": "~2.3.1"
50 + },
51 + "gitHead": "2fb65bac7c09ab8b09e87b791b146b82c209076e",
52 + "homepage": "https://github.com/aheckmann/gm",
53 + "_id": "gm@1.17.0",
54 + "_shasum": "27a261e0bdfee3d373d24b5a27bd249057355068",
55 + "_from": "gm@",
56 + "_npmVersion": "1.4.28",
57 + "_npmUser": {
58 + "name": "rwky",
59 + "email": "admin@rwky.net"
60 + },
61 + "maintainers": [
62 + {
63 + "name": "aaron",
64 + "email": "aaron.heckmann+github@gmail.com"
65 + },
66 + {
67 + "name": "jongleberry",
68 + "email": "me@jongleberry.com"
69 + },
70 + {
71 + "name": "rwky",
72 + "email": "admin@rwky.net"
73 + },
74 + {
75 + "name": "fragphace",
76 + "email": "fragphace@gmail.com"
77 + }
78 + ],
79 + "dist": {
80 + "shasum": "27a261e0bdfee3d373d24b5a27bd249057355068",
81 + "tarball": "http://registry.npmjs.org/gm/-/gm-1.17.0.tgz"
82 + },
83 + "directories": {},
84 + "_resolved": "https://registry.npmjs.org/gm/-/gm-1.17.0.tgz"
85 +}
1 +{
2 + "Records":[
3 + {
4 + "eventVersion":"2.0",
5 + "eventSource":"aws:s3",
6 + "awsRegion":"us-east-1",
7 + "eventTime":"1970-01-01T00:00:00.000Z",
8 + "eventName":"ObjectCreated:Put",
9 + "userIdentity":{
10 + "principalId":"AIDAJDPLRKLG7UEXAMPLE"
11 + },
12 + "requestParameters":{
13 + "sourceIPAddress":"127.0.0.1"
14 + },
15 + "responseElements":{
16 + "x-amz-request-id":"C3D13FE58DE4C810",
17 + "x-amz-id-2":"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD"
18 + },
19 + "s3":{
20 + "s3SchemaVersion":"1.0",
21 + "configurationId":"testConfigRule",
22 + "bucket":{
23 + "name":"sourcebucket",
24 + "ownerIdentity":{
25 + "principalId":"A3NL1KOZZKExample"
26 + },
27 + "arn":"arn:aws:s3:::sourcebucket"
28 + },
29 + "object":{
30 + "key":"HappyFace.jpg",
31 + "size":1024,
32 + "eTag":"d41d8cd98f00b204e9800998ecf8427e",
33 + "versionId":"096fKKXTRTtl3on89fVO.nfljtsv6qko"
34 + }
35 + }
36 + }
37 + ]
38 +}
1 +{
2 + "AWSTemplateFormatVersion": "2010-09-09",
3 + "Resources": {
4 + "ExecRole": {
5 + "Type": "AWS::IAM::Role",
6 + "Properties": {
7 + "AssumeRolePolicyDocument": {
8 + "Version" : "2012-10-17",
9 + "Statement": [ {
10 + "Effect": "Allow",
11 + "Principal": {
12 + "Service": [ "lambda.amazonaws.com" ]
13 + },
14 + "Action": [ "sts:AssumeRole" ]
15 + } ]
16 + }
17 + }
18 + },
19 + "ExecRolePolicies": {
20 + "Type": "AWS::IAM::Policy",
21 + "Properties": {
22 + "PolicyName": "ExecRolePolicy",
23 + "PolicyDocument": {
24 + "Version" : "2012-10-17",
25 + "Statement": [ {
26 + "Effect": "Allow",
27 + "Action": [
28 + "logs:*"
29 + ],
30 + "Resource": "arn:aws:logs:*:*:*"
31 + },
32 + {
33 + "Effect": "Allow",
34 + "Action": [
35 + "s3:GetObject",
36 + "s3:PutObject"
37 + ],
38 + "Resource": [
39 + "arn:aws:s3:::*"
40 + ]
41 + } ]
42 + },
43 + "Roles": [ { "Ref": "ExecRole" } ]
44 + }
45 + },
46 + "InvokeRole": {
47 + "Type": "AWS::IAM::Role",
48 + "Properties": {
49 + "AssumeRolePolicyDocument": {
50 + "Version" : "2012-10-17",
51 + "Statement": [ {
52 + "Effect": "Allow",
53 + "Principal": {
54 + "Service": [ "s3.amazonaws.com" ]
55 + },
56 + "Action": [ "sts:AssumeRole" ],
57 + "Condition": {
58 + "ArnLike": {
59 + "sts:ExternalId": "arn:aws:s3:::*"
60 + }
61 + }
62 + } ]
63 + }
64 + }
65 + },
66 + "InvokeRolePolicies": {
67 + "Type": "AWS::IAM::Policy",
68 + "Properties": {
69 + "PolicyName": "ExecRolePolicy",
70 + "PolicyDocument": {
71 + "Version" : "2012-10-17",
72 + "Statement": [
73 + {
74 + "Effect": "Allow",
75 + "Resource": [
76 + "*"
77 + ],
78 + "Action": [
79 + "lambda:InvokeFunction"
80 + ]
81 + }
82 + ]
83 + },
84 + "Roles": [ { "Ref": "InvokeRole" } ]
85 + }
86 + }
87 + }
88 +}