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