From b82412d7e1c516b5dac3967acefd3233cb008f65 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 10 May 2018 09:41:24 -0400 Subject: [PATCH 01/94] Fixes #57 --- docs/COMBINATORS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index c72530b..6989ac2 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -75,9 +75,9 @@ composer.action('hello', { filename: 'hello.js' }) // specify a sequence of actions composer.action('helloAndBye', { sequence: ['hello', 'bye'] }) ``` -The action may de defined by providing the code for the action as a string, as a Javascript function, or as a file name. Alternatively, a sequence action may be defined by providing the list of sequenced actions. The code (specified as a string) may be annotated with the kind of the action runtime. +The action may be defined by providing the code for the action as a string, as a Javascript function, or as a file name. Alternatively, a sequence action may be defined by providing the list of sequenced actions. The code (specified as a string) may be annotated with the kind of the action runtime. -### Environment capture +### Environment capture in actions Javascript functions used to define actions cannot capture any part of their declaration environment. The following code is not correct as the declaration of `name` would not be available at invocation time: ```javascript @@ -107,7 +107,7 @@ function product({ x, y }) { return { product: x * y } } composer.function(product) ``` -### Environment capture +### Environment capture in functions Functions intended for compositions cannot capture any part of their declaration environment. They may however access and mutate variables in an environment consisting of the variables declared by the [composer.let](#composerletname-value-composition_1-composition_2-) combinator discussed below. From 7eca708039edae421b4cf49db84f349faf7b5ae5 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 10 May 2018 10:14:11 -0400 Subject: [PATCH 02/94] Fixes #58 --- bin/compose | 11 ++++- docs/COMPOSE.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/bin/compose b/bin/compose index fd16e8a..aea6426 100755 --- a/bin/compose +++ b/bin/compose @@ -8,7 +8,7 @@ const minimist = require('minimist') const composer = require('../composer') const argv = minimist(process.argv.slice(2), { - string: ['apihost', 'auth', 'deploy', 'lower'], + string: ['apihost', 'auth', 'deploy', 'lower', 'entity', 'entities'], boolean: ['insecure', 'encode', 'json', 'version'], alias: { auth: 'u', insecure: 'i', version: 'v' } }) @@ -21,14 +21,17 @@ if (argv.version) { let count = 0 if (argv.json) count++ if (argv.encode) count++ +if (argv.entity) count++ if (typeof argv.deploy !== 'undefined') count++ -if (argv._.length !== 1 || count > 1 || argv.deploy === '') { +if (argv._.length !== 1 || count > 1 || argv.deploy === '' || argv.entity === '' || argv.entities === '') { console.error('Usage:') console.error(' compose composition.js[on] command [flags]') console.error('Commands:') console.error(' --json output the json representation for the composition (default command)') console.error(' --deploy NAME deploy the composition with name NAME') + console.error(' --entity NAME output the conductor action definition for the composition (giving name NAME to the composition)') + console.error(' --entities NAME convert the composition into an array of action definition (giving name NAME to the composition)') console.error(' --encode output the conductor action code for the composition') console.error('Flags:') console.error(' --lower [VERSION] lower to primitive combinators or specific composer version') @@ -54,6 +57,10 @@ if (argv.deploy) { }, console.error) } else if (argv.encode) { console.log(composer.encode(composer.composition('anonymous', composition), lower).actions.slice(-1)[0].action.exec.code) +} else if (argv.entity) { + console.log(JSON.stringify(composer.encode(composer.composition(argv.entity, composition), lower).actions.slice(-1)[0], null, 4)) +} else if (argv.entities) { + console.log(JSON.stringify(composer.encode(composer.composition(argv.entities, composition), lower).actions, null, 4)) } else { console.log(JSON.stringify(composer.lower(composition, lower), null, 4)) } diff --git a/docs/COMPOSE.md b/docs/COMPOSE.md index 4142ab8..4750fa2 100644 --- a/docs/COMPOSE.md +++ b/docs/COMPOSE.md @@ -15,21 +15,26 @@ Usage: Commands: --json output the json representation for the composition (default command) --deploy NAME deploy the composition with name NAME + --entity NAME output the conductor action definition for the composition (giving name NAME to the composition) + --entities NAME convert the composition into an array of action definition (giving name NAME to the composition) --encode output the conductor action code for the composition Flags: --lower [VERSION] lower to primitive combinators or specific composer version --apihost HOST API HOST -u, --auth KEY authorization KEY -i, --insecure bypass certificate checking + -v, --version output the composer version ``` The `compose` command requires either a Javascript file that evaluates to a composition (for example [demo.js](../samples/demo.js)) or a JSON file that encodes a composition (for example [demo.json](../samples/demo.json)). The JSON format is documented in [FORMAT.md](FORMAT.md). -The `compose` command has three modes of operation: +The `compose` command has several modes of operation: - By default or when the `--json` option is specified, the command returns the composition encoded as a JSON dictionary. - When the `--deploy` option is specified, the command deploys the composition given the desired name for the composition. - When the `--encode` option is specified, the command returns the Javascript code for the [conductor action](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) for the composition. +- When the `--entity` option is specified, the command returns the complete conductor action definition as a JSON dictionary. +- When the `--entities` option is specified, the command returns an array of action definitions including not only the conductor action for the composition, but possibly also the nested action definitions. -## JSON format +## JSON option By default, the `compose` command evaluates the composition code and outputs the resulting JSON dictionary: ``` @@ -76,7 +81,122 @@ composer = require('@ibm-functions/composer') ``` In other words, there is no need to require the `composer` module explicitly in the composition code. -## Deployment +## Entity option + +With the `--entity` option the `compose` command returns the conductor action definition for the composition. +``` +compose demo.js --entity demo +``` +```json +{ + "name": "/_/demo", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "..." + }, + "annotations": [ + { + "key": "conductor", + "value": { + "type": "if", + "test": { + "type": "action", + "name": "/_/authenticate" + }, + "consequent": { + "type": "action", + "name": "/_/success" + }, + "alternate": { + "type": "action", + "name": "/_/failure" + } + } + }, + { + "key": "composer", + "value": "0.4.0" + } + ] + } +} +``` + + +## Entities option + +With the `--entities` option the `compose` command returns not only the conductor action definition for the composition but also the definitions of nested actions and compositions. +``` +compose demo.js --entities demo +``` +```json +[ + { + "name": "/_/authenticate", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function ({ password }) { return { value: password === 'abc123' } }" + } + } + }, + { + "name": "/_/success", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function () { return { message: 'success' } }" + } + } + }, + { + "name": "/_/failure", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function () { return { message: 'failure' } }" + } + } + }, + { + "name": "/_/demo", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "..." + }, + "annotations": [ + { + "key": "conductor", + "value": { + "type": "if", + "test": { + "type": "action", + "name": "/_/authenticate" + }, + "consequent": { + "type": "action", + "name": "/_/success" + }, + "alternate": { + "type": "action", + "name": "/_/failure" + } + } + }, + { + "key": "composer", + "value": "0.4.0" + } + ] + } + } +] + +``` + +## Deploy option The `--deploy` option makes it possible to deploy a composition (Javascript or JSON) given the desired name for the composition: ``` @@ -115,7 +235,7 @@ If the `--auth` flag is absent, the environment variable `__OW_API_KEY` is used The default path for the whisk property file is `$HOME/.wskprops`. It can be altered by setting the `WSK_CONFIG_FILE` environment variable. -## Code generation +## Encode option The `compose` command returns the code of the conductor action for the composition (Javascript or JSON) when invoked with the `--encode` option. For instance, the conductor action code for the [demo.js](../samples/demo.js) composition is [demo-conductor.js](../samples/demo-conductor.js): From 7f469033e8042486bb552c9281c44fd0a1e7f8d2 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 10 May 2018 10:34:24 -0400 Subject: [PATCH 03/94] Fixes #56 --- composer.js | 3 ++- test/test.js | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/composer.js b/composer.js index 7b446a7..a20d7c6 100644 --- a/composer.js +++ b/composer.js @@ -318,7 +318,8 @@ function composer() { * /ns/pkg/foo => /ns/pkg/foo */ function parseActionName(name) { - if (typeof name !== 'string' || name.trim().length == 0) throw new ComposerError('Name is not specified') + if (typeof name !== 'string') throw new ComposerError('Name must be a string') + if (name.trim().length == 0) throw new ComposerError('Name is not valid') name = name.trim() let delimiter = '/' let parts = name.split(delimiter) diff --git a/test/test.js b/test/test.js index eed442f..9c64aab 100644 --- a/test/test.js +++ b/test/test.js @@ -33,8 +33,9 @@ describe('composer', function () { it('action name must parse to fully qualified', function () { let combos = [ - { n: '', s: false, e: 'Name is not specified' }, - { n: ' ', s: false, e: 'Name is not specified' }, + { n: 42, s: false, e: 'Name must be a string' }, + { n: '', s: false, e: 'Name is not valid' }, + { n: ' ', s: false, e: 'Name is not valid' }, { n: '/', s: false, e: 'Name is not valid' }, { n: '//', s: false, e: 'Name is not valid' }, { n: '/a', s: false, e: 'Name is not valid' }, From 74b2e88fb41db1ff712e949c025db1e7db3a4d3f Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Fri, 11 May 2018 16:24:07 -0400 Subject: [PATCH 04/94] Add exit codes to compose command --- bin/compose | 85 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/bin/compose b/bin/compose index aea6426..123a7bd 100755 --- a/bin/compose +++ b/bin/compose @@ -9,7 +9,7 @@ const composer = require('../composer') const argv = minimist(process.argv.slice(2), { string: ['apihost', 'auth', 'deploy', 'lower', 'entity', 'entities'], - boolean: ['insecure', 'encode', 'json', 'version'], + boolean: ['insecure', 'encode', 'json', 'version', 'quiet'], alias: { auth: 'u', insecure: 'i', version: 'v' } }) @@ -39,28 +39,67 @@ if (argv._.length !== 1 || count > 1 || argv.deploy === '' || argv.entity === '' console.error(' -u, --auth KEY authorization KEY') console.error(' -i, --insecure bypass certificate checking') console.error(' -v, --version output the composer version') - return + console.error(' --quiet omit detailed diagnostic messages') + process.exit(127) } -const filename = argv._[0] -const source = fs.readFileSync(filename, { encoding: 'utf8' }) -let composition = filename.slice(filename.lastIndexOf('.')) === '.js' ? vm.runInNewContext(source, { composer, require, console, process }) : composer.deserialize(JSON.parse(source)) -const lower = typeof argv.lower === 'string' ? argv.lower : false -if (argv.deploy) { - const options = { ignore_certs: argv.insecure } - if (argv.apihost) options.apihost = argv.apihost - if (argv.auth) options.api_key = argv.auth - composer.openwhisk(options).compositions.deploy(composer.composition(argv.deploy, composition), lower) - .then(obj => { - const names = obj.actions.map(action => action.name) - console.log(`ok: created action${names.length > 1 ? 's' : ''} ${names}`) - }, console.error) -} else if (argv.encode) { - console.log(composer.encode(composer.composition('anonymous', composition), lower).actions.slice(-1)[0].action.exec.code) -} else if (argv.entity) { - console.log(JSON.stringify(composer.encode(composer.composition(argv.entity, composition), lower).actions.slice(-1)[0], null, 4)) -} else if (argv.entities) { - console.log(JSON.stringify(composer.encode(composer.composition(argv.entities, composition), lower).actions, null, 4)) -} else { - console.log(JSON.stringify(composer.lower(composition, lower), null, 4)) +try { + const filename = argv._[0] + let source + try { + source = fs.readFileSync(filename, { encoding: 'utf8' }) + } catch (error) { + console.error('File not found') + if (!argv.quiet) console.log(error) + process.exit(6) + } + let composition + try { + composition = filename.slice(filename.lastIndexOf('.')) === '.js' ? vm.runInNewContext(source, { composer, require, console, process }) : composer.deserialize(JSON.parse(source)) + if (typeof argv.lower === 'string') composition = composer.lower(composition, argv.lower) + } catch (error) { + console.error('Bad composition') + if (!argv.quiet) console.log(error) + process.exit(4) + } + if (argv.deploy) { + const options = { ignore_certs: argv.insecure } + if (argv.apihost) options.apihost = argv.apihost + if (argv.auth) options.api_key = argv.auth + return Promise.resolve() + .then(() => composer.openwhisk(options).compositions.deploy(composer.composition(argv.deploy, composition), false)) + .then(obj => { + const names = obj.actions.map(action => action.name) + console.log(`ok: created action${names.length > 1 ? 's' : ''} ${names}`) + }) + .catch(error => { + if (error.constructor && error.constructor.name === 'OpenWhiskError') { + switch (error.statusCode) { + case 401: + console.error('Authentication failure') + if (!argv.quiet) console.log(error) + process.exit(2) + case 403: + console.error('Authorization failure') + if (!argv.quiet) console.log(error) + process.exit(3) + } + } + console.error('Server error') + if (!argv.quiet) console.log(error) + process.exit(5) + }) + } else if (argv.encode) { + console.log(composer.encode(composer.composition('anonymous', composition), false).actions.slice(-1)[0].action.exec.code) + } else if (argv.entity) { + console.log(JSON.stringify(composer.encode(composer.composition(argv.entity, composition), false).actions.slice(-1)[0], null, 4)) + } else if (argv.entities) { + console.log(JSON.stringify(composer.encode(composer.composition(argv.entities, composition), false).actions, null, 4)) + } else { + console.log(JSON.stringify(composition, null, 4)) + } +} catch (error) { + console.error('Internal error') + if (!argv.quiet) console.log(error) + process.exit(1) } From 29392163401091997b5c16a07328ab8eefe7f08e Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 14 May 2018 09:12:55 -0400 Subject: [PATCH 05/94] A function may now return a promise --- composer.js | 28 +++++++++++++++------------- test/test.js | 4 ++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/composer.js b/composer.js index a20d7c6..86ac671 100644 --- a/composer.js +++ b/composer.js @@ -614,7 +614,7 @@ function conductor({ Compiler }) { } } - while (true) { + function step() { // final state, return composition result if (state === undefined) { console.log(`Entering final state`) @@ -645,18 +645,17 @@ function conductor({ Compiler }) { return { action: json.name, params, state: { $resume: { state, stack } } } // invoke continuation break case 'function': - let result - try { - result = run(json.exec.code) - } catch (error) { - console.error(error) - result = { error: `An exception was caught at state ${current} (see log for details)` } - } - if (typeof result === 'function') result = { error: `State ${current} evaluated to a function` } - // if a function has only side effects and no return value, return params - params = JSON.parse(JSON.stringify(result === undefined ? params : result)) - inspect() - break + return Promise.resolve().then(() => run(json.exec.code)) + .catch(error => { + console.error(error) + return { error: `An exception was caught at state ${current} (see log for details)` } + }) + .then(result => { + if (typeof result === 'function') result = { error: `State ${current} evaluated to a function` } + // if a function has only side effects and no return value, return params + params = JSON.parse(JSON.stringify(result === undefined ? params : result)) + inspect() + }).then(step) case 'empty': inspect() break @@ -665,6 +664,9 @@ function conductor({ Compiler }) { default: return internalError(`State ${current} has an unknown type`) } + return step() } + + return step() } } diff --git a/test/test.js b/test/test.js index 9c64aab..613c6f8 100644 --- a/test/test.js +++ b/test/test.js @@ -137,6 +137,10 @@ describe('composer', function () { return invoke(composer.function('({ n }) => n % 2 === 0'), { n: 4 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) }) + it('function may return a promise', function () { + return invoke(composer.function(({ n }) => Promise.resolve(n % 2 === 0)), { n: 4 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) + }) + it('invalid argument', function () { try { invoke(composer.function(42)) From 064bb350e2cb1ff96ffd6c96c91d52530b324ae3 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 14 May 2018 09:50:56 -0400 Subject: [PATCH 06/94] Support composer.action('foo', { async: true }). Support composer.composition(name, composition, { async: true }). Fixes #5. --- composer.js | 35 +++++++++++++++++++++++++++-------- test/test.js | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/composer.js b/composer.js index 86ac671..bd6b948 100644 --- a/composer.js +++ b/composer.js @@ -39,8 +39,8 @@ function compiler() { retain_catch: { components: true, since: '0.4.0' }, let: { args: [{ _: 'declarations', type: 'object' }], components: true, since: '0.4.0' }, mask: { components: true, since: '0.4.0' }, - action: { args: [{ _: 'name', type: 'string' }, { _: 'action', type: 'object', optional: true }], since: '0.4.0' }, - composition: { args: [{ _: 'name', type: 'string' }, { _: 'composition' }], since: '0.4.0' }, + action: { args: [{ _: 'name', type: 'string' }, { _: 'options', type: 'object', optional: true }], since: '0.4.0' }, + composition: { args: [{ _: 'name', type: 'string' }, { _: 'composition' }, { _: 'options', type: 'object', optional: true }], since: '0.4.0' }, repeat: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, retry: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, value: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, @@ -358,6 +358,7 @@ function composer() { // enhanced action combinator: mangle name, capture code action(name, options = {}) { if (arguments.length > 2) throw new ComposerError('Too many arguments') + if (typeof options !== 'object') throw new ComposerError('Invalid argument', options) name = parseActionName(name) // throws ComposerError if name is not valid let exec if (Array.isArray(options.sequence)) { // native sequence @@ -378,15 +379,18 @@ function composer() { } const composition = { type: 'action', name } if (exec) composition.action = { exec } + if (options.async) composition.async = true return new Composition(composition) } // enhanced composition combinator: mangle name - composition(name, composition) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (typeof name !== 'string') throw new ComposerError('Invalid argument', name) + composition(name, composition, options = {}) { + if (arguments.length > 3) throw new ComposerError('Too many arguments') + if (typeof options !== 'object') throw new ComposerError('Invalid argument', options) name = parseActionName(name) - return new Composition({ type: 'composition', name, composition: this.task(composition) }) + const obj = { type: 'composition', name, composition: this.task(composition) } + if (options.async) obj.async = true + return new Composition(obj) } // return enhanced openwhisk client capable of deploying compositions @@ -464,6 +468,8 @@ function conductor({ Compiler }) { const compiler = new Compiler() this.require = require + const openwhisk = require('openwhisk') + let wsk function chain(front, back) { front.slice(-1)[0].next = 1 @@ -482,7 +488,7 @@ function conductor({ Compiler }) { case 'sequence': return chain([{ type: 'pass', path }], sequence(json.components)) case 'action': - return [{ type: 'action', name: json.name, path }] + return [{ type: 'action', name: json.name, async: json.async, path }] case 'function': return [{ type: 'function', exec: json.function.exec, path }] case 'finally': @@ -642,7 +648,20 @@ function conductor({ Compiler }) { stack.shift() break case 'action': - return { action: json.name, params, state: { $resume: { state, stack } } } // invoke continuation + if (json.async) { + if (!wsk) wsk = openwhisk({ ignore_certs: true }) + return wsk.actions.invoke({ name: json.name, params }) + .catch(error => { + console.error(error) + return { error: `An exception was caught at state ${current} (see log for details)` } + }) + .then(result => { + params = result + inspect() + }).then(step) + } else { + return { action: json.name, params, state: { $resume: { state, stack } } } // invoke continuation + } break case 'function': return Promise.resolve().then(() => run(json.exec.code)) diff --git a/test/test.js b/test/test.js index 613c6f8..ece8237 100644 --- a/test/test.js +++ b/test/test.js @@ -1,6 +1,7 @@ const assert = require('assert') const composer = require('../composer') const name = 'TestAction' +const compositionName = 'TestComposition' const wsk = composer.openwhisk({ ignore_certs: process.env.IGNORE_CERTS && process.env.IGNORE_CERTS !== 'false' && process.env.IGNORE_CERTS !== '0' }) // deploy action @@ -31,6 +32,10 @@ describe('composer', function () { return invoke(composer.action('isNotOne'), { n: 1 }).then(activation => assert.deepEqual(activation.response.result, { value: false })) }) + it('action must return activationId', function () { + return invoke(composer.action('isNotOne', { async: true }), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) + }) + it('action name must parse to fully qualified', function () { let combos = [ { n: 42, s: false, e: 'Name must be a string' }, @@ -65,9 +70,46 @@ describe('composer', function () { }) }) + it('invalid options', function () { + try { + invoke(composer.action('foo', 42)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('too many arguments', function () { + try { + invoke(composer.action('foo', {}, 'foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('compositions', function () { + it('composition must return true', function () { + return invoke(composer.composition(compositionName, composer.action('isNotOne')), { n: 0 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) + }) + + it('action must return activationId', function () { + return invoke(composer.composition(compositionName, composer.action('isNotOne'), { async: true }), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) + }) + it('invalid argument', function () { try { - invoke(composer.function(42)) + invoke(composer.composition(compositionName, 42)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('invalid options', function () { + try { + invoke(composer.composition(compositionName, 'foo', 42)) assert.fail() } catch (error) { assert.ok(error.message.startsWith('Invalid argument')) @@ -76,7 +118,7 @@ describe('composer', function () { it('too many arguments', function () { try { - invoke(composer.function('foo', 'foo')) + invoke(composer.composition(compositionName, 'foo', {}, 'foo')) assert.fail() } catch (error) { assert.ok(error.message.startsWith('Too many arguments')) From 926bd38773e7c8be774763258345ee5861005937 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 14 May 2018 13:27:15 -0400 Subject: [PATCH 07/94] Add discussion of composition templates --- docs/README.md | 1 + docs/TEMPLATES.md | 104 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 docs/TEMPLATES.md diff --git a/docs/README.md b/docs/README.md index ec4d3b2..7b7b26c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,4 +10,5 @@ The documentation for the Composer package is organized as follows: - [COMPOSE.md](COMPOSE.md) documents the `compose` command. - [COMBINATORS.md](COMBINATORS.md) documents the methods of the `composer` object. - [FORMAT.md](FORMAT.md) documents the JSON format for encoding compositions. +- [TEMPLATES.md](TEMPLATES.md) demonstrates various composition templates. - The [tutorials](tutorials) folder includes various tutorials. diff --git a/docs/TEMPLATES.md b/docs/TEMPLATES.md new file mode 100644 index 0000000..abb971f --- /dev/null +++ b/docs/TEMPLATES.md @@ -0,0 +1,104 @@ +# Composition Templates + +Composer makes it easy to define new composition templates. In essence, a composition template is just a composition with one or more variable arguments. In this document, we discuss key concepts of composition templates and describe a few useful templates. To use any of these templates, simply paste the template code into your composition file. + +## A first example + +The following composition templates invokes composition `composition` and returns the input dictionary augmented with the fields of the output dictionary, overwriting existing fields on name clashes: +```javascript +function merge(composition) { + return composer.seq(composer.retain(composition), ({ params, result }) => Object.assign(params, result)) +} +``` + +To instantiate a composition template, simply apply the Javascript function to concrete arguments as in: +```javascript +merge(({ n }) => ({ nPlusOne: n + 1 })) +``` +For example, invoking this composition on input `{ n: 42 }` outputs `{ n: 42, nPlusOne: 43 }`. + +The `composer` object itself may be extended with the new template using _monkey patching_: +```javascript +composer.merge = composition => composition.seq(composer.retain(composition), ({ params, result }) => Object.assign(params, result)) +``` + +## On the importance of mask + +Many predefined combinators are actually templates over more primitive combinators. For instance the `retain` combinator is essentially defined as follows: +```javascript +function retain(composition) { + return composer.let( + { params: null }, + args => { params = args }, + composer.mask(composition), + result => ({ params, result })) +} +``` + +This implementation first declares a variable named `params` using `composer.let`. It then saves the input dictionary by assigning it to `params`. Next it runs `composition`. It produces the final result by combining the output dictionary (bound to `result`) with the input dictionary (bound to `params`). + +It is important to notice the use of the `mask` combinator here. Since this implementation introduces a variable named `params` and invokes the parameter `composition` in the scope of the `params` variable, this variable declaration may clash with another declaration of `params` in the user code. By wrapping the `composition` invocation with `mask` we ensure that the `params` variable declared in this template is hidden from `composition`. Thanks to `mask`, the following composition correctly writes ```'Hi there!'``` to the standard output: +```javascript +composer.let({ params: 'Hi there!' }, retain(() => { console.log(params) })) +``` + +Because `composer` variables are dynamically scoped, without the `mask` combinator, the action log would show the value of the `params` variable declared in the template instead of the expected value. + +## Pseudo parallel + +The `composer` module does not support parallel execution at this time but we can fake it as follows: +```javascript +composer.par = (f, g) => + composer.let( + { input: null, left: null }, + args => { input = args }, + composer.mask(f), + args => { left = args; return input }, + composer.mask(g), + right => ({ left, right })) +``` +This code pretends to execute compositions `f` and `g` in parallel. They both receive the same input dictionary. The output dictionary for the composition has two fields: `left` carries the result of `f` and `right` carries the result of `g`. In fact the two composition are executed in sequence but `let`, `mask`, and a few Javascript function can flow the data as if running in parallel. + +This implementation does not handle exceptions in `f` or `g`. This is left as an exercise to the reader. + +## Apply + +This `apply` combinator makes it possible to invoke a `composition` on a `field` of the input dictionary, leaving other fields unchanged. +```javascript +// example.js +composer.apply = (field, composition) => + composer.let( + { field }, + composer.retain(p => p[field], composer.mask(composition)), + p => { p.params[field] = p.result; return p.params }) + +composer.apply('payload', p => { p.n++ }) +``` + +``` +compose example.js --deploy example +ok: created action /_/example +``` +``` +wsk action invoke example -r -p payload '{"n":1,"p":42}' +{ + "payload": { + "n": 2, + "p": 42 + } +} +``` + +## Forward + +This `forward` combinator excludes the specified `fields` from the input dictionary for `composition` and restores them afterwards. It is useful for instance to hide secrets from a composition. + +```javascript +composer.forward = (fields, composition) => + composer.let( + { fields }, + composer.retain(p => require('lodash').omit(p, ...fields), composer.mask(composition)), + ({ params, result }) => Object.assign(result, require('lodash').pick(params, ...fields))) + +composer.forward(['user', 'password'], evilComposition) +``` From ce44f49712ed3c0e325271cdc7f0d137c7720720 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 14 May 2018 14:28:12 -0400 Subject: [PATCH 08/94] Tweak --- composer.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.js b/composer.js index bd6b948..4fcf44f 100644 --- a/composer.js +++ b/composer.js @@ -659,10 +659,8 @@ function conductor({ Compiler }) { params = result inspect() }).then(step) - } else { - return { action: json.name, params, state: { $resume: { state, stack } } } // invoke continuation } - break + return { action: json.name, params, state: { $resume: { state, stack } } } // invoke continuation case 'function': return Promise.resolve().then(() => run(json.exec.code)) .catch(error => { From a8c1c9cf5cbeab44b3151890f73e99bab59ba446 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 22 May 2018 12:56:52 -0400 Subject: [PATCH 09/94] Add initial support for composer plugins (#59) * Add support for composer plugins * Permit omitting any component of a plugin --- bin/compose | 12 +- composer.js | 768 ++++++++++++++++++++++++++++------------------------ 2 files changed, 417 insertions(+), 363 deletions(-) diff --git a/bin/compose b/bin/compose index 123a7bd..34d6d6a 100755 --- a/bin/compose +++ b/bin/compose @@ -5,10 +5,10 @@ const fs = require('fs') const vm = require('vm') const minimist = require('minimist') -const composer = require('../composer') +let composer = require('../composer') const argv = minimist(process.argv.slice(2), { - string: ['apihost', 'auth', 'deploy', 'lower', 'entity', 'entities'], + string: ['apihost', 'auth', 'deploy', 'lower', 'entity', 'entities', 'string'], boolean: ['insecure', 'encode', 'json', 'version', 'quiet'], alias: { auth: 'u', insecure: 'i', version: 'v' } }) @@ -40,10 +40,18 @@ if (argv._.length !== 1 || count > 1 || argv.deploy === '' || argv.entity === '' console.error(' -i, --insecure bypass certificate checking') console.error(' -v, --version output the composer version') console.error(' --quiet omit detailed diagnostic messages') + console.error(' --plugin PLUGIN register a composer plugin') process.exit(127) } try { + switch (typeof argv.plugin) { + case 'string': + composer = composer.register(require(argv.plugin)) + break + case 'object': + for (let plugin of argv.plugin) composer = composer.register(require(plugin)) + } const filename = argv._[0] let source try { diff --git a/composer.js b/composer.js index 4fcf44f..c901880 100644 --- a/composer.js +++ b/composer.js @@ -16,13 +16,14 @@ 'use strict' -// compiler code shared between composer and conductor (to permit client-side and server-side lowering) - -function compiler() { +function main() { + const fs = require('fs') const util = require('util') const semver = require('semver') - // standard combinators + const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) + + // default combinators const combinators = { empty: { since: '0.4.0' }, seq: { components: true, since: '0.4.0' }, @@ -48,7 +49,7 @@ function compiler() { function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' } } - // composer error class + // error class class ComposerError extends Error { constructor(message, argument) { super(message + (argument !== undefined ? '\nArgument: ' + util.inspect(argument) : '')) @@ -68,7 +69,7 @@ function compiler() { } // apply f to all fields of type composition - visit(f) { + visit(combinators, f) { const combinator = combinators[this.type] if (combinator.components) { this.components = this.components.map(f) @@ -81,8 +82,11 @@ function compiler() { } } - // compiler class - class Compiler { + // registered plugins + const plugins = [] + + // composer & lowerer + const composer = { // detect task type and create corresponding composition object task(task) { if (arguments.length > 1) throw new ComposerError('Too many arguments') @@ -91,7 +95,7 @@ function compiler() { if (typeof task === 'function') return this.function(task) if (typeof task === 'string') return this.action(task) throw new ComposerError('Invalid argument', task) - } + }, // function combinator: stringify function code function(fun) { @@ -103,27 +107,65 @@ function compiler() { if (typeof fun === 'string') { fun = { kind: 'nodejs:default', code: fun } } - if (typeof fun !== 'object' || fun === null) throw new ComposerError('Invalid argument', fun) + if (!isObject(fun)) throw new ComposerError('Invalid argument', fun) return new Composition({ type: 'function', function: { exec: fun } }) - } + }, + + // enhanced action combinator: mangle name, capture code + action(name, options = {}) { + if (arguments.length > 2) throw new ComposerError('Too many arguments') + if (!isObject(options)) throw new ComposerError('Invalid argument', options) + name = parseActionName(name) // throws ComposerError if name is not valid + let exec + if (Array.isArray(options.sequence)) { // native sequence + exec = { kind: 'sequence', components: options.sequence.map(parseActionName) } + } + if (typeof options.filename === 'string') { // read action code from file + exec = fs.readFileSync(options.filename, { encoding: 'utf8' }) + } + if (typeof options.action === 'function') { // capture function + exec = `const main = ${options.action}` + if (exec.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', options.action) + } + if (typeof options.action === 'string' || isObject(options.action)) { + exec = options.action + } + if (typeof exec === 'string') { + exec = { kind: 'nodejs:default', code: exec } + } + const composition = { type: 'action', name } + if (exec) composition.action = { exec } + if (options.async) composition.async = true + return new Composition(composition) + }, + + // enhanced composition combinator: mangle name + composition(name, composition, options = {}) { + if (arguments.length > 3) throw new ComposerError('Too many arguments') + if (!isObject(options)) throw new ComposerError('Invalid argument', options) + name = parseActionName(name) + const obj = { type: 'composition', name, composition: this.task(composition) } + if (options.async) obj.async = true + return new Composition(obj) + }, // lowering _empty() { return this.sequence() - } + }, _seq(composition) { return this.sequence(...composition.components) - } + }, _value(composition) { return this._literal(composition) - } + }, _literal(composition) { return this.let({ value: composition.value }, () => value) - } + }, _retain(composition) { return this.let( @@ -131,7 +173,7 @@ function compiler() { args => { params = args }, this.mask(...composition.components), result => ({ params, result })) - } + }, _retain_catch(composition) { return this.seq( @@ -140,7 +182,7 @@ function compiler() { this.seq(...composition.components), result => ({ result }))), ({ params, result }) => ({ params, result: result.result })) - } + }, _if(composition) { return this.let( @@ -150,7 +192,7 @@ function compiler() { this.mask(composition.test), this.seq(() => params, this.mask(composition.consequent)), this.seq(() => params, this.mask(composition.alternate)))) - } + }, _while(composition) { return this.let( @@ -160,7 +202,7 @@ function compiler() { this.mask(composition.test), this.seq(() => params, this.mask(composition.body), args => { params = args })), () => params) - } + }, _dowhile(composition) { return this.let( @@ -170,7 +212,7 @@ function compiler() { this.seq(() => params, this.mask(composition.body), args => { params = args }), this.mask(composition.test)), () => params) - } + }, _repeat(composition) { return this.let( @@ -178,7 +220,7 @@ function compiler() { this.while( () => count-- > 0, this.mask(this.seq(...composition.components)))) - } + }, _retry(composition) { return this.let( @@ -188,57 +230,17 @@ function compiler() { this.finally(({ params }) => params, this.mask(this.retain_catch(...composition.components))), ({ result }) => result.error !== undefined && count-- > 0), ({ result }) => result) - } - - // define combinator methods for the standard combinators - static init() { - for (let type in combinators) { - const combinator = combinators[type] - // do not overwrite hand-written combinators - Compiler.prototype[type] = Compiler.prototype[type] || function () { - const composition = new Composition({ type }) - const skip = combinator.args && combinator.args.length || 0 - if (!combinator.components && (arguments.length > skip)) { - throw new ComposerError('Too many arguments') - } - for (let i = 0; i < skip; ++i) { - const arg = combinator.args[i] - const argument = arg.optional ? arguments[i] || null : arguments[i] - switch (arg.type) { - case undefined: - composition[arg._] = this.task(argument) - continue - case 'value': - if (typeof argument === 'function') throw new ComposerError('Invalid argument', argument) - composition[arg._] = argument === undefined ? {} : argument - continue - case 'object': - if (argument === null || Array.isArray(argument)) throw new ComposerError('Invalid argument', argument) - default: - if (typeof argument !== arg.type) throw new ComposerError('Invalid argument', argument) - composition[arg._] = argument - } - } - if (combinator.components) { - composition.components = Array.prototype.slice.call(arguments, skip).map(obj => this.task(obj)) - } - return composition - } - } - } + }, - // return combinator list - get combinators() { - return combinators - } + combinators: {}, // recursively deserialize composition deserialize(composition) { if (arguments.length > 1) throw new ComposerError('Too many arguments') composition = new Composition(composition) // copy - composition.visit(composition => this.deserialize(composition)) + composition.visit(this.combinators, composition => this.deserialize(composition)) return composition - } + }, // label combinators with the json path label(composition) { @@ -249,23 +251,22 @@ function compiler() { composition = new Composition(composition) // copy composition.path = path + (name !== undefined ? (array === undefined ? `.${name}` : `[${name}]`) : '') // label nested combinators - composition.visit(label(composition.path)) + composition.visit(this.combinators, label(composition.path)) return composition } return label('')(composition) - } + }, // recursively label and lower combinators to the desired set of combinators (including primitive combinators) lower(composition, combinators = []) { if (arguments.length > 2) throw new ComposerError('Too many arguments') if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) if (!Array.isArray(combinators) && typeof combinators !== 'boolean' && typeof combinators !== 'string') throw new ComposerError('Invalid argument', combinators) - if (combinators === false) return composition // no lowering if (combinators === true || combinators === '') combinators = [] // maximal lowering if (typeof combinators === 'string') { // lower to combinators of specific composer version - combinators = Object.keys(this.combinators).filter(key => semver.gte(combinators, this.combinators[key].since)) + combinators = Object.keys(this.combinators.filter(key => semver.gte(combinators, this.combinators[key].since))) } const lower = composition => { @@ -277,36 +278,22 @@ function compiler() { if (path !== undefined) composition.path = path } // lower nested combinators - composition.visit(lower) + composition.visit(this.combinators, lower) return composition } return lower(composition) - } + }, + + // register plugin + register(plugin) { + if (plugin.combinators) init(plugin.combinators()) + if (plugin.composer) Object.assign(this, plugin.composer({ ComposerError, Composition })) + plugins.push(plugin) + return this + }, } - Compiler.init() - - return { ComposerError, Composition, Compiler } -} - -// composer module - -function composer() { - const fs = require('fs') - const os = require('os') - const path = require('path') - const { minify } = require('uglify-es') - - // read composer version number - const { version } = require('./package.json') - - // initialize compiler - const { ComposerError, Composition, Compiler } = compiler() - - // capture compiler and conductor code (omitting composer code) - const conductorCode = minify(`const main=(${conductor})(${compiler}())`, { output: { max_line_len: 127 }, mangle: { reserved: [Composition.name] } }).code - /** * Parses a (possibly fully qualified) resource name and validates it. If it's not a fully qualified name, * then attempts to qualify it. @@ -321,274 +308,358 @@ function composer() { if (typeof name !== 'string') throw new ComposerError('Name must be a string') if (name.trim().length == 0) throw new ComposerError('Name is not valid') name = name.trim() - let delimiter = '/' - let parts = name.split(delimiter) - let n = parts.length - let leadingSlash = name[0] == delimiter + const delimiter = '/' + const parts = name.split(delimiter) + const n = parts.length + const leadingSlash = name[0] == delimiter // no more than /ns/p/a if (n < 1 || n > 4 || (leadingSlash && n == 2) || (!leadingSlash && n == 4)) throw new ComposerError('Name is not valid') // skip leading slash, all parts must be non empty (could tighten this check to match EntityName regex) parts.forEach(function (part, i) { if (i > 0 && part.trim().length == 0) throw new ComposerError('Name is not valid') }) - let newName = parts.join(delimiter) + const newName = parts.join(delimiter) if (leadingSlash) return newName else if (n < 3) return `${delimiter}_${delimiter}${newName}` else return `${delimiter}${newName}` } - // management class for compositions - class Compositions { - constructor(wsk, composer) { - this.actions = wsk.actions - this.composer = composer - } - - deploy(composition, combinators) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (composition.type !== 'composition') throw new ComposerError('Cannot deploy anonymous composition') - const obj = this.composer.encode(composition, combinators) - return obj.actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) - .then(() => this.actions.update(action)), Promise.resolve()) - .then(() => obj) - } - } - - // enhanced client-side compiler - class Composer extends Compiler { - // enhanced action combinator: mangle name, capture code - action(name, options = {}) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (typeof options !== 'object') throw new ComposerError('Invalid argument', options) - name = parseActionName(name) // throws ComposerError if name is not valid - let exec - if (Array.isArray(options.sequence)) { // native sequence - exec = { kind: 'sequence', components: options.sequence.map(parseActionName) } - } - if (typeof options.filename === 'string') { // read action code from file - exec = fs.readFileSync(options.filename, { encoding: 'utf8' }) - } - if (typeof options.action === 'function') { // capture function - exec = `const main = ${options.action}` - if (exec.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', options.action) - } - if (typeof options.action === 'string' || typeof options.action === 'object' && options.action !== null && !Array.isArray(options.action)) { - exec = options.action - } - if (typeof exec === 'string') { - exec = { kind: 'nodejs:default', code: exec } - } - const composition = { type: 'action', name } - if (exec) composition.action = { exec } - if (options.async) composition.async = true - return new Composition(composition) - } - - // enhanced composition combinator: mangle name - composition(name, composition, options = {}) { - if (arguments.length > 3) throw new ComposerError('Too many arguments') - if (typeof options !== 'object') throw new ComposerError('Invalid argument', options) - name = parseActionName(name) - const obj = { type: 'composition', name, composition: this.task(composition) } - if (options.async) obj.async = true - return new Composition(obj) - } - - // return enhanced openwhisk client capable of deploying compositions - openwhisk(options) { - // try to extract apihost and key first from whisk property file file and then from process.env - let apihost - let api_key - - try { - const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') - const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') - - for (let line of lines) { - let parts = line.trim().split('=') - if (parts.length === 2) { - if (parts[0] === 'APIHOST') { - apihost = parts[1] - } else if (parts[0] === 'AUTH') { - api_key = parts[1] - } - } + // derive combinator methods from combinator table + function init(combinators) { + Object.assign(composer.combinators, combinators) + for (let type in combinators) { + const combinator = combinators[type] + // do not overwrite existing combinators + composer[type] = composer[type] || function () { + const composition = new Composition({ type }) + const skip = combinator.args && combinator.args.length || 0 + if (!combinator.components && (arguments.length > skip)) { + throw new ComposerError('Too many arguments') } - } catch (error) { } - - if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST - if (process.env.__OW_API_KEY) api_key = process.env.__OW_API_KEY - - const wsk = require('openwhisk')(Object.assign({ apihost, api_key }, options)) - wsk.compositions = new Compositions(wsk, this) - return wsk - } - - // recursively encode composition into { composition, actions } by encoding nested compositions into actions and extracting nested action definitions - encode(composition, combinators = []) { // lower non-primitive combinators by default - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - - composition = this.lower(composition, combinators) - - const actions = [] - - const encode = composition => { - composition = new Composition(composition) // copy - composition.visit(encode) - if (composition.type === 'composition') { - const code = `// generated by composer v${version}\n\nconst composition = ${JSON.stringify(encode(composition.composition), null, 4)}\n\n// do not edit below this point\n\n${conductorCode}` // invoke conductor on composition - composition.action = { exec: { kind: 'nodejs:default', code }, annotations: [{ key: 'conductor', value: composition.composition }, { key: 'composer', value: version }] } - delete composition.composition - composition.type = 'action' + for (let i = 0; i < skip; ++i) { + const arg = combinator.args[i] + const argument = arg.optional ? arguments[i] || null : arguments[i] + switch (arg.type) { + case undefined: + composition[arg._] = composer.task(argument) + continue + case 'value': + if (typeof argument === 'function') throw new ComposerError('Invalid argument', argument) + composition[arg._] = argument === undefined ? {} : argument + continue + case 'object': + if (!isObject(argument)) throw new ComposerError('Invalid argument', argument) + default: + if (typeof argument !== arg.type) throw new ComposerError('Invalid argument', argument) + composition[arg._] = argument + } } - if (composition.type === 'action' && composition.action) { - actions.push({ name: composition.name, action: composition.action }) - delete composition.action + if (combinator.components) { + composition.components = Array.prototype.slice.call(arguments, skip).map(obj => composer.task(obj)) } return composition } - - composition = encode(composition) - return { composition, actions } - } - - get version() { - return version } } - return new Composer() -} + init(combinators) -module.exports = composer() + // client-side stuff + function client() { + const os = require('os') + const path = require('path') + const minify = require('uglify-es').minify -// conductor action + // read composer version number + const version = require('./package.json').version -function conductor({ Compiler }) { - const compiler = new Compiler() + // management class for compositions + class Compositions { + constructor(wsk, composer) { + this.actions = wsk.actions + this.composer = composer + } - this.require = require - const openwhisk = require('openwhisk') - let wsk + deploy(composition, combinators) { + if (arguments.length > 2) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + if (composition.type !== 'composition') throw new ComposerError('Cannot deploy anonymous composition') + const obj = this.composer.encode(composition, combinators) + return obj.actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) + .then(() => this.actions.update(action)), Promise.resolve()) + .then(() => obj) + } + } - function chain(front, back) { - front.slice(-1)[0].next = 1 - front.push(...back) - return front - } + // client-side only methods + Object.assign(composer, { + // return enhanced openwhisk client capable of deploying compositions + openwhisk(options) { + // try to extract apihost and key first from whisk property file file and then from process.env + let apihost + let api_key + + try { + const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') + const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') + + for (let line of lines) { + let parts = line.trim().split('=') + if (parts.length === 2) { + if (parts[0] === 'APIHOST') { + apihost = parts[1] + } else if (parts[0] === 'AUTH') { + api_key = parts[1] + } + } + } + } catch (error) { } + + if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST + if (process.env.__OW_API_KEY) api_key = process.env.__OW_API_KEY + + const wsk = require('openwhisk')(Object.assign({ apihost, api_key }, options)) + wsk.compositions = new Compositions(wsk, this) + return wsk + }, + + // recursively encode composition into { composition, actions } by encoding nested compositions into actions and extracting nested action definitions + encode(composition, combinators = []) { // lower non-primitive combinators by default + if (arguments.length > 2) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + + composition = this.lower(composition, combinators) + + const actions = [] + + const encode = composition => { + composition = new Composition(composition) // copy + composition.visit(this.combinators, encode) + if (composition.type === 'composition') { + let code = `const main=(${main})().server(` + for (let plugin of plugins) { + code += `{plugin:new(${plugin.constructor})()` + if (plugin.configure) code += `,config:${JSON.stringify(plugin.configure())}` + code += '},' + } + code = minify(`${code})`, { output: { max_line_len: 127 } }).code + code = `// generated by composer v${version}\n\nconst composition = ${JSON.stringify(encode(composition.composition), null, 4)}\n\n// do not edit below this point\n\n${code}` // invoke conductor on composition + composition.action = { exec: { kind: 'nodejs:default', code }, annotations: [{ key: 'conductor', value: composition.composition }, { key: 'composer', value: version }] } + delete composition.composition + composition.type = 'action' + } + if (composition.type === 'action' && composition.action) { + actions.push({ name: composition.name, action: composition.action }) + delete composition.action + } + return composition + } + + composition = encode(composition) + return { composition, actions } + }, + + // return composer version + get version() { + return version + } + }) - function sequence(components) { - if (components.length === 0) return [{ type: 'empty' }] - return components.map(compile).reduce(chain) + return composer } - function compile(json) { - const path = json.path - switch (json.type) { - case 'sequence': - return chain([{ type: 'pass', path }], sequence(json.components)) - case 'action': - return [{ type: 'action', name: json.name, async: json.async, path }] - case 'function': - return [{ type: 'function', exec: json.function.exec, path }] - case 'finally': - var body = compile(json.body) - const finalizer = compile(json.finalizer) - var fsm = [[{ type: 'try', path }], body, [{ type: 'exit' }], finalizer].reduce(chain) + // server-side stuff + function server() { + function chain(front, back) { + front.slice(-1)[0].next = 1 + front.push(...back) + return front + } + + const compiler = { + compile(node) { + if (arguments.length === 0) return [{ type: 'empty' }] + if (arguments.length === 1) return this[node.type](node) + return Array.prototype.map.call(arguments, node => this.compile(node)).reduce(chain) + }, + + sequence(node) { + return chain([{ type: 'pass', path: node.path }], this.compile(...node.components)) + }, + + action(node) { + return [{ type: 'action', name: node.name, async: node.async, path: node.path }] + }, + + function(node) { + return [{ type: 'function', exec: node.function.exec, path: node.path }] + }, + + finally(node) { + var body = this.compile(node.body) + const finalizer = this.compile(node.finalizer) + var fsm = [[{ type: 'try', path: node.path }], body, [{ type: 'exit' }], finalizer].reduce(chain) fsm[0].catch = fsm.length - finalizer.length return fsm - case 'let': - var body = sequence(json.components) - return [[{ type: 'let', let: json.declarations, path }], body, [{ type: 'exit' }]].reduce(chain) - case 'mask': - var body = sequence(json.components) - return [[{ type: 'let', let: null, path }], body, [{ type: 'exit' }]].reduce(chain) - case 'try': - var body = compile(json.body) - const handler = chain(compile(json.handler), [{ type: 'pass' }]) - var fsm = [[{ type: 'try', path }], body, [{ type: 'exit' }]].reduce(chain) + }, + + let(node) { + var body = this.compile(...node.components) + return [[{ type: 'let', let: node.declarations, path: node.path }], body, [{ type: 'exit' }]].reduce(chain) + }, + + mask(node) { + var body = this.compile(...node.components) + return [[{ type: 'let', let: null, path: node.path }], body, [{ type: 'exit' }]].reduce(chain) + }, + + try(node) { + var body = this.compile(node.body) + const handler = chain(this.compile(node.handler), [{ type: 'pass' }]) + var fsm = [[{ type: 'try', path: node.path }], body, [{ type: 'exit' }]].reduce(chain) fsm[0].catch = fsm.length fsm.slice(-1)[0].next = handler.length fsm.push(...handler) return fsm - case 'if_nosave': - var consequent = compile(json.consequent) - var alternate = chain(compile(json.alternate), [{ type: 'pass' }]) - var fsm = [[{ type: 'pass', path }], compile(json.test), [{ type: 'choice', then: 1, else: consequent.length + 1 }]].reduce(chain) + }, + + if_nosave(node) { + var consequent = this.compile(node.consequent) + var alternate = chain(this.compile(node.alternate), [{ type: 'pass' }]) + var fsm = [[{ type: 'pass', path: node.path }], this.compile(node.test), [{ type: 'choice', then: 1, else: consequent.length + 1 }]].reduce(chain) consequent.slice(-1)[0].next = alternate.length fsm.push(...consequent) fsm.push(...alternate) return fsm - case 'while_nosave': - var consequent = compile(json.body) + }, + + while_nosave(node) { + var consequent = this.compile(node.body) var alternate = [{ type: 'pass' }] - var fsm = [[{ type: 'pass', path }], compile(json.test), [{ type: 'choice', then: 1, else: consequent.length + 1 }]].reduce(chain) + var fsm = [[{ type: 'pass', path: node.path }], this.compile(node.test), [{ type: 'choice', then: 1, else: consequent.length + 1 }]].reduce(chain) consequent.slice(-1)[0].next = 1 - fsm.length - consequent.length fsm.push(...consequent) fsm.push(...alternate) return fsm - case 'dowhile_nosave': - var test = compile(json.test) - var fsm = [[{ type: 'pass', path }], compile(json.body), test, [{ type: 'choice', then: 1, else: 2 }]].reduce(chain) + }, + + dowhile_nosave(node) { + var test = this.compile(node.test) + var fsm = [[{ type: 'pass', path: node.path }], this.compile(node.body), test, [{ type: 'choice', then: 1, else: 2 }]].reduce(chain) fsm.slice(-1)[0].then = 1 - fsm.length fsm.slice(-1)[0].else = 1 var alternate = [{ type: 'pass' }] fsm.push(...alternate) return fsm + }, } - } - const fsm = compile(compiler.lower(compiler.label(compiler.deserialize(composition)))) + const openwhisk = require('openwhisk') + let wsk - const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) + const conductor = { + choice({ p, node, index }) { + p.s.state = index + (p.params.value ? node.then : node.else) + }, + + try({ p, node, index }) { + p.s.stack.unshift({ catch: index + node.catch }) + }, + + let({ p, node, index }) { + p.s.stack.unshift({ let: JSON.parse(JSON.stringify(node.let)) }) + }, - // encode error object - const encodeError = error => ({ - code: typeof error.code === 'number' && error.code || 500, - error: (typeof error.error === 'string' && error.error) || error.message || (typeof error === 'string' && error) || 'An internal error occurred' - }) - - // error status codes - const badRequest = error => Promise.reject({ code: 400, error }) - const internalError = error => Promise.reject(encodeError(error)) - - return params => Promise.resolve().then(() => invoke(params)).catch(internalError) - - // do invocation - function invoke(params) { - // initial state and stack - let state = 0 - let stack = [] - - // restore state and stack when resuming - if (params.$resume !== undefined) { - if (!isObject(params.$resume)) return badRequest('The type of optional $resume parameter must be object') - state = params.$resume.state - stack = params.$resume.stack - if (state !== undefined && typeof state !== 'number') return badRequest('The type of optional $resume.state parameter must be number') - if (!Array.isArray(stack)) return badRequest('The type of $resume.stack must be an array') - delete params.$resume - inspect() // handle error objects when resuming + exit({ p, node, index }) { + if (p.s.stack.length === 0) return internalError(`State ${index} attempted to pop from an empty stack`) + p.s.stack.shift() + }, + + action({ p, node, index }) { + if (node.async) { + if (!wsk) wsk = openwhisk({ ignore_certs: true }) + return wsk.actions.invoke({ name: node.name, params: p.params }) + .catch(error => { + console.error(error) + return { error: `An exception was caught at state ${index} (see log for details)` } + }) + .then(result => { + p.params = result + inspect(p) + return step(p) + }) + } + return { action: node.name, params: p.params, state: { $resume: p.s } } + }, + + function({ p, node, index }) { + return Promise.resolve().then(() => run(node.exec.code, p)) + .catch(error => { + console.error(error) + return { error: `An exception was caught at state ${index} (see log for details)` } + }) + .then(result => { + if (typeof result === 'function') result = { error: `State ${index} evaluated to a function` } + // if a function has only side effects and no return value, return params + p.params = JSON.parse(JSON.stringify(result === undefined ? p.params : result)) + inspect(p) + return step(p) + }) + }, + + empty({ p, node, index }) { + inspect(p) + }, + + pass({ p, node, index }) { + }, + } + + const finishers = [] + + for ({ plugin, config } of arguments) { + composer.register(plugin) + if (plugin.compiler) Object.assign(compiler, plugin.compiler()) + if (plugin.conductor) { + const r = plugin.conductor(config) + if (r._finish) { + finishers.push(r._finish) + delete r._finish + } + Object.assign(conductor, r) + } } + const fsm = compiler.compile(composer.lower(composer.label(composer.deserialize(composition)))) + + // encode error object + const encodeError = error => ({ + code: typeof error.code === 'number' && error.code || 500, + error: (typeof error.error === 'string' && error.error) || error.message || (typeof error === 'string' && error) || 'An internal error occurred' + }) + + // error status codes + const badRequest = error => Promise.reject({ code: 400, error }) + const internalError = error => Promise.reject(encodeError(error)) + // wrap params if not a dictionary, branch to error handler if error - function inspect() { - if (!isObject(params)) params = { value: params } - if (params.error !== undefined) { - params = { error: params.error } // discard all fields but the error field - state = undefined // abort unless there is a handler in the stack - while (stack.length > 0) { - if (typeof (state = stack.shift().catch) === 'number') break + function inspect(p) { + if (!isObject(p.params)) p.params = { value: p.params } + if (p.params.error !== undefined) { + p.params = { error: p.params.error } // discard all fields but the error field + p.s.state = undefined // abort unless there is a handler in the stack + while (p.s.stack.length > 0) { + if (typeof (p.s.state = p.s.stack.shift().catch) === 'number') break } } } // run function f on current stack - function run(f) { + function run(f, p) { + this.require = require + // handle let/mask pairs const view = [] let n = 0 - for (let frame of stack) { + for (let frame of p.s.stack) { if (frame.let === null) { n++ } else if (frame.let !== undefined) { @@ -607,83 +678,58 @@ function conductor({ Compiler }) { } // collapse stack for invocation - const env = view.reduceRight((acc, cur) => typeof cur.let === 'object' ? Object.assign(acc, cur.let) : acc, {}) + const env = view.reduceRight((acc, cur) => cur.let ? Object.assign(acc, cur.let) : acc, {}) let main = '(function(){try{' for (const name in env) main += `var ${name}=arguments[1]['${name}'];` main += `return eval((${f}))(arguments[0])}finally{` for (const name in env) main += `arguments[1]['${name}']=${name};` main += '}})' try { - return (1, eval)(main)(params, env) + return (1, eval)(main)(p.params, env) } finally { for (const name in env) set(name, env[name]) } } - function step() { + function step(p) { // final state, return composition result - if (state === undefined) { + if (p.s.state === undefined) { console.log(`Entering final state`) - console.log(JSON.stringify(params)) - if (params.error) return params; else return { params } + console.log(JSON.stringify(p.params)) + return finishers.reduce((promise, _finish) => promise.then(() => _finish(p)), Promise.resolve()) + .then(() => p.params.error ? p.params : { params: p.params }) } // process one state - const json = fsm[state] // json definition for current state - if (json.path !== undefined) console.log(`Entering composition${json.path}`) - const current = state - state = json.next === undefined ? undefined : current + json.next // default next state - switch (json.type) { - case 'choice': - state = current + (params.value ? json.then : json.else) - break - case 'try': - stack.unshift({ catch: current + json.catch }) - break - case 'let': - stack.unshift({ let: JSON.parse(JSON.stringify(json.let)) }) - break - case 'exit': - if (stack.length === 0) return internalError(`State ${current} attempted to pop from an empty stack`) - stack.shift() - break - case 'action': - if (json.async) { - if (!wsk) wsk = openwhisk({ ignore_certs: true }) - return wsk.actions.invoke({ name: json.name, params }) - .catch(error => { - console.error(error) - return { error: `An exception was caught at state ${current} (see log for details)` } - }) - .then(result => { - params = result - inspect() - }).then(step) - } - return { action: json.name, params, state: { $resume: { state, stack } } } // invoke continuation - case 'function': - return Promise.resolve().then(() => run(json.exec.code)) - .catch(error => { - console.error(error) - return { error: `An exception was caught at state ${current} (see log for details)` } - }) - .then(result => { - if (typeof result === 'function') result = { error: `State ${current} evaluated to a function` } - // if a function has only side effects and no return value, return params - params = JSON.parse(JSON.stringify(result === undefined ? params : result)) - inspect() - }).then(step) - case 'empty': - inspect() - break - case 'pass': - break - default: - return internalError(`State ${current} has an unknown type`) + const node = fsm[p.s.state] // json definition for index state + if (node.path !== undefined) console.log(`Entering composition${node.path}`) + const index = p.s.state // save current state for logging purposes + p.s.state = node.next === undefined ? undefined : p.s.state + node.next // default next state + return conductor[node.type]({ p, index, node, inspect, step }) || step(p) + } + + return params => Promise.resolve().then(() => invoke(params)).catch(internalError) + + // do invocation + function invoke(params) { + const p = { s: { state: 0, stack: [] }, params } // initial state + + if (params.$resume !== undefined) { + if (!isObject(params.$resume)) return badRequest('The type of optional $resume parameter must be object') + const resuming = params.$resume.stack + Object.assign(p.s, params.$resume) + if (resuming) p.s.state = params.$resume.state // undef + if (p.s.state !== undefined && typeof p.s.state !== 'number') return badRequest('The type of optional $resume.state parameter must be number') + if (!Array.isArray(p.s.stack)) return badRequest('The type of $resume.stack must be an array') + delete params.$resume + if (resuming) inspect(p) // handle error objects when resuming } - return step() - } - return step() + return step(p) + } } + + return { client, server } } + +module.exports = main().client() From c93e6231e11da763054c9990cadb44f9cc9598ed Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 22 May 2018 13:04:15 -0400 Subject: [PATCH 10/94] Bump mocha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f96bd70..1a6a241 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "uglify-es": "^3.3.9" }, "devDependencies": { - "mocha": "^3.5.0" + "mocha": "^5.2.0" }, "author": { "name": "Olivier Tardieu", From a959e9a43568ade874d956d28e799adf816ec02a Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 22 May 2018 14:57:51 -0400 Subject: [PATCH 11/94] 0.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a6a241..1ed9dab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.4.0", + "version": "0.5.0", "description": "Composer is an IBM Cloud Functions programming model for composing individual functions into larger applications.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From 1f8e11945e0dbe5b886c2b48b0647a083995616f Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 22 May 2018 16:05:58 -0400 Subject: [PATCH 12/94] Fix parsing of optional combinator arguments --- composer.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/composer.js b/composer.js index c901880..23db8f9 100644 --- a/composer.js +++ b/composer.js @@ -336,17 +336,18 @@ function main() { } for (let i = 0; i < skip; ++i) { const arg = combinator.args[i] - const argument = arg.optional ? arguments[i] || null : arguments[i] + const argument = arguments[i] + if (argument === undefined && arg.optional && arg.type !== undefined) continue switch (arg.type) { case undefined: - composition[arg._] = composer.task(argument) + composition[arg._] = this.task(arg.optional ? argument || null : argument) continue case 'value': if (typeof argument === 'function') throw new ComposerError('Invalid argument', argument) composition[arg._] = argument === undefined ? {} : argument continue case 'object': - if (!isObject(argument)) throw new ComposerError('Invalid argument', argument) + if (argument === null || Array.isArray(argument)) throw new ComposerError('Invalid argument', argument) default: if (typeof argument !== arg.type) throw new ComposerError('Invalid argument', argument) composition[arg._] = argument From 2911b1ef010395750230fbd5f8953ff30dc4fe1b Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 22 May 2018 16:19:31 -0400 Subject: [PATCH 13/94] 0.5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ed9dab..8222d62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.5.0", + "version": "0.5.1", "description": "Composer is an IBM Cloud Functions programming model for composing individual functions into larger applications.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From 4129be7b8f660425025c91cb00855763bf803deb Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 22 May 2018 16:30:08 -0400 Subject: [PATCH 14/94] Lowering fix --- composer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.js b/composer.js index 23db8f9..ec017a3 100644 --- a/composer.js +++ b/composer.js @@ -266,7 +266,7 @@ function main() { if (combinators === false) return composition // no lowering if (combinators === true || combinators === '') combinators = [] // maximal lowering if (typeof combinators === 'string') { // lower to combinators of specific composer version - combinators = Object.keys(this.combinators.filter(key => semver.gte(combinators, this.combinators[key].since))) + combinators = Object.keys(this.combinators).filter(key => semver.gte(combinators, this.combinators[key].since)) } const lower = composition => { From c9ce451774ce9045bfda9eddd543bb74aa835fbe Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 22 May 2018 16:32:04 -0400 Subject: [PATCH 15/94] 0.5.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8222d62..23c6a96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.5.1", + "version": "0.5.2", "description": "Composer is an IBM Cloud Functions programming model for composing individual functions into larger applications.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From a79f6af467d7f11c04aeda1b23c763c1adc89cb0 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 23 May 2018 10:01:59 -0400 Subject: [PATCH 16/94] Add new templates --- docs/TEMPLATES.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/TEMPLATES.md b/docs/TEMPLATES.md index abb971f..b6df123 100644 --- a/docs/TEMPLATES.md +++ b/docs/TEMPLATES.md @@ -88,6 +88,7 @@ wsk action invoke example -r -p payload '{"n":1,"p":42}' } } ``` +In this example, the `let` combinator is used to capture the desired field name: it binds the `field` variable to the field name. ## Forward @@ -100,5 +101,15 @@ composer.forward = (fields, composition) => composer.retain(p => require('lodash').omit(p, ...fields), composer.mask(composition)), ({ params, result }) => Object.assign(result, require('lodash').pick(params, ...fields))) -composer.forward(['user', 'password'], evilComposition) +composer.forward(['user', 'password'], untrustedComposition) +``` + +## Inject and extract + +The following combinators make it possible to bind a field of the parameter object to the value of the homonymous variable and vice versa. +```javascript +composer.inject = v => composer.seq(composer.let({ v }, params => { params[v] = eval(v) })) +composer.extract = v => composer.seq(composer.let({ v }, params => { eval(`${v} = params[v]`); delete params[v] })) + +composer.let({ token: null }, 'getSecretToken', composer.extract('token'), untrustedAction, composer.inject('token'), trustedAction) ``` From 18ef33aa4efcc61f6717814f6b4a178002cc0dca Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 23 May 2018 10:41:58 -0400 Subject: [PATCH 17/94] Add type for named compositions --- composer.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/composer.js b/composer.js index ec017a3..6604d73 100644 --- a/composer.js +++ b/composer.js @@ -46,7 +46,7 @@ function main() { retry: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, value: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, literal: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, - function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' } + function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' }, } // error class @@ -341,6 +341,7 @@ function main() { switch (arg.type) { case undefined: composition[arg._] = this.task(arg.optional ? argument || null : argument) + if (arg.named && composition[arg._].name === undefined) throw new ComposerError('Invalid argument', argument) continue case 'value': if (typeof argument === 'function') throw new ComposerError('Invalid argument', argument) @@ -354,7 +355,11 @@ function main() { } } if (combinator.components) { - composition.components = Array.prototype.slice.call(arguments, skip).map(obj => composer.task(obj)) + composition.components = Array.prototype.slice.call(arguments, skip).map(obj => { + const task = composer.task(obj) + if (combinator.components.named && task.name === undefined) throw new ComposerError('Invalid argument', obj) + return task + }) } return composition } @@ -382,7 +387,7 @@ function main() { deploy(composition, combinators) { if (arguments.length > 2) throw new ComposerError('Too many arguments') if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (composition.type !== 'composition') throw new ComposerError('Cannot deploy anonymous composition') + if (composition.name === undefined) throw new ComposerError('Cannot deploy anonymous entity') const obj = this.composer.encode(composition, combinators) return obj.actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) .then(() => this.actions.update(action)), Promise.resolve()) From 8fd1925331f8faa5bc17830cac0109e7ea6f3a24 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 19 Jun 2018 13:20:38 -0400 Subject: [PATCH 18/94] v0.6 dev branch (#60) - composition files must now be modules (include require and exports statements) - add composer.async combinator - remove composer.composition combinator - bug fixes --- README.md | 14 +- bin/compose | 43 +-- composer.js | 721 +++++++++++++++++++++---------------------- docs/COMBINATORS.md | 26 +- docs/COMPOSE.md | 14 +- docs/COMPOSER.md | 62 ++-- docs/COMPOSITIONS.md | 19 +- docs/FORMAT.md | 6 +- samples/demo.js | 4 +- samples/node-demo.js | 4 +- test/test.js | 47 +-- 11 files changed, 438 insertions(+), 522 deletions(-) diff --git a/README.md b/README.md index e2b66cf..7ca67d1 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,14 @@ compositions should continue to run fine without redeployment. Composer is distributed as Node.js package. To install this package, use the Node Package Manager: ``` +npm install @ibm-functions/composer +``` +We recommend to also install the package globally (with `-g` option) if you intend to +use the `compose` command to define and deploy compositions. +``` npm -g install @ibm-functions/composer ``` -We recommend to install the package globally (with `-g` option) if you intend to -use the `compose` command to define and deploy compositions. Use a local install -(without `-g` option) if you intend to use `node` instead. The two installations -can coexist. Shell embeds the Composer package, so there is no need to install +Shell embeds the Composer package, so there is no need to install Composer explicitly when using Shell. ## Defining a composition @@ -59,7 +61,9 @@ Composer explicitly when using Shell. A composition is typically defined by means of a Javascript expression as illustrated in [samples/demo.js](samples/demo.js): ```javascript -composer.if( +const composer = require('@ibm-functions/composer') + +module.exports = composer.if( composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), composer.action('success', { action: function () { return { message: 'success' } } }), composer.action('failure', { action: function () { return { message: 'failure' } } })) diff --git a/bin/compose b/bin/compose index 34d6d6a..b2b5246 100755 --- a/bin/compose +++ b/bin/compose @@ -2,19 +2,18 @@ 'use strict' -const fs = require('fs') -const vm = require('vm') const minimist = require('minimist') -let composer = require('../composer') +const path = require('path') const argv = minimist(process.argv.slice(2), { - string: ['apihost', 'auth', 'deploy', 'lower', 'entity', 'entities', 'string'], + string: ['apihost', 'auth', 'deploy', 'lower', 'entity', 'entities', 'composer'], boolean: ['insecure', 'encode', 'json', 'version', 'quiet'], alias: { auth: 'u', insecure: 'i', version: 'v' } }) +const { util } = require(argv.composer || '../composer') if (argv.version) { - console.log(composer.version) + console.log(util.version) return } @@ -40,31 +39,17 @@ if (argv._.length !== 1 || count > 1 || argv.deploy === '' || argv.entity === '' console.error(' -i, --insecure bypass certificate checking') console.error(' -v, --version output the composer version') console.error(' --quiet omit detailed diagnostic messages') - console.error(' --plugin PLUGIN register a composer plugin') + console.error(' --composer COMPOSER instantiate a custom composer module') process.exit(127) } try { - switch (typeof argv.plugin) { - case 'string': - composer = composer.register(require(argv.plugin)) - break - case 'object': - for (let plugin of argv.plugin) composer = composer.register(require(plugin)) - } const filename = argv._[0] - let source - try { - source = fs.readFileSync(filename, { encoding: 'utf8' }) - } catch (error) { - console.error('File not found') - if (!argv.quiet) console.log(error) - process.exit(6) - } let composition try { - composition = filename.slice(filename.lastIndexOf('.')) === '.js' ? vm.runInNewContext(source, { composer, require, console, process }) : composer.deserialize(JSON.parse(source)) - if (typeof argv.lower === 'string') composition = composer.lower(composition, argv.lower) + composition = require(path.resolve(filename)) + if (filename.slice(filename.lastIndexOf('.')) === '.json') composition = util.deserialize(composition) + if (typeof argv.lower === 'string') composition = util.lower(composition, argv.lower || []) } catch (error) { console.error('Bad composition') if (!argv.quiet) console.log(error) @@ -75,9 +60,9 @@ try { if (argv.apihost) options.apihost = argv.apihost if (argv.auth) options.api_key = argv.auth return Promise.resolve() - .then(() => composer.openwhisk(options).compositions.deploy(composer.composition(argv.deploy, composition), false)) - .then(obj => { - const names = obj.actions.map(action => action.name) + .then(() => util.openwhisk(options).compositions.deploy(argv.deploy, composition)) + .then(actions => { + const names = actions.map(action => action.name) console.log(`ok: created action${names.length > 1 ? 's' : ''} ${names}`) }) .catch(error => { @@ -98,11 +83,11 @@ try { process.exit(5) }) } else if (argv.encode) { - console.log(composer.encode(composer.composition('anonymous', composition), false).actions.slice(-1)[0].action.exec.code) + console.log(util.encode('noname', composition).slice(-1)[0].action.exec.code) } else if (argv.entity) { - console.log(JSON.stringify(composer.encode(composer.composition(argv.entity, composition), false).actions.slice(-1)[0], null, 4)) + console.log(JSON.stringify(util.encode(argv.entity, composition).slice(-1)[0], null, 4)) } else if (argv.entities) { - console.log(JSON.stringify(composer.encode(composer.composition(argv.entities, composition), false).actions, null, 4)) + console.log(JSON.stringify(util.encode(argv.entities, composition), null, 4)) } else { console.log(JSON.stringify(composition, null, 4)) } diff --git a/composer.js b/composer.js index 6604d73..2dcdca3 100644 --- a/composer.js +++ b/composer.js @@ -14,40 +14,22 @@ * limitations under the License. */ -'use strict' - function main() { + 'use strict' + const fs = require('fs') - const util = require('util') + const os = require('os') + const path = require('path') const semver = require('semver') + const util = require('util') + + // read composer version number + const version = require('./package.json').version const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) - // default combinators - const combinators = { - empty: { since: '0.4.0' }, - seq: { components: true, since: '0.4.0' }, - sequence: { components: true, since: '0.4.0' }, - if: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, - if_nosave: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, - while: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, - while_nosave: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, - dowhile: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, - dowhile_nosave: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, - try: { args: [{ _: 'body' }, { _: 'handler' }], since: '0.4.0' }, - finally: { args: [{ _: 'body' }, { _: 'finalizer' }], since: '0.4.0' }, - retain: { components: true, since: '0.4.0' }, - retain_catch: { components: true, since: '0.4.0' }, - let: { args: [{ _: 'declarations', type: 'object' }], components: true, since: '0.4.0' }, - mask: { components: true, since: '0.4.0' }, - action: { args: [{ _: 'name', type: 'string' }, { _: 'options', type: 'object', optional: true }], since: '0.4.0' }, - composition: { args: [{ _: 'name', type: 'string' }, { _: 'composition' }, { _: 'options', type: 'object', optional: true }], since: '0.4.0' }, - repeat: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, - retry: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, - value: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, - literal: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, - function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' }, - } + // combinator signatures + const combinators = {} // error class class ComposerError extends Error { @@ -56,44 +38,18 @@ function main() { } } - // composition class - class Composition { - // weaker instanceof to tolerate multiple instances of this class - static [Symbol.hasInstance](instance) { - return instance.constructor && instance.constructor.name === Composition.name - } - - // construct a composition object with the specified fields - constructor(composition) { - return Object.assign(this, composition) - } - - // apply f to all fields of type composition - visit(combinators, f) { - const combinator = combinators[this.type] - if (combinator.components) { - this.components = this.components.map(f) - } - for (let arg of combinator.args || []) { - if (arg.type === undefined) { - this[arg._] = f(this[arg._], arg._) - } - } - } - } - // registered plugins const plugins = [] - // composer & lowerer - const composer = { + const composer = {} + Object.assign(composer, { // detect task type and create corresponding composition object task(task) { if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (task === null) return this.empty() + if (task === null) return composer.empty() if (task instanceof Composition) return task - if (typeof task === 'function') return this.function(task) - if (typeof task === 'string') return this.action(task) + if (typeof task === 'function') return composer.function(task) + if (typeof task === 'string') return composer.action(task) throw new ComposerError('Invalid argument', task) }, @@ -111,23 +67,20 @@ function main() { return new Composition({ type: 'function', function: { exec: fun } }) }, - // enhanced action combinator: mangle name, capture code + // action combinator action(name, options = {}) { if (arguments.length > 2) throw new ComposerError('Too many arguments') if (!isObject(options)) throw new ComposerError('Invalid argument', options) - name = parseActionName(name) // throws ComposerError if name is not valid + name = composer.util.canonical(name) // throws ComposerError if name is not valid let exec if (Array.isArray(options.sequence)) { // native sequence - exec = { kind: 'sequence', components: options.sequence.map(parseActionName) } - } - if (typeof options.filename === 'string') { // read action code from file + exec = { kind: 'sequence', components: options.sequence.map(canonical) } + } else if (typeof options.filename === 'string') { // read action code from file exec = fs.readFileSync(options.filename, { encoding: 'utf8' }) - } - if (typeof options.action === 'function') { // capture function + } else if (typeof options.action === 'function') { // capture function exec = `const main = ${options.action}` if (exec.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', options.action) - } - if (typeof options.action === 'string' || isObject(options.action)) { + } else if (typeof options.action === 'string' || isObject(options.action)) { exec = options.action } if (typeof exec === 'string') { @@ -135,150 +88,166 @@ function main() { } const composition = { type: 'action', name } if (exec) composition.action = { exec } - if (options.async) composition.async = true return new Composition(composition) }, + }) - // enhanced composition combinator: mangle name - composition(name, composition, options = {}) { - if (arguments.length > 3) throw new ComposerError('Too many arguments') - if (!isObject(options)) throw new ComposerError('Invalid argument', options) - name = parseActionName(name) - const obj = { type: 'composition', name, composition: this.task(composition) } - if (options.async) obj.async = true - return new Composition(obj) + const lowerer = { + empty() { + return composer.sequence() }, - // lowering - - _empty() { - return this.sequence() + seq({ components }) { + return composer.sequence(...components) }, - _seq(composition) { - return this.sequence(...composition.components) + value({ value }) { + return composer.literal(value) }, - _value(composition) { - return this._literal(composition) + literal({ value }) { + return composer.let({ value }, composer.function('() => value')) }, - _literal(composition) { - return this.let({ value: composition.value }, () => value) - }, - - _retain(composition) { - return this.let( + retain({ components }) { + return composer.let( { params: null }, - args => { params = args }, - this.mask(...composition.components), - result => ({ params, result })) + composer.finally( + args => { params = args }, + composer.seq(composer.mask(...components), + result => ({ params, result })))) }, - _retain_catch(composition) { - return this.seq( - this.retain( - this.finally( - this.seq(...composition.components), + retain_catch({ components }) { + return composer.seq( + composer.retain( + composer.finally( + composer.seq(...components), result => ({ result }))), ({ params, result }) => ({ params, result: result.result })) }, - _if(composition) { - return this.let( + if({ test, consequent, alternate }) { + return composer.let( { params: null }, - args => { params = args }, - this.if_nosave( - this.mask(composition.test), - this.seq(() => params, this.mask(composition.consequent)), - this.seq(() => params, this.mask(composition.alternate)))) + composer.finally( + args => { params = args }, + composer.if_nosave( + composer.mask(test), + composer.finally(() => params, composer.mask(consequent)), + composer.finally(() => params, composer.mask(alternate))))) }, - _while(composition) { - return this.let( + while({ test, body }) { + return composer.let( { params: null }, - args => { params = args }, - this.while_nosave( - this.mask(composition.test), - this.seq(() => params, this.mask(composition.body), args => { params = args })), - () => params) + composer.finally( + args => { params = args }, + composer.seq(composer.while_nosave( + composer.mask(test), + composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args }))), + () => params))) }, - _dowhile(composition) { - return this.let( + dowhile({ body, test }) { + return composer.let( { params: null }, - args => { params = args }, - this.dowhile_nosave( - this.seq(() => params, this.mask(composition.body), args => { params = args }), - this.mask(composition.test)), - () => params) + composer.finally( + args => { params = args }, + composer.seq(composer.dowhile_nosave( + composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args })), + composer.mask(test)), + () => params))) }, - _repeat(composition) { - return this.let( - { count: composition.count }, - this.while( - () => count-- > 0, - this.mask(this.seq(...composition.components)))) + repeat({ count, components }) { + return composer.let( + { count }, + composer.while( + composer.function('() => count-- > 0'), + composer.mask(...components))) }, - _retry(composition) { - return this.let( - { count: composition.count }, + retry({ count, components }) { + return composer.let( + { count }, params => ({ params }), - this.dowhile( - this.finally(({ params }) => params, this.mask(this.retain_catch(...composition.components))), - ({ result }) => result.error !== undefined && count-- > 0), + composer.dowhile( + composer.finally(({ params }) => params, composer.mask(composer.retain_catch(...components))), + composer.function('({ result }) => result.error !== undefined && count-- > 0')), ({ result }) => result) }, + } - combinators: {}, + // recursively flatten composition into { composition, actions } by extracting embedded action definitions + function flatten(composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - // recursively deserialize composition - deserialize(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') + const actions = [] + + const flatten = composition => { composition = new Composition(composition) // copy - composition.visit(this.combinators, composition => this.deserialize(composition)) + composition.visit(flatten) + if (composition.type === 'action' && composition.action) { + actions.push({ name: composition.name, action: composition.action }) + delete composition.action + } return composition - }, + } - // label combinators with the json path - label(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + composition = flatten(composition) + return { composition, actions } + } - const label = path => (composition, name, array) => { - composition = new Composition(composition) // copy - composition.path = path + (name !== undefined ? (array === undefined ? `.${name}` : `[${name}]`) : '') - // label nested combinators - composition.visit(this.combinators, label(composition.path)) - return composition - } + // synthesize composition code + function synthesize(composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + let code = `const main=(${main})().runtime(` + for (let plugin of plugins) { + code += `{plugin:new(${plugin.constructor})()` + if (plugin.configure) code += `,config:${JSON.stringify(plugin.configure())}` + code += '},' + } + code = require('uglify-es').minify(`${code})`, { output: { max_line_len: 127 } }).code + code = `// generated by composer v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n${code}` // invoke conductor on composition + return { exec: { kind: 'nodejs:default', code }, annotations: [{ key: 'conductor', value: composition }, { key: 'composer', value: version }] } + } - return label('')(composition) + composer.util = { + // return the signatures of the combinators + get combinators() { + return combinators + }, + + // recursively deserialize composition + deserialize(composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + composition = new Composition(composition) // copy + composition.visit(composition => composer.util.deserialize(composition)) + return composition }, - // recursively label and lower combinators to the desired set of combinators (including primitive combinators) + // recursively lower combinators to the desired set of combinators (including primitive combinators) lower(composition, combinators = []) { if (arguments.length > 2) throw new ComposerError('Too many arguments') if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (!Array.isArray(combinators) && typeof combinators !== 'boolean' && typeof combinators !== 'string') throw new ComposerError('Invalid argument', combinators) - if (combinators === false) return composition // no lowering - if (combinators === true || combinators === '') combinators = [] // maximal lowering if (typeof combinators === 'string') { // lower to combinators of specific composer version - combinators = Object.keys(this.combinators).filter(key => semver.gte(combinators, this.combinators[key].since)) + combinators = Object.keys(composer.util.combinators).filter(key => semver.gte(combinators, composer.util.combinators[key].since)) } + if (!Array.isArray(combinators)) throw new ComposerError('Invalid argument', combinators) const lower = composition => { composition = new Composition(composition) // copy // repeatedly lower root combinator - while (combinators.indexOf(composition.type) < 0 && this[`_${composition.type}`]) { + while (combinators.indexOf(composition.type) < 0 && lowerer[composition.type]) { const path = composition.path - composition = this[`_${composition.type}`](composition) - if (path !== undefined) composition.path = path + composition = lowerer[composition.type](composition) + if (path !== undefined) composition.path = path // preserve path } // lower nested combinators - composition.visit(this.combinators, lower) + composition.visit(lower) return composition } @@ -288,43 +257,116 @@ function main() { // register plugin register(plugin) { if (plugin.combinators) init(plugin.combinators()) - if (plugin.composer) Object.assign(this, plugin.composer({ ComposerError, Composition })) + if (plugin.composer) Object.assign(composer, plugin.composer({ composer, ComposerError, Composition })) + if (plugin.lowerer) Object.assign(lowerer, plugin.lowerer({ composer, ComposerError, Composition })) plugins.push(plugin) - return this + return composer + }, + + /** + * Parses a (possibly fully qualified) resource name and validates it. If it's not a fully qualified name, + * then attempts to qualify it. + * + * Examples string to namespace, [package/]action name + * foo => /_/foo + * pkg/foo => /_/pkg/foo + * /ns/foo => /ns/foo + * /ns/pkg/foo => /ns/pkg/foo + */ + canonical(name) { + if (typeof name !== 'string') throw new ComposerError('Name must be a string') + if (name.trim().length == 0) throw new ComposerError('Name is not valid') + name = name.trim() + const delimiter = '/' + const parts = name.split(delimiter) + const n = parts.length + const leadingSlash = name[0] == delimiter + // no more than /ns/p/a + if (n < 1 || n > 4 || (leadingSlash && n == 2) || (!leadingSlash && n == 4)) throw new ComposerError('Name is not valid') + // skip leading slash, all parts must be non empty (could tighten this check to match EntityName regex) + parts.forEach(function (part, i) { if (i > 0 && part.trim().length == 0) throw new ComposerError('Name is not valid') }) + const newName = parts.join(delimiter) + if (leadingSlash) return newName + else if (n < 3) return `${delimiter}_${delimiter}${newName}` + else return `${delimiter}${newName}` + }, + + // encode composition as an action table + encode(name, composition, combinators) { + if (arguments.length > 3) throw new ComposerError('Too many arguments') + name = composer.util.canonical(name) // throws ComposerError if name is not valid + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + if (combinators) composition = composer.util.lower(composition, combinators) + const table = flatten(composition) + table.actions.push({ name, action: synthesize(table.composition) }) + return table.actions + }, + + // return composer version + get version() { + return version + }, + + // return enhanced openwhisk client capable of deploying compositions + openwhisk(options) { + // try to extract apihost and key first from whisk property file file and then from process.env + let apihost + let api_key + + try { + const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') + const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') + + for (let line of lines) { + let parts = line.trim().split('=') + if (parts.length === 2) { + if (parts[0] === 'APIHOST') { + apihost = parts[1] + } else if (parts[0] === 'AUTH') { + api_key = parts[1] + } + } + } + } catch (error) { } + + if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST + if (process.env.__OW_API_KEY) api_key = process.env.__OW_API_KEY + + const wsk = require('openwhisk')(Object.assign({ apihost, api_key }, options)) + wsk.compositions = new Compositions(wsk) + return wsk }, } - /** - * Parses a (possibly fully qualified) resource name and validates it. If it's not a fully qualified name, - * then attempts to qualify it. - * - * Examples string to namespace, [package/]action name - * foo => /_/foo - * pkg/foo => /_/pkg/foo - * /ns/foo => /ns/foo - * /ns/pkg/foo => /ns/pkg/foo - */ - function parseActionName(name) { - if (typeof name !== 'string') throw new ComposerError('Name must be a string') - if (name.trim().length == 0) throw new ComposerError('Name is not valid') - name = name.trim() - const delimiter = '/' - const parts = name.split(delimiter) - const n = parts.length - const leadingSlash = name[0] == delimiter - // no more than /ns/p/a - if (n < 1 || n > 4 || (leadingSlash && n == 2) || (!leadingSlash && n == 4)) throw new ComposerError('Name is not valid') - // skip leading slash, all parts must be non empty (could tighten this check to match EntityName regex) - parts.forEach(function (part, i) { if (i > 0 && part.trim().length == 0) throw new ComposerError('Name is not valid') }) - const newName = parts.join(delimiter) - if (leadingSlash) return newName - else if (n < 3) return `${delimiter}_${delimiter}${newName}` - else return `${delimiter}${newName}` + // composition class + class Composition { + // weaker instanceof to tolerate multiple instances of this class + static [Symbol.hasInstance](instance) { + return instance.constructor && instance.constructor.name === Composition.name + } + + // construct a composition object with the specified fields + constructor(composition) { + return Object.assign(this, composition) + } + + // apply f to all fields of type composition + visit(f) { + const combinator = composer.util.combinators[this.type] + if (combinator.components) { + this.components = this.components.map(f) + } + for (let arg of combinator.args || []) { + if (arg.type === undefined && this[arg._] !== undefined) { + this[arg._] = f(this[arg._], arg._) + } + } + } } // derive combinator methods from combinator table function init(combinators) { - Object.assign(composer.combinators, combinators) + Object.assign(composer.util.combinators, combinators) for (let type in combinators) { const combinator = combinators[type] // do not overwrite existing combinators @@ -340,8 +382,7 @@ function main() { if (argument === undefined && arg.optional && arg.type !== undefined) continue switch (arg.type) { case undefined: - composition[arg._] = this.task(arg.optional ? argument || null : argument) - if (arg.named && composition[arg._].name === undefined) throw new ComposerError('Invalid argument', argument) + composition[arg._] = composer.task(arg.optional ? argument || null : argument) continue case 'value': if (typeof argument === 'function') throw new ComposerError('Invalid argument', argument) @@ -355,144 +396,83 @@ function main() { } } if (combinator.components) { - composition.components = Array.prototype.slice.call(arguments, skip).map(obj => { - const task = composer.task(obj) - if (combinator.components.named && task.name === undefined) throw new ComposerError('Invalid argument', obj) - return task - }) + composition.components = Array.prototype.slice.call(arguments, skip).map(obj => composer.task(obj)) } return composition } } } - init(combinators) - - // client-side stuff - function client() { - const os = require('os') - const path = require('path') - const minify = require('uglify-es').minify - - // read composer version number - const version = require('./package.json').version - - // management class for compositions - class Compositions { - constructor(wsk, composer) { - this.actions = wsk.actions - this.composer = composer - } + init({ + empty: { since: '0.4.0' }, + seq: { components: true, since: '0.4.0' }, + sequence: { components: true, since: '0.4.0' }, + if: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, + if_nosave: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, + while: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, + while_nosave: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, + dowhile: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, + dowhile_nosave: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, + try: { args: [{ _: 'body' }, { _: 'handler' }], since: '0.4.0' }, + finally: { args: [{ _: 'body' }, { _: 'finalizer' }], since: '0.4.0' }, + retain: { components: true, since: '0.4.0' }, + retain_catch: { components: true, since: '0.4.0' }, + let: { args: [{ _: 'declarations', type: 'object' }], components: true, since: '0.4.0' }, + mask: { components: true, since: '0.4.0' }, + action: { args: [{ _: 'name', type: 'string' }, { _: 'action', type: 'object', optional: true }], since: '0.4.0' }, + repeat: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, + retry: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, + value: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, + literal: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, + function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' }, + async: { args: [{ _: 'body' }], since: '0.6.0' }, + }) - deploy(composition, combinators) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (composition.name === undefined) throw new ComposerError('Cannot deploy anonymous entity') - const obj = this.composer.encode(composition, combinators) - return obj.actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) - .then(() => this.actions.update(action)), Promise.resolve()) - .then(() => obj) - } + // management class for compositions + class Compositions { + constructor(wsk) { + this.actions = wsk.actions } - // client-side only methods - Object.assign(composer, { - // return enhanced openwhisk client capable of deploying compositions - openwhisk(options) { - // try to extract apihost and key first from whisk property file file and then from process.env - let apihost - let api_key - - try { - const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') - const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') - - for (let line of lines) { - let parts = line.trim().split('=') - if (parts.length === 2) { - if (parts[0] === 'APIHOST') { - apihost = parts[1] - } else if (parts[0] === 'AUTH') { - api_key = parts[1] - } - } - } - } catch (error) { } - - if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST - if (process.env.__OW_API_KEY) api_key = process.env.__OW_API_KEY - - const wsk = require('openwhisk')(Object.assign({ apihost, api_key }, options)) - wsk.compositions = new Compositions(wsk, this) - return wsk - }, - - // recursively encode composition into { composition, actions } by encoding nested compositions into actions and extracting nested action definitions - encode(composition, combinators = []) { // lower non-primitive combinators by default - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - - composition = this.lower(composition, combinators) - - const actions = [] - - const encode = composition => { - composition = new Composition(composition) // copy - composition.visit(this.combinators, encode) - if (composition.type === 'composition') { - let code = `const main=(${main})().server(` - for (let plugin of plugins) { - code += `{plugin:new(${plugin.constructor})()` - if (plugin.configure) code += `,config:${JSON.stringify(plugin.configure())}` - code += '},' - } - code = minify(`${code})`, { output: { max_line_len: 127 } }).code - code = `// generated by composer v${version}\n\nconst composition = ${JSON.stringify(encode(composition.composition), null, 4)}\n\n// do not edit below this point\n\n${code}` // invoke conductor on composition - composition.action = { exec: { kind: 'nodejs:default', code }, annotations: [{ key: 'conductor', value: composition.composition }, { key: 'composer', value: version }] } - delete composition.composition - composition.type = 'action' - } - if (composition.type === 'action' && composition.action) { - actions.push({ name: composition.name, action: composition.action }) - delete composition.action - } - return composition - } + deploy(name, composition, combinators) { + const actions = composer.util.encode(name, composition, combinators) + return actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) + .then(() => this.actions.update(action)), Promise.resolve()) + .then(() => actions) + } + } - composition = encode(composition) - return { composition, actions } - }, + // runtime stuff + function runtime() { + // recursively label combinators with the json path + function label(composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - // return composer version - get version() { - return version + const label = path => (composition, name, array) => { + composition = new Composition(composition) // copy + composition.path = path + (name !== undefined ? (array === undefined ? `.${name}` : `[${name}]`) : '') + // label nested combinators + composition.visit(label(composition.path)) + return composition } - }) - - return composer - } - // server-side stuff - function server() { - function chain(front, back) { - front.slice(-1)[0].next = 1 - front.push(...back) - return front + return label('')(composition) } + // compile ast to fsm const compiler = { - compile(node) { - if (arguments.length === 0) return [{ type: 'empty' }] - if (arguments.length === 1) return this[node.type](node) - return Array.prototype.map.call(arguments, node => this.compile(node)).reduce(chain) - }, - sequence(node) { - return chain([{ type: 'pass', path: node.path }], this.compile(...node.components)) + return [{ type: 'pass', path: node.path }, ...compile(...node.components)] }, action(node) { - return [{ type: 'action', name: node.name, async: node.async, path: node.path }] + return [{ type: 'action', name: node.name, path: node.path }] + }, + + async(node) { + const body = compile(node.body) + return [{ type: 'async', path: node.path, return: body.length + 2 }, ...body, { type: 'stop' }, { type: 'pass' }] }, function(node) { @@ -500,64 +480,56 @@ function main() { }, finally(node) { - var body = this.compile(node.body) - const finalizer = this.compile(node.finalizer) - var fsm = [[{ type: 'try', path: node.path }], body, [{ type: 'exit' }], finalizer].reduce(chain) + const finalizer = compile(node.finalizer) + const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...finalizer] fsm[0].catch = fsm.length - finalizer.length return fsm }, let(node) { - var body = this.compile(...node.components) - return [[{ type: 'let', let: node.declarations, path: node.path }], body, [{ type: 'exit' }]].reduce(chain) + return [{ type: 'let', let: node.declarations, path: node.path }, ...compile(...node.components), { type: 'exit' }] }, mask(node) { - var body = this.compile(...node.components) - return [[{ type: 'let', let: null, path: node.path }], body, [{ type: 'exit' }]].reduce(chain) + return [{ type: 'let', let: null, path: node.path }, ...compile(...node.components), { type: 'exit' }] }, try(node) { - var body = this.compile(node.body) - const handler = chain(this.compile(node.handler), [{ type: 'pass' }]) - var fsm = [[{ type: 'try', path: node.path }], body, [{ type: 'exit' }]].reduce(chain) - fsm[0].catch = fsm.length - fsm.slice(-1)[0].next = handler.length - fsm.push(...handler) + const handler = [...compile(node.handler), { type: 'pass' }] + const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...handler] + fsm[0].catch = fsm.length - handler.length + fsm[fsm.length - handler.length - 1].next = handler.length return fsm }, if_nosave(node) { - var consequent = this.compile(node.consequent) - var alternate = chain(this.compile(node.alternate), [{ type: 'pass' }]) - var fsm = [[{ type: 'pass', path: node.path }], this.compile(node.test), [{ type: 'choice', then: 1, else: consequent.length + 1 }]].reduce(chain) - consequent.slice(-1)[0].next = alternate.length - fsm.push(...consequent) - fsm.push(...alternate) + const consequent = compile(node.consequent) + const alternate = [...compile(node.alternate), { type: 'pass' }] + const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: consequent.length + 1 }, ...consequent, ...alternate] + fsm[fsm.length - alternate.length - 1].next = alternate.length return fsm }, while_nosave(node) { - var consequent = this.compile(node.body) - var alternate = [{ type: 'pass' }] - var fsm = [[{ type: 'pass', path: node.path }], this.compile(node.test), [{ type: 'choice', then: 1, else: consequent.length + 1 }]].reduce(chain) - consequent.slice(-1)[0].next = 1 - fsm.length - consequent.length - fsm.push(...consequent) - fsm.push(...alternate) + const body = compile(node.body) + const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: body.length + 1 }, ...body, { type: 'pass' }] + fsm[fsm.length - 2].next = 2 - fsm.length return fsm }, dowhile_nosave(node) { - var test = this.compile(node.test) - var fsm = [[{ type: 'pass', path: node.path }], this.compile(node.body), test, [{ type: 'choice', then: 1, else: 2 }]].reduce(chain) - fsm.slice(-1)[0].then = 1 - fsm.length - fsm.slice(-1)[0].else = 1 - var alternate = [{ type: 'pass' }] - fsm.push(...alternate) + const fsm = [{ type: 'pass', path: node.path }, ...compile(node.body), ...compile(node.test), { type: 'choice', else: 1 }, { type: 'pass' }] + fsm[fsm.length - 2].then = 2 - fsm.length return fsm }, } + function compile(node) { + if (arguments.length === 0) return [{ type: 'empty' }] + if (arguments.length === 1) return compiler[node.type](node) + return Array.prototype.reduce.call(arguments, (fsm, node) => { fsm.push(...compile(node)); return fsm }, []) + } + const openwhisk = require('openwhisk') let wsk @@ -580,19 +552,6 @@ function main() { }, action({ p, node, index }) { - if (node.async) { - if (!wsk) wsk = openwhisk({ ignore_certs: true }) - return wsk.actions.invoke({ name: node.name, params: p.params }) - .catch(error => { - console.error(error) - return { error: `An exception was caught at state ${index} (see log for details)` } - }) - .then(result => { - p.params = result - inspect(p) - return step(p) - }) - } return { action: node.name, params: p.params, state: { $resume: p.s } } }, @@ -617,24 +576,43 @@ function main() { pass({ p, node, index }) { }, + + async({ p, node, index, inspect, step }) { + if (!wsk) wsk = openwhisk({ ignore_certs: true }) + p.params.$resume = { state: p.s.state } + p.s.state = index + node.return + return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) + .catch(error => { + console.error(error) + return { error: `An exception was caught at state ${index} (see log for details)` } + }) + .then(result => { + p.params = result + inspect(p) + return step(p) + }) + }, + + stop({ p, node, index, inspect, step }) { + p.s.state = -1 + }, } const finishers = [] - for ({ plugin, config } of arguments) { - composer.register(plugin) - if (plugin.compiler) Object.assign(compiler, plugin.compiler()) + for (let { plugin, config } of arguments) { + composer.util.register(plugin) + if (plugin.compiler) Object.assign(compiler, plugin.compiler({ compile })) if (plugin.conductor) { - const r = plugin.conductor(config) - if (r._finish) { - finishers.push(r._finish) - delete r._finish + Object.assign(conductor, plugin.conductor(config)) + if (conductor._finish) { + finishers.push(conductor._finish) + delete conductor._finish } - Object.assign(conductor, r) } } - const fsm = compiler.compile(composer.lower(composer.label(composer.deserialize(composition)))) + const fsm = compile(composer.util.lower(label(composer.util.deserialize(composition)))) // encode error object const encodeError = error => ({ @@ -651,17 +629,15 @@ function main() { if (!isObject(p.params)) p.params = { value: p.params } if (p.params.error !== undefined) { p.params = { error: p.params.error } // discard all fields but the error field - p.s.state = undefined // abort unless there is a handler in the stack + p.s.state = -1 // abort unless there is a handler in the stack while (p.s.stack.length > 0) { - if (typeof (p.s.state = p.s.stack.shift().catch) === 'number') break + if ((p.s.state = p.s.stack.shift().catch || -1) >= 0) break } } } // run function f on current stack function run(f, p) { - this.require = require - // handle let/mask pairs const view = [] let n = 0 @@ -699,7 +675,7 @@ function main() { function step(p) { // final state, return composition result - if (p.s.state === undefined) { + if (p.s.state < 0 || p.s.state >= fsm.length) { console.log(`Entering final state`) console.log(JSON.stringify(p.params)) return finishers.reduce((promise, _finish) => promise.then(() => _finish(p)), Promise.resolve()) @@ -709,8 +685,8 @@ function main() { // process one state const node = fsm[p.s.state] // json definition for index state if (node.path !== undefined) console.log(`Entering composition${node.path}`) - const index = p.s.state // save current state for logging purposes - p.s.state = node.next === undefined ? undefined : p.s.state + node.next // default next state + const index = p.s.state // current state + p.s.state = p.s.state + (node.next || 1) // default next state return conductor[node.type]({ p, index, node, inspect, step }) || step(p) } @@ -724,9 +700,8 @@ function main() { if (!isObject(params.$resume)) return badRequest('The type of optional $resume parameter must be object') const resuming = params.$resume.stack Object.assign(p.s, params.$resume) - if (resuming) p.s.state = params.$resume.state // undef - if (p.s.state !== undefined && typeof p.s.state !== 'number') return badRequest('The type of optional $resume.state parameter must be number') - if (!Array.isArray(p.s.stack)) return badRequest('The type of $resume.stack must be an array') + if (typeof p.s.state !== 'number') return badRequest('The type of optional $resume.state parameter must be number') + if (!Array.isArray(p.s.stack)) return badRequest('The type of optional $resume.stack parameter must be an array') delete params.$resume if (resuming) inspect(p) // handle error objects when resuming } @@ -735,7 +710,7 @@ function main() { } } - return { client, server } + return { composer, runtime } } -module.exports = main().client() +module.exports = main().composer diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index 6989ac2..83af8c9 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -7,9 +7,9 @@ The `composer` module offers a number of combinators to define compositions: | [`action`](#action) | action | `composer.action('echo')` | | [`function`](#function) | function | `composer.function(({ x, y }) => ({ product: x * y }))` | | [`literal` or `value`](#literal) | constant value | `composer.literal({ message: 'Hello, World!' })` | -| [`composition`](#composition) | named composition | `composer.composition('myCompositionName', myComposition)` | | [`empty`](#empty) | empty sequence | `composer.empty()` | [`sequence` or `seq`](#sequence) | sequence | `composer.sequence('hello', 'bye')` | +| [`task`](#task) | single task | `composer.task('echo')` | [`let`](#let) | variable declarations | `composer.let({ count: 3, message: 'hello' }, ...)` | | [`mask`](#mask) | variable hiding | `composer.let({ n }, composer.while(_ => n-- > 0, composer.mask(composition)))` | | [`if` and `if_nosave`](#if) | conditional | `composer.if('authenticate', 'success', 'failure')` | @@ -20,6 +20,7 @@ The `composer` module offers a number of combinators to define compositions: | [`finally`](#finally) | finalization | `composer.finally('tryThis', 'doThatAlways')` | | [`retry`](#retry) | error recovery | `composer.retry(3, 'connect')` | | [`retain` and `retain_catch`](#retain) | persistence | `composer.retain('validateInput')` | +| [`async`](#async) | asynchronous invocation | `composer.async('sendMessage')` | The `action`, `function`, and `literal` combinators construct compositions respectively from actions, functions, and constant values. The other combinators combine existing compositions to produce new compositions. @@ -32,7 +33,7 @@ Where a composition is expected, the following shorthands are permitted: ## Primitive combinators -Some of these combinators are _derived_ combinators: they are equivalent to combinations of other combinators. The `composer` module offers a `composer.lower` method (see [COMPOSER.md](#COMPOSER.md)) that can eliminate derived combinators from a composition, producing an equivalent composition made only of _primitive_ combinators. The primitive combinators are: `action`, `function`, `composition`, `sequence`, `let`, `mask`, `if_nosave`, `while_nosave`, `dowhile_nosave`, `try`, and `finally`. +Some of these combinators are _derived_ combinators: they are equivalent to combinations of other combinators. The `composer` module offers a `composer.lower` method (see [COMPOSER.md](#COMPOSER.md)) that can eliminate derived combinators from a composition, producing an equivalent composition made only of _primitive_ combinators. ## Action @@ -136,19 +137,6 @@ JSON values cannot represent functions. Applying `composer.literal` to a value o In general, a function can be embedded in a composition either by using the `composer.function` combinator, or by embedding the source code for the function as a string and later using `eval` to evaluate the function code. -## Composition - -`composition(name, composition)` returns a composition consisting of the invocation of the composition named `name` and of the declaration of the composition named `name` defined to be `composition`. - -```javascript -composer.if('isEven', 'half', composer.composition('tripleAndIncrement', composer.sequence('triple', 'increment'))) -``` -In this example, the `composer.sequence('triple', 'increment')` composition is given the name `tripleAndIncrement` and the enclosing composition references the `tripleAndIncrement` composition by name. In particular, deploying this composition actually deploys two compositions: -- a composition named `tripleAndIncrement` defined as `composer.sequence('triple', 'increment')`, and -- a composition defined as `composer.if('isEven', 'half', 'tripleAndIncrement')` whose name will be specified as deployment time. - -Importantly, the behavior of the second composition would be altered if we redefine the `tripleAndIncrement` composition to do something else, since it refers to the composition by name. - ## Empty `composer.empty()` is a shorthand for the empty sequence `composer.sequence()`. It is typically used to make it clear that a composition, e.g., a branch of an `if` combinator, is intentionally doing nothing. @@ -163,6 +151,10 @@ If one of the components fails (i.e., returns an error object), the remainder of An empty sequence behaves as a sequence with a single function `params => params`. The output parameter object for the empty sequence is its input parameter object unless it is an error object, in which case, as usual, the error object only contains the `error` field of the input parameter object. +## Task + +`composer.task(composition)` is equivalent to `composer.sequence(composition)`. + ## Let `composer.let({ name_1: value_1, name_2: value_2, ... }, composition_1_, _composition_2_, ...)` declares one or more variables with the given names and initial values, and runs a sequence of compositions in the scope of these declarations. @@ -266,3 +258,7 @@ The _finalizer_ is invoked in sequence after _body_ even if _body_ returns an er `composer.retain(body)` runs _body_ on the input parameter object producing an object with two fields `params` and `result` such that `params` is the input parameter object of the composition and `result` is the output parameter object of _body_. If _body_ fails, the output of the `retain` combinator is only the error object (i.e., the input parameter object is not preserved). In constrast, the `retain_catch` combinator always outputs `{ params, result }`, even if `result` is an error result. + +## Async + +`composer.async(body)` runs the _body_ composition asynchronously. It spawns _body_ but does not wait for it to execute. It immediately returns a dictionary with a single field named `activationId` identifying the invocation of _body_. diff --git a/docs/COMPOSE.md b/docs/COMPOSE.md index 4750fa2..a1c1f03 100644 --- a/docs/COMPOSE.md +++ b/docs/COMPOSE.md @@ -24,6 +24,8 @@ Flags: -u, --auth KEY authorization KEY -i, --insecure bypass certificate checking -v, --version output the composer version + --quiet omit detailed diagnostic messages + --composer COMPOSER instantiate a custom composer module ``` The `compose` command requires either a Javascript file that evaluates to a composition (for example [demo.js](../samples/demo.js)) or a JSON file that encodes a composition (for example [demo.json](../samples/demo.json)). The JSON format is documented in [FORMAT.md](FORMAT.md). @@ -74,12 +76,6 @@ compose demo.js } } } -``` -The evaluation context includes the `composer` object implicitly defined as: -```javascript -composer = require('@ibm-functions/composer') -``` -In other words, there is no need to require the `composer` module explicitly in the composition code. ## Entity option @@ -253,8 +249,12 @@ The conductor action code does not include definitions for nested actions or com ## Lowering -If the `--lower VERSION` option is specified, the `compose` command uses the set of combinators of the specified revision of the `composer` module. More recently introduced combinators (if any) are translated into combinators of the older set. +If the `--lower VERSION` option is specified, the `compose` command uses the set of combinators of the specified revision of the `composer` module. Derived combinators that are more recent (if any) are translated into combinators of the older set. If the `--lower` option is specified without a version number, the `compose` command uses only primitive combinators. These options may be combined with any of the `compose` commands. + +## Composer option + +If the composition code uses a custom `composer` module, the path to the module must be specified via the `--composer` option. \ No newline at end of file diff --git a/docs/COMPOSER.md b/docs/COMPOSER.md index 71efd2e..cf76add 100644 --- a/docs/COMPOSER.md +++ b/docs/COMPOSER.md @@ -14,6 +14,7 @@ To take advantage of the `compose` command, it may be useful to install the modu The [samples/node-demo.js](../samples/node-demo.js) file illustrates how to define, deploy, and invoke a composition using `node`: ```javascript + // require the composer module const composer = require('@ibm-functions/composer') @@ -24,13 +25,12 @@ const composition = composer.if( composer.action('failure', { action: function () { return { message: 'failure' } } })) // instantiate OpenWhisk client -const wsk = composer.openwhisk({ ignore_certs: true }) +const wsk = composer.util.openwhisk({ ignore_certs: true }) -wsk.compositions.deploy(composer.composition('demo', composition)) // name and deploy composition +wsk.compositions.deploy('demo', composition) // deploy composition .then(() => wsk.actions.invoke({ name: 'demo', params: { password: 'abc123' }, blocking: true })) // invoke composition .then(({ response }) => console.log(JSON.stringify(response.result, null, 4)), console.error) ``` -``` node samples/node-demo.js ``` ```json @@ -40,67 +40,69 @@ node samples/node-demo.js ``` Alternatively, the `compose` command can deploy compositions and the OpenWhisk CLI can invoke compositions. See [COMPOSE.md](COMPOSE.md) for details. -# Composer methods +# Helper methods -The `composer` object offers a number of combinator methods to define composition objects, e.g., `composer.if`. Combinators are documented in [COMBINATORS.md](COMBINATORS.md). It also offers a series of helper methods described below: +The `composer` object offers a number of combinator methods to define composition objects, e.g., `composer.if`. Combinators are documented in [COMBINATORS.md](COMBINATORS.md). It also offers a series of helper methods via the `composer.util` object. -| Combinator | Description | Example | +| Helper method | Example | | --:| --- | --- | -| [`deserialize`](#deserialize) | deserialization | `composer.deserialize(JSON.stringify(composition))` | -| [`lower`](#lower) | lowering | `composer.lower(composer.if('authenticate', 'success', 'failure'), '0.4.0')` | -| [`encode`](#encode) | code generation | `composer.encode(composition, '0.4.0')` | +| [`version`](#version) | `composer.util.version` | +| [`deserialize`](#deserialize) | `composer.util.deserialize(JSON.stringify(composition))` | +| [`canonical`](#canonical) | `composer.util.canonical('demo')` | +| [`lower`](#lower) | `composer.util.lower(composer.if('authenticate', 'success', 'failure'), '0.4.0')` | +| [`encode`](#encode) | `composer.util.encode('demo', composition, '0.4.0')` | +| [`openwhisk`](#openwhisk-client) | `composer.util.openwhisk()` | + +## Version -Finally, the `composer` object object offers an extension to the [OpenWhisk Client for Javascript](https://github.com/apache/incubator-openwhisk-client-js) that supports [deploying](#deployment) compositions. +`composer.util.version` returns the version number for the composer module. ## Deserialize -`composer.deserialize(composition)` recursively deserializes a serialized composition object. In other words, it recreates a `Composition` object from the input JSON dictionary. +`composer.util.deserialize(composition)` recursively deserializes a serialized composition object. In other words, it recreates a `Composition` object from the input JSON dictionary. + +## Canonical + +`composer.util.canonical(name)` attempts to validate and expand the action name `name` to its canonical form. ## Lower -`composer.lower(composition, [combinators])` outputs a composition object equivalent to the input `composition` object but using a reduced set of combinators. The optional `combinators` parameter may specify the desired set, either directly as an array of combinator names, e.g., `['retain', 'retry']` or indirectly as a revision of the composer module, e.g., `'0.4.0'`. If the `combinators` parameter is undefined, the set of combinators is the set of _primitive_ combinators (see [COMBINATORS.md](COMBINATORS.md])). If an array of combinators is specified the primitive combinators are implicitly added to the array. If a `composer` module revision is specified, the target combinator set is the set of combinators available as of the specified revision of the `composer` module. The `combinators` parameter may also have type Boolean. If `combinators === true` only primitive combinators are used. If `combinators === false`, there is no change to the composition. +`composer.util.lower(composition, [combinators])` outputs a composition object equivalent to the input `composition` object but using a reduced set of combinators. The optional `combinators` parameter may specify the desired set, either directly as an array of combinator names, e.g., `['retain', 'retry']` or indirectly as a revision of the composer module, e.g., `'0.4.0'`. If the `combinators` parameter is undefined, the set of combinators is the set of _primitive_ combinators (see [COMBINATORS.md](COMBINATORS.md])). If an array of combinators is specified the primitive combinators are implicitly added to the array. If a `composer` module revision is specified, the target combinator set is the set of combinators available as of the specified revision of the `composer` module. -For instance, `composer.lower(composition, ['retry'])` will preserve any instance of the `retry` combinator but replace other non-primitive combinators sur as `retain`. +For instance, `composer.util.lower(composition, ['retry'])` will preserve any instance of the `retry` combinator but replace other non-primitive combinators sur as `retain`. ## Encode -`composer.encode(composition, [combinators])` first lowers the composition. It then converts compositions nested into `composition` into conductor actions. It finally extracts the action definitions from `composition` (both embedded action definitions and synthesized conductor actions) returning a dictionary with two fields `{ composition, actions }` where `composition` no longer contains any action or composition definitions and `actions` is the corresponding array of extracted action definitions. +`composer.util.encode(name, composition, [combinators])` first invokes `composer.util.lower` on the composition with the specified `combinators` argument if any. It then encodes the composition as an array of actions. This array consists of all the actions defined as part of the composition plus the conductor action synthesized for the composition itself. -The optional `combinators` parameter controls the lowering. See [lower](#lower) for details. +The optional `combinators` parameter controls the optional lowering. See [lower](#lower) for details. -# Deployment +## Openwhisk client The `composer` object offers an extension to the [OpenWhisk Client for Javascript](https://github.com/apache/incubator-openwhisk-client-js) that supports deploying compositions. -## Openwhisk client - -A client instance is obtained by invoking `composer.openwhisk([options])`, for instance with: +An OpenWhisk client instance is obtained by invoking `composer.util.openwhisk([options])`, for instance with: ```javascript -const wsk = composer.openwhisk({ ignore_certs: true }) +const wsk = composer.util.openwhisk({ ignore_certs: true }) ``` The specific OpenWhisk deployment to use may be specified via the optional `options` argument, environment variables, or the OpenWhisk property file. Options have priority over environment variables, which have priority over the OpenWhisk property file. Options and environment variables are documented [here](https://github.com/apache/incubator-openwhisk-client-js#constructor-options). The default path for the whisk property file is `$HOME/.wskprops`. It can be altered by setting the `WSK_CONFIG_FILE` environment variable. The `composer` module adds to the OpenWhisk client instance a new top-level category named `compositions` with a method named `deploy`. -## Deploying compositions - -`wsk.compositions.deploy(composition, [combinators])` lowers and deploys the composition `composition`. More precisely, it successively deploys all the actions and compositions defined in `composition` including `composition` itself. The composition `composition` must have a name, hence the `deploy` method is typically used as illustrated above: -``` -wsk.compositions.deploy(composer.composition('demo', composition)) -``` +### Deploying compositions -The optional `combinators` parameter controls the lowering. See [lower](#lower) for details. +`wsk.compositions.deploy(name, composition, [combinators])` optionally lowers, encodes, and deploys the composition `composition`. More precisely, it successively deploys all the actions defined in `composition` as well as `composition` itself (encoded as a conductor action). -The compositions are encoded into conductor actions prior to deployment. In other words, the `deploy` method deploys one or several actions. +The optional `combinators` parameter controls the optional lowering. See [lower](#lower) for details. The `deploy` method returns a successful promise if all the actions were deployed successfully, or a rejected promise otherwise. In the later, the state of the various actions is unknown. The `deploy` method deletes the deployed actions before recreating them if necessary. As a result, default parameters, limits, and annotations on preexisting actions are lost. -## Invoking, updating, and deleting compositions +### Invoking, updating, and deleting compositions -Since compositions are deployed as conductor actions, other management tasks for compositions can be achieved by invoking methods of `wsk.actions`, for instance: +Since compositions are deployed as conductor actions, other management tasks for compositions can be achieved by invoking methods of `wsk.actions`. For example, to delete a composition named `demo`, use command: ```javascript wsk.actions.delete('demo') ``` diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index 4c8e416..87f51a0 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -37,18 +37,17 @@ Components of a compositions can be actions, Javascript functions, or compositio Javascript functions can be viewed as simple, anonymous actions that do not need to be deployed and managed separately from the composition they belong to. Functions are typically used to alter a parameter object between two actions that expect different schemas, as in: ```javascript -composer.if('getUserNameAndPassword', params => ({ key = btoa(params.user + ':' + params.password) }), 'authenticate') +composer.sequence('getUserNameAndPassword', params => ({ key = btoa(params.user + ':' + params.password) }), 'authenticate') ``` - -Compositions may be nested inside compositions in two ways. First, combinators can be nested, e.g., +Combinators can be nested, e.g., ```javascript composer.if('isEven', 'half', composer.sequence('triple', 'increment')) ``` -Second, compositions can reference other compositions by name. For instance, assuming we deploy the sequential composition of the `triple` and `increment` actions as the composition `tripleAndIncrement`, the following code behaves identically to the previous example: +Compositions can reference other compositions by name. For instance, assuming we deploy the sequential composition of the `triple` and `increment` actions as the composition `tripleAndIncrement`, the following code behaves identically to the previous example: ```javascript composer.if('isEven', 'half', 'tripleAndIncrement') ``` -Observe however, that the behavior of the second composition would be altered if we redefine the `tripleAndIncrement` composition to do something else, whereas the first example would not be affected. +The behavior of this last composition would be altered if we redefine the `tripleAndIncrement` composition to do something else, whereas the first example would not be affected. ## Nested declarations @@ -62,18 +61,10 @@ composer.if( ``` Deploying such a composition deploys the embedded actions. -A composition can also include the definition of another composition: -```javascript -composer.if('isEven', 'half', composer.composition('tripleAndIncrement', composer.sequence('triple', 'increment'))) -``` -In this example, the `composer.sequence('triple', 'increment')` composition is given the name `tripleAndIncrement` and the enclosing composition references the `tripleAndIncrement` composition by name. In other words, deploying this composition actually deploys two compositions: -- a composition named `tripleAndIncrement` defined as `composer.sequence('triple', 'increment')`, and -- a composition defined as `composer.if('isEven', 'half', 'tripleAndIncrement')` whose name will be specified as deployment time. - ## Serialization and deserialization Compositions objects can be serialized to JSON dictionaries by invoking `JSON.stringify` on them. Serialized compositions can be deserialized to composition objects using the `composer.deserialize(serializedComposition)` method. The JSON format is documented in [FORMAT.md](FORMAT.md). - In short, the JSON dictionary for a composition contains a representation of the syntax tree for this composition as well as the definition of all the actions and compositions embedded inside the composition. + In short, the JSON dictionary for a composition contains a representation of the syntax tree for this composition as well as the definition of all the actions embedded inside the composition. ## Conductor actions diff --git a/docs/FORMAT.md b/docs/FORMAT.md index 6822db1..47f0901 100644 --- a/docs/FORMAT.md +++ b/docs/FORMAT.md @@ -43,9 +43,8 @@ The field names and types typically match the combinator method signatures: | Type | Fields | | --:| --- | | `action` | name:string, action:optional object | -| `function` | function:string | -| `literal` or `value` | value:any | -| `composition` | name:string, composition:composition | +| `function` | function:object | +| `literal` or `value` | value:json value | | `empty` | | `sequence` or `seq` | components:array of compositions | | `let` | declarations:object, components:array of compositions | @@ -58,3 +57,4 @@ The field names and types typically match the combinator method signatures: | `finally` | body:composition, finalizer:composition | | `retry` | count:number, components:array of compositions | | `retain` and `retain_catch` | components:array of compositions | +| `async` | body:composition | \ No newline at end of file diff --git a/samples/demo.js b/samples/demo.js index 71cc939..f5e3805 100644 --- a/samples/demo.js +++ b/samples/demo.js @@ -14,7 +14,9 @@ * limitations under the License. */ -composer.if( +const composer = require('@ibm-functions/composer') + +module.exports = composer.if( composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), composer.action('success', { action: function () { return { message: 'success' } } }), composer.action('failure', { action: function () { return { message: 'failure' } } })) diff --git a/samples/node-demo.js b/samples/node-demo.js index 5956715..62a986d 100644 --- a/samples/node-demo.js +++ b/samples/node-demo.js @@ -24,8 +24,8 @@ const composition = composer.if( composer.action('failure', { action: function () { return { message: 'failure' } } })) // instantiate OpenWhisk client -const wsk = composer.openwhisk({ ignore_certs: true }) +const wsk = composer.util.openwhisk({ ignore_certs: true }) -wsk.compositions.deploy(composer.composition('demo', composition)) // deploy composition +wsk.compositions.deploy('demo', composition) // deploy composition .then(() => wsk.actions.invoke({ name: 'demo', params: { password: 'abc123' }, blocking: true })) // invoke composition .then(({ response }) => console.log(JSON.stringify(response.result, null, 4)), console.error) diff --git a/test/test.js b/test/test.js index ece8237..d0ba083 100644 --- a/test/test.js +++ b/test/test.js @@ -1,14 +1,13 @@ const assert = require('assert') const composer = require('../composer') const name = 'TestAction' -const compositionName = 'TestComposition' -const wsk = composer.openwhisk({ ignore_certs: process.env.IGNORE_CERTS && process.env.IGNORE_CERTS !== 'false' && process.env.IGNORE_CERTS !== '0' }) +const wsk = composer.util.openwhisk({ ignore_certs: process.env.IGNORE_CERTS && process.env.IGNORE_CERTS !== 'false' && process.env.IGNORE_CERTS !== '0' }) // deploy action const define = action => wsk.actions.delete(action.name).catch(() => { }).then(() => wsk.actions.create(action)) // deploy and invoke composition -const invoke = (task, params = {}, blocking = true) => wsk.compositions.deploy(composer.composition(name, task)).then(() => wsk.actions.invoke({ name, params, blocking })) +const invoke = (composition, params = {}, blocking = true) => wsk.compositions.deploy(name, composition).then(() => wsk.actions.invoke({ name, params, blocking })) describe('composer', function () { this.timeout(60000) @@ -21,7 +20,6 @@ describe('composer', function () { .then(() => define({ name: 'isEven', action: 'function main({n}) { return { value: n % 2 == 0 } }' })) }) - describe('blocking invocations', function () { describe('actions', function () { it('action must return true', function () { @@ -33,7 +31,7 @@ describe('composer', function () { }) it('action must return activationId', function () { - return invoke(composer.action('isNotOne', { async: true }), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) + return invoke(composer.async('isNotOne'), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) }) it('action name must parse to fully qualified', function () { @@ -89,43 +87,6 @@ describe('composer', function () { }) }) - describe('compositions', function () { - it('composition must return true', function () { - return invoke(composer.composition(compositionName, composer.action('isNotOne')), { n: 0 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - - it('action must return activationId', function () { - return invoke(composer.composition(compositionName, composer.action('isNotOne'), { async: true }), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) - }) - - it('invalid argument', function () { - try { - invoke(composer.composition(compositionName, 42)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - - it('invalid options', function () { - try { - invoke(composer.composition(compositionName, 'foo', 42)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - - it('too many arguments', function () { - try { - invoke(composer.composition(compositionName, 'foo', {}, 'foo')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - describe('literals', function () { it('true', function () { return invoke(composer.literal(true)).then(activation => assert.deepEqual(activation.response.result, { value: true })) @@ -214,7 +175,7 @@ describe('composer', function () { "name": "echo" }] } - return invoke(composer.deserialize(json), { message: 'hi' }).then(activation => assert.deepEqual(activation.response.result, { message: 'hi' })) + return invoke(composer.util.deserialize(json), { message: 'hi' }).then(activation => assert.deepEqual(activation.response.result, { message: 'hi' })) }) }) From 90a104b59e7186e62971a6c67d7a1087dc25378b Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 19 Jun 2018 13:42:25 -0400 Subject: [PATCH 19/94] 0.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23c6a96..32d8108 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.5.2", + "version": "0.6.0", "description": "Composer is an IBM Cloud Functions programming model for composing individual functions into larger applications.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From 46804a70831404ffe4c771101502909e1acfa093 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 19 Jun 2018 14:35:01 -0400 Subject: [PATCH 20/94] v0.6.1 dev branch (#61) * Always invoke deserialize in compose command * More validation of composition object --- bin/compose | 3 +-- composer.js | 10 ++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/compose b/bin/compose index b2b5246..8c297e8 100755 --- a/bin/compose +++ b/bin/compose @@ -47,8 +47,7 @@ try { const filename = argv._[0] let composition try { - composition = require(path.resolve(filename)) - if (filename.slice(filename.lastIndexOf('.')) === '.json') composition = util.deserialize(composition) + composition = util.deserialize(require(path.resolve(filename))) if (typeof argv.lower === 'string') composition = util.lower(composition, argv.lower || []) } catch (error) { console.error('Bad composition') diff --git a/composer.js b/composer.js index 2dcdca3..de97ca6 100644 --- a/composer.js +++ b/composer.js @@ -347,6 +347,12 @@ function main() { // construct a composition object with the specified fields constructor(composition) { + if (!isObject(composition) || composer.util.combinators[composition.type] === undefined) throw new ComposerError('Invalid argument', composition) + const combinator = composer.util.combinators[composition.type] + if (combinator.components && composition.components === undefined)throw new ComposerError('Invalid argument', composition) + for (let arg of combinator.args || []) { + if (!arg.optional && composition[arg._] === undefined) throw new ComposerError('Invalid argument', composition) + } return Object.assign(this, composition) } @@ -371,7 +377,7 @@ function main() { const combinator = combinators[type] // do not overwrite existing combinators composer[type] = composer[type] || function () { - const composition = new Composition({ type }) + const composition = { type } const skip = combinator.args && combinator.args.length || 0 if (!combinator.components && (arguments.length > skip)) { throw new ComposerError('Too many arguments') @@ -398,7 +404,7 @@ function main() { if (combinator.components) { composition.components = Array.prototype.slice.call(arguments, skip).map(obj => composer.task(obj)) } - return composition + return new Composition(composition) } } } From aeed36feb640fd2d782b16a0359ab90c22a44458 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 19 Jun 2018 14:35:45 -0400 Subject: [PATCH 21/94] 0.6.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32d8108..05e3cf4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.6.0", + "version": "0.6.1", "description": "Composer is an IBM Cloud Functions programming model for composing individual functions into larger applications.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From 84ea76c2109c85f3a9b68a06f606111c91e40c0e Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 27 Jun 2018 11:32:06 -0400 Subject: [PATCH 22/94] v0.7 dev branch (#63) * Lower predeployment. Update plugin interface. Reuse composer module from composition * Update composer.deploy schema. Update doc. --- README.md | 2 +- bin/compose | 14 +- composer.js | 1213 +++++++++++++++++++++--------------------- docs/COMPOSE.md | 4 +- docs/COMPOSER.md | 4 +- docs/TEMPLATES.md | 2 +- samples/node-demo.js | 2 +- test/test.js | 2 +- 8 files changed, 625 insertions(+), 618 deletions(-) diff --git a/README.md b/README.md index 7ca67d1..a1e1637 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ One way to deploy a composition is to use the [compose](docs/COMPOSE.md) command compose demo.js --deploy demo ``` ``` -ok: created actions /_/authenticate,/_/success,/_/failure,/_/demo +ok: created /_/authenticate,/_/success,/_/failure,/_/demo ``` The `compose` command synthesizes and deploys an action named `demo` that implements the composition. It also deploys the composed actions if definitions diff --git a/bin/compose b/bin/compose index 8c297e8..0139fd9 100755 --- a/bin/compose +++ b/bin/compose @@ -10,7 +10,7 @@ const argv = minimist(process.argv.slice(2), { boolean: ['insecure', 'encode', 'json', 'version', 'quiet'], alias: { auth: 'u', insecure: 'i', version: 'v' } }) -const { util } = require(argv.composer || '../composer') +let { util } = require(argv.composer || '../composer') if (argv.version) { console.log(util.version) @@ -21,6 +21,7 @@ let count = 0 if (argv.json) count++ if (argv.encode) count++ if (argv.entity) count++ +if (argv.entities) count++ if (typeof argv.deploy !== 'undefined') count++ if (argv._.length !== 1 || count > 1 || argv.deploy === '' || argv.entity === '' || argv.entities === '') { @@ -47,7 +48,12 @@ try { const filename = argv._[0] let composition try { - composition = util.deserialize(require(path.resolve(filename))) + composition = require(path.resolve(filename)) + if (composition.constructor && composition.constructor.name === 'Composition') { + util = composition.constructor.composer.util + } else { + composition = util.deserialize(composition) + } if (typeof argv.lower === 'string') composition = util.lower(composition, argv.lower || []) } catch (error) { console.error('Bad composition') @@ -59,10 +65,10 @@ try { if (argv.apihost) options.apihost = argv.apihost if (argv.auth) options.api_key = argv.auth return Promise.resolve() - .then(() => util.openwhisk(options).compositions.deploy(argv.deploy, composition)) + .then(() => util.frontend(options).compositions.deploy({ name: argv.deploy, composition })) .then(actions => { const names = actions.map(action => action.name) - console.log(`ok: created action${names.length > 1 ? 's' : ''} ${names}`) + console.log(`ok: created ${names}`) }) .catch(error => { if (error.constructor && error.constructor.name === 'OpenWhiskError') { diff --git a/composer.js b/composer.js index de97ca6..b1b0ac9 100644 --- a/composer.js +++ b/composer.js @@ -14,364 +14,327 @@ * limitations under the License. */ -function main() { - 'use strict' +'use strict' - const fs = require('fs') - const os = require('os') - const path = require('path') - const semver = require('semver') - const util = require('util') +const fs = require('fs') +const os = require('os') +const path = require('path') +const semver = require('semver') +const util = require('util') - // read composer version number - const version = require('./package.json').version +// read composer version number +const version = require('./package.json').version - const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) +const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) - // combinator signatures - const combinators = {} +// combinator signatures +const combinators = {} - // error class - class ComposerError extends Error { - constructor(message, argument) { - super(message + (argument !== undefined ? '\nArgument: ' + util.inspect(argument) : '')) - } +// error class +class ComposerError extends Error { + constructor(message, argument) { + super(message + (argument !== undefined ? '\nArgument: ' + util.inspect(argument) : '')) } +} - // registered plugins - const plugins = [] - - const composer = {} - Object.assign(composer, { - // detect task type and create corresponding composition object - task(task) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (task === null) return composer.empty() - if (task instanceof Composition) return task - if (typeof task === 'function') return composer.function(task) - if (typeof task === 'string') return composer.action(task) - throw new ComposerError('Invalid argument', task) - }, - - // function combinator: stringify function code - function(fun) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (typeof fun === 'function') { - fun = `${fun}` - if (fun.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', fun) - } - if (typeof fun === 'string') { - fun = { kind: 'nodejs:default', code: fun } - } - if (!isObject(fun)) throw new ComposerError('Invalid argument', fun) - return new Composition({ type: 'function', function: { exec: fun } }) - }, - - // action combinator - action(name, options = {}) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!isObject(options)) throw new ComposerError('Invalid argument', options) - name = composer.util.canonical(name) // throws ComposerError if name is not valid - let exec - if (Array.isArray(options.sequence)) { // native sequence - exec = { kind: 'sequence', components: options.sequence.map(canonical) } - } else if (typeof options.filename === 'string') { // read action code from file - exec = fs.readFileSync(options.filename, { encoding: 'utf8' }) - } else if (typeof options.action === 'function') { // capture function - exec = `const main = ${options.action}` - if (exec.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', options.action) - } else if (typeof options.action === 'string' || isObject(options.action)) { - exec = options.action - } - if (typeof exec === 'string') { - exec = { kind: 'nodejs:default', code: exec } - } - const composition = { type: 'action', name } - if (exec) composition.action = { exec } - return new Composition(composition) - }, - }) - - const lowerer = { - empty() { - return composer.sequence() - }, - - seq({ components }) { - return composer.sequence(...components) - }, - - value({ value }) { - return composer.literal(value) - }, - - literal({ value }) { - return composer.let({ value }, composer.function('() => value')) - }, +// registered plugins +const plugins = [] - retain({ components }) { - return composer.let( - { params: null }, +const composer = {} +Object.assign(composer, { + // detect task type and create corresponding composition object + task(task) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (task === null) return composer.empty() + if (task instanceof Composition) return task + if (typeof task === 'function') return composer.function(task) + if (typeof task === 'string') return composer.action(task) + throw new ComposerError('Invalid argument', task) + }, + + // function combinator: stringify function code + function(fun) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (typeof fun === 'function') { + fun = `${fun}` + if (fun.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', fun) + } + if (typeof fun === 'string') { + fun = { kind: 'nodejs:default', code: fun } + } + if (!isObject(fun)) throw new ComposerError('Invalid argument', fun) + return new Composition({ type: 'function', function: { exec: fun } }) + }, + + // action combinator + action(name, options = {}) { + if (arguments.length > 2) throw new ComposerError('Too many arguments') + if (!isObject(options)) throw new ComposerError('Invalid argument', options) + name = composer.util.canonical(name) // throws ComposerError if name is not valid + let exec + if (Array.isArray(options.sequence)) { // native sequence + exec = { kind: 'sequence', components: options.sequence.map(canonical) } + } else if (typeof options.filename === 'string') { // read action code from file + exec = fs.readFileSync(options.filename, { encoding: 'utf8' }) + } else if (typeof options.action === 'function') { // capture function + exec = `const main = ${options.action}` + if (exec.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', options.action) + } else if (typeof options.action === 'string' || isObject(options.action)) { + exec = options.action + } + if (typeof exec === 'string') { + exec = { kind: 'nodejs:default', code: exec } + } + const composition = { type: 'action', name } + if (exec) composition.action = { exec } + return new Composition(composition) + }, +}) + +const lowerer = { + empty() { + return composer.sequence() + }, + + seq({ components }) { + return composer.sequence(...components) + }, + + value({ value }) { + return composer.literal(value) + }, + + literal({ value }) { + return composer.let({ value }, composer.function('() => value')) + }, + + retain({ components }) { + return composer.let( + { params: null }, + composer.finally( + args => { params = args }, + composer.seq(composer.mask(...components), + result => ({ params, result })))) + }, + + retain_catch({ components }) { + return composer.seq( + composer.retain( composer.finally( - args => { params = args }, - composer.seq(composer.mask(...components), - result => ({ params, result })))) - }, - - retain_catch({ components }) { - return composer.seq( - composer.retain( - composer.finally( - composer.seq(...components), - result => ({ result }))), - ({ params, result }) => ({ params, result: result.result })) - }, + composer.seq(...components), + result => ({ result }))), + ({ params, result }) => ({ params, result: result.result })) + }, + + if({ test, consequent, alternate }) { + return composer.let( + { params: null }, + composer.finally( + args => { params = args }, + composer.if_nosave( + composer.mask(test), + composer.finally(() => params, composer.mask(consequent)), + composer.finally(() => params, composer.mask(alternate))))) + }, + + while({ test, body }) { + return composer.let( + { params: null }, + composer.finally( + args => { params = args }, + composer.seq(composer.while_nosave( + composer.mask(test), + composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args }))), + () => params))) + }, + + dowhile({ body, test }) { + return composer.let( + { params: null }, + composer.finally( + args => { params = args }, + composer.seq(composer.dowhile_nosave( + composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args })), + composer.mask(test)), + () => params))) + }, + + repeat({ count, components }) { + return composer.let( + { count }, + composer.while( + composer.function('() => count-- > 0'), + composer.mask(...components))) + }, + + retry({ count, components }) { + return composer.let( + { count }, + params => ({ params }), + composer.dowhile( + composer.finally(({ params }) => params, composer.mask(composer.retain_catch(...components))), + composer.function('({ result }) => result.error !== undefined && count-- > 0')), + ({ result }) => result) + }, +} - if({ test, consequent, alternate }) { - return composer.let( - { params: null }, - composer.finally( - args => { params = args }, - composer.if_nosave( - composer.mask(test), - composer.finally(() => params, composer.mask(consequent)), - composer.finally(() => params, composer.mask(alternate))))) - }, +// recursively compile composition composition into { composition, actions } +function flatten(composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - while({ test, body }) { - return composer.let( - { params: null }, - composer.finally( - args => { params = args }, - composer.seq(composer.while_nosave( - composer.mask(test), - composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args }))), - () => params))) - }, + const actions = [] - dowhile({ body, test }) { - return composer.let( - { params: null }, - composer.finally( - args => { params = args }, - composer.seq(composer.dowhile_nosave( - composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args })), - composer.mask(test)), - () => params))) - }, + const flatten = composition => { + composition = new Composition(composition) // copy + composition.visit(flatten) + if (composition.type === 'action' && composition.action) { + actions.push({ name: composition.name, action: composition.action }) + delete composition.action + } + return composition + } - repeat({ count, components }) { - return composer.let( - { count }, - composer.while( - composer.function('() => count-- > 0'), - composer.mask(...components))) - }, + composition = flatten(composition) + return { composition, actions } +} - retry({ count, components }) { - return composer.let( - { count }, - params => ({ params }), - composer.dowhile( - composer.finally(({ params }) => params, composer.mask(composer.retain_catch(...components))), - composer.function('({ result }) => result.error !== undefined && count-- > 0')), - ({ result }) => result) - }, +// synthesize conductor action code from composition +function synthesize(composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + let code = `const main=(${main})(` + for (let plugin of plugins) { + code += `{plugin:new(${plugin.constructor})()` + if (plugin.configure) code += `,config:${JSON.stringify(plugin.configure())}` + code += '},' } + code = require('uglify-es').minify(`${code})`, { output: { max_line_len: 127 } }).code + code = `// generated by composer v${composer.util.version}\n\nconst composition = ${JSON.stringify(composer.util.lower(label(composition)), null, 4)}\n\n// do not edit below this point\n\n${code}` // invoke conductor on composition + return { exec: { kind: 'nodejs:default', code }, annotations: [{ key: 'conductor', value: composition }, { key: 'composer', value: version }] } +} - // recursively flatten composition into { composition, actions } by extracting embedded action definitions - function flatten(composition) { +composer.util = { + // return the signatures of the combinators + get combinators() { + return combinators + }, + + // recursively deserialize composition + deserialize(composition) { if (arguments.length > 1) throw new ComposerError('Too many arguments') + composition = new Composition(composition) // copy + composition.visit(composition => composer.util.deserialize(composition)) + return composition + }, + + // recursively lower combinators to the desired set of combinators (including primitive combinators) + lower(composition, combinators = []) { + if (arguments.length > 2) throw new ComposerError('Too many arguments') if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + if (typeof combinators === 'string') { // lower to combinators of specific composer version + combinators = Object.keys(composer.util.combinators).filter(key => semver.gte(combinators, composer.util.combinators[key].since)) + } + if (!Array.isArray(combinators)) throw new ComposerError('Invalid argument', combinators) - const actions = [] - - const flatten = composition => { + const lower = composition => { composition = new Composition(composition) // copy - composition.visit(flatten) - if (composition.type === 'action' && composition.action) { - actions.push({ name: composition.name, action: composition.action }) - delete composition.action + // repeatedly lower root combinator + while (combinators.indexOf(composition.type) < 0 && lowerer[composition.type]) { + const path = composition.path + composition = lowerer[composition.type](composition) + if (path !== undefined) composition.path = path // preserve path } + // lower nested combinators + composition.visit(lower) return composition } - composition = flatten(composition) - return { composition, actions } - } - - // synthesize composition code - function synthesize(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') + return lower(composition) + }, + + // register plugin + register(plugin) { + plugins.push(plugin) + }, + + /** + * Parses a (possibly fully qualified) resource name and validates it. If it's not a fully qualified name, + * then attempts to qualify it. + * + * Examples string to namespace, [package/]action name + * foo => /_/foo + * pkg/foo => /_/pkg/foo + * /ns/foo => /ns/foo + * /ns/pkg/foo => /ns/pkg/foo + */ + canonical(name) { + if (typeof name !== 'string') throw new ComposerError('Name must be a string') + if (name.trim().length == 0) throw new ComposerError('Name is not valid') + name = name.trim() + const delimiter = '/' + const parts = name.split(delimiter) + const n = parts.length + const leadingSlash = name[0] == delimiter + // no more than /ns/p/a + if (n < 1 || n > 4 || (leadingSlash && n == 2) || (!leadingSlash && n == 4)) throw new ComposerError('Name is not valid') + // skip leading slash, all parts must be non empty (could tighten this check to match EntityName regex) + parts.forEach(function (part, i) { if (i > 0 && part.trim().length == 0) throw new ComposerError('Name is not valid') }) + const newName = parts.join(delimiter) + if (leadingSlash) return newName + else if (n < 3) return `${delimiter}_${delimiter}${newName}` + else return `${delimiter}${newName}` + }, + + + // encode composition as an action table + encode(name, composition, combinators) { + if (arguments.length > 3) throw new ComposerError('Too many arguments') + name = composer.util.canonical(name) // throws ComposerError if name is not valid if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - let code = `const main=(${main})().runtime(` - for (let plugin of plugins) { - code += `{plugin:new(${plugin.constructor})()` - if (plugin.configure) code += `,config:${JSON.stringify(plugin.configure())}` - code += '},' - } - code = require('uglify-es').minify(`${code})`, { output: { max_line_len: 127 } }).code - code = `// generated by composer v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n${code}` // invoke conductor on composition - return { exec: { kind: 'nodejs:default', code }, annotations: [{ key: 'conductor', value: composition }, { key: 'composer', value: version }] } - } - - composer.util = { - // return the signatures of the combinators - get combinators() { - return combinators - }, - - // recursively deserialize composition - deserialize(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - composition = new Composition(composition) // copy - composition.visit(composition => composer.util.deserialize(composition)) - return composition - }, - - // recursively lower combinators to the desired set of combinators (including primitive combinators) - lower(composition, combinators = []) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (typeof combinators === 'string') { // lower to combinators of specific composer version - combinators = Object.keys(composer.util.combinators).filter(key => semver.gte(combinators, composer.util.combinators[key].since)) - } - if (!Array.isArray(combinators)) throw new ComposerError('Invalid argument', combinators) - - const lower = composition => { - composition = new Composition(composition) // copy - // repeatedly lower root combinator - while (combinators.indexOf(composition.type) < 0 && lowerer[composition.type]) { - const path = composition.path - composition = lowerer[composition.type](composition) - if (path !== undefined) composition.path = path // preserve path - } - // lower nested combinators - composition.visit(lower) - return composition - } - - return lower(composition) - }, - - // register plugin - register(plugin) { - if (plugin.combinators) init(plugin.combinators()) - if (plugin.composer) Object.assign(composer, plugin.composer({ composer, ComposerError, Composition })) - if (plugin.lowerer) Object.assign(lowerer, plugin.lowerer({ composer, ComposerError, Composition })) - plugins.push(plugin) - return composer - }, - - /** - * Parses a (possibly fully qualified) resource name and validates it. If it's not a fully qualified name, - * then attempts to qualify it. - * - * Examples string to namespace, [package/]action name - * foo => /_/foo - * pkg/foo => /_/pkg/foo - * /ns/foo => /ns/foo - * /ns/pkg/foo => /ns/pkg/foo - */ - canonical(name) { - if (typeof name !== 'string') throw new ComposerError('Name must be a string') - if (name.trim().length == 0) throw new ComposerError('Name is not valid') - name = name.trim() - const delimiter = '/' - const parts = name.split(delimiter) - const n = parts.length - const leadingSlash = name[0] == delimiter - // no more than /ns/p/a - if (n < 1 || n > 4 || (leadingSlash && n == 2) || (!leadingSlash && n == 4)) throw new ComposerError('Name is not valid') - // skip leading slash, all parts must be non empty (could tighten this check to match EntityName regex) - parts.forEach(function (part, i) { if (i > 0 && part.trim().length == 0) throw new ComposerError('Name is not valid') }) - const newName = parts.join(delimiter) - if (leadingSlash) return newName - else if (n < 3) return `${delimiter}_${delimiter}${newName}` - else return `${delimiter}${newName}` - }, - - // encode composition as an action table - encode(name, composition, combinators) { - if (arguments.length > 3) throw new ComposerError('Too many arguments') - name = composer.util.canonical(name) // throws ComposerError if name is not valid - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (combinators) composition = composer.util.lower(composition, combinators) - const table = flatten(composition) - table.actions.push({ name, action: synthesize(table.composition) }) - return table.actions - }, - - // return composer version - get version() { - return version - }, - - // return enhanced openwhisk client capable of deploying compositions - openwhisk(options) { - // try to extract apihost and key first from whisk property file file and then from process.env - let apihost - let api_key - - try { - const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') - const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') - - for (let line of lines) { - let parts = line.trim().split('=') - if (parts.length === 2) { - if (parts[0] === 'APIHOST') { - apihost = parts[1] - } else if (parts[0] === 'AUTH') { - api_key = parts[1] - } + if (combinators) composition = composer.util.lower(composition, combinators) + const table = flatten(composition) + table.actions.push({ name, action: synthesize(table.composition) }) + return table.actions + }, + + // return composer version + get version() { + return version + }, + + // return enhanced openwhisk client capable of deploying compositions + openwhisk(options) { + // try to extract apihost and key first from whisk property file file and then from process.env + let apihost + let api_key + + try { + const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') + const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') + + for (let line of lines) { + let parts = line.trim().split('=') + if (parts.length === 2) { + if (parts[0] === 'APIHOST') { + apihost = parts[1] + } else if (parts[0] === 'AUTH') { + api_key = parts[1] } } - } catch (error) { } - - if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST - if (process.env.__OW_API_KEY) api_key = process.env.__OW_API_KEY - - const wsk = require('openwhisk')(Object.assign({ apihost, api_key }, options)) - wsk.compositions = new Compositions(wsk) - return wsk - }, - } - - // composition class - class Composition { - // weaker instanceof to tolerate multiple instances of this class - static [Symbol.hasInstance](instance) { - return instance.constructor && instance.constructor.name === Composition.name - } - - // construct a composition object with the specified fields - constructor(composition) { - if (!isObject(composition) || composer.util.combinators[composition.type] === undefined) throw new ComposerError('Invalid argument', composition) - const combinator = composer.util.combinators[composition.type] - if (combinator.components && composition.components === undefined)throw new ComposerError('Invalid argument', composition) - for (let arg of combinator.args || []) { - if (!arg.optional && composition[arg._] === undefined) throw new ComposerError('Invalid argument', composition) } - return Object.assign(this, composition) - } + } catch (error) { } - // apply f to all fields of type composition - visit(f) { - const combinator = composer.util.combinators[this.type] - if (combinator.components) { - this.components = this.components.map(f) - } - for (let arg of combinator.args || []) { - if (arg.type === undefined && this[arg._] !== undefined) { - this[arg._] = f(this[arg._], arg._) - } - } - } - } + if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST + if (process.env.__OW_API_KEY) api_key = process.env.__OW_API_KEY + + const wsk = require('openwhisk')(Object.assign({ apihost, api_key }, options)) + wsk.compositions = new Compositions(wsk) + return wsk + }, // derive combinator methods from combinator table - function init(combinators) { + declare(combinators) { Object.assign(composer.util.combinators, combinators) for (let type in combinators) { const combinator = combinators[type] @@ -407,316 +370,354 @@ function main() { return new Composition(composition) } } - } + }, - init({ - empty: { since: '0.4.0' }, - seq: { components: true, since: '0.4.0' }, - sequence: { components: true, since: '0.4.0' }, - if: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, - if_nosave: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, - while: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, - while_nosave: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, - dowhile: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, - dowhile_nosave: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, - try: { args: [{ _: 'body' }, { _: 'handler' }], since: '0.4.0' }, - finally: { args: [{ _: 'body' }, { _: 'finalizer' }], since: '0.4.0' }, - retain: { components: true, since: '0.4.0' }, - retain_catch: { components: true, since: '0.4.0' }, - let: { args: [{ _: 'declarations', type: 'object' }], components: true, since: '0.4.0' }, - mask: { components: true, since: '0.4.0' }, - action: { args: [{ _: 'name', type: 'string' }, { _: 'action', type: 'object', optional: true }], since: '0.4.0' }, - repeat: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, - retry: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, - value: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, - literal: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, - function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' }, - async: { args: [{ _: 'body' }], since: '0.6.0' }, - }) + get lowerer() { + return lowerer + }, +} - // management class for compositions - class Compositions { - constructor(wsk) { - this.actions = wsk.actions - } +composer.util.frontend = composer.util.openwhisk - deploy(name, composition, combinators) { - const actions = composer.util.encode(name, composition, combinators) - return actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) - .then(() => this.actions.update(action)), Promise.resolve()) - .then(() => actions) +// composition class +class Composition { + // weaker instanceof to tolerate multiple instances of this class + static [Symbol.hasInstance](instance) { + return instance.constructor && instance.constructor.name === Composition.name + } + + // construct a composition object with the specified fields + constructor(composition) { + if (!isObject(composition) || composer.util.combinators[composition.type] === undefined) throw new ComposerError('Invalid argument', composition) + const combinator = composer.util.combinators[composition.type] + if (combinator.components && composition.components === undefined) throw new ComposerError('Invalid argument', composition) + for (let arg of combinator.args || []) { + if (!arg.optional && composition[arg._] === undefined) throw new ComposerError('Invalid argument', composition) } + return Object.assign(this, composition) } - // runtime stuff - function runtime() { - // recursively label combinators with the json path - function label(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - - const label = path => (composition, name, array) => { - composition = new Composition(composition) // copy - composition.path = path + (name !== undefined ? (array === undefined ? `.${name}` : `[${name}]`) : '') - // label nested combinators - composition.visit(label(composition.path)) - return composition + // apply f to all fields of type composition + visit(f) { + const combinator = composer.util.combinators[this.type] + if (combinator.components) { + this.components = this.components.map(f) + } + for (let arg of combinator.args || []) { + if (arg.type === undefined && this[arg._] !== undefined) { + this[arg._] = f(this[arg._], arg._) } - - return label('')(composition) } + } +} - // compile ast to fsm - const compiler = { - sequence(node) { - return [{ type: 'pass', path: node.path }, ...compile(...node.components)] - }, - - action(node) { - return [{ type: 'action', name: node.name, path: node.path }] - }, - - async(node) { - const body = compile(node.body) - return [{ type: 'async', path: node.path, return: body.length + 2 }, ...body, { type: 'stop' }, { type: 'pass' }] - }, - - function(node) { - return [{ type: 'function', exec: node.function.exec, path: node.path }] - }, - - finally(node) { - const finalizer = compile(node.finalizer) - const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...finalizer] - fsm[0].catch = fsm.length - finalizer.length - return fsm - }, - - let(node) { - return [{ type: 'let', let: node.declarations, path: node.path }, ...compile(...node.components), { type: 'exit' }] - }, - - mask(node) { - return [{ type: 'let', let: null, path: node.path }, ...compile(...node.components), { type: 'exit' }] - }, - - try(node) { - const handler = [...compile(node.handler), { type: 'pass' }] - const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...handler] - fsm[0].catch = fsm.length - handler.length - fsm[fsm.length - handler.length - 1].next = handler.length - return fsm - }, - - if_nosave(node) { - const consequent = compile(node.consequent) - const alternate = [...compile(node.alternate), { type: 'pass' }] - const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: consequent.length + 1 }, ...consequent, ...alternate] - fsm[fsm.length - alternate.length - 1].next = alternate.length - return fsm - }, - - while_nosave(node) { - const body = compile(node.body) - const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: body.length + 1 }, ...body, { type: 'pass' }] - fsm[fsm.length - 2].next = 2 - fsm.length - return fsm - }, - - dowhile_nosave(node) { - const fsm = [{ type: 'pass', path: node.path }, ...compile(node.body), ...compile(node.test), { type: 'choice', else: 1 }, { type: 'pass' }] - fsm[fsm.length - 2].then = 2 - fsm.length - return fsm - }, - } +Composition.composer = composer + +composer.util.declare({ + empty: { since: '0.4.0' }, + seq: { components: true, since: '0.4.0' }, + sequence: { components: true, since: '0.4.0' }, + if: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, + if_nosave: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, + while: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, + while_nosave: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, + dowhile: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, + dowhile_nosave: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, + try: { args: [{ _: 'body' }, { _: 'handler' }], since: '0.4.0' }, + finally: { args: [{ _: 'body' }, { _: 'finalizer' }], since: '0.4.0' }, + retain: { components: true, since: '0.4.0' }, + retain_catch: { components: true, since: '0.4.0' }, + let: { args: [{ _: 'declarations', type: 'object' }], components: true, since: '0.4.0' }, + mask: { components: true, since: '0.4.0' }, + action: { args: [{ _: 'name', type: 'string' }, { _: 'action', type: 'object', optional: true }], since: '0.4.0' }, + repeat: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, + retry: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, + value: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, + literal: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, + function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' }, + async: { args: [{ _: 'body' }], since: '0.6.0' }, +}) + +// management class for compositions +class Compositions { + constructor(wsk) { + this.actions = wsk.actions + } - function compile(node) { - if (arguments.length === 0) return [{ type: 'empty' }] - if (arguments.length === 1) return compiler[node.type](node) - return Array.prototype.reduce.call(arguments, (fsm, node) => { fsm.push(...compile(node)); return fsm }, []) - } + deploy({ name, composition, combinators }) { + const actions = composer.util.encode(name, composition, combinators) + return actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) + .then(() => this.actions.update(action)), Promise.resolve()) + .then(() => actions) + } +} - const openwhisk = require('openwhisk') - let wsk - - const conductor = { - choice({ p, node, index }) { - p.s.state = index + (p.params.value ? node.then : node.else) - }, - - try({ p, node, index }) { - p.s.stack.unshift({ catch: index + node.catch }) - }, - - let({ p, node, index }) { - p.s.stack.unshift({ let: JSON.parse(JSON.stringify(node.let)) }) - }, - - exit({ p, node, index }) { - if (p.s.stack.length === 0) return internalError(`State ${index} attempted to pop from an empty stack`) - p.s.stack.shift() - }, - - action({ p, node, index }) { - return { action: node.name, params: p.params, state: { $resume: p.s } } - }, - - function({ p, node, index }) { - return Promise.resolve().then(() => run(node.exec.code, p)) - .catch(error => { - console.error(error) - return { error: `An exception was caught at state ${index} (see log for details)` } - }) - .then(result => { - if (typeof result === 'function') result = { error: `State ${index} evaluated to a function` } - // if a function has only side effects and no return value, return params - p.params = JSON.parse(JSON.stringify(result === undefined ? p.params : result)) - inspect(p) - return step(p) - }) - }, - - empty({ p, node, index }) { - inspect(p) - }, - - pass({ p, node, index }) { - }, - - async({ p, node, index, inspect, step }) { - if (!wsk) wsk = openwhisk({ ignore_certs: true }) - p.params.$resume = { state: p.s.state } - p.s.state = index + node.return - return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) - .catch(error => { - console.error(error) - return { error: `An exception was caught at state ${index} (see log for details)` } - }) - .then(result => { - p.params = result - inspect(p) - return step(p) - }) - }, - - stop({ p, node, index, inspect, step }) { - p.s.state = -1 - }, - } +// recursively label combinators with the json path +function label(composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments') + if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) + const label = path => (composition, name, array) => { + composition = new Composition(composition) // copy + composition.path = path + (name !== undefined ? (array === undefined ? `.${name}` : `[${name}]`) : '') + // label nested combinators + composition.visit(label(composition.path)) + return composition + } - const finishers = [] + return label('')(composition) +} - for (let { plugin, config } of arguments) { - composer.util.register(plugin) - if (plugin.compiler) Object.assign(compiler, plugin.compiler({ compile })) - if (plugin.conductor) { - Object.assign(conductor, plugin.conductor(config)) - if (conductor._finish) { - finishers.push(conductor._finish) - delete conductor._finish - } +// runtime code +function main() { + const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) + + // compile ast to fsm + const compiler = { + sequence(node) { + return [{ type: 'pass', path: node.path }, ...compile(...node.components)] + }, + + action(node) { + return [{ type: 'action', name: node.name, path: node.path }] + }, + + async(node) { + const body = compile(node.body) + return [{ type: 'async', path: node.path, return: body.length + 2 }, ...body, { type: 'stop' }, { type: 'pass' }] + }, + + function(node) { + return [{ type: 'function', exec: node.function.exec, path: node.path }] + }, + + finally(node) { + const finalizer = compile(node.finalizer) + const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...finalizer] + fsm[0].catch = fsm.length - finalizer.length + return fsm + }, + + let(node) { + return [{ type: 'let', let: node.declarations, path: node.path }, ...compile(...node.components), { type: 'exit' }] + }, + + mask(node) { + return [{ type: 'let', let: null, path: node.path }, ...compile(...node.components), { type: 'exit' }] + }, + + try(node) { + const handler = [...compile(node.handler), { type: 'pass' }] + const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...handler] + fsm[0].catch = fsm.length - handler.length + fsm[fsm.length - handler.length - 1].next = handler.length + return fsm + }, + + if_nosave(node) { + const consequent = compile(node.consequent) + const alternate = [...compile(node.alternate), { type: 'pass' }] + const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: consequent.length + 1 }, ...consequent, ...alternate] + fsm[fsm.length - alternate.length - 1].next = alternate.length + return fsm + }, + + while_nosave(node) { + const body = compile(node.body) + const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: body.length + 1 }, ...body, { type: 'pass' }] + fsm[fsm.length - 2].next = 2 - fsm.length + return fsm + }, + + dowhile_nosave(node) { + const fsm = [{ type: 'pass', path: node.path }, ...compile(node.body), ...compile(node.test), { type: 'choice', else: 1 }, { type: 'pass' }] + fsm[fsm.length - 2].then = 2 - fsm.length + return fsm + }, + } + + function compile(node) { + if (arguments.length === 0) return [{ type: 'empty' }] + if (arguments.length === 1) return compiler[node.type](node) + return Array.prototype.reduce.call(arguments, (fsm, node) => { fsm.push(...compile(node)); return fsm }, []) + } + + const openwhisk = require('openwhisk') + let wsk + + const conductor = { + choice({ p, node, index }) { + p.s.state = index + (p.params.value ? node.then : node.else) + }, + + try({ p, node, index }) { + p.s.stack.unshift({ catch: index + node.catch }) + }, + + let({ p, node, index }) { + p.s.stack.unshift({ let: JSON.parse(JSON.stringify(node.let)) }) + }, + + exit({ p, node, index }) { + if (p.s.stack.length === 0) return internalError(`State ${index} attempted to pop from an empty stack`) + p.s.stack.shift() + }, + + action({ p, node, index }) { + return { action: node.name, params: p.params, state: { $resume: p.s } } + }, + + function({ p, node, index }) { + return Promise.resolve().then(() => run(node.exec.code, p)) + .catch(error => { + console.error(error) + return { error: `An exception was caught at state ${index} (see log for details)` } + }) + .then(result => { + if (typeof result === 'function') result = { error: `State ${index} evaluated to a function` } + // if a function has only side effects and no return value, return params + p.params = JSON.parse(JSON.stringify(result === undefined ? p.params : result)) + inspect(p) + return step(p) + }) + }, + + empty({ p, node, index }) { + inspect(p) + }, + + pass({ p, node, index }) { + }, + + async({ p, node, index, inspect, step }) { + if (!wsk) wsk = openwhisk({ ignore_certs: true }) + p.params.$resume = { state: p.s.state } + p.s.state = index + node.return + return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) + .catch(error => { + console.error(error) + return { error: `An exception was caught at state ${index} (see log for details)` } + }) + .then(result => { + p.params = result + inspect(p) + return step(p) + }) + }, + + stop({ p, node, index, inspect, step }) { + p.s.state = -1 + }, + } + + const finishers = [] + + for (let { plugin, config } of arguments) { + if (plugin.compiler) Object.assign(compiler, plugin.compiler({ compile })) + if (plugin.conductor) { + Object.assign(conductor, plugin.conductor(config)) + if (conductor._finish) { + finishers.push(conductor._finish) + delete conductor._finish } } + } - const fsm = compile(composer.util.lower(label(composer.util.deserialize(composition)))) - - // encode error object - const encodeError = error => ({ - code: typeof error.code === 'number' && error.code || 500, - error: (typeof error.error === 'string' && error.error) || error.message || (typeof error === 'string' && error) || 'An internal error occurred' - }) - - // error status codes - const badRequest = error => Promise.reject({ code: 400, error }) - const internalError = error => Promise.reject(encodeError(error)) - - // wrap params if not a dictionary, branch to error handler if error - function inspect(p) { - if (!isObject(p.params)) p.params = { value: p.params } - if (p.params.error !== undefined) { - p.params = { error: p.params.error } // discard all fields but the error field - p.s.state = -1 // abort unless there is a handler in the stack - while (p.s.stack.length > 0) { - if ((p.s.state = p.s.stack.shift().catch || -1) >= 0) break - } + const fsm = compile(composition) + + // encode error object + const encodeError = error => ({ + code: typeof error.code === 'number' && error.code || 500, + error: (typeof error.error === 'string' && error.error) || error.message || (typeof error === 'string' && error) || 'An internal error occurred' + }) + + // error status codes + const badRequest = error => Promise.reject({ code: 400, error }) + const internalError = error => Promise.reject(encodeError(error)) + + // wrap params if not a dictionary, branch to error handler if error + function inspect(p) { + if (!isObject(p.params)) p.params = { value: p.params } + if (p.params.error !== undefined) { + p.params = { error: p.params.error } // discard all fields but the error field + p.s.state = -1 // abort unless there is a handler in the stack + while (p.s.stack.length > 0) { + if ((p.s.state = p.s.stack.shift().catch || -1) >= 0) break } } + } - // run function f on current stack - function run(f, p) { - // handle let/mask pairs - const view = [] - let n = 0 - for (let frame of p.s.stack) { - if (frame.let === null) { - n++ - } else if (frame.let !== undefined) { - if (n === 0) { - view.push(frame) - } else { - n-- - } + // run function f on current stack + function run(f, p) { + // handle let/mask pairs + const view = [] + let n = 0 + for (let frame of p.s.stack) { + if (frame.let === null) { + n++ + } else if (frame.let !== undefined) { + if (n === 0) { + view.push(frame) + } else { + n-- } } + } - // update value of topmost matching symbol on stack if any - function set(symbol, value) { - const element = view.find(element => element.let !== undefined && element.let[symbol] !== undefined) - if (element !== undefined) element.let[symbol] = JSON.parse(JSON.stringify(value)) - } - - // collapse stack for invocation - const env = view.reduceRight((acc, cur) => cur.let ? Object.assign(acc, cur.let) : acc, {}) - let main = '(function(){try{' - for (const name in env) main += `var ${name}=arguments[1]['${name}'];` - main += `return eval((${f}))(arguments[0])}finally{` - for (const name in env) main += `arguments[1]['${name}']=${name};` - main += '}})' - try { - return (1, eval)(main)(p.params, env) - } finally { - for (const name in env) set(name, env[name]) - } + // update value of topmost matching symbol on stack if any + function set(symbol, value) { + const element = view.find(element => element.let !== undefined && element.let[symbol] !== undefined) + if (element !== undefined) element.let[symbol] = JSON.parse(JSON.stringify(value)) } - function step(p) { - // final state, return composition result - if (p.s.state < 0 || p.s.state >= fsm.length) { - console.log(`Entering final state`) - console.log(JSON.stringify(p.params)) - return finishers.reduce((promise, _finish) => promise.then(() => _finish(p)), Promise.resolve()) - .then(() => p.params.error ? p.params : { params: p.params }) - } + // collapse stack for invocation + const env = view.reduceRight((acc, cur) => cur.let ? Object.assign(acc, cur.let) : acc, {}) + let main = '(function(){try{' + for (const name in env) main += `var ${name}=arguments[1]['${name}'];` + main += `return eval((${f}))(arguments[0])}finally{` + for (const name in env) main += `arguments[1]['${name}']=${name};` + main += '}})' + try { + return (1, eval)(main)(p.params, env) + } finally { + for (const name in env) set(name, env[name]) + } + } - // process one state - const node = fsm[p.s.state] // json definition for index state - if (node.path !== undefined) console.log(`Entering composition${node.path}`) - const index = p.s.state // current state - p.s.state = p.s.state + (node.next || 1) // default next state - return conductor[node.type]({ p, index, node, inspect, step }) || step(p) + function step(p) { + // final state, return composition result + if (p.s.state < 0 || p.s.state >= fsm.length) { + console.log(`Entering final state`) + console.log(JSON.stringify(p.params)) + return finishers.reduce((promise, _finish) => promise.then(() => _finish(p)), Promise.resolve()) + .then(() => p.params.error ? p.params : { params: p.params }) } - return params => Promise.resolve().then(() => invoke(params)).catch(internalError) + // process one state + const node = fsm[p.s.state] // json definition for index state + if (node.path !== undefined) console.log(`Entering composition${node.path}`) + const index = p.s.state // current state + p.s.state = p.s.state + (node.next || 1) // default next state + return conductor[node.type]({ p, index, node, inspect, step }) || step(p) + } - // do invocation - function invoke(params) { - const p = { s: { state: 0, stack: [] }, params } // initial state + return params => Promise.resolve().then(() => invoke(params)).catch(internalError) - if (params.$resume !== undefined) { - if (!isObject(params.$resume)) return badRequest('The type of optional $resume parameter must be object') - const resuming = params.$resume.stack - Object.assign(p.s, params.$resume) - if (typeof p.s.state !== 'number') return badRequest('The type of optional $resume.state parameter must be number') - if (!Array.isArray(p.s.stack)) return badRequest('The type of optional $resume.stack parameter must be an array') - delete params.$resume - if (resuming) inspect(p) // handle error objects when resuming - } + // do invocation + function invoke(params) { + const p = { s: { state: 0, stack: [] }, params } // initial state - return step(p) + if (params.$resume !== undefined) { + if (!isObject(params.$resume)) return badRequest('The type of optional $resume parameter must be object') + const resuming = params.$resume.stack + Object.assign(p.s, params.$resume) + if (typeof p.s.state !== 'number') return badRequest('The type of optional $resume.state parameter must be number') + if (!Array.isArray(p.s.stack)) return badRequest('The type of optional $resume.stack parameter must be an array') + delete params.$resume + if (resuming) inspect(p) // handle error objects when resuming } - } - return { composer, runtime } + return step(p) + } } -module.exports = main().composer +module.exports = composer diff --git a/docs/COMPOSE.md b/docs/COMPOSE.md index a1c1f03..5513735 100644 --- a/docs/COMPOSE.md +++ b/docs/COMPOSE.md @@ -199,7 +199,7 @@ The `--deploy` option makes it possible to deploy a composition (Javascript or J compose demo.js --deploy demo ``` ``` -ok: created actions /_/authenticate,/_/success,/_/failure,/_/demo +ok: created /_/authenticate,/_/success,/_/failure,/_/demo ``` Or: ``` @@ -207,7 +207,7 @@ compose demo.js > demo.json compose demo.json --deploy demo ``` ``` -ok: created actions /_/authenticate,/_/success,/_/failure,/_/demo +ok: created /_/authenticate,/_/success,/_/failure,/_/demo ``` The `compose` command synthesizes and deploys a conductor action that implements the composition with the given name. It also deploys the composed actions for which diff --git a/docs/COMPOSER.md b/docs/COMPOSER.md index cf76add..68bf8eb 100644 --- a/docs/COMPOSER.md +++ b/docs/COMPOSER.md @@ -27,7 +27,7 @@ const composition = composer.if( // instantiate OpenWhisk client const wsk = composer.util.openwhisk({ ignore_certs: true }) -wsk.compositions.deploy('demo', composition) // deploy composition +wsk.compositions.deploy({ name: 'demo', composition }) // deploy composition .then(() => wsk.actions.invoke({ name: 'demo', params: { password: 'abc123' }, blocking: true })) // invoke composition .then(({ response }) => console.log(JSON.stringify(response.result, null, 4)), console.error) ``` @@ -92,7 +92,7 @@ The `composer` module adds to the OpenWhisk client instance a new top-level cate ### Deploying compositions -`wsk.compositions.deploy(name, composition, [combinators])` optionally lowers, encodes, and deploys the composition `composition`. More precisely, it successively deploys all the actions defined in `composition` as well as `composition` itself (encoded as a conductor action). +`wsk.compositions.deploy({ name, composition, [combinators] })` optionally lowers, encodes, and deploys the composition `composition`. More precisely, it successively deploys all the actions defined in `composition` as well as `composition` itself (encoded as a conductor action). The optional `combinators` parameter controls the optional lowering. See [lower](#lower) for details. diff --git a/docs/TEMPLATES.md b/docs/TEMPLATES.md index b6df123..0d61b56 100644 --- a/docs/TEMPLATES.md +++ b/docs/TEMPLATES.md @@ -77,7 +77,7 @@ composer.apply('payload', p => { p.n++ }) ``` compose example.js --deploy example -ok: created action /_/example +ok: created /_/example ``` ``` wsk action invoke example -r -p payload '{"n":1,"p":42}' diff --git a/samples/node-demo.js b/samples/node-demo.js index 62a986d..f223cc4 100644 --- a/samples/node-demo.js +++ b/samples/node-demo.js @@ -26,6 +26,6 @@ const composition = composer.if( // instantiate OpenWhisk client const wsk = composer.util.openwhisk({ ignore_certs: true }) -wsk.compositions.deploy('demo', composition) // deploy composition +wsk.compositions.deploy({ name: 'demo', composition }) // deploy composition .then(() => wsk.actions.invoke({ name: 'demo', params: { password: 'abc123' }, blocking: true })) // invoke composition .then(({ response }) => console.log(JSON.stringify(response.result, null, 4)), console.error) diff --git a/test/test.js b/test/test.js index d0ba083..8d72a4f 100644 --- a/test/test.js +++ b/test/test.js @@ -7,7 +7,7 @@ const wsk = composer.util.openwhisk({ ignore_certs: process.env.IGNORE_CERTS && const define = action => wsk.actions.delete(action.name).catch(() => { }).then(() => wsk.actions.create(action)) // deploy and invoke composition -const invoke = (composition, params = {}, blocking = true) => wsk.compositions.deploy(name, composition).then(() => wsk.actions.invoke({ name, params, blocking })) +const invoke = (composition, params = {}, blocking = true) => wsk.compositions.deploy({ name, composition }).then(() => wsk.actions.invoke({ name, params, blocking })) describe('composer', function () { this.timeout(60000) From cc814ff38a29d4750a835b60a55ca0e8eb241a4a Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 27 Jun 2018 11:33:40 -0400 Subject: [PATCH 23/94] 0.7.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 05e3cf4..7dad465 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.6.1", + "version": "0.7.0", "description": "Composer is an IBM Cloud Functions programming model for composing individual functions into larger applications.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From eb8d236ff0f7b867acc28de94697b2a2ba9822fd Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 27 Jun 2018 23:05:48 -0400 Subject: [PATCH 24/94] Always recognize 401 and 403 status codes (#64) --- bin/compose | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/bin/compose b/bin/compose index 0139fd9..0110160 100755 --- a/bin/compose +++ b/bin/compose @@ -71,17 +71,15 @@ try { console.log(`ok: created ${names}`) }) .catch(error => { - if (error.constructor && error.constructor.name === 'OpenWhiskError') { - switch (error.statusCode) { - case 401: - console.error('Authentication failure') - if (!argv.quiet) console.log(error) - process.exit(2) - case 403: - console.error('Authorization failure') - if (!argv.quiet) console.log(error) - process.exit(3) - } + switch (error.statusCode) { + case 401: + console.error('Authentication failure') + if (!argv.quiet) console.log(error) + process.exit(2) + case 403: + console.error('Authorization failure') + if (!argv.quiet) console.log(error) + process.exit(3) } console.error('Server error') if (!argv.quiet) console.log(error) From f75410f49bb83b989b06bb21d0c2743931f5e8a7 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 1 Oct 2018 17:32:46 -0400 Subject: [PATCH 25/94] Prepare composer for Apache handoff (#66) * Prep work for new release * Update setup.sh * Update .gitignore * Ignore certs in async invoke for now * Replace uglify-es with terser * Bump standard version to 12.0.1 * Delete outdated content. Update documentation. --- .gitignore | 1 + .travis.yml | 1 - CLA-CORPORATE.md | 56 - CLA-INDIVIDUAL.md | 44 - CONTRIBUTING.md | 38 - README.md | 132 +-- bin/compose | 101 -- bin/compose.js | 70 ++ bin/deploy.js | 99 ++ composer.js | 971 ++++++------------ conductor.js | 321 ++++++ docs/COMBINATORS.md | 312 ++++-- docs/COMMANDS.md | 99 ++ docs/COMPOSE.md | 260 ----- docs/COMPOSER.md | 109 -- docs/COMPOSITIONS.md | 79 +- docs/FORMAT.md | 60 -- docs/README.md | 13 +- docs/TEMPLATES.md | 115 --- docs/tutorials/README.md | 10 - docs/tutorials/introduction/README.md | 468 --------- docs/tutorials/introduction/editor.png | Bin 57283 -> 0 bytes .../introduction/hello-composition.png | Bin 45011 -> 0 bytes docs/tutorials/introduction/hello-session.png | Bin 58771 -> 0 bytes docs/tutorials/introduction/if-preview.png | Bin 48774 -> 0 bytes docs/tutorials/introduction/preview.png | Bin 279539 -> 0 bytes docs/tutorials/introduction/retain.png | Bin 55681 -> 0 bytes docs/tutorials/introduction/try-session.png | Bin 59975 -> 0 bytes docs/tutorials/translateBot/README.md | 260 ----- docs/tutorials/translateBot/finishedBot.png | Bin 58568 -> 0 bytes docs/tutorials/translateBot/hello_bot.png | Bin 88194 -> 0 bytes docs/tutorials/translateBot/mySlackApp.png | Bin 208733 -> 0 bytes .../translateBot/myTranslateApp-edit.png | Bin 120049 -> 0 bytes package.json | 17 +- samples/demo-conductor.js | 105 -- samples/demo.js | 8 +- samples/demo.json | 158 ++- samples/node-demo.js | 31 - test/composer.js | 416 ++++++++ test/conductor.js | 591 +++++++++++ test/test.js | 559 ---------- travis/runtimes.json | 30 + travis/setup.sh | 8 +- 43 files changed, 2407 insertions(+), 3135 deletions(-) delete mode 100644 CLA-CORPORATE.md delete mode 100644 CLA-INDIVIDUAL.md delete mode 100644 CONTRIBUTING.md delete mode 100755 bin/compose create mode 100755 bin/compose.js create mode 100755 bin/deploy.js create mode 100644 conductor.js create mode 100644 docs/COMMANDS.md delete mode 100644 docs/COMPOSE.md delete mode 100644 docs/COMPOSER.md delete mode 100644 docs/FORMAT.md delete mode 100644 docs/TEMPLATES.md delete mode 100644 docs/tutorials/README.md delete mode 100644 docs/tutorials/introduction/README.md delete mode 100644 docs/tutorials/introduction/editor.png delete mode 100644 docs/tutorials/introduction/hello-composition.png delete mode 100644 docs/tutorials/introduction/hello-session.png delete mode 100644 docs/tutorials/introduction/if-preview.png delete mode 100644 docs/tutorials/introduction/preview.png delete mode 100644 docs/tutorials/introduction/retain.png delete mode 100644 docs/tutorials/introduction/try-session.png delete mode 100644 docs/tutorials/translateBot/README.md delete mode 100644 docs/tutorials/translateBot/finishedBot.png delete mode 100644 docs/tutorials/translateBot/hello_bot.png delete mode 100644 docs/tutorials/translateBot/mySlackApp.png delete mode 100644 docs/tutorials/translateBot/myTranslateApp-edit.png delete mode 100644 samples/demo-conductor.js delete mode 100644 samples/node-demo.js create mode 100644 test/composer.js create mode 100644 test/conductor.js delete mode 100644 test/test.js create mode 100644 travis/runtimes.json diff --git a/.gitignore b/.gitignore index 3c3629e..ef84937 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +openwhisk diff --git a/.travis.yml b/.travis.yml index c13ce0b..2d444b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,5 @@ services: env: global: - IGNORE_CERTS=true - - REDIS=redis://172.17.0.1:6379 before_script: - ./travis/setup.sh diff --git a/CLA-CORPORATE.md b/CLA-CORPORATE.md deleted file mode 100644 index 952896b..0000000 --- a/CLA-CORPORATE.md +++ /dev/null @@ -1,56 +0,0 @@ -# International Business Machines, Inc. (IBM) -### Software Grant and Corporate Contributor License Agreement ("Agreement") - -https://github.com/ibm-functions/composer/ - -Thank you for your interest in IBM’s Composer project ("the Project"). - -In order to clarify the intellectual property license granted with Contributions from any person or entity, IBM must have a Contributor License Agreement (CLA) on file that has been signed by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of IBM and its users; it does not change your rights to use your own Contributions for any other purpose. - -This version of the Agreement allows an entity (the "Corporation") to submit Contributions to the Project, to authorize Contributions submitted by its designated employees to the Project, and to grant copyright and patent licenses thereto. - -If you have not already done so, please complete and sign, then scan and email a pdf file of this Agreement to tardieu@us.ibm.com. If necessary, send an original signed agreement to: - - IBM Corporation, 1101 Kitchawan Rd Route 134 / PO Box 218 Yorktown Heights, NY 10598 Attn: Olivier Tardieu - -Please read this document carefully before signing and keep a copy for your records. - - Corporation name: - Corporation address: - Point of Contact: - E-Mail: - Telephone: - -You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the Project. Except for the license granted herein to IBM and recipients of software distributed by IBM, You reserve all right, title, and interest in and to Your Contributions. - -1. Definitions. - "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with IBM. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - "Contribution" shall mean the code, documentation or other original works of authorship expressly identified in Schedule B, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to IBM for inclusion in, or documentation of, the Project managed by IBM (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to IBM or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, IBM for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." - -2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to IBM and to recipients of software distributed by IBM a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. - -3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to IBM and to recipients of software distributed by IBM a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) were submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. - -4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated on Schedule A below (or in a subsequent written modification to that Schedule) is authorized to submit Contributions on behalf of the Corporation. - -5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). - -6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. - -7. Should You wish to submit work that is not Your original creation, You may submit it to IBM separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]". - -8. It is your responsibility to notify IBM when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with IBM. - -Please sign and date: ______________________________________________________________ - - Title: - Corporation: - -Schedule A - -[Initial list of designated employees. NB: authorization is not tied to particular Contributions.] - -Schedule B - -[Identification of optional concurrent software grant. Would be left blank or omitted if there is no concurrent software grant.] - diff --git a/CLA-INDIVIDUAL.md b/CLA-INDIVIDUAL.md deleted file mode 100644 index 7846733..0000000 --- a/CLA-INDIVIDUAL.md +++ /dev/null @@ -1,44 +0,0 @@ -# International Business Machines, Inc. (IBM) -### Individual Contributor License Agreement ("Agreement") - -https://github.com/ibm-functions/composer/ - -Thank you for your interest in the Composer project ("the Project"). - -In order to clarify the intellectual property license granted with Contributions from any person or entity, IBM must have a Contributor License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of IBM and its customers; it does not change your rights to use your own Contributions for any other purpose. - -If you have not already done so, please complete and sign, then scan and email a pdf file of this Agreement to tardieu@us.ibm.com. If necessary, send an original signed agreement to: - - IBM Corporation, 1101 Kitchawan Rd Route 134 / PO Box 218 Yorktown Heights, NY 10598 Attn: Olivier Tardieu - -Please read this document carefully before signing and keep a copy for your records. - - Full name: - GitHub Username: - Address: - Country: - E-Mail: - Telephone: - -You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the Project. Except for the license granted herein to IBM and recipients of software distributed by IBM, You reserve all right, title, and interest in and to Your Contributions. - -1. Definitions. - "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with IBM. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to the Project for inclusion in, or documentation of, the Project (”the Work”). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Project or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." - -2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to IBM and to recipients of software distributed by IBM a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. - -3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to IBM and to recipients of software distributed by IBM a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work to which Your Contribution(s) were submitted, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. - -4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to the Project, or that your employer has executed a separate Corporate CLA with IBM. - -5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions. - -6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. - -7. Should You wish to submit work that is not Your original creation, You may submit it to the Project separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]". - -8. You agree to notify IBM of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect. - -Please sign and date: ______________________________________________________________ - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index be6a15b..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,38 +0,0 @@ -# Contributing to Composer - -We welcome contributions, but request you follow these guidelines. - - - [Raising issues](#raising-issues) - - [Contributor License Agreement](#contributor-license-agreement) - - [Coding Standards](#coding-standards) - -## Raising issues - -Please raise any bug reports on the issue tracker. Be sure to -search the list to see if your issue has already been raised. - -A good bug report is one that make it easy for us to understand what you were -trying to do and what went wrong. Provide as much context as possible so we can try to recreate the issue. - - -### Contributor License Agreement - -In order for us to accept pull-requests, the contributor must first complete -a Contributor License Agreement (CLA). This clarifies the intellectual -property license granted with any contribution. It is for your protection as a -Contributor as well as the protection of IBM and its clients; it does not -change your rights to use your own Contributions for any other purpose. - -You can download the CLAs here: - -- [individual](CLA-INDIVIDUAL.md) -- [corporate](CLA-CORPORATE.md) - - -### Coding standards - -Please ensure you follow the coding standards used throughout the existing -code base. Some basic rules include: - - - all files must have the Apache license in the header. - - all PRs must have passing builds for all operating systems. diff --git a/README.md b/README.md index a1e1637..a86afb2 100644 --- a/README.md +++ b/README.md @@ -5,56 +5,33 @@ [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) -Composer is a new programming model from [IBM -Research](https://ibm.biz/serverless-research) for composing [IBM Cloud -Functions](https://ibm.biz/openwhisk), built on [Apache -OpenWhisk](https://github.com/apache/incubator-openwhisk). With Composer, -developers can build even more serverless applications including using it for -IoT, with workflow orchestration, conversation services, and devops automation, -to name a few examples. - -Programming compositions for IBM Cloud Functions is supported by a new developer -tool called [IBM Cloud Shell](https://github.com/ibm-functions/shell), or just -_Shell_. Shell offers a CLI and graphical interface for fast, incremental, -iterative, and local development of serverless applications. While we recommend -using Shell, Shell is not required to work with compositions. Compositions may -be managed using a combination of the Composer [compose](docs/COMPOSE.md) command -(for deployment) and the [OpenWhisk -CLI](https://console.bluemix.net/openwhisk/learn/cli) (for configuration, -invocation, and life-cycle management). - -**In contrast to earlier releases of Composer, a Redis server is not required to -run compositions**. Composer now synthesizes OpenWhisk [conductor +Composer is a new programming model for composing cloud functions built on +[Apache OpenWhisk](https://github.com/apache/incubator-openwhisk). With +Composer, developers can build even more serverless applications including using +it for IoT, with workflow orchestration, conversation services, and devops +automation, to name a few examples. + +Composer synthesizes OpenWhisk [conductor actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) to implement compositions. Compositions have all the attributes and capabilities -of an action (e.g., default parameters, limits, blocking invocation, web -export). +of an action, e.g., default parameters, limits, blocking invocation, web export. This repository includes: -* the [composer](docs/COMPOSER.md) Node.js module for authoring compositions using +* the [composer](composer.js) Node.js module for authoring compositions using JavaScript, -* the [compose](docs/COMPOSE.md) command for deploying compositions, +* the [compose](bin/compose.js) and [deploy](bin/deploy.js) + [commands](docs/COMMANDS.md) for compiling and deploying compositions, * [documentation](docs), [examples](samples), and [tests](test). -Composer and Shell are currently available as _IBM Research previews_. As -Composer and Shell continue to evolve, it may be necessary to redeploy existing -compositions to take advantage of new capabilities. However existing -compositions should continue to run fine without redeployment. - ## Installation Composer is distributed as Node.js package. To install this package, use the Node Package Manager: ``` -npm install @ibm-functions/composer -``` -We recommend to also install the package globally (with `-g` option) if you intend to -use the `compose` command to define and deploy compositions. +npm install -g @ibm-functions/composer ``` -npm -g install @ibm-functions/composer -``` -Shell embeds the Composer package, so there is no need to install -Composer explicitly when using Shell. +We recommend to install the package globally (with `-g` option) if you intend to +use the `compose` and `deploy` commands to compile and deploy compositions. ## Defining a composition @@ -68,13 +45,13 @@ module.exports = composer.if( composer.action('success', { action: function () { return { message: 'success' } } }), composer.action('failure', { action: function () { return { message: 'failure' } } })) ``` -Compositions compose actions using _combinator_ methods. These methods -implement the typical control-flow constructs of a sequential imperative -programming language. This example composition composes three actions named -`authenticate`, `success`, and `failure` using the `composer.if` combinator, -which implements the usual conditional construct. It take three actions (or -compositions) as parameters. It invokes the first one and, depending on the -result of this invocation, invokes either the second or third action. +Compositions compose actions using [combinator](docs/COMBINATORS.md) methods. +These methods implement the typical control-flow constructs of a sequential +imperative programming language. This example composition composes three actions +named `authenticate`, `success`, and `failure` using the `composer.if` +combinator, which implements the usual conditional construct. It take three +actions (or compositions) as parameters. It invokes the first one and, depending +on the result of this invocation, invokes either the second or third action. This composition includes the definitions of the three composed actions. If the actions are defined and deployed elsewhere, the composition code can be shorten @@ -85,16 +62,19 @@ composer.if('authenticate', 'success', 'failure') ## Deploying a composition -One way to deploy a composition is to use the [compose](docs/COMPOSE.md) command: +One way to deploy a composition is to use the `compose` and `deploy` commands: ``` -compose demo.js --deploy demo +compose demo.js > demo.json +deploy demo demo.json -w ``` ``` ok: created /_/authenticate,/_/success,/_/failure,/_/demo ``` -The `compose` command synthesizes and deploys an action named `demo` that -implements the composition. It also deploys the composed actions if definitions -are provided for them. +The `compose` command compiles the composition code to a portable JSON format. +The `deploy` command deploys the JSON-encoded composition creating an action +with the given name. It also deploys the composed actions if definitions are +provided for them. The `-w` option authorizes the `deploy` command to overwrite +existing definitions. ## Running a composition @@ -116,7 +96,7 @@ wsk activation result 4f91f9ed0d874aaa91f9ed0d87baaa07 "message": "failure" } ``` -## Execution traces +### Execution traces This invocation creates a trace, i.e., a series of activation records: ``` @@ -143,55 +123,3 @@ Compositions are implemented by means of OpenWhisk conductor actions. The [documentation of conductor actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) explains execution traces in greater details. - -## Getting started -* [Introduction to Serverless - Composition](docs/tutorials/introduction/README.md): Setting up your - programming environment and getting started with Shell and Composer. -* [Building a Translation Slack Bot with Serverless - Composition](docs/tutorials/translateBot/README.md): A more advanced tutorial - using Composition to build a serverless Slack chatbot that does language - translation. -* [Composer Reference](docs/README.md): A comprehensive reference manual for the - Node.js programmer. - -## Videos -* The [IBM Cloud Shell YouTube - channel](https://www.youtube.com/channel/UCcu16nIMNclSujJWDOgUI_g) hosts demo - videos of IBM Cloud Shell, including editing a composition [using a built-in - editor](https://youtu.be/1wmkSYl7EDM) or [an external - editor](https://youtu.be/psqoysnVgE4), and [visualizing a composition's - execution](https://youtu.be/jTaHgDQDZnQ). -* Watch [our presentation at - Serverlessconf'17](https://acloud.guru/series/serverlessconf/view/ibm-cloud-functions) - about Composer and Shell. -* [Conductor Actions and Composer - v2](https://urldefense.proofpoint.com/v2/url?u=https-3A__youtu.be_qkqenC5b1kE&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=C3zA0dhyHjF4WaOy8EW8kQHtYUl9-dKPdS8OrjFeQmE&m=vCx7thSf3YtT7x3Pe2DaLYw-dcjU1hNIfDkTM_21ObA&s=MGh9y3vSvssj1xTzwEurJ6TewdE7Dr2Ycs10Tix8sNg&e=) - (29:30 minutes into the video): A discussion of the composition runtime. - -## Blog posts -* [Serverless Composition with IBM Cloud - Functions](https://www.raymondcamden.com/2017/10/09/serverless-composition-with-ibm-cloud-functions/) -* [Building Your First Serverless Composition with IBM Cloud - Functions](https://www.raymondcamden.com/2017/10/18/building-your-first-serverless-composition-with-ibm-cloud-functions/) -* [Upgrading Serverless Superman to IBM - Composer](https://www.raymondcamden.com/2017/10/20/upgrading-serverless-superman-to-ibm-composer/) -* [Calling Multiple Serverless Actions and Retaining Values with IBM - Composer](https://www.raymondcamden.com/2017/10/25/calling-multiple-serverless-actions-and-retaining-values-with-ibm-composer/) -* [Serverless Try/Catch/Finally with IBM - Composer](https://www.raymondcamden.com/2017/11/22/serverless-trycatchfinally-with-ibm-composer/) -* [Composing functions into - applications](https://medium.com/openwhisk/composing-functions-into-applications-70d3200d0fac) -* [A composition story: using IBM Cloud Functions to relay SMS to - email](https://medium.com/openwhisk/a-composition-story-using-ibm-cloud-functions-to-relay-sms-to-email-d67fc65d29c) -* [Data Flows in Serverless Cloud-Native - Applications](http://heidloff.net/article/serverless-data-flows) -* [Transforming JSON Data in Serverless - Applications](http://heidloff.net/article/transforming-json-serverless) - -## Contributions -We are looking forward to your feedback and criticism. We encourage you to [join -us on slack](http://ibm.biz/composer-users). File bugs and we will squash them. - -We welcome contributions to Composer and Shell. See -[CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/bin/compose b/bin/compose deleted file mode 100755 index 0110160..0000000 --- a/bin/compose +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env node - -'use strict' - -const minimist = require('minimist') -const path = require('path') - -const argv = minimist(process.argv.slice(2), { - string: ['apihost', 'auth', 'deploy', 'lower', 'entity', 'entities', 'composer'], - boolean: ['insecure', 'encode', 'json', 'version', 'quiet'], - alias: { auth: 'u', insecure: 'i', version: 'v' } -}) -let { util } = require(argv.composer || '../composer') - -if (argv.version) { - console.log(util.version) - return -} - -let count = 0 -if (argv.json) count++ -if (argv.encode) count++ -if (argv.entity) count++ -if (argv.entities) count++ -if (typeof argv.deploy !== 'undefined') count++ - -if (argv._.length !== 1 || count > 1 || argv.deploy === '' || argv.entity === '' || argv.entities === '') { - console.error('Usage:') - console.error(' compose composition.js[on] command [flags]') - console.error('Commands:') - console.error(' --json output the json representation for the composition (default command)') - console.error(' --deploy NAME deploy the composition with name NAME') - console.error(' --entity NAME output the conductor action definition for the composition (giving name NAME to the composition)') - console.error(' --entities NAME convert the composition into an array of action definition (giving name NAME to the composition)') - console.error(' --encode output the conductor action code for the composition') - console.error('Flags:') - console.error(' --lower [VERSION] lower to primitive combinators or specific composer version') - console.error(' --apihost HOST API HOST') - console.error(' -u, --auth KEY authorization KEY') - console.error(' -i, --insecure bypass certificate checking') - console.error(' -v, --version output the composer version') - console.error(' --quiet omit detailed diagnostic messages') - console.error(' --composer COMPOSER instantiate a custom composer module') - process.exit(127) -} - -try { - const filename = argv._[0] - let composition - try { - composition = require(path.resolve(filename)) - if (composition.constructor && composition.constructor.name === 'Composition') { - util = composition.constructor.composer.util - } else { - composition = util.deserialize(composition) - } - if (typeof argv.lower === 'string') composition = util.lower(composition, argv.lower || []) - } catch (error) { - console.error('Bad composition') - if (!argv.quiet) console.log(error) - process.exit(4) - } - if (argv.deploy) { - const options = { ignore_certs: argv.insecure } - if (argv.apihost) options.apihost = argv.apihost - if (argv.auth) options.api_key = argv.auth - return Promise.resolve() - .then(() => util.frontend(options).compositions.deploy({ name: argv.deploy, composition })) - .then(actions => { - const names = actions.map(action => action.name) - console.log(`ok: created ${names}`) - }) - .catch(error => { - switch (error.statusCode) { - case 401: - console.error('Authentication failure') - if (!argv.quiet) console.log(error) - process.exit(2) - case 403: - console.error('Authorization failure') - if (!argv.quiet) console.log(error) - process.exit(3) - } - console.error('Server error') - if (!argv.quiet) console.log(error) - process.exit(5) - }) - } else if (argv.encode) { - console.log(util.encode('noname', composition).slice(-1)[0].action.exec.code) - } else if (argv.entity) { - console.log(JSON.stringify(util.encode(argv.entity, composition).slice(-1)[0], null, 4)) - } else if (argv.entities) { - console.log(JSON.stringify(util.encode(argv.entities, composition), null, 4)) - } else { - console.log(JSON.stringify(composition, null, 4)) - } -} catch (error) { - console.error('Internal error') - if (!argv.quiet) console.log(error) - process.exit(1) -} diff --git a/bin/compose.js b/bin/compose.js new file mode 100755 index 0000000..8821eba --- /dev/null +++ b/bin/compose.js @@ -0,0 +1,70 @@ +#!/usr/bin/env node + +/* + * Copyright 2017-2018 IBM Corporation + * + * 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. + */ + +'use strict' + +const composer = require('../composer') +const json = require('../package.json') +const minimist = require('minimist') +const Module = require('module') +const path = require('path') + +const argv = minimist(process.argv.slice(2), { + boolean: ['version', 'ast'], + alias: { version: 'v' } +}) + +if (argv.version) { + console.log(json.version) + process.exit(0) +} + +// resolve module even if not in default path +const _resolveFilename = Module._resolveFilename +Module._resolveFilename = function (request, parent) { + if (request.startsWith(json.name)) { + try { + return _resolveFilename(request, parent) + } catch (error) { + return require.resolve(request.replace(request.startsWith(json.name + '/') ? json.name : json.name.substring(0, json.name.indexOf('/')), '..')) + } + } else { + return _resolveFilename(request, parent) + } +} + +if (argv._.length !== 1 || path.extname(argv._[0]) !== '.js') { + console.error('Usage:') + console.error(' compose composition.js [flags]') + console.error('Flags:') + console.error(' --ast only output the ast for the composition') + console.error(' -v, --version output the composer version') + process.exit(1) +} + +let composition +try { + composition = composer.parse(require(path.resolve(argv._[0]))) // load and validate composition + composition = composition.compile() +} catch (error) { + error.statusCode = 422 + console.error(error) + process.exit(422 - 256) // Unprocessable Entity +} +if (argv.ast) composition = composition.ast +console.log(JSON.stringify(composition, null, 4)) diff --git a/bin/deploy.js b/bin/deploy.js new file mode 100755 index 0000000..bbd9bce --- /dev/null +++ b/bin/deploy.js @@ -0,0 +1,99 @@ +#!/usr/bin/env node + +/* + * Copyright 2017-2018 IBM Corporation + * + * 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. + */ + +'use strict' + +const composer = require('../composer') +const conductor = require('../conductor') +const fqn = require('openwhisk-fqn') +const fs = require('fs') +const json = require('../package.json') +const minimist = require('minimist') +const path = require('path') + +const argv = minimist(process.argv.slice(2), { + string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file'], + boolean: ['insecure', 'version', 'overwrite'], + alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w' } +}) + +if (argv.version) { + console.log(json.version) + process.exit(0) +} + +if (argv._.length !== 2 || path.extname(argv._[1]) !== '.json') { + console.error('Usage:') + console.error(' deploy composition composition.json [flags]') + console.error('Flags:') + console.error(' -a, --annotation KEY=VALUE add KEY annotation with VALUE') + console.error(' -A, --annotation-file KEY=FILE add KEY annotation with FILE content') + console.error(' --apihost HOST API HOST') + console.error(' -i, --insecure bypass certificate checking') + console.error(' -u, --auth KEY authorization KEY') + console.error(' -v, --version output the composer version') + console.error(' -w, --overwrite overwrite actions if already defined') + process.exit(1) +} +let composition +try { + composition = JSON.parse(fs.readFileSync(argv._[1], 'utf8')) + if (typeof composition !== 'object') throw new Error('Composition must be a dictionary') + if (typeof composition.ast !== 'object') throw new Error('Composition must have a field "ast" of type dictionary') + if (typeof composition.composition !== 'object') throw new Error('Composition must have a field "composition" of type dictionary') + if (typeof composition.version !== 'string') throw new Error('Composition must have a field "version" of type string') + if (composition.actions !== undefined && !Array.isArray(composition.actions)) throw new Error('Optional field "actions" must be an array') + composition.composition = composer.parse(composition.composition) // validate composition + if (typeof argv.annotation === 'string') argv.annotation = [argv.annotation] + composition.annotations = [] + for (let annotation of [...(argv.annotation || [])]) { + const index = annotation.indexOf('=') + if (index < 0) throw Error('Annotation syntax must be "KEY=VALUE"') + composition.annotations.push({ key: annotation.substring(0, index), value: annotation.substring(index + 1) }) + } + if (typeof argv['annotation-file'] === 'string') argv['annotation-file'] = [argv['annotation-file']] + for (let annotation of argv['annotation-file'] || []) { + const index = annotation.indexOf('=') + if (index < 0) throw Error('Annotation syntax must be "KEY=FILE"') + composition.annotations.push({ key: annotation.substring(0, index), value: fs.readFileSync(annotation.substring(index + 1), 'utf8') }) + } +} catch (error) { + error.statusCode = 422 + console.error(error) + process.exit(422 - 256) // Unprocessable Entity +} +const options = { ignore_certs: argv.insecure } +if (argv.apihost) options.apihost = argv.apihost +if (argv.auth) options.api_key = argv.auth +try { + composition.name = fqn(argv._[0]) +} catch (error) { + error.statusCode = 400 + console.error(error) + process.exit(400 - 256) // Bad Request +} +conductor(options).compositions.deploy(composition, argv.overwrite) + .then(actions => { + const names = actions.map(action => action.name) + console.log(`ok: created action${actions.length > 1 ? 's' : ''} ${names}`) + }) + .catch(error => { + error.statusCode = error.statusCode || 500 + console.error(error) + process.exit(error.statusCode - 256) + }) diff --git a/composer.js b/composer.js index b1b0ac9..e86af89 100644 --- a/composer.js +++ b/composer.js @@ -16,708 +16,355 @@ 'use strict' +const fqn = require('openwhisk-fqn') const fs = require('fs') -const os = require('os') -const path = require('path') -const semver = require('semver') const util = require('util') -// read composer version number const version = require('./package.json').version const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) -// combinator signatures -const combinators = {} - // error class class ComposerError extends Error { - constructor(message, argument) { - super(message + (argument !== undefined ? '\nArgument: ' + util.inspect(argument) : '')) - } + constructor (message, argument) { + super(message + (argument !== undefined ? '\nArgument value: ' + util.inspect(argument) : '')) + } } -// registered plugins -const plugins = [] - -const composer = {} -Object.assign(composer, { - // detect task type and create corresponding composition object - task(task) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (task === null) return composer.empty() - if (task instanceof Composition) return task - if (typeof task === 'function') return composer.function(task) - if (typeof task === 'string') return composer.action(task) - throw new ComposerError('Invalid argument', task) - }, - - // function combinator: stringify function code - function(fun) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (typeof fun === 'function') { - fun = `${fun}` - if (fun.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', fun) - } - if (typeof fun === 'string') { - fun = { kind: 'nodejs:default', code: fun } - } - if (!isObject(fun)) throw new ComposerError('Invalid argument', fun) - return new Composition({ type: 'function', function: { exec: fun } }) - }, - - // action combinator - action(name, options = {}) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!isObject(options)) throw new ComposerError('Invalid argument', options) - name = composer.util.canonical(name) // throws ComposerError if name is not valid - let exec - if (Array.isArray(options.sequence)) { // native sequence - exec = { kind: 'sequence', components: options.sequence.map(canonical) } - } else if (typeof options.filename === 'string') { // read action code from file - exec = fs.readFileSync(options.filename, { encoding: 'utf8' }) - } else if (typeof options.action === 'function') { // capture function - exec = `const main = ${options.action}` - if (exec.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function', options.action) - } else if (typeof options.action === 'string' || isObject(options.action)) { - exec = options.action - } - if (typeof exec === 'string') { - exec = { kind: 'nodejs:default', code: exec } - } - const composition = { type: 'action', name } - if (exec) composition.action = { exec } - return new Composition(composition) - }, -}) +const composer = { util: { declare, version } } const lowerer = { - empty() { - return composer.sequence() - }, - - seq({ components }) { - return composer.sequence(...components) - }, - - value({ value }) { - return composer.literal(value) - }, - - literal({ value }) { - return composer.let({ value }, composer.function('() => value')) - }, - - retain({ components }) { - return composer.let( - { params: null }, - composer.finally( - args => { params = args }, - composer.seq(composer.mask(...components), - result => ({ params, result })))) - }, - - retain_catch({ components }) { - return composer.seq( - composer.retain( - composer.finally( - composer.seq(...components), - result => ({ result }))), - ({ params, result }) => ({ params, result: result.result })) - }, - - if({ test, consequent, alternate }) { - return composer.let( - { params: null }, - composer.finally( - args => { params = args }, - composer.if_nosave( - composer.mask(test), - composer.finally(() => params, composer.mask(consequent)), - composer.finally(() => params, composer.mask(alternate))))) - }, - - while({ test, body }) { - return composer.let( - { params: null }, - composer.finally( - args => { params = args }, - composer.seq(composer.while_nosave( - composer.mask(test), - composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args }))), - () => params))) - }, - - dowhile({ body, test }) { - return composer.let( - { params: null }, - composer.finally( - args => { params = args }, - composer.seq(composer.dowhile_nosave( - composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args })), - composer.mask(test)), - () => params))) - }, - - repeat({ count, components }) { - return composer.let( - { count }, - composer.while( - composer.function('() => count-- > 0'), - composer.mask(...components))) - }, - - retry({ count, components }) { - return composer.let( - { count }, - params => ({ params }), - composer.dowhile( - composer.finally(({ params }) => params, composer.mask(composer.retain_catch(...components))), - composer.function('({ result }) => result.error !== undefined && count-- > 0')), - ({ result }) => result) - }, + literal (value) { + return composer.let({ value }, () => value) + }, + + retain (...components) { + let params = null + return composer.let( + { params }, + composer.finally( + args => { params = args }, + composer.seq(composer.mask(...components), + result => ({ params, result })))) + }, + + retain_catch (...components) { + return composer.seq( + composer.retain( + composer.finally( + composer.seq(...components), + result => ({ result }))), + ({ params, result }) => ({ params, result: result.result })) + }, + + if (test, consequent, alternate) { + let params = null + return composer.let( + { params }, + composer.finally( + args => { params = args }, + composer.if_nosave( + composer.mask(test), + composer.finally(() => params, composer.mask(consequent)), + composer.finally(() => params, composer.mask(alternate))))) + }, + + while (test, body) { + let params = null + return composer.let( + { params }, + composer.finally( + args => { params = args }, + composer.seq(composer.while_nosave( + composer.mask(test), + composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args }))), + () => params))) + }, + + dowhile (body, test) { + let params = null + return composer.let( + { params }, + composer.finally( + args => { params = args }, + composer.seq(composer.dowhile_nosave( + composer.finally(() => params, composer.seq(composer.mask(body), args => { params = args })), + composer.mask(test)), + () => params))) + }, + + repeat (count, ...components) { + return composer.let( + { count }, + composer.while( + () => count-- > 0, + composer.mask(...components))) + }, + + retry (count, ...components) { + return composer.let( + { count }, + params => ({ params }), + composer.dowhile( + composer.finally(({ params }) => params, composer.mask(composer.retain_catch(...components))), + ({ result }) => result.error !== undefined && count-- > 0), + ({ result }) => result) + }, + + merge (...components) { + return composer.seq(composer.retain(...components), ({ params, result }) => Object.assign(params, result)) + } } -// recursively compile composition composition into { composition, actions } -function flatten(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - - const actions = [] - - const flatten = composition => { - composition = new Composition(composition) // copy - composition.visit(flatten) - if (composition.type === 'action' && composition.action) { - actions.push({ name: composition.name, action: composition.action }) - delete composition.action - } - return composition +// apply f to all fields of type composition +function visit (composition, f) { + composition = Object.assign({}, composition) // copy + const combinator = composition['.combinator']() + if (combinator.components) { + composition.components = composition.components.map(f) + } + for (let arg of combinator.args || []) { + if (arg.type === undefined && composition[arg.name] !== undefined) { + composition[arg.name] = f(composition[arg.name], arg.name) } - - composition = flatten(composition) - return { composition, actions } + } + return new Composition(composition) } -// synthesize conductor action code from composition -function synthesize(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - let code = `const main=(${main})(` - for (let plugin of plugins) { - code += `{plugin:new(${plugin.constructor})()` - if (plugin.configure) code += `,config:${JSON.stringify(plugin.configure())}` - code += '},' - } - code = require('uglify-es').minify(`${code})`, { output: { max_line_len: 127 } }).code - code = `// generated by composer v${composer.util.version}\n\nconst composition = ${JSON.stringify(composer.util.lower(label(composition)), null, 4)}\n\n// do not edit below this point\n\n${code}` // invoke conductor on composition - return { exec: { kind: 'nodejs:default', code }, annotations: [{ key: 'conductor', value: composition }, { key: 'composer', value: version }] } +// recursively label combinators with the json path +function label (composition) { + const label = path => (composition, name, array) => { + const p = path + (name !== undefined ? (array === undefined ? `.${name}` : `[${name}]`) : '') + composition = visit(composition, label(p)) // copy + composition.path = p + return composition + } + return label('')(composition) } -composer.util = { - // return the signatures of the combinators - get combinators() { - return combinators - }, - - // recursively deserialize composition - deserialize(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - composition = new Composition(composition) // copy - composition.visit(composition => composer.util.deserialize(composition)) - return composition - }, - - // recursively lower combinators to the desired set of combinators (including primitive combinators) - lower(composition, combinators = []) { - if (arguments.length > 2) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (typeof combinators === 'string') { // lower to combinators of specific composer version - combinators = Object.keys(composer.util.combinators).filter(key => semver.gte(combinators, composer.util.combinators[key].since)) - } - if (!Array.isArray(combinators)) throw new ComposerError('Invalid argument', combinators) - - const lower = composition => { - composition = new Composition(composition) // copy - // repeatedly lower root combinator - while (combinators.indexOf(composition.type) < 0 && lowerer[composition.type]) { - const path = composition.path - composition = lowerer[composition.type](composition) - if (path !== undefined) composition.path = path // preserve path - } - // lower nested combinators - composition.visit(lower) - return composition - } - - return lower(composition) - }, - - // register plugin - register(plugin) { - plugins.push(plugin) - }, - - /** - * Parses a (possibly fully qualified) resource name and validates it. If it's not a fully qualified name, - * then attempts to qualify it. - * - * Examples string to namespace, [package/]action name - * foo => /_/foo - * pkg/foo => /_/pkg/foo - * /ns/foo => /ns/foo - * /ns/pkg/foo => /ns/pkg/foo - */ - canonical(name) { - if (typeof name !== 'string') throw new ComposerError('Name must be a string') - if (name.trim().length == 0) throw new ComposerError('Name is not valid') - name = name.trim() - const delimiter = '/' - const parts = name.split(delimiter) - const n = parts.length - const leadingSlash = name[0] == delimiter - // no more than /ns/p/a - if (n < 1 || n > 4 || (leadingSlash && n == 2) || (!leadingSlash && n == 4)) throw new ComposerError('Name is not valid') - // skip leading slash, all parts must be non empty (could tighten this check to match EntityName regex) - parts.forEach(function (part, i) { if (i > 0 && part.trim().length == 0) throw new ComposerError('Name is not valid') }) - const newName = parts.join(delimiter) - if (leadingSlash) return newName - else if (n < 3) return `${delimiter}_${delimiter}${newName}` - else return `${delimiter}${newName}` - }, - - - // encode composition as an action table - encode(name, composition, combinators) { - if (arguments.length > 3) throw new ComposerError('Too many arguments') - name = composer.util.canonical(name) // throws ComposerError if name is not valid - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - if (combinators) composition = composer.util.lower(composition, combinators) - const table = flatten(composition) - table.actions.push({ name, action: synthesize(table.composition) }) - return table.actions - }, - - // return composer version - get version() { - return version - }, - - // return enhanced openwhisk client capable of deploying compositions - openwhisk(options) { - // try to extract apihost and key first from whisk property file file and then from process.env - let apihost - let api_key - - try { - const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') - const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') - - for (let line of lines) { - let parts = line.trim().split('=') - if (parts.length === 2) { - if (parts[0] === 'APIHOST') { - apihost = parts[1] - } else if (parts[0] === 'AUTH') { - api_key = parts[1] - } - } - } - } catch (error) { } - - if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST - if (process.env.__OW_API_KEY) api_key = process.env.__OW_API_KEY - - const wsk = require('openwhisk')(Object.assign({ apihost, api_key }, options)) - wsk.compositions = new Compositions(wsk) - return wsk - }, - - // derive combinator methods from combinator table - declare(combinators) { - Object.assign(composer.util.combinators, combinators) - for (let type in combinators) { - const combinator = combinators[type] - // do not overwrite existing combinators - composer[type] = composer[type] || function () { - const composition = { type } - const skip = combinator.args && combinator.args.length || 0 - if (!combinator.components && (arguments.length > skip)) { - throw new ComposerError('Too many arguments') - } - for (let i = 0; i < skip; ++i) { - const arg = combinator.args[i] - const argument = arguments[i] - if (argument === undefined && arg.optional && arg.type !== undefined) continue - switch (arg.type) { - case undefined: - composition[arg._] = composer.task(arg.optional ? argument || null : argument) - continue - case 'value': - if (typeof argument === 'function') throw new ComposerError('Invalid argument', argument) - composition[arg._] = argument === undefined ? {} : argument - continue - case 'object': - if (argument === null || Array.isArray(argument)) throw new ComposerError('Invalid argument', argument) - default: - if (typeof argument !== arg.type) throw new ComposerError('Invalid argument', argument) - composition[arg._] = argument - } - } - if (combinator.components) { - composition.components = Array.prototype.slice.call(arguments, skip).map(obj => composer.task(obj)) - } - return new Composition(composition) - } - } - }, - - get lowerer() { - return lowerer - }, +// derive combinator methods from combinator table +// check argument count and map argument positions to argument names +// delegate to Composition constructor for the rest of the validation +function declare (combinators, prefix) { + if (arguments.length > 2) throw new ComposerError('Too many arguments in "declare"') + if (!isObject(combinators)) throw new ComposerError('Invalid argument "combinators" in "declare"', combinators) + if (prefix !== undefined && typeof prefix !== 'string') throw new ComposerError('Invalid argument "prefix" in "declare"', prefix) + const composer = {} + for (let key in combinators) { + const type = prefix ? prefix + '.' + key : key + const combinator = combinators[key] + if (!isObject(combinator) || (combinator.args !== undefined && !Array.isArray(combinator.args))) { + throw new ComposerError(`Invalid "${type}" combinator specification in "declare"`, combinator) + } + for (let arg of combinator.args || []) { + if (typeof arg.name !== 'string') throw new ComposerError(`Invalid "${type}" combinator specification in "declare"`, combinator) + } + composer[key] = function () { + const composition = { type, '.combinator': () => combinator } + const skip = (combinator.args && combinator.args.length) || 0 + if (!combinator.components && (arguments.length > skip)) { + throw new ComposerError(`Too many arguments in "${type}" combinator`) + } + for (let i = 0; i < skip; ++i) { + composition[combinator.args[i].name] = arguments[i] + } + if (combinator.components) { + composition.components = Array.prototype.slice.call(arguments, skip) + } + return new Composition(composition) + } + } + return composer } -composer.util.frontend = composer.util.openwhisk - // composition class class Composition { - // weaker instanceof to tolerate multiple instances of this class - static [Symbol.hasInstance](instance) { - return instance.constructor && instance.constructor.name === Composition.name + // weaker instanceof to tolerate multiple instances of this class + static [Symbol.hasInstance] (instance) { + return instance.constructor && instance.constructor.name === Composition.name + } + + // construct a composition object with the specified fields + constructor (composition) { + const combinator = composition['.combinator']() + Object.assign(this, composition) + for (let arg of combinator.args || []) { + if (composition[arg.name] === undefined && arg.optional && arg.type !== undefined) continue + switch (arg.type) { + case undefined: + try { + this[arg.name] = composer.task(arg.optional ? composition[arg.name] || null : composition[arg.name]) + } catch (error) { + throw new ComposerError(`Invalid argument "${arg.name}" in "${composition.type} combinator"`, composition[arg.name]) + } + break + case 'name': + try { + this[arg.name] = fqn(composition[arg.name]) + } catch (error) { + throw new ComposerError(`${error.message} in "${composition.type} combinator"`, composition[arg.name]) + } + break + case 'value': + if (typeof composition[arg.name] === 'function' || composition[arg.name] === undefined) { + throw new ComposerError(`Invalid argument "${arg.name}" in "${composition.type} combinator"`, composition[arg.name]) + } + break + case 'object': + if (!isObject(composition[arg.name])) { + throw new ComposerError(`Invalid argument "${arg.name}" in "${composition.type} combinator"`, composition[arg.name]) + } + break + default: + if ('' + typeof composition[arg.name] !== arg.type) { + throw new ComposerError(`Invalid argument "${arg.name}" in "${composition.type} combinator"`, composition[arg.name]) + } + } } + if (combinator.components) this.components = (composition.components || []).map(obj => composer.task(obj)) + return this + } - // construct a composition object with the specified fields - constructor(composition) { - if (!isObject(composition) || composer.util.combinators[composition.type] === undefined) throw new ComposerError('Invalid argument', composition) - const combinator = composer.util.combinators[composition.type] - if (combinator.components && composition.components === undefined) throw new ComposerError('Invalid argument', composition) - for (let arg of combinator.args || []) { - if (!arg.optional && composition[arg._] === undefined) throw new ComposerError('Invalid argument', composition) - } - return Object.assign(this, composition) - } - - // apply f to all fields of type composition - visit(f) { - const combinator = composer.util.combinators[this.type] - if (combinator.components) { - this.components = this.components.map(f) - } - for (let arg of combinator.args || []) { - if (arg.type === undefined && this[arg._] !== undefined) { - this[arg._] = f(this[arg._], arg._) - } - } - } -} - -Composition.composer = composer - -composer.util.declare({ - empty: { since: '0.4.0' }, - seq: { components: true, since: '0.4.0' }, - sequence: { components: true, since: '0.4.0' }, - if: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, - if_nosave: { args: [{ _: 'test' }, { _: 'consequent' }, { _: 'alternate', optional: true }], since: '0.4.0' }, - while: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, - while_nosave: { args: [{ _: 'test' }, { _: 'body' }], since: '0.4.0' }, - dowhile: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, - dowhile_nosave: { args: [{ _: 'body' }, { _: 'test' }], since: '0.4.0' }, - try: { args: [{ _: 'body' }, { _: 'handler' }], since: '0.4.0' }, - finally: { args: [{ _: 'body' }, { _: 'finalizer' }], since: '0.4.0' }, - retain: { components: true, since: '0.4.0' }, - retain_catch: { components: true, since: '0.4.0' }, - let: { args: [{ _: 'declarations', type: 'object' }], components: true, since: '0.4.0' }, - mask: { components: true, since: '0.4.0' }, - action: { args: [{ _: 'name', type: 'string' }, { _: 'action', type: 'object', optional: true }], since: '0.4.0' }, - repeat: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, - retry: { args: [{ _: 'count', type: 'number' }], components: true, since: '0.4.0' }, - value: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, - literal: { args: [{ _: 'value', type: 'value' }], since: '0.4.0' }, - function: { args: [{ _: 'function', type: 'object' }], since: '0.4.0' }, - async: { args: [{ _: 'body' }], since: '0.6.0' }, -}) + // compile composition + compile () { + if (arguments.length > 0) throw new ComposerError('Too many arguments in "compile"') -// management class for compositions -class Compositions { - constructor(wsk) { - this.actions = wsk.actions - } + const actions = [] - deploy({ name, composition, combinators }) { - const actions = composer.util.encode(name, composition, combinators) - return actions.reduce((promise, action) => promise.then(() => this.actions.delete(action).catch(() => { })) - .then(() => this.actions.update(action)), Promise.resolve()) - .then(() => actions) + const flatten = composition => { + composition = visit(composition, flatten) + if (composition.type === 'action' && composition.action) { + actions.push({ name: composition.name, action: composition.action }) + delete composition.action + } + return composition } -} -// recursively label combinators with the json path -function label(composition) { - if (arguments.length > 1) throw new ComposerError('Too many arguments') - if (!(composition instanceof Composition)) throw new ComposerError('Invalid argument', composition) - const label = path => (composition, name, array) => { - composition = new Composition(composition) // copy - composition.path = path + (name !== undefined ? (array === undefined ? `.${name}` : `[${name}]`) : '') - // label nested combinators - composition.visit(label(composition.path)) - return composition + const obj = { composition: label(flatten(this)).lower(), ast: this, version } + if (actions.length > 0) obj.actions = actions + return obj + } + + // recursively lower combinators to the desired set of combinators (including primitive combinators) + lower (combinators = []) { + if (arguments.length > 1) throw new ComposerError('Too many arguments in "lower"') + if (!Array.isArray(combinators)) throw new ComposerError('Invalid argument "combinators" in "lower"', combinators) + + const lower = composition => { + // repeatedly lower root combinator + while (composition['.combinator']().def) { + const path = composition.path + const combinator = composition['.combinator']() + if (Array.isArray(combinators) && combinators.indexOf(composition.type) >= 0) break + // map argument names to positions + const args = [] + const skip = (combinator.args && combinator.args.length) || 0 + for (let i = 0; i < skip; i++) args.push(composition[combinator.args[i].name]) + if (combinator.components) args.push(...composition.components) + composition = combinator.def(...args) + if (path !== undefined) composition.path = path // preserve path + } + // lower nested combinators + return visit(composition, lower) } - return label('')(composition) + return lower(this) + } } -// runtime code -function main() { - const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) - - // compile ast to fsm - const compiler = { - sequence(node) { - return [{ type: 'pass', path: node.path }, ...compile(...node.components)] - }, - - action(node) { - return [{ type: 'action', name: node.name, path: node.path }] - }, - - async(node) { - const body = compile(node.body) - return [{ type: 'async', path: node.path, return: body.length + 2 }, ...body, { type: 'stop' }, { type: 'pass' }] - }, - - function(node) { - return [{ type: 'function', exec: node.function.exec, path: node.path }] - }, - - finally(node) { - const finalizer = compile(node.finalizer) - const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...finalizer] - fsm[0].catch = fsm.length - finalizer.length - return fsm - }, - - let(node) { - return [{ type: 'let', let: node.declarations, path: node.path }, ...compile(...node.components), { type: 'exit' }] - }, - - mask(node) { - return [{ type: 'let', let: null, path: node.path }, ...compile(...node.components), { type: 'exit' }] - }, - - try(node) { - const handler = [...compile(node.handler), { type: 'pass' }] - const fsm = [{ type: 'try', path: node.path }, ...compile(node.body), { type: 'exit' }, ...handler] - fsm[0].catch = fsm.length - handler.length - fsm[fsm.length - handler.length - 1].next = handler.length - return fsm - }, - - if_nosave(node) { - const consequent = compile(node.consequent) - const alternate = [...compile(node.alternate), { type: 'pass' }] - const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: consequent.length + 1 }, ...consequent, ...alternate] - fsm[fsm.length - alternate.length - 1].next = alternate.length - return fsm - }, - - while_nosave(node) { - const body = compile(node.body) - const fsm = [{ type: 'pass', path: node.path }, ...compile(node.test), { type: 'choice', then: 1, else: body.length + 1 }, ...body, { type: 'pass' }] - fsm[fsm.length - 2].next = 2 - fsm.length - return fsm - }, - - dowhile_nosave(node) { - const fsm = [{ type: 'pass', path: node.path }, ...compile(node.body), ...compile(node.test), { type: 'choice', else: 1 }, { type: 'pass' }] - fsm[fsm.length - 2].then = 2 - fsm.length - return fsm - }, - } +// primitive combinators +const combinators = { + sequence: { components: true }, + if_nosave: { args: [{ name: 'test' }, { name: 'consequent' }, { name: 'alternate', optional: true }] }, + while_nosave: { args: [{ name: 'test' }, { name: 'body' }] }, + dowhile_nosave: { args: [{ name: 'body' }, { name: 'test' }] }, + try: { args: [{ name: 'body' }, { name: 'handler' }] }, + finally: { args: [{ name: 'body' }, { name: 'finalizer' }] }, + let: { args: [{ name: 'declarations', type: 'object' }], components: true }, + mask: { components: true }, + action: { args: [{ name: 'name', type: 'name' }, { name: 'action', type: 'object', optional: true }] }, + function: { args: [{ name: 'function', type: 'object' }] }, + async: { components: true } +} - function compile(node) { - if (arguments.length === 0) return [{ type: 'empty' }] - if (arguments.length === 1) return compiler[node.type](node) - return Array.prototype.reduce.call(arguments, (fsm, node) => { fsm.push(...compile(node)); return fsm }, []) - } +Object.assign(composer, declare(combinators)) + +// derived combinators +const extra = { + empty: { def: composer.sequence }, + seq: { components: true, def: composer.sequence }, + if: { args: [{ name: 'test' }, { name: 'consequent' }, { name: 'alternate', optional: true }], def: lowerer.if }, + while: { args: [{ name: 'test' }, { name: 'body' }], def: lowerer.while }, + dowhile: { args: [{ name: 'body' }, { name: 'test' }], def: lowerer.dowhile }, + repeat: { args: [{ name: 'count', type: 'number' }], components: true, def: lowerer.repeat }, + retry: { args: [{ name: 'count', type: 'number' }], components: true, def: lowerer.retry }, + retain: { components: true, def: lowerer.retain }, + retain_catch: { components: true, def: lowerer.retain_catch }, + value: { args: [{ name: 'value', type: 'value' }], def: lowerer.literal }, + literal: { args: [{ name: 'value', type: 'value' }], def: lowerer.literal }, + merge: { components: true, def: lowerer.merge } +} - const openwhisk = require('openwhisk') - let wsk - - const conductor = { - choice({ p, node, index }) { - p.s.state = index + (p.params.value ? node.then : node.else) - }, - - try({ p, node, index }) { - p.s.stack.unshift({ catch: index + node.catch }) - }, - - let({ p, node, index }) { - p.s.stack.unshift({ let: JSON.parse(JSON.stringify(node.let)) }) - }, - - exit({ p, node, index }) { - if (p.s.stack.length === 0) return internalError(`State ${index} attempted to pop from an empty stack`) - p.s.stack.shift() - }, - - action({ p, node, index }) { - return { action: node.name, params: p.params, state: { $resume: p.s } } - }, - - function({ p, node, index }) { - return Promise.resolve().then(() => run(node.exec.code, p)) - .catch(error => { - console.error(error) - return { error: `An exception was caught at state ${index} (see log for details)` } - }) - .then(result => { - if (typeof result === 'function') result = { error: `State ${index} evaluated to a function` } - // if a function has only side effects and no return value, return params - p.params = JSON.parse(JSON.stringify(result === undefined ? p.params : result)) - inspect(p) - return step(p) - }) - }, - - empty({ p, node, index }) { - inspect(p) - }, - - pass({ p, node, index }) { - }, - - async({ p, node, index, inspect, step }) { - if (!wsk) wsk = openwhisk({ ignore_certs: true }) - p.params.$resume = { state: p.s.state } - p.s.state = index + node.return - return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) - .catch(error => { - console.error(error) - return { error: `An exception was caught at state ${index} (see log for details)` } - }) - .then(result => { - p.params = result - inspect(p) - return step(p) - }) - }, - - stop({ p, node, index, inspect, step }) { - p.s.state = -1 - }, - } +Object.assign(composer, declare(extra)) - const finishers = [] - - for (let { plugin, config } of arguments) { - if (plugin.compiler) Object.assign(compiler, plugin.compiler({ compile })) - if (plugin.conductor) { - Object.assign(conductor, plugin.conductor(config)) - if (conductor._finish) { - finishers.push(conductor._finish) - delete conductor._finish - } - } - } - - const fsm = compile(composition) - - // encode error object - const encodeError = error => ({ - code: typeof error.code === 'number' && error.code || 500, - error: (typeof error.error === 'string' && error.error) || error.message || (typeof error === 'string' && error) || 'An internal error occurred' - }) - - // error status codes - const badRequest = error => Promise.reject({ code: 400, error }) - const internalError = error => Promise.reject(encodeError(error)) - - // wrap params if not a dictionary, branch to error handler if error - function inspect(p) { - if (!isObject(p.params)) p.params = { value: p.params } - if (p.params.error !== undefined) { - p.params = { error: p.params.error } // discard all fields but the error field - p.s.state = -1 // abort unless there is a handler in the stack - while (p.s.stack.length > 0) { - if ((p.s.state = p.s.stack.shift().catch || -1) >= 0) break - } - } +// add or override definitions of some combinators +Object.assign(composer, { + // detect task type and create corresponding composition object + task (task) { + if (arguments.length > 1) throw new ComposerError('Too many arguments in "task" combinator') + if (task === undefined) throw new ComposerError('Invalid argument in "task" combinator', task) + if (task === null) return composer.empty() + if (task instanceof Composition) return task + if (typeof task === 'function') return composer.function(task) + if (typeof task === 'string') return composer.action(task) + throw new ComposerError('Invalid argument "task" in "task" combinator', task) + }, + + // function combinator: stringify function code + function (fun) { + if (arguments.length > 1) throw new ComposerError('Too many arguments in "function" combinator') + if (typeof fun === 'function') { + fun = `${fun}` + if (fun.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function in "function" combinator', fun) } - - // run function f on current stack - function run(f, p) { - // handle let/mask pairs - const view = [] - let n = 0 - for (let frame of p.s.stack) { - if (frame.let === null) { - n++ - } else if (frame.let !== undefined) { - if (n === 0) { - view.push(frame) - } else { - n-- - } - } - } - - // update value of topmost matching symbol on stack if any - function set(symbol, value) { - const element = view.find(element => element.let !== undefined && element.let[symbol] !== undefined) - if (element !== undefined) element.let[symbol] = JSON.parse(JSON.stringify(value)) - } - - // collapse stack for invocation - const env = view.reduceRight((acc, cur) => cur.let ? Object.assign(acc, cur.let) : acc, {}) - let main = '(function(){try{' - for (const name in env) main += `var ${name}=arguments[1]['${name}'];` - main += `return eval((${f}))(arguments[0])}finally{` - for (const name in env) main += `arguments[1]['${name}']=${name};` - main += '}})' - try { - return (1, eval)(main)(p.params, env) - } finally { - for (const name in env) set(name, env[name]) - } + if (typeof fun === 'string') { + fun = { kind: 'nodejs:default', code: fun } } - - function step(p) { - // final state, return composition result - if (p.s.state < 0 || p.s.state >= fsm.length) { - console.log(`Entering final state`) - console.log(JSON.stringify(p.params)) - return finishers.reduce((promise, _finish) => promise.then(() => _finish(p)), Promise.resolve()) - .then(() => p.params.error ? p.params : { params: p.params }) - } - - // process one state - const node = fsm[p.s.state] // json definition for index state - if (node.path !== undefined) console.log(`Entering composition${node.path}`) - const index = p.s.state // current state - p.s.state = p.s.state + (node.next || 1) // default next state - return conductor[node.type]({ p, index, node, inspect, step }) || step(p) + if (!isObject(fun)) throw new ComposerError('Invalid argument "function" in "function" combinator', fun) + return new Composition({ type: 'function', function: { exec: fun }, '.combinator': () => combinators.function }) + }, + + // action combinator + action (name, options = {}) { + if (arguments.length > 2) throw new ComposerError('Too many arguments in "action" combinator') + if (!isObject(options)) throw new ComposerError('Invalid argument "options" in "action" combinator', options) + let exec + if (Array.isArray(options.sequence)) { // native sequence + exec = { kind: 'sequence', components: options.sequence.map(fqn) } + } else if (typeof options.filename === 'string') { // read action code from file + exec = fs.readFileSync(options.filename, { encoding: 'utf8' }) + } else if (typeof options.action === 'function') { // capture function + exec = `const main = ${options.action}` + if (exec.indexOf('[native code]') !== -1) throw new ComposerError('Cannot capture native function in "action" combinator', options.action) + } else if (typeof options.action === 'string' || isObject(options.action)) { + exec = options.action } - - return params => Promise.resolve().then(() => invoke(params)).catch(internalError) - - // do invocation - function invoke(params) { - const p = { s: { state: 0, stack: [] }, params } // initial state - - if (params.$resume !== undefined) { - if (!isObject(params.$resume)) return badRequest('The type of optional $resume parameter must be object') - const resuming = params.$resume.stack - Object.assign(p.s, params.$resume) - if (typeof p.s.state !== 'number') return badRequest('The type of optional $resume.state parameter must be number') - if (!Array.isArray(p.s.stack)) return badRequest('The type of optional $resume.stack parameter must be an array') - delete params.$resume - if (resuming) inspect(p) // handle error objects when resuming - } - - return step(p) + if (typeof exec === 'string') { + exec = { kind: 'nodejs:default', code: exec } } -} + const composition = { type: 'action', name, '.combinator': () => combinators.action } + if (exec) composition.action = { exec } + return new Composition(composition) + }, + + // recursively deserialize composition + parse (composition) { + if (arguments.length > 1) throw new ComposerError('Too many arguments in "parse" combinator') + if (!isObject(composition)) throw new ComposerError('Invalid argument "composition" in "parse" combinator', composition) + const combinator = typeof composition['.combinator'] === 'function' ? composition['.combinator']() : combinators[composition.type] + if (!isObject(combinator)) throw new ComposerError('Invalid composition type in "parse" combinator', composition) + return visit(Object.assign({ '.combinator': () => combinator }, composition), composition => composer.parse(composition)) + } +}) module.exports = composer diff --git a/conductor.js b/conductor.js new file mode 100644 index 0000000..bac9641 --- /dev/null +++ b/conductor.js @@ -0,0 +1,321 @@ +/* + * Copyright 2017-2018 IBM Corporation + * + * 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. + */ + +/* eslint no-eval: 0 */ + +'use strict' + +const fs = require('fs') +const { minify } = require('terser') +const openwhisk = require('openwhisk') +const os = require('os') +const path = require('path') + +// read conductor version number +const version = require('./package.json').version + +// synthesize conductor action code from composition +function synthesize ({ name, composition, ast, version: composer, annotations = [] }) { + const code = `// generated by composer v${composer} and conductor v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n` + + minify(`const main=(${main})(composition)`, { output: { max_line_len: 127 } }).code + annotations = annotations.concat([{ key: 'conductor', value: ast }, { key: 'composerVersion', value: composer }, { key: 'conductorVersion', value: version }]) + return { name, action: { exec: { kind: 'nodejs:default', code }, annotations } } +} + +// return enhanced openwhisk client capable of deploying compositions +module.exports = function (options) { + // try to extract apihost and key first from whisk property file file and then from process.env + let apihost + let apikey + + try { + const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') + const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') + + for (let line of lines) { + let parts = line.trim().split('=') + if (parts.length === 2) { + if (parts[0] === 'APIHOST') { + apihost = parts[1] + } else if (parts[0] === 'AUTH') { + apikey = parts[1] + } + } + } + } catch (error) { } + + if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST + if (process.env.__OW_API_KEY) apikey = process.env.__OW_API_KEY + + const wsk = openwhisk(Object.assign({ apihost, api_key: apikey }, options)) + wsk.compositions = new Compositions(wsk) + return wsk +} + +// management class for compositions +class Compositions { + constructor (wsk) { + this.actions = wsk.actions + } + + deploy (composition, overwrite) { + const actions = (composition.actions || []).concat(synthesize(composition)) + return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) + .then(() => this.actions.create(action)), Promise.resolve()) + .then(() => actions) + } +} + +// runtime code +function main (composition) { + const openwhisk = require('openwhisk') + let wsk + + const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) + + // compile ast to fsm + const compiler = { + sequence (parent, node) { + return [{ parent, type: 'pass' }, ...compile(parent, ...node.components)] + }, + + action (parent, node) { + return [{ parent, type: 'action', name: node.name }] + }, + + async (parent, node) { + const body = [...compile(parent, ...node.components)] + return [{ parent, type: 'async', return: body.length + 2 }, ...body, { parent, type: 'stop' }, { parent, type: 'pass' }] + }, + + function (parent, node) { + return [{ parent, type: 'function', exec: node.function.exec }] + }, + + finally (parent, node) { + const finalizer = compile(parent, node.finalizer) + const fsm = [{ parent, type: 'try' }, ...compile(parent, node.body), { parent, type: 'exit' }, ...finalizer] + fsm[0].catch = fsm.length - finalizer.length + return fsm + }, + + let (parent, node) { + return [{ parent, type: 'let', let: node.declarations }, ...compile(parent, ...node.components), { parent, type: 'exit' }] + }, + + mask (parent, node) { + return [{ parent, type: 'let', let: null }, ...compile(parent, ...node.components), { parent, type: 'exit' }] + }, + + try (parent, node) { + const handler = [...compile(parent, node.handler), { parent, type: 'pass' }] + const fsm = [{ parent, type: 'try' }, ...compile(parent, node.body), { parent, type: 'exit' }, ...handler] + fsm[0].catch = fsm.length - handler.length + fsm[fsm.length - handler.length - 1].next = handler.length + return fsm + }, + + if_nosave (parent, node) { + const consequent = compile(parent, node.consequent) + const alternate = [...compile(parent, node.alternate), { parent, type: 'pass' }] + const fsm = [{ parent, type: 'pass' }, ...compile(parent, node.test), { parent, type: 'choice', then: 1, else: consequent.length + 1 }, ...consequent, ...alternate] + fsm[fsm.length - alternate.length - 1].next = alternate.length + return fsm + }, + + while_nosave (parent, node) { + const body = compile(parent, node.body) + const fsm = [{ parent, type: 'pass' }, ...compile(parent, node.test), { parent, type: 'choice', then: 1, else: body.length + 1 }, ...body, { parent, type: 'pass' }] + fsm[fsm.length - 2].next = 2 - fsm.length + return fsm + }, + + dowhile_nosave (parent, node) { + const fsm = [{ parent, type: 'pass' }, ...compile(parent, node.body), ...compile(parent, node.test), { parent, type: 'choice', else: 1 }, { parent, type: 'pass' }] + fsm[fsm.length - 2].then = 2 - fsm.length + return fsm + } + } + + function compile (parent, node) { + if (arguments.length === 1) return [{ parent, type: 'empty' }] + if (arguments.length === 2) return Object.assign(compiler[node.type](node.path || parent, node), { path: node.path }) + return Array.prototype.slice.call(arguments, 1).reduce((fsm, node) => { fsm.push(...compile(parent, node)); return fsm }, []) + } + + const fsm = compile('', composition) + + const conductor = { + choice ({ p, node, index }) { + p.s.state = index + (p.params.value ? node.then : node.else) + }, + + try ({ p, node, index }) { + p.s.stack.unshift({ catch: index + node.catch }) + }, + + let ({ p, node, index }) { + p.s.stack.unshift({ let: JSON.parse(JSON.stringify(node.let)) }) + }, + + exit ({ p, node, index }) { + if (p.s.stack.length === 0) return internalError(`pop from an empty stack`) + p.s.stack.shift() + }, + + action ({ p, node, index }) { + return { method: 'action', action: node.name, params: p.params, state: { $resume: p.s } } + }, + + function ({ p, node, index }) { + return Promise.resolve().then(() => run(node.exec.code, p)) + .catch(error => { + console.error(error) + return { error: `Function combinator threw an exception at AST node root${node.parent} (see log for details)` } + }) + .then(result => { + if (typeof result === 'function') result = { error: `Function combinator evaluated to a function type at AST node root${node.parent}` } + // if a function has only side effects and no return value, return params + p.params = JSON.parse(JSON.stringify(result === undefined ? p.params : result)) + inspect(p) + return step(p) + }) + }, + + empty ({ p, node, index }) { + inspect(p) + }, + + pass ({ p, node, index }) { + }, + + async ({ p, node, index, inspect, step }) { + p.params.$resume = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack) } + p.s.state = index + node.return + if (!wsk) wsk = openwhisk({ ignore_certs: true }) + return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) + .then(response => ({ method: 'async', activationId: response.activationId, sessionId: p.s.session }), error => { + console.error(error) // invoke failed + return { error: `Async combinator failed to invoke composition at AST node root${node.parent} (see log for details)` } + }) + .then(result => { + p.params = result + inspect(p) + return step(p) + }) + }, + + stop ({ p, node, index, inspect, step }) { + p.s.state = -1 + } + } + + function finish (p) { + return p.params.error ? p.params : { params: p.params } + } + + const internalError = error => Promise.reject(error) // terminate composition execution and record error + + // wrap params if not a dictionary, branch to error handler if error + function inspect (p) { + if (!isObject(p.params)) p.params = { value: p.params } + if (p.params.error !== undefined) { + p.params = { error: p.params.error } // discard all fields but the error field + p.s.state = -1 // abort unless there is a handler in the stack + while (p.s.stack.length > 0 && !p.s.stack[0].marker) { + if ((p.s.state = p.s.stack.shift().catch || -1) >= 0) break + } + } + } + + // run function f on current stack + function run (f, p) { + // handle let/mask pairs + const view = [] + let n = 0 + for (let frame of p.s.stack) { + if (frame.let === null) { + n++ + } else if (frame.let !== undefined) { + if (n === 0) { + view.push(frame) + } else { + n-- + } + } + } + + // update value of topmost matching symbol on stack if any + function set (symbol, value) { + const element = view.find(element => element.let !== undefined && element.let[symbol] !== undefined) + if (element !== undefined) element.let[symbol] = JSON.parse(JSON.stringify(value)) + } + + // collapse stack for invocation + const env = view.reduceRight((acc, cur) => cur.let ? Object.assign(acc, cur.let) : acc, {}) + let main = '(function(){try{const require=arguments[2];' + for (const name in env) main += `var ${name}=arguments[1]['${name}'];` + main += `return eval((function(){return(${f})})())(arguments[0])}finally{` + for (const name in env) main += `arguments[1]['${name}']=${name};` + main += '}})' + try { + return (1, eval)(main)(p.params, env, require) + } finally { + for (const name in env) set(name, env[name]) + } + } + + function step (p) { + // final state, return composition result + if (p.s.state < 0 || p.s.state >= fsm.length) { + console.log(`Entering final state`) + console.log(JSON.stringify(p.params)) + return + } + + // process one state + const node = fsm[p.s.state] // json definition for index state + if (node.path !== undefined) console.log(`Entering composition${node.path}`) + const index = p.s.state // current state + p.s.state = p.s.state + (node.next || 1) // default next state + if (typeof conductor[node.type] !== 'function') return internalError(`unexpected "${node.type}" combinator`) + return conductor[node.type]({ p, index, node, inspect, step }) || step(p) + } + + // do invocation + return (params) => { + // extract parameters + const $resume = params.$resume || {} + delete params.$resume + $resume.session = $resume.session || process.env.__OW_ACTIVATION_ID + + // current state + const p = { s: Object.assign({ state: 0, stack: [], resuming: true }, $resume), params } + + // step and catch all errors + return Promise.resolve().then(() => { + if (typeof p.s.state !== 'number') return internalError('state parameter is not a number') + if (!Array.isArray(p.s.stack)) return internalError('stack parameter is not an array') + + if ($resume.resuming) inspect(p) // handle error objects when resuming + + return step(p) + }).catch(error => { + const message = (typeof error.error === 'string' && error.error) || error.message || (typeof error === 'string' && error) + p.params = { error: message ? `Internal error: ${message}` : 'Internal error' } + }).then(params => params || finish(p)) // params is defined iff execution will be resumed + } +} diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index 83af8c9..b4d29fc 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -4,25 +4,28 @@ The `composer` module offers a number of combinators to define compositions: | Combinator | Description | Example | | --:| --- | --- | -| [`action`](#action) | action | `composer.action('echo')` | -| [`function`](#function) | function | `composer.function(({ x, y }) => ({ product: x * y }))` | -| [`literal` or `value`](#literal) | constant value | `composer.literal({ message: 'Hello, World!' })` | +| [`action`](#action) | named action | `composer.action('echo')` | +| [`async`](#async) | asynchronous invocation | `composer.async('compress', 'upload')` | +| [`dowhile` and `dowhile_nosave`](#dowhile) | loop at least once | `composer.dowhile('fetchData', 'needMoreData')` | | [`empty`](#empty) | empty sequence | `composer.empty()` -| [`sequence` or `seq`](#sequence) | sequence | `composer.sequence('hello', 'bye')` | -| [`task`](#task) | single task | `composer.task('echo')` +| [`finally`](#finally) | finalization | `composer.finally('tryThis', 'doThatAlways')` | +| [`function`](#function) | Javascript function | `composer.function(({ x, y }) => ({ product: x * y }))` | +| [`if` and `if_nosave`](#if) | conditional | `composer.if('authenticate', 'success', 'failure')` | | [`let`](#let) | variable declarations | `composer.let({ count: 3, message: 'hello' }, ...)` | +| [`literal` or `value`](#literal) | constant value | `composer.literal({ message: 'Hello, World!' })` | | [`mask`](#mask) | variable hiding | `composer.let({ n }, composer.while(_ => n-- > 0, composer.mask(composition)))` | -| [`if` and `if_nosave`](#if) | conditional | `composer.if('authenticate', 'success', 'failure')` | -| [`while` and `while_nosave`](#while) | loop | `composer.while('notEnough', 'doMore')` | -| [`dowhile` and `dowhile_nosave`](#dowhile) | loop at least once | `composer.dowhile('fetchData', 'needMoreData')` | +| [`merge`](#merge) | data augmentation | `composer.merge('hash')` | | [`repeat`](#repeat) | counted loop | `composer.repeat(3, 'hello')` | -| [`try`](#try) | error handling | `composer.try('divideByN', 'NaN')` | -| [`finally`](#finally) | finalization | `composer.finally('tryThis', 'doThatAlways')` | -| [`retry`](#retry) | error recovery | `composer.retry(3, 'connect')` | | [`retain` and `retain_catch`](#retain) | persistence | `composer.retain('validateInput')` | -| [`async`](#async) | asynchronous invocation | `composer.async('sendMessage')` | +| [`retry`](#retry) | error recovery | `composer.retry(3, 'connect')` | +| [`sequence` or `seq`](#sequence) | sequence | `composer.sequence('hello', 'bye')` | +| [`task`](#task) | single task | `composer.task('echo')` +| [`try`](#try) | error handling | `composer.try('divideByN', 'NaN')` | +| [`while` and `while_nosave`](#while) | loop | `composer.while('notEnough', 'doMore')` | -The `action`, `function`, and `literal` combinators construct compositions respectively from actions, functions, and constant values. The other combinators combine existing compositions to produce new compositions. +The `action`, `function`, and `literal` combinators construct compositions +respectively from OpenWhisk actions, Javascript functions, and constant values. +The other combinators combine existing compositions to produce new compositions. ## Shorthands @@ -31,15 +34,16 @@ Where a composition is expected, the following shorthands are permitted: - `fun` of type `function` stands for `composer.function(fun)`, - `null` stands for the empty sequence `composer.empty()`. -## Primitive combinators - -Some of these combinators are _derived_ combinators: they are equivalent to combinations of other combinators. The `composer` module offers a `composer.lower` method (see [COMPOSER.md](#COMPOSER.md)) that can eliminate derived combinators from a composition, producing an equivalent composition made only of _primitive_ combinators. - ## Action -`composer.action(name, [options])` is a composition with a single action named _name_. It invokes the action named _name_ on the input parameter object for the composition and returns the output parameter object of this action invocation. +`composer.action(name, [options])` is a composition with a single action named +_name_. It invokes the action named _name_ on the input parameter object for the +composition and returns the output parameter object of this action invocation. -The action _name_ may specify the namespace and/or package containing the action following the usual OpenWhisk grammar. If no namespace is specified, the default namespace is assumed. If no package is specified, the default package is assumed. +The action _name_ may specify the namespace and/or package containing the action +following the usual OpenWhisk grammar. If no namespace is specified, the default +namespace is assumed. If no package is specified, the default package is +assumed. Examples: ```javascript @@ -47,7 +51,8 @@ composer.action('hello') composer.action('myPackage/myAction') composer.action('/whisk.system/utils/echo') ``` -The optional `options` dictionary makes it possible to provide a definition for the action being composed. +The optional `options` dictionary makes it possible to provide a definition for +the action being composed. ```javascript // specify the code for the action as a function composer.action('hello', { action: function () { return { message: 'hello' } } }) @@ -76,16 +81,22 @@ composer.action('hello', { filename: 'hello.js' }) // specify a sequence of actions composer.action('helloAndBye', { sequence: ['hello', 'bye'] }) ``` -The action may be defined by providing the code for the action as a string, as a Javascript function, or as a file name. Alternatively, a sequence action may be defined by providing the list of sequenced actions. The code (specified as a string) may be annotated with the kind of the action runtime. +The action may be defined by providing the code for the action as a string, as a +Javascript function, or as a file name. Alternatively, a sequence action may be +defined by providing the list of sequenced actions. The code (specified as a +string) may be annotated with the kind of the action runtime. ### Environment capture in actions -Javascript functions used to define actions cannot capture any part of their declaration environment. The following code is not correct as the declaration of `name` would not be available at invocation time: +Javascript functions used to define actions cannot capture any part of their +declaration environment. The following code is not correct as the declaration of +`name` would not be available at invocation time: ```javascript let name = 'Dave' composer.action('hello', { action: function main() { return { message: 'Hello ' + name } } }) ``` -In contrast, the following code is correct as it resolves `name`'s value at composition time. +In contrast, the following code is correct as it resolves `name`'s value at +composition time. ```javascript let name = 'Dave' composer.action('hello', { action: `function main() { return { message: 'Hello ' + '${name}' } }` }) @@ -93,11 +104,21 @@ composer.action('hello', { action: `function main() { return { message: 'Hello ' ## Function -`composer.function(fun)` is a composition with a single Javascript function _fun_. It applies the specified function to the input parameter object for the composition. - - If the function returns a value of type `function`, the composition returns an error object. - - If the function throws an exception, the composition returns an error object. The exception is logged as part of the conductor action invocation. - - If the function returns a value of type other than function, the value is first converted to a JSON value using `JSON.stringify` followed by `JSON.parse`. If the resulting JSON value is not a JSON dictionary, the JSON value is then wrapped into a `{ value }` dictionary. The composition returns the final JSON dictionary. - - If the function does not return a value and does not throw an exception, the composition returns the input parameter object for the composition converted to a JSON dictionary using `JSON.stringify` followed by `JSON.parse`. +`composer.function(fun)` is a composition with a single Javascript function +_fun_. It applies the specified function to the input parameter object for the +composition. + - If the function returns a value of type `function`, the composition returns + an error object. + - If the function throws an exception, the composition returns an error object. + The exception is logged as part of the conductor action invocation. + - If the function returns a value of type other than function, the value is + first converted to a JSON value using `JSON.stringify` followed by + `JSON.parse`. If the resulting JSON value is not a JSON dictionary, the JSON + value is then wrapped into a `{ value }` dictionary. The composition returns + the final JSON dictionary. + - If the function does not return a value and does not throw an exception, the + composition returns the input parameter object for the composition converted + to a JSON dictionary using `JSON.stringify` followed by `JSON.parse`. Examples: ```javascript @@ -110,46 +131,74 @@ composer.function(product) ### Environment capture in functions -Functions intended for compositions cannot capture any part of their declaration environment. They may however access and mutate variables in an environment consisting of the variables declared by the [composer.let](#composerletname-value-composition_1-composition_2-) combinator discussed below. +Functions intended for compositions cannot capture any part of their declaration +environment. They may however access and mutate variables in an environment +consisting of the variables declared by the [let](#let) combinator discussed +below. -The following is not legal: +The following code is not correct: ```javascript let name = 'Dave' composer.function(params => ({ message: 'Hello ' + name })) ``` -The following is legal: +The following code is correct: ```javascript composer.let({ name: 'Dave' }, composer.function(params => ({ message: 'Hello ' + name }))) ``` ## Literal -`composer.literal(value)` and its synonymous `composer.value(value)` output a constant JSON dictionary. This dictionary is obtained by first converting the _value_ argument to JSON using `JSON.stringify` followed by `JSON.parse`. If the resulting JSON value is not a JSON dictionary, the JSON value is then wrapped into a `{ value }` dictionary. +`composer.literal(value)` and its synonymous `composer.value(value)` output a +constant JSON dictionary. This dictionary is obtained by first converting the +_value_ argument to JSON using `JSON.stringify` followed by `JSON.parse`. If the +resulting JSON value is not a JSON dictionary, the JSON value is then wrapped +into a `{ value }` dictionary. -The _value_ argument may be computed at composition time. For instance, the following composition captures the date at the time the composition is encoded to JSON: +The _value_ argument may be computed at composition time. For instance, the +following composition captures the date at the time the composition is encoded +to JSON: ```javascript composer.sequence( composer.literal(Date()), composer.action('log', { action: params => ({ message: 'Composition time: ' + params.value }) })) ``` -JSON values cannot represent functions. Applying `composer.literal` to a value of type `'function'` will result in an error. Functions embedded in a `value` of type `'object'`, e.g., `{ f: p => p, n: 42 }` will be silently omitted from the JSON dictionary. In other words, `composer.literal({ f: p => p, n: 42 })` will output `{ n: 42 }`. +JSON values cannot represent functions. Applying `composer.literal` to a value +of type `'function'` will result in an error. Functions embedded in a `value` of +type `'object'`, e.g., `{ f: p => p, n: 42 }` will be silently omitted from the +JSON dictionary. In other words, `composer.literal({ f: p => p, n: 42 })` will +output `{ n: 42 }`. -In general, a function can be embedded in a composition either by using the `composer.function` combinator, or by embedding the source code for the function as a string and later using `eval` to evaluate the function code. +In general, a function can be embedded in a composition either by using the +`composer.function` combinator, or by embedding the source code for the function +as a string and later using `eval` to evaluate the function code. -## Empty +## Sequence -`composer.empty()` is a shorthand for the empty sequence `composer.sequence()`. It is typically used to make it clear that a composition, e.g., a branch of an `if` combinator, is intentionally doing nothing. +`composer.sequence(composition_1, composition_2, ...)` or it synonymous +`composer.seq(composition_1, composition_2, ...)` chain a series of compositions +(possibly empty). -## Sequence +The input parameter object for the composition is the input parameter object of +the first composition in the sequence. The output parameter object of one +composition in the sequence is the input parameter object for the next +composition in the sequence. The output parameter object of the last composition +in the sequence is the output parameter object for the composition. -`composer.sequence(composition_1, composition_2, ...)` chains a series of compositions (possibly empty). +If one of the components fails (i.e., returns an error object), the remainder of +the sequence is not executed. The output parameter object for the composition is +the error object produced by the failed component. -The input parameter object for the composition is the input parameter object of the first composition in the sequence. The output parameter object of one composition in the sequence is the input parameter object for the next composition in the sequence. The output parameter object of the last composition in the sequence is the output parameter object for the composition. +An empty sequence behaves as a sequence with a single function `params => +params`. The output parameter object for the empty sequence is its input +parameter object unless it is an error object, in which case, as usual, the +error object only contains the `error` field of the input parameter object. -If one of the components fails (i.e., returns an error object), the remainder of the sequence is not executed. The output parameter object for the composition is the error object produced by the failed component. +## Empty -An empty sequence behaves as a sequence with a single function `params => params`. The output parameter object for the empty sequence is its input parameter object unless it is an error object, in which case, as usual, the error object only contains the `error` field of the input parameter object. +`composer.empty()` is a shorthand for the empty sequence `composer.sequence()`. +It is typically used to make it clear that a composition, e.g., a branch of an +`if` combinator, is intentionally doing nothing. ## Task @@ -157,108 +206,203 @@ An empty sequence behaves as a sequence with a single function `params => params ## Let -`composer.let({ name_1: value_1, name_2: value_2, ... }, composition_1_, _composition_2_, ...)` declares one or more variables with the given names and initial values, and runs a sequence of compositions in the scope of these declarations. - -The initial values must be valid JSON values. In particular, `composer.let({ foo: undefined })` is incorrect as `undefined` is not representable by a JSON value. On the other hand, `composer.let({ foo: null })` is correct. For the same reason, initial values cannot be functions, e.g., `composer.let({ foo: params => params })` is incorrect. - -Variables declared with `composer.let` may be accessed and mutated by functions __running__ as part of the following sequence (irrespective of their place of definition). In other words, name resolution is [dynamic](https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Static_versus_dynamic). If a variable declaration is nested inside a declaration of a variable with the same name, the innermost declaration masks the earlier declarations. - -For example, the following composition invokes composition `composition` repeatedly `n` times. +`composer.let({ name_1: value_1, name_2: value_2, ... }, composition_1, +composition_2, ...)` declares one or more variables with the given names and +initial values, and runs a sequence of compositions in the scope of these +declarations. + +The initial values must be valid JSON values. In particular, `composer.let({foo: +undefined }, composition)` is incorrect as `undefined` is not representable by a +JSON value. Use `composer.let({ foo: null }, composition)` instead. For the same +reason, initial values cannot be functions, e.g., `composer.let({ foo: params => +params }, composition)` is incorrect. + +Variables declared with `composer.let` may be accessed and mutated by functions +__running__ as part of the following sequence (irrespective of their place of +definition). In other words, name resolution is +[dynamic](https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Static_versus_dynamic). +If a variable declaration is nested inside a declaration of a variable with the +same name, the innermost declaration masks the earlier declarations. + +For example, the following composition invokes composition `composition` +repeatedly `n` times. ```javascript composer.let({ i: n }, composer.while(() => i-- > 0, composition)) ``` -Variables declared with `composer.let` are not visible to invoked actions. However, they may be passed as parameters to actions as for instance in: +Variables declared with `composer.let` are not visible to invoked actions. +However, they may be passed as parameters to actions as for instance in: ```javascript composer.let({ n: 42 }, () => ({ n }), 'increment', params => { n = params.n }) ``` -In this example, the variable `n` is exposed to the invoked action as a field of the input parameter object. Moreover, the value of the field `n` of the output parameter object is assigned back to variable `n`. +In this example, the variable `n` is exposed to the invoked action as a field of +the input parameter object. Moreover, the value of the field `n` of the output +parameter object is assigned back to variable `n`. ## Mask -`composer.mask(composition)` is meant to be used in combination with the `let` combinator. It makes it possible to hide the innermost enclosing `let` combinator from _composition_. It is typically used to define composition templates that need to introduce variables. +`composer.mask(composition_1, composition_2, ...)` is meant to be used in +combination with the `let` combinator. It runs a sequence of compositions +excluding from their scope the variables declared by the innermost enclosing +`let`. It is typically used to define composition templates that need to +introduce variables. -For instance, the following function is a possible implementation of a repeat loop: +For instance, the following function is a possible implementation of a repeat +loop: ```javascript function loop(n, composition) { - return .let({ n }, composer.while(() => n-- > 0, composer.mask(composition))) + return composer.let({ n }, composer.while(() => n-- > 0, composer.mask(composition))) } ``` -This function takes two parameters: the number of iterations _n_ and the _composition_ to repeat _n_ times. Here, the `mask` combinator makes sure that this declaration of _n_ is not visible to _composition_. Thanks to `mask`, the following example correctly returns `{ value: 12 }`. +This function takes two parameters: the number of iterations _n_ and the +_composition_ to repeat _n_ times. Here, the `mask` combinator makes sure that +this declaration of _n_ is not visible to _composition_. Thanks to `mask`, the +following example correctly returns `{ value: 12 }`. ```javascript composer.let({ n: 0 }, loop(3, loop(4, () => ++n))) ``` -While composer variables are dynamically scoped, the `mask` combinator alleviates the biggest concern with dynamic scoping: incidental name collision. +While composer variables are dynamically scoped, judicious use of the `mask` +combinator can prevent incidental name collision. ## If -`composer.if(condition, consequent, [alternate])` runs either the _consequent_ composition if the _condition_ evaluates to true or the _alternate_ composition if not. - -A _condition_ composition evaluates to true if and only if it produces a JSON dictionary with a field `value` with value `true`. Other fields are ignored. Because JSON values other than dictionaries are implicitly lifted to dictionaries with a `value` field, _condition_ may be a Javascript function returning a Boolean value. An expression such as `params.n > 0` is not a valid condition (or in general a valid composition). One should write instead `params => params.n > 0`. The input parameter object for the composition is the input parameter object for the _condition_ composition. - -The _alternate_ composition may be omitted. If _condition_ fails, neither branch is executed. - -The output parameter object of the _condition_ composition is discarded, one the choice of a branch has been made and the _consequent_ composition or _alternate_ composition is invoked on the input parameter object for the composition. For example, the following composition divides parameter `n` by two if `n` is even: +`composer.if(condition, consequent, [alternate])` runs either the _consequent_ +composition if the _condition_ evaluates to true or the _alternate_ composition +if not. + +A _condition_ composition evaluates to true if and only if it produces a JSON +dictionary with a field `value` with value `true`. Other fields are ignored. +Because JSON values other than dictionaries are implicitly lifted to +dictionaries with a `value` field, _condition_ may be a Javascript function +returning a Boolean value. An expression such as `params.n > 0` is not a valid +condition (or in general a valid composition). One should write instead `params +=> params.n > 0`. The input parameter object for the composition is the input +parameter object for the _condition_ composition. + +The _alternate_ composition may be omitted. If _condition_ fails, neither branch +is executed. + +The output parameter object of the _condition_ composition is discarded, one the +choice of a branch has been made and the _consequent_ composition or _alternate_ +composition is invoked on the input parameter object for the composition. For +example, the following composition divides parameter `n` by two if `n` is even: ```javascript composer.if(params => params.n % 2 === 0, params => { params.n /= 2 }) ``` -The `if_nosave` combinator is similar but it does not preserve the input parameter object, i.e., the _consequent_ composition or _alternate_ composition is invoked on the output parameter object of _condition_. The following example also divides parameter `n` by two if `n` is even: +The `if_nosave` combinator is similar but it does not preserve the input +parameter object, i.e., the _consequent_ composition or _alternate_ composition +is invoked on the output parameter object of _condition_. The following example +also divides parameter `n` by two if `n` is even: ```javascript composer.if_nosave(params => { params.value = params.n % 2 === 0 }, params => { params.n /= 2 }) ``` -In the first example, the condition function simply returns a Boolean value. The consequent function uses the saved input parameter object to compute `n`'s value. In the second example, the condition function adds a `value` field to the input parameter object. The consequent function applies to the resulting object. In particular, in the second example, the output parameter object for the condition includes the `value` field. - -While, the `if` combinator is typically more convenient, preserving the input parameter object is not free as it counts toward the parameter size limit for OpenWhisk actions. In essence, the limit on the size of parameter objects processed during the evaluation of the condition is reduced by the size of the saved parameter object. The `if_nosave` combinator omits the parameter save, hence preserving the parameter size limit. +In the first example, the condition function simply returns a Boolean value. The +consequent function uses the saved input parameter object to compute `n`'s +value. In the second example, the condition function adds a `value` field to the +input parameter object. The consequent function applies to the resulting object. +In particular, in the second example, the output parameter object for the +condition includes the `value` field. + +While, the `if` combinator is typically more convenient, preserving the input +parameter object is not free as it counts toward the parameter size limit for +OpenWhisk actions. In essence, the limit on the size of parameter objects +processed during the evaluation of the condition is reduced by the size of the +saved parameter object. The `if_nosave` combinator omits the parameter save, +hence preserving the parameter size limit. ## While -`composer.while(condition, body)` runs _body_ repeatedly while _condition_ evaluates to true. The _condition_ composition is evaluated before any execution of the _body_ composition. See [composer.if](#composerifcondition-consequent-alternate) for a discussion of conditions. - -A failure of _condition_ or _body_ interrupts the execution. The composition returns the error object from the failed component. - -The output parameter object of the _condition_ composition is discarded and the input parameter object for the _body_ composition is either the input parameter object for the whole composition the first time around or the output parameter object of the previous iteration of _body_. However, if `while_nosave` combinator is used, the input parameter object for _body_ is the output parameter object of _condition_. Moreover, the output parameter object for the whole composition is the output parameter object of the last _condition_ evaluation. - -For instance, the following composition invoked on dictionary `{ n: 28 }` returns `{ n: 7 }`: +`composer.while(condition, body)` runs _body_ repeatedly while _condition_ +evaluates to true. The _condition_ composition is evaluated before any execution +of the _body_ composition. See +[composer.if](#composerifcondition-consequent-alternate) for a discussion of +conditions. + +A failure of _condition_ or _body_ interrupts the execution. The composition +returns the error object from the failed component. + +The output parameter object of the _condition_ composition is discarded and the +input parameter object for the _body_ composition is either the input parameter +object for the whole composition the first time around or the output parameter +object of the previous iteration of _body_. However, if `while_nosave` +combinator is used, the input parameter object for _body_ is the output +parameter object of _condition_. Moreover, the output parameter object for the +whole composition is the output parameter object of the last _condition_ +evaluation. + +For instance, the following composition invoked on dictionary `{ n: 28 }` +returns `{ n: 7 }`: ```javascript composer.while(params => params.n % 2 === 0, params => { params.n /= 2 }) ``` -For instance, the following composition invoked on dictionary `{ n: 28 }` returns `{ n: 7, value: false }`: +For instance, the following composition invoked on dictionary `{ n: 28 }` +returns `{ n: 7, value: false }`: ```javascript composer.while_nosave(params => { params.value = params.n % 2 === 0 }, params => { params.n /= 2 }) ``` ## Dowhile -`composer.dowhile(condition, body)` is similar to `composer.while(body, condition)` except that _body_ is invoked before _condition_ is evaluated, hence _body_ is always invoked at least once. +`composer.dowhile(condition, body)` is similar to `composer.while(body, +condition)` except that _body_ is invoked before _condition_ is evaluated, hence +_body_ is always invoked at least once. -Like `while_nosave`, `dowhile_nosave` does not implicitly preserve the parameter object while evaluating _condition_. +Like `while_nosave`, `dowhile_nosave` does not implicitly preserve the parameter +object while evaluating _condition_. ## Repeat -`composer.repeat(count, body)` invokes _body_ _count_ times. +`composer.repeat(count, composition_1, composition_2, ...)` invokes a sequence +of compositions _count_ times. ## Try `composer.try(body, handler)` runs _body_ with error handler _handler_. -If _body_ returns an error object, _handler_ is invoked with this error object as its input parameter object. Otherwise, _handler_ is not run. +If _body_ returns an error object, _handler_ is invoked with this error object +as its input parameter object. Otherwise, _handler_ is not run. ## Finally `composer.finally(body, finalizer)` runs _body_ and then _finalizer_. -The _finalizer_ is invoked in sequence after _body_ even if _body_ returns an error object. +The _finalizer_ is invoked in sequence after _body_ even if _body_ returns an +error object. The output parameter object of _body_ (error object or not) is the +input parameter object of _finalizer_. ## Retry -`composer.retry(count, body)` runs _body_ and retries _body_ up to _count_ times if it fails. The output parameter object for the composition is either the output parameter object of the successful _body_ invocation or the error object produced by the last _body_ invocation. +`composer.retry(count, composition_1, composition_2, ...)` runs a sequence of +compositions retrying the sequence up to _count_ times if it fails. The output +parameter object for the composition is either the output parameter object of +the successful sequence invocation or the error object produced by the last +sequence invocation. ## Retain -`composer.retain(body)` runs _body_ on the input parameter object producing an object with two fields `params` and `result` such that `params` is the input parameter object of the composition and `result` is the output parameter object of _body_. +`composer.retain(composition_1, composition_2, ...)` runs a sequence of +compositions on the input parameter object producing an object with two fields +`params` and `result` such that `params` is the input parameter object of the +composition and `result` is the output parameter object of the sequence. -If _body_ fails, the output of the `retain` combinator is only the error object (i.e., the input parameter object is not preserved). In constrast, the `retain_catch` combinator always outputs `{ params, result }`, even if `result` is an error result. +If the sequence fails, the output of the `retain` combinator is only the error +object (i.e., the input parameter object is not preserved). In contrast, the +`retain_catch` combinator always outputs `{ params, result }`, even if `result` +is an error object. + +## Merge + +`composer.merge(composition_1, composition_2, ...)` runs a sequence of +compositions on the input parameter object and merge the output parameter object +of the sequence into the input parameter object. In other words, +`composer.merge(composition_1, composition_2, ...)` is a shorthand for: +``` +composer.seq(composer.retain(composition_1, composition_2, ...), ({ params, result }) => Object.assign(params, result)) +``` ## Async -`composer.async(body)` runs the _body_ composition asynchronously. It spawns _body_ but does not wait for it to execute. It immediately returns a dictionary with a single field named `activationId` identifying the invocation of _body_. +`composer.async(composition_1, composition_2, ...)` runs a sequence of +compositions asynchronously. It invokes the sequence but does not wait for it to +execute. It immediately returns a dictionary that includes a field named +`activationId` with the activation id for the sequence invocation. diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md new file mode 100644 index 0000000..17e0e19 --- /dev/null +++ b/docs/COMMANDS.md @@ -0,0 +1,99 @@ +# Commands + +The `compose` command compiles composition code to a portable JSON format. The +`deploy` command deploys JSON-encoded compositions. These commands are intended +as a minimal complement to the OpenWhisk CLI. The OpenWhisk CLI already has the +capability to configure, invoke, and delete compositions since these are just +OpenWhisk actions but lacks the capability to create composition actions. The +`compose` and `deploy` commands bridge this gap. They make it possible to deploy +compositions as part of the development cycle or in shell scripts. They do not +replace the OpenWhisk CLI however as they do not duplicate existing OpenWhisk +CLI capabilities. + +## Compose + +``` +compose +``` +``` +Usage: + compose composition.js [flags] +Flags: + --ast only output the ast for the composition + -v, --version output the composer version +``` +The `compose` command takes a Javascript module that exports a composition +object (for example [demo.js](../samples/demo.js)) and compiles this object to a +portable JSON format on the standard output. +``` +compose demo.js > demo.json +``` +If the `--ast` option is specified, the `compose` command only outputs a JSON +representation of the Abstract Syntax Tree for the composition. + +# Deploy + +``` +deploy +``` +``` +Usage: + deploy composition composition.json [flags] +Flags: + -a, --annotation KEY=VALUE add KEY annotation with VALUE + -A, --annotation-file KEY=FILE add KEY annotation with FILE content + --apihost HOST API HOST + -i, --insecure bypass certificate checking + -u, --auth KEY authorization KEY + -v, --version output the composer version + -w, --overwrite overwrite actions if already defined +``` +The `deploy` command deploys a JSON-encoded composition with the given name. +``` +deploy demo demo.json -w +``` +``` +ok: created /_/authenticate,/_/success,/_/failure,/_/demo +``` + +The `deploy` command synthesizes and deploys a conductor action that implements +the composition with the given name. It also deploys the composed actions for +which definitions are provided as part of the composition. + +The `deploy` command outputs the list of deployed actions or an error result. If +an error occurs during deployment, the state of the various actions is unknown. + +The `-w` option authorizes the `deploy` command to overwrite existing +definitions. More precisely, it deletes the deployed actions before recreating +them. As a result, default parameters, limits, and annotations on preexisting +actions are lost. + +### Annotations + +The `deploy` command implicitly annotates the deployed composition action with +the required `conductor` annotations. Other annotations may be specified by +means of the flags: +``` + -a, --annotation KEY=VALUE add KEY annotation with VALUE + -A, --annotation-file KEY=FILE add KEY annotation with FILE content +``` + +### OpenWhisk instance + +Like the OpenWhisk CLI, the `deploy` command supports the following flags for +specifying the OpenWhisk instance to use: +``` + --apihost HOST API HOST + -i, --insecure bypass certificate checking + -u, --auth KEY authorization KEY +``` +If the `--apihost` flag is absent, the environment variable `__OW_API_HOST` is +used in its place. If neither is available, the `deploy` command extracts the +`APIHOST` key from the whisk property file for the current user. + +If the `--auth` flag is absent, the environment variable `__OW_API_KEY` is used +in its place. If neither is available, the `deploy` command extracts the `AUTH` +key from the whisk property file for the current user. + +The default path for the whisk property file is `$HOME/.wskprops`. It can be +altered by setting the `WSK_CONFIG_FILE` environment variable. diff --git a/docs/COMPOSE.md b/docs/COMPOSE.md deleted file mode 100644 index 5513735..0000000 --- a/docs/COMPOSE.md +++ /dev/null @@ -1,260 +0,0 @@ -# Compose Command - -The `compose` command makes it possible to deploy compositions from the command line. - -The `compose` command is intended as a minimal complement to the OpenWhisk CLI. The OpenWhisk CLI already has the capability to configure, invoke, and delete compositions (since these are just OpenWhisk actions) but lacks the capability to create composition actions. The `compose` command bridges this gap. It makes it possible to deploy compositions as part of the development cycle or in shell scripts. It is not a replacement for the OpenWhisk CLI however as it does not duplicate existing OpenWhisk CLI capabilities. Moreover, for a much richer developer experience, we recommend using [Shell](https://github.com/ibm-functions/shell). - -## Usage - -``` -compose -``` -``` -Usage: - compose composition.js[on] command [flags] -Commands: - --json output the json representation for the composition (default command) - --deploy NAME deploy the composition with name NAME - --entity NAME output the conductor action definition for the composition (giving name NAME to the composition) - --entities NAME convert the composition into an array of action definition (giving name NAME to the composition) - --encode output the conductor action code for the composition -Flags: - --lower [VERSION] lower to primitive combinators or specific composer version - --apihost HOST API HOST - -u, --auth KEY authorization KEY - -i, --insecure bypass certificate checking - -v, --version output the composer version - --quiet omit detailed diagnostic messages - --composer COMPOSER instantiate a custom composer module -``` -The `compose` command requires either a Javascript file that evaluates to a composition (for example [demo.js](../samples/demo.js)) or a JSON file that encodes a composition (for example [demo.json](../samples/demo.json)). The JSON format is documented in [FORMAT.md](FORMAT.md). - -The `compose` command has several modes of operation: -- By default or when the `--json` option is specified, the command returns the composition encoded as a JSON dictionary. -- When the `--deploy` option is specified, the command deploys the composition given the desired name for the composition. -- When the `--encode` option is specified, the command returns the Javascript code for the [conductor action](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) for the composition. -- When the `--entity` option is specified, the command returns the complete conductor action definition as a JSON dictionary. -- When the `--entities` option is specified, the command returns an array of action definitions including not only the conductor action for the composition, but possibly also the nested action definitions. - -## JSON option - -By default, the `compose` command evaluates the composition code and outputs the resulting JSON dictionary: -``` -compose demo.js -``` -```json -{ - "type": "if", - "test": { - "type": "action", - "name": "/_/authenticate", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function ({ password }) { return { value: password === 'abc123' } }" - } - } - }, - "consequent": { - "type": "action", - "name": "/_/success", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'success' } }" - } - } - }, - "alternate": { - "type": "action", - "name": "/_/failure", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'failure' } }" - } - } - } -} - -## Entity option - -With the `--entity` option the `compose` command returns the conductor action definition for the composition. -``` -compose demo.js --entity demo -``` -```json -{ - "name": "/_/demo", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "..." - }, - "annotations": [ - { - "key": "conductor", - "value": { - "type": "if", - "test": { - "type": "action", - "name": "/_/authenticate" - }, - "consequent": { - "type": "action", - "name": "/_/success" - }, - "alternate": { - "type": "action", - "name": "/_/failure" - } - } - }, - { - "key": "composer", - "value": "0.4.0" - } - ] - } -} -``` - - -## Entities option - -With the `--entities` option the `compose` command returns not only the conductor action definition for the composition but also the definitions of nested actions and compositions. -``` -compose demo.js --entities demo -``` -```json -[ - { - "name": "/_/authenticate", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function ({ password }) { return { value: password === 'abc123' } }" - } - } - }, - { - "name": "/_/success", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'success' } }" - } - } - }, - { - "name": "/_/failure", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'failure' } }" - } - } - }, - { - "name": "/_/demo", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "..." - }, - "annotations": [ - { - "key": "conductor", - "value": { - "type": "if", - "test": { - "type": "action", - "name": "/_/authenticate" - }, - "consequent": { - "type": "action", - "name": "/_/success" - }, - "alternate": { - "type": "action", - "name": "/_/failure" - } - } - }, - { - "key": "composer", - "value": "0.4.0" - } - ] - } - } -] - -``` - -## Deploy option - -The `--deploy` option makes it possible to deploy a composition (Javascript or JSON) given the desired name for the composition: -``` -compose demo.js --deploy demo -``` -``` -ok: created /_/authenticate,/_/success,/_/failure,/_/demo -``` -Or: -``` -compose demo.js > demo.json -compose demo.json --deploy demo -``` -``` -ok: created /_/authenticate,/_/success,/_/failure,/_/demo -``` -The `compose` command synthesizes and deploys a conductor action that implements the -composition with the given name. It also deploys the composed actions for which -definitions are provided as part of the composition. - -The `compose` command outputs the list of deployed actions or an error result. If an error occurs during deployment, the state of the various actions is unknown. - -The `compose` command deletes the deployed actions before recreating them if necessary. As a result, default parameters, limits, and annotations on preexisting actions are lost. - -### Configuration - -Like the OpenWhisk CLI, the `compose` command supports the following flags for specifying the OpenWhisk deployment to use: -``` - --apihost HOST API HOST - -u, --auth KEY authorization KEY - -i, --insecure bypass certificate checking -``` -If the `--apihost` flag is absent, the environment variable `__OW_API_HOST` is used in its place. If neither is available, the `compose` command extracts the `APIHOST` key from the whisk property file for the current user. - -If the `--auth` flag is absent, the environment variable `__OW_API_KEY` is used in its place. If neither is available, the `compose` command extracts the `AUTH` key from the whisk property file for the current user. - -The default path for the whisk property file is `$HOME/.wskprops`. It can be altered by setting the `WSK_CONFIG_FILE` environment variable. - -## Encode option - -The `compose` command returns the code of the conductor action for the composition (Javascript or JSON) when invoked with the `--encode` option. -For instance, the conductor action code for the [demo.js](../samples/demo.js) composition is [demo-conductor.js](../samples/demo-conductor.js): -``` -compose demo.js --encode > demo-conductor.js -``` -This code may be deployed using the OpenWhisk CLI: -``` -wsk action create demo demo-conductor.js -a conductor true -``` -``` -ok: created action demo -``` -The conductor action code does not include definitions for nested actions or compositions. - -## Lowering - -If the `--lower VERSION` option is specified, the `compose` command uses the set of combinators of the specified revision of the `composer` module. Derived combinators that are more recent (if any) are translated into combinators of the older set. - -If the `--lower` option is specified without a version number, the `compose` command uses only primitive combinators. - -These options may be combined with any of the `compose` commands. - -## Composer option - -If the composition code uses a custom `composer` module, the path to the module must be specified via the `--composer` option. \ No newline at end of file diff --git a/docs/COMPOSER.md b/docs/COMPOSER.md deleted file mode 100644 index 68bf8eb..0000000 --- a/docs/COMPOSER.md +++ /dev/null @@ -1,109 +0,0 @@ -# Composer Module - -The [`composer`](../composer.js) Node.js module makes it possible define, deploy, and invoke compositions. - -## Installation - -To install the `composer` module, use the Node Package Manager: -``` -npm install @ibm-functions/composer -``` -To take advantage of the `compose` command, it may be useful to install the module globally as well (`-g` option). - -## Example - -The [samples/node-demo.js](../samples/node-demo.js) file illustrates how to define, deploy, and invoke a composition using `node`: -```javascript - -// require the composer module -const composer = require('@ibm-functions/composer') - -// define the composition -const composition = composer.if( - composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), - composer.action('success', { action: function () { return { message: 'success' } } }), - composer.action('failure', { action: function () { return { message: 'failure' } } })) - -// instantiate OpenWhisk client -const wsk = composer.util.openwhisk({ ignore_certs: true }) - -wsk.compositions.deploy({ name: 'demo', composition }) // deploy composition - .then(() => wsk.actions.invoke({ name: 'demo', params: { password: 'abc123' }, blocking: true })) // invoke composition - .then(({ response }) => console.log(JSON.stringify(response.result, null, 4)), console.error) -``` -node samples/node-demo.js -``` -```json -{ - "message": "success" -} -``` -Alternatively, the `compose` command can deploy compositions and the OpenWhisk CLI can invoke compositions. See [COMPOSE.md](COMPOSE.md) for details. - -# Helper methods - -The `composer` object offers a number of combinator methods to define composition objects, e.g., `composer.if`. Combinators are documented in [COMBINATORS.md](COMBINATORS.md). It also offers a series of helper methods via the `composer.util` object. - -| Helper method | Example | -| --:| --- | --- | -| [`version`](#version) | `composer.util.version` | -| [`deserialize`](#deserialize) | `composer.util.deserialize(JSON.stringify(composition))` | -| [`canonical`](#canonical) | `composer.util.canonical('demo')` | -| [`lower`](#lower) | `composer.util.lower(composer.if('authenticate', 'success', 'failure'), '0.4.0')` | -| [`encode`](#encode) | `composer.util.encode('demo', composition, '0.4.0')` | -| [`openwhisk`](#openwhisk-client) | `composer.util.openwhisk()` | - -## Version - -`composer.util.version` returns the version number for the composer module. - -## Deserialize - -`composer.util.deserialize(composition)` recursively deserializes a serialized composition object. In other words, it recreates a `Composition` object from the input JSON dictionary. - -## Canonical - -`composer.util.canonical(name)` attempts to validate and expand the action name `name` to its canonical form. - -## Lower - -`composer.util.lower(composition, [combinators])` outputs a composition object equivalent to the input `composition` object but using a reduced set of combinators. The optional `combinators` parameter may specify the desired set, either directly as an array of combinator names, e.g., `['retain', 'retry']` or indirectly as a revision of the composer module, e.g., `'0.4.0'`. If the `combinators` parameter is undefined, the set of combinators is the set of _primitive_ combinators (see [COMBINATORS.md](COMBINATORS.md])). If an array of combinators is specified the primitive combinators are implicitly added to the array. If a `composer` module revision is specified, the target combinator set is the set of combinators available as of the specified revision of the `composer` module. - -For instance, `composer.util.lower(composition, ['retry'])` will preserve any instance of the `retry` combinator but replace other non-primitive combinators sur as `retain`. - -## Encode - -`composer.util.encode(name, composition, [combinators])` first invokes `composer.util.lower` on the composition with the specified `combinators` argument if any. It then encodes the composition as an array of actions. This array consists of all the actions defined as part of the composition plus the conductor action synthesized for the composition itself. - -The optional `combinators` parameter controls the optional lowering. See [lower](#lower) for details. - -## Openwhisk client - -The `composer` object offers an extension to the [OpenWhisk Client for Javascript](https://github.com/apache/incubator-openwhisk-client-js) that supports deploying compositions. - -An OpenWhisk client instance is obtained by invoking `composer.util.openwhisk([options])`, for instance with: -```javascript -const wsk = composer.util.openwhisk({ ignore_certs: true }) - -``` -The specific OpenWhisk deployment to use may be specified via the optional `options` argument, environment variables, or the OpenWhisk property file. Options have priority over environment variables, which have priority over the OpenWhisk property file. Options and environment variables are documented [here](https://github.com/apache/incubator-openwhisk-client-js#constructor-options). The default path for the whisk property file is `$HOME/.wskprops`. It can be altered by setting the `WSK_CONFIG_FILE` environment variable. - -The `composer` module adds to the OpenWhisk client instance a new top-level category named `compositions` with a method named `deploy`. - -### Deploying compositions - -`wsk.compositions.deploy({ name, composition, [combinators] })` optionally lowers, encodes, and deploys the composition `composition`. More precisely, it successively deploys all the actions defined in `composition` as well as `composition` itself (encoded as a conductor action). - -The optional `combinators` parameter controls the optional lowering. See [lower](#lower) for details. - -The `deploy` method returns a successful promise if all the actions were deployed successfully, or a rejected promise otherwise. In the later, the state of the various actions is unknown. - -The `deploy` method deletes the deployed actions before recreating them if necessary. As a result, default parameters, limits, and annotations on preexisting actions are lost. - -### Invoking, updating, and deleting compositions - -Since compositions are deployed as conductor actions, other management tasks for compositions can be achieved by invoking methods of `wsk.actions`. For example, to delete a composition named `demo`, use command: -```javascript -wsk.actions.delete('demo') -``` -Updating or deleting a conductor action only affect the action itself. It does not affect any other action deployed as part of the composition. diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index 87f51a0..b06b331 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -1,10 +1,14 @@ # Compositions -Composer makes it possible to assemble actions into rich workflows called _compositions_. An example composition is described in [../README.md](../README.md). +Composer makes it possible to assemble actions into rich workflows called +_compositions_. An example composition is described in +[../README.md](../README.md). ## Control flow -Compositions can express the control flow of typical a sequential imperative programming language: sequences, conditionals, loops, error handling. This control flow is specified using _combinator_ methods such as: +Compositions can express the control flow of typical a sequential imperative +programming language: sequences, conditionals, loops, structured error handling. +This control flow is specified using _combinator_ methods such as: - `composer.sequence(firstAction, secondAction)` - `composer.if(conditionAction, consequentAction, alternateAction)` - `composer.try(bodyAction, handlerAction)` @@ -13,29 +17,54 @@ Combinators are described in [COMBINATORS.md](COMBINATORS.md). ## Composition objects -Combinators return composition objects, i.e., instances of the `Composition` class. +Combinators return composition objects, i.e., instances of the `Composition` +class. ## Parameter objects and error objects -A composition, like any action, accepts a JSON dictionary (the _input parameter object_) and produces a JSON dictionary (the _output parameter object_). An output parameter object with an `error` field is an _error object_. A composition _fails_ if it produces an error object. +A composition, like any action, accepts a JSON dictionary (the _input parameter +object_) and produces a JSON dictionary (the _output parameter object_). An +output parameter object with an `error` field is an _error object_. A +composition _fails_ if it produces an error object. -By convention, an error object returned by a composition is stripped from all fields except from the `error` field. This behavior is consistent with the OpenWhisk action semantics, e.g., the action with code `function main() { return { error: 'KO', message: 'OK' } }` outputs `{ error: 'KO' }`. +By convention, an error object returned by a composition is stripped from all +fields except from the `error` field. This behavior is consistent with the +OpenWhisk action semantics, e.g., the action with code `function main() { return +{ error: 'KO', message: 'OK' } }` outputs `{ error: 'KO' }`. -Error objects play a specific role as they interrupt the normal flow of execution, akin to exceptions in traditional programming languages. For instance, if a component of a sequence returns an error object, the remainder of the sequence is not executed. Moreover, if the sequence is enclosed in an error handling composition like a `composer.try(sequence, handler)` combinator, the execution continues with the error handler. +Error objects play a specific role as they interrupt the normal flow of +execution, akin to exceptions in traditional programming languages. For +instance, if a component of a sequence returns an error object, the remainder of +the sequence is not executed. Moreover, if the sequence is enclosed in an error +handling composition like a `composer.try(sequence, handler)` combinator, the +execution continues with the error handler. ## Data flow -The invocation of a composition triggers a series of computations (possibly empty, e.g., for the empty sequence) obtained by chaining the components of the composition along the path of execution. The input parameter object for the composition is the input parameter object of the first component in the chain. The output parameter object of a component in the chain is typically the input parameter object for the next component if any or the output parameter object for the composition if this is the final component in the chain. +The invocation of a composition triggers a series of computations (possibly +empty, e.g., for the empty sequence) obtained by chaining the components of the +composition along the path of execution. The input parameter object for the +composition is the input parameter object of the first component in the chain. +The output parameter object of a component in the chain is typically the input +parameter object for the next component if any or the output parameter object +for the composition if this is the final component in the chain. -For example, the composition `composer.sequence('triple', 'increment')` invokes the `increment` action on the output of the `triple` action. +For example, the composition `composer.sequence('triple', 'increment')` invokes +the `increment` action on the output of the `triple` action. -Some combinators however are designed to alter the default flow of data. For instance, the `composer.retain(myAction)` composition returns a combination of the input parameter object and the output parameter object of `myAction`. +Some combinators however are designed to alter the default flow of data. For +instance, the `composer.merge('myAction')` composition merges the input and +output parameter objects of `myAction`. ## Components -Components of a compositions can be actions, Javascript functions, or compositions. +Components of a compositions can be actions, Javascript functions, or +compositions. -Javascript functions can be viewed as simple, anonymous actions that do not need to be deployed and managed separately from the composition they belong to. Functions are typically used to alter a parameter object between two actions that expect different schemas, as in: +Javascript functions can be viewed as simple, anonymous actions that do not need +to be deployed and managed separately from the composition they belong to. +Functions are typically used to alter a parameter object between two actions +that expect different schemas, as in: ```javascript composer.sequence('getUserNameAndPassword', params => ({ key = btoa(params.user + ':' + params.password) }), 'authenticate') ``` @@ -43,15 +72,21 @@ Combinators can be nested, e.g., ```javascript composer.if('isEven', 'half', composer.sequence('triple', 'increment')) ``` -Compositions can reference other compositions by name. For instance, assuming we deploy the sequential composition of the `triple` and `increment` actions as the composition `tripleAndIncrement`, the following code behaves identically to the previous example: +Compositions can reference other compositions by name. For instance, assuming we +deploy the sequential composition of the `triple` and `increment` actions as the +composition `tripleAndIncrement`, the following code behaves identically to the +previous example: ```javascript composer.if('isEven', 'half', 'tripleAndIncrement') ``` -The behavior of this last composition would be altered if we redefine the `tripleAndIncrement` composition to do something else, whereas the first example would not be affected. +The behavior of this last composition would be altered if we redefine the +`tripleAndIncrement` composition to do something else, whereas the first example +would not be affected. -## Nested declarations +## Embedded action definitions -A composition can embed the definitions of none, some, or all the composed actions as illustrated in [demo.js](../samples/demo.js): +A composition can embed the definitions of none, some, or all the composed +actions as illustrated in [demo.js](../samples/demo.js): ```javascript composer.if( composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), @@ -61,11 +96,13 @@ composer.if( ``` Deploying such a composition deploys the embedded actions. -## Serialization and deserialization - - Compositions objects can be serialized to JSON dictionaries by invoking `JSON.stringify` on them. Serialized compositions can be deserialized to composition objects using the `composer.deserialize(serializedComposition)` method. The JSON format is documented in [FORMAT.md](FORMAT.md). - In short, the JSON dictionary for a composition contains a representation of the syntax tree for this composition as well as the definition of all the actions embedded inside the composition. - ## Conductor actions -Compositions are implemented by means of OpenWhisk [conductor actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md). The conductor actions are implicitly synthesized when compositions are deployed using the `compose` command or the `composer.deploy` method. Alternatively, the `composer.encode` method can encode compositions without deploying them. See [COMPOSER.md](COMPOSER.md) for details. \ No newline at end of file +Compositions are implemented by means of OpenWhisk [conductor +actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md). +Compositions have all the attributes and capabilities of an action, e.g., +default parameters, limits, blocking invocation, web export. Execution +[traces](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md#activations) +and +[limits](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md#limits) +of compositions follow from conductor actions. diff --git a/docs/FORMAT.md b/docs/FORMAT.md deleted file mode 100644 index 47f0901..0000000 --- a/docs/FORMAT.md +++ /dev/null @@ -1,60 +0,0 @@ -# JSON Format - -Compositions are encoded as JSON dictionaries prior to deployment. For instance the composition in [demo.js](../samples/demo.js) is encoded as: -```json -{ - "type": "if", - "test": { - "type": "action", - "name": "/_/authenticate", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function ({ password }) { return { value: password === 'abc123' } }" - } - } - }, - "consequent": { - "type": "action", - "name": "/_/success", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'success' } }" - } - } - }, - "alternate": { - "type": "action", - "name": "/_/failure", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'failure' } }" - } - } - } -} -``` -This json dictionary has one mandatory field named `type` with the name of the combinator and possible other fields that depend on the specific combinator. The values of some of these fields may be themselves composition dictionaries. In this example, the `test`, `consequent`, and `alternate` fields are compositions of `type` action. - -The field names and types typically match the combinator method signatures: - -| Type | Fields | -| --:| --- | -| `action` | name:string, action:optional object | -| `function` | function:object | -| `literal` or `value` | value:json value | -| `empty` | -| `sequence` or `seq` | components:array of compositions | -| `let` | declarations:object, components:array of compositions | -| `mask`| components:array of compositions | -| `if` and `if_nosave` | test:composition, consequent:composition, alternate:composition | -| `while` and `while_nosave` | test:composition, body:composition | -| `dowhile` and `dowhile_nosave` | body:composition, test:composition | -| `repeat` | count:number, components:array of compositions | -| `try` | body:composition, handler:composition | -| `finally` | body:composition, finalizer:composition | -| `retry` | count:number, components:array of compositions | -| `retain` and `retain_catch` | components:array of compositions | -| `async` | body:composition | \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 7b7b26c..0cf3e8b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,14 +1,11 @@ # Composer Package The Composer package consists of: -* the [composer](../composer.js) Node.js module for authoring, deploying, and invoking compositions, -* the [compose](../bin/compose) command for managing compositions from the command line. +* the [composer](../composer.js) Node.js module for authoring compositions, +* the [compose](../bin/compose.js) and [deploy](../bin/deploy.js) commands for + managing compositions from the command line. The documentation for the Composer package is organized as follows: - [COMPOSITIONS.md](COMPOSITIONS.md) gives a brief introduction to compositions. -- [COMPOSER.md](COMPOSER.md) documents the `composer` module. -- [COMPOSE.md](COMPOSE.md) documents the `compose` command. -- [COMBINATORS.md](COMBINATORS.md) documents the methods of the `composer` object. -- [FORMAT.md](FORMAT.md) documents the JSON format for encoding compositions. -- [TEMPLATES.md](TEMPLATES.md) demonstrates various composition templates. -- The [tutorials](tutorials) folder includes various tutorials. +- [COMBINATORS.md](COMBINATORS.md) explains the composition constructs. +- [COMMANDS.md](COMMANDS.md) describes the `compose` and `deploy` commands. diff --git a/docs/TEMPLATES.md b/docs/TEMPLATES.md deleted file mode 100644 index 0d61b56..0000000 --- a/docs/TEMPLATES.md +++ /dev/null @@ -1,115 +0,0 @@ -# Composition Templates - -Composer makes it easy to define new composition templates. In essence, a composition template is just a composition with one or more variable arguments. In this document, we discuss key concepts of composition templates and describe a few useful templates. To use any of these templates, simply paste the template code into your composition file. - -## A first example - -The following composition templates invokes composition `composition` and returns the input dictionary augmented with the fields of the output dictionary, overwriting existing fields on name clashes: -```javascript -function merge(composition) { - return composer.seq(composer.retain(composition), ({ params, result }) => Object.assign(params, result)) -} -``` - -To instantiate a composition template, simply apply the Javascript function to concrete arguments as in: -```javascript -merge(({ n }) => ({ nPlusOne: n + 1 })) -``` -For example, invoking this composition on input `{ n: 42 }` outputs `{ n: 42, nPlusOne: 43 }`. - -The `composer` object itself may be extended with the new template using _monkey patching_: -```javascript -composer.merge = composition => composition.seq(composer.retain(composition), ({ params, result }) => Object.assign(params, result)) -``` - -## On the importance of mask - -Many predefined combinators are actually templates over more primitive combinators. For instance the `retain` combinator is essentially defined as follows: -```javascript -function retain(composition) { - return composer.let( - { params: null }, - args => { params = args }, - composer.mask(composition), - result => ({ params, result })) -} -``` - -This implementation first declares a variable named `params` using `composer.let`. It then saves the input dictionary by assigning it to `params`. Next it runs `composition`. It produces the final result by combining the output dictionary (bound to `result`) with the input dictionary (bound to `params`). - -It is important to notice the use of the `mask` combinator here. Since this implementation introduces a variable named `params` and invokes the parameter `composition` in the scope of the `params` variable, this variable declaration may clash with another declaration of `params` in the user code. By wrapping the `composition` invocation with `mask` we ensure that the `params` variable declared in this template is hidden from `composition`. Thanks to `mask`, the following composition correctly writes ```'Hi there!'``` to the standard output: -```javascript -composer.let({ params: 'Hi there!' }, retain(() => { console.log(params) })) -``` - -Because `composer` variables are dynamically scoped, without the `mask` combinator, the action log would show the value of the `params` variable declared in the template instead of the expected value. - -## Pseudo parallel - -The `composer` module does not support parallel execution at this time but we can fake it as follows: -```javascript -composer.par = (f, g) => - composer.let( - { input: null, left: null }, - args => { input = args }, - composer.mask(f), - args => { left = args; return input }, - composer.mask(g), - right => ({ left, right })) -``` -This code pretends to execute compositions `f` and `g` in parallel. They both receive the same input dictionary. The output dictionary for the composition has two fields: `left` carries the result of `f` and `right` carries the result of `g`. In fact the two composition are executed in sequence but `let`, `mask`, and a few Javascript function can flow the data as if running in parallel. - -This implementation does not handle exceptions in `f` or `g`. This is left as an exercise to the reader. - -## Apply - -This `apply` combinator makes it possible to invoke a `composition` on a `field` of the input dictionary, leaving other fields unchanged. -```javascript -// example.js -composer.apply = (field, composition) => - composer.let( - { field }, - composer.retain(p => p[field], composer.mask(composition)), - p => { p.params[field] = p.result; return p.params }) - -composer.apply('payload', p => { p.n++ }) -``` - -``` -compose example.js --deploy example -ok: created /_/example -``` -``` -wsk action invoke example -r -p payload '{"n":1,"p":42}' -{ - "payload": { - "n": 2, - "p": 42 - } -} -``` -In this example, the `let` combinator is used to capture the desired field name: it binds the `field` variable to the field name. - -## Forward - -This `forward` combinator excludes the specified `fields` from the input dictionary for `composition` and restores them afterwards. It is useful for instance to hide secrets from a composition. - -```javascript -composer.forward = (fields, composition) => - composer.let( - { fields }, - composer.retain(p => require('lodash').omit(p, ...fields), composer.mask(composition)), - ({ params, result }) => Object.assign(result, require('lodash').pick(params, ...fields))) - -composer.forward(['user', 'password'], untrustedComposition) -``` - -## Inject and extract - -The following combinators make it possible to bind a field of the parameter object to the value of the homonymous variable and vice versa. -```javascript -composer.inject = v => composer.seq(composer.let({ v }, params => { params[v] = eval(v) })) -composer.extract = v => composer.seq(composer.let({ v }, params => { eval(`${v} = params[v]`); delete params[v] })) - -composer.let({ token: null }, 'getSecretToken', composer.extract('token'), untrustedAction, composer.inject('token'), trustedAction) -``` diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md deleted file mode 100644 index 1070fc3..0000000 --- a/docs/tutorials/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Tutorials - -This folder contains a few tutorials to get started: -* [Introduction to Serverless - Composition](introduction/README.md): Setting up your - programming environment and getting started with Shell and Composer. -* [Building a Translation Slack Bot with Serverless - Composition](translateBot/README.md): A more advanced tutorial - using Composition to build a serverless Slack chatbot that does language - translation. diff --git a/docs/tutorials/introduction/README.md b/docs/tutorials/introduction/README.md deleted file mode 100644 index d4aa87c..0000000 --- a/docs/tutorials/introduction/README.md +++ /dev/null @@ -1,468 +0,0 @@ -# Introduction to Serverless Composition - -Composer is an [IBM Cloud Functions](https://ibm.biz/openwhisk) -programming model for composing individual functions into larger -applications. Compositions, informally named _apps_, run in the cloud -using automatically managed compute and memory resources. Composer is -an extension of the function-as-a-service computing model, and enables -stateful computation, control flow, and rich patterns of data flow. - -Programming for the serverless cloud is a uniquely new experience. For -this reason, we have developed a unified environment that offers the -benefits and familiarity of a command line interface, with -visualization and a graphical interface to assist in certain -tasks. This environment is offered through a new tool called -[IBM Cloud Shell](https://github.com/ibm-functions/shell), or just _Shell_. - -## Shell quick start - -Shell is a cross-platform desktop application powered by [Electron](https://electronjs.org/). - -### Before you run your first app - -You must have a valid IBM Cloud (i.e., Bluemix) -[account](https://ibm.biz/openwhisk), or deploy [Apache -OpenWhisk](https://github.com/apache/incubator-openwhisk) -locally. This is needed because Composer builds on and extends Apache -OpenWhisk, which powers IBM Cloud Functions. - -* Existing `wsk` CLI users: You can go directly to [Installing Shell](#installing-shell). - -* _New users using composer with IBM Cloud Functions:_ you need an IBM Cloud -[account](https://ibm.biz/openwhisk), and the [IBM Cloud CLI](https://console.bluemix.net/docs/cli/reference/bluemix_cli/download_cli.html#download_install) (`bx`). You will also need to install the Cloud Function Plugin for bx: - - ``` - $ bx plugin install Cloud-Functions -r bluemix - ``` - - After installing `bx` and the Cloud Function plugin, use `bx login` to generate a access token for Cloud Function. - - ``` - $ bx login -a api.ng.bluemix.net -o yourBluemixOrg -s yourBluemixSpace - ``` - - Run a test to generate credentials and verify your setup. Here, we perform a blocking (synchronous) invocation of echo, passing it "hello" as an argument. If you see the return message, you are good to go. - ``` - $ bx wsk action invoke /whisk.system/utils/echo -p message hello --result - { - "message": "hello" - } - ``` - -* _New users using composer with Apache OpenWhisk:_ you need a valid `$HOME/.wskprops` file and a locally deployed OpenWhisk instance. - - -### Installing Shell - -Shell is currently distributed through the [Node -package manager](https://www.npmjs.com/package/@ibm-functions/shell). - -``` -$ npm install -g @ibm-functions/shell -``` - -We roll out frequent updates and bug fixes. You can check for new -releases via `fsh version -u`. - -``` -$ fsh version -u -You are currently on version x.y.z -Checking for updates... you are up to date! -``` - -We recommend updating the shell via the same `npm install` command -shown earlier. Consult the [troubleshooting -guide](https://github.com/ibm-functions/shell/blob/master/npm.md) if -your installation fails. - - -### Starting Shell - -``` -$ fsh shell -``` - -You will see a window popping up. Welcome to Shell! - -_Tip:_ If you are using Mac, you can keep Shell in the dock by right-clicking on the blue Cloud Function Shell icon and choose `Options > Keep in Dock`. Next time you can click on the icon in the dock to launch Shell. - - -## Your first app - -Compositions are described using a [Node.js library](../../README.md) -which offers an SDK for describing control structures. We call these -_combinators_. The simplest combinator constructs a sequence. For example, here is -a snippet for your first app: - -```javascript -composer.sequence(args => ({msg: `hello ${args.name}!`})) -``` - -The code describes a sequence app with just one function that is inlined for convenience. - -There are two ways to deploy a composition code snippet. One is using Shell to write the code and deploy it. The other is using any editor to write this code, save it as a local file, and deploy the file using a Shell command. We describe both here. - - -### Write an app in Shell - -In Shell, enter - -```bash -# enter in Shell -> compose myApp -``` - -where `myApp` is the name of the app in the cloud. This command opens a built-in editor in a sidecar for writing code. Copy the `composer.sequence` code above and paste it into the editor. Hit "Deploy" at the bottom stripe to deploy it. After the app is successfully deployed, Shell will show a flow graph that represents the textual composition code at the bottom of the editor as a verification. - -_Tip:_ Enter `edit myApp` to edit `myApp` after it is deployed. - -|| -|:--:| -|Your first app, composed in Shell.| - - -### Write an app in an external editor - -You may also use your favorite editor to compose apps. When finished, save your code to a file on your machine with the extension `.js`. To view your local composition javascript file as a graph, enter - -```bash -# enter in Shell -> app preview path/to/file.js -``` - -Shell watches the file you are editing and automatically -updates the graph as you compose. You can use this active preview mode -to incrementally build your application, sanity checking your control -flow as you go. - -|| -|:--:| -|Writing an app in my own editor, and previewing the code as a graph in Shell.| - - -To deploy a local composition file to the cloud, enter this command: -```bash -# enter in Shell -> app create myApp path/to/file.js -``` - -Again, `myApp` is the name of the app in the cloud. - -_Tip_: If you have an action already named `myApp`, the shell will report a name conflict. Use a different name for your app, or use `app update` if you want to update an existing app. Apps are stored as OpenWhisk actions, and hence the naming restrictions for OpenWhisk apply. - - -## Running your first app - -Run your first app using this command: - -```bash -# enter in Shell -> app invoke myApp -p name composer -``` - -You will see the result in the sidecar. Click on different buttons in the sidecar bottom stripe to explore different views. - -_Tip #1:_ Enter `app invoke --help` to view the usage of the `app invoke` command. You can access the usage information of other commands in Shell in the same way using `--help`. - -_Tip #2:_ Enter `session list` to view a list of previous app executions. - - -## Composing OpenWhisk actions - -Combinators accept either inline Node.js functions or actions by name. -For the latter, you may use a fully qualified name of an action (i.e., -`/namespace[/package]/action`) or its short name. Here is an example -using the `date` action from the `/whisk.system/utils` package. - -```javascript -composer.sequence('/whisk.system/utils/date') -``` - -A composition which refers to actions by name will not run correctly -if there are missing referenced entities. The `app preview` will -highlight any missing entities. As an example, preview the built-in -[`@demos/if.js`](https://github.com/ibm-functions/shell/blob/master/app/demos/if.js) -composition, which is [described in the next -section](#if-combinator). The control flow graph should be -self-explanatory. An action is gray when it is not yet deployed, and -blue otherwise. - -```bash -# enter in Shell -> app preview @demos/if.js -``` - -|| -|:--:| -|Control flow graph for `if` combinator. An action that is not yet deployed is gray, and blue otherwise.| - -_Tip:_ Shell supports `wsk` CLI commands for deploying OpenWhisk actions. We will explain how to do so next. You can also read more about using `wsk` commands in Shell [here](https://github.com/ibm-functions/shell/blob/master/fsh.md). - - -### Composing inline functions vs. OpenWhisk actions - -The main difference between using an inline function verses a OpenWhisk action in a composition is that an inline function does not generate an activation like an OpenWhisk action. [Activations](https://github.com/apache/incubator-openwhisk/blob/master/docs/reference.md) record runtime data like the execution time and output. They are useful for debugging. - -When making a real app, we encourage you to create the main components as OpenWhisk actions, as OpenWhisk actions can be reused by different apps and are easier to debug. Inline functions can be used as a convenient way to connect different components together (such as renaming input and output, generating an error message) and are better kept short and simple. - - -## Compositions by example - -You now have the basic tools to build a serverless composition, invoke -it, and inspect its execution and result. Currently, Composer offers [13 different combinators](../../README.md#combinators) to support conditions, iterations, error handling, variable declarations and other common programming constructs for building various types of apps. - -This section will introduce you to some combinators for creating richer control and data flow, while other combinators are covered in the [reference manual](../../README.md). All javascript code described below is [bundled in Shell](https://github.com/ibm-functions/shell/blob/master/app/demos) and can be accessed within Shell using the prefix `@demos/`. - - -### `if` combinator - -An `if` combinator allows you to describe a conditional flow with a -`then` and optional `else` branch. This is convenient for -short-circuiting a sequence for example, or taking data-dependent -paths in the control flow. - -Here is a short example. Say you have a function `welcome` which generates an HTML page. - -```javascript -// @demos/welcome.js -let welcome = args => ({ html: `welcome ${args.name}!` }) -``` - -In order to use this function as part of an authenticated API, we can -modify the function itself to introduce authentication middleware. Or, -we can compose it with an authentication function. - -```javascript -// @demos/authenticate.js -let authenticate = args => ({ value: args.token === "secret" }) -``` - -For illustration purposes, `authenticate` is a simple token based -checker. If the token equals the secret value, return `true`, and -`false` otherwise. In a real scenario, this function may delegate to a -third party service or identity provider. - -Let's add a third function, this one to deal with the -non-authenticated case and return a different HTML page, perhaps -informing the client to try again with the proper secret. - -```javascript -// @demos/login.js -let login = args => ({ html: `please say the magic word.` }) -``` - -The `if` combinator composes these three functions as you might -expect. - -```javascript -// @demos/if.js -composer.if( - /* cond */ 'authenticate', - /* then */ 'welcome', - /* else */ 'login') -``` - -Now, enter the following in Shell to deploy and run the app. - -```bash -# enter in Shell -# create required actions -> action create authenticate @demos/authenticate.js -> action create welcome @demos/welcome.js -> action create login @demos/login.js - -# create app -> app create if @demos/if.js - -# invoke app, with no secret parameter -> app invoke if -{ - html: "please say the magic word." -} - -# now invoke with secret parameter -> app invoke if -p token secret -p name if-combinator -{ - html: "welcome if-combinator!" -} -``` - -_Tip:_ You can see the output data of an action node in the `Session Flow` graph by clicking on the node. This will bring you to the corresponding activation. _Note:_ An inline function node is not clickable as it does not generate an activation. - -Each of the activations will have a different session id, which are reported by listing the available sessions. - -```bash -# enter in Shell -> session list -``` - -Clicking on a session id from the list will open that session in the sidecar. - -_Tip:_ Clicking on a session id invokes the command `session get sessionId` to view the session info in the sidecar. - - -### `try` combinator - -Another common composition pattern is for error handling and -recovery. Composer offers a `try` combinator that is analogous to -`try-catch`. - -A example to illustrate using `try` is a schema or data validation -action. Let `validate` be an action which checks if a string is base64 -encoded, and which throws an exception if the input is not valid. A -`try` combinator allows an error handler to rewrite the result, as -one example, to suite the particular usage scenario in the app. - -```javascript -// @demos/try.js -composer.try( - /* try */ 'validate', - /* catch */ args => ({ ok: false })) -``` - -The `validate` action is available as [`@demos/validate.js`](https://github.com/ibm-functions/shell/blob/master/app/demos/validate.js) and the -composition as [`@demos/try.js`](https://github.com/ibm-functions/shell/blob/master/app/demos/try.js) for your convenience. - -```bash -# enter in Shell -# create validate action -> action create validate @demos/validate.js - -# create app -> app create try @demos/try.js - -# invoke app with valid parameter -> app invoke try -p str aGVsbG8gdHJ5IQ== -{ - ok: true -} - -# and now for the failing case -> app invoke try -p str bogus -{ - ok: false -} -``` - -It is worth looking at the session flow of the second app invoke where -the catch handler is invoked. - -```bash -# enter in Shell -> session get --last try -``` - -|| -|:--:| -|Session execution for `try` where the handler is invoked.| - - -Notice that the `validate` action failed, as expected. This is -visually recognized by the red-colored action, and the hover text which -shows the action result containing the error. The app result is -successful however, as the handler rewrites the exception into a -different result. - -## Nesting and forwarding - -An important property of the combinators is that they nest. This -encourages modularity and composition reuse. The example that follows -illustrates both composition nesting, and data forwarding. The example -builds on the `try` app described in the previous section. Here, after -the validate task, we extend the composition with a base64 decoder to -render the input `str` in plain text. - -Recall that the result of the `validate` task is `{ok: true}`, -not the `str` argument that it processed. So we need a way to forward -`str` around this action. In other words, we _retain_ the input -arguments to `validate`, and pass them to the next action in the -sequence. Composer offers a combinator for just this purpose. Below -is the composition showing the inner sequence with the data forwarding -combinator `retain`. - -```javascript -// @demos/retain.js -composer.try( - composer.sequence( - composer.retain('validate'), - args => ({ text: new Buffer(args.params.str, 'base64').toString() })), - args => ({ ok: false })) -``` - -The `retain` combinator produces an output with two fields: `params` -and `result`. The former is the input parameter of the -composition. The latter is the output of `validate`. The control and -dataflow for this composition is shown below, and is available in the -shell as -[`@demos/retain.js`](https://github.com/ibm-functions/shell/blob/master/app/demos/retain.js). - -```bash -# enter in Shell -> app preview @demos/retain.js -``` - -|| -|:--:| -|Control flow graph showing the `retain` combinator and the implied dataflow around `validate`.| - -The app will now produce the decoded text as its final output. - -```bash -# enter in Shell -# create app -> app create retain @demos/retain.js - -# invoke app with valid parameter -> app invoke retain -p str aGVsbG8gdHJ5IQ== -{ - text: "hello try!" -} - -# and now for the failing case -> app invoke retain -p str bogus -{ - ok: false -} -``` - -## Variables and scoping - -The composer allows you to introduce variables within a composition, -and to limit their scope. This is useful when you have to introduce -service keys and credentials for example. A scoped variable is defined -using `let`. The example below illustrates how you might introduce a -"secret" for a specific task without its value escaping to other -compositions or functions. - -```javascript -// @demos/let.js -composer.sequence( - composer.let({secret: 42}, - composer.task(_ => ({ ok: secret === 42 }))), - composer.task(_ => ({ ok: (typeof secret === 'undefined') }))) -``` - -The composition will execute successfully only if `secret` is not -leaked to the final task in the composition, while the value is -available inside the task nested within the `let`. - -```bash -# enter in Shell -> app create let @demos/let.js -> app invoke let -{ - ok: true -} -``` - -## Other combinators - -The examples shown here illustrate the more common combinators you -may use to create serverless compositions. There are more combinators -available in the Composer library. Refer to the [Composer reference -manual](../../README.md) for more details. - -## Next step - -Try the second tutorial, [building a translation chatbot](../translateBot/README.md). - diff --git a/docs/tutorials/introduction/editor.png b/docs/tutorials/introduction/editor.png deleted file mode 100644 index 47f446ca417d617a20aa604726895ce744dca9b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57283 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%0AIk$ezqB*?6KT;0$)5BWik9YZ%T8+ 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%0DFsF5xH4J( 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 diff --git a/docs/tutorials/introduction/if-preview.png b/docs/tutorials/introduction/if-preview.png deleted file mode 100644 index d1fd1c45976e061664181ea9e6e8737e00ef148a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48774 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

IYLyFB-Q45-G6q_eKxI`~a|{;GHUCxv?xSKct}o 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 E0K}3UF#rGn diff --git a/docs/tutorials/introduction/preview.png b/docs/tutorials/introduction/preview.png deleted file mode 100644 index b2ddea93eef2239323af95a97c001f0fb1cd319f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 279539 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

4Jg>_L(D(sCkwwx(B5ES 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 IlQDhwKMi^e761SM diff --git a/docs/tutorials/introduction/retain.png b/docs/tutorials/introduction/retain.png deleted file mode 100644 index 7266d34ce07ca996b66656c6d5b1fc7db71fd8ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55681 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 z 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 U3a=nKLI8i>i^_-;3+Z_O4`>pEIsgCw diff --git a/docs/tutorials/introduction/try-session.png b/docs/tutorials/introduction/try-session.png deleted file mode 100644 index 855bf6a4e5010b555e13ec76ae445d210039522b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59975 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 diff --git a/docs/tutorials/translateBot/README.md b/docs/tutorials/translateBot/README.md deleted file mode 100644 index cd4e41c..0000000 --- a/docs/tutorials/translateBot/README.md +++ /dev/null @@ -1,260 +0,0 @@ -# Building a Translation Slack Bot with Serverless Composition - -Let's do something fun with Composition: We will build a serverless chatbot that translates the user's message using the IBM Watson Language Translation services. This tutorial assumes you have finished the [introduction](../introduction/README.md), which describes the basics about Composition and the instructions to setup the development environment ([Shell](https://github.com/ibm-functions/shell)). - -Here's what our chatbot does. -* First, it identifies the language of the user's message. -* If the language is not English, it translates the message to English. -* If the language is already English, just to make things more fun, it translates the message to "Shakespeare English". -* If the message is not translatable (such as if the message is a number), it returns a error message. - -Let's get started. - -## Composing the app - -Here is our composition code, using the [Composer NodeJs library](../../README.md). -```javascript -composer.try( - composer.sequence( - 'myWatsonTranslator/languageId', - composer.if( - p => p.language !== 'en', - composer.sequence( - p => ({translateFrom: p.language, translateTo: 'en', payload: p.payload}), - 'myWatsonTranslator/translator' - ), - composer.sequence( - p => ({text: p.payload}), - 'en2shakespeare' - ) - ) - ), - err => ({payload: 'Sorry we cannot translate your text'}) -) -``` - -In Shell, enter - -```bash -# in Shell -> compose myTranslateApp -``` - -Copy and paste the javascript code above to the editor, and hit "Deploy". You will see a graph that represents your the textual composition code when the app is successfully deployed. - -|| -|:--:| -|Your translate app. _Tip:_ You can click on the "full width" icon at the bottom right of the sidecar to expand the sidecar to full width.| - -This app first calls an OpenWhisk action `myWatsonTranslator/languageId` to identify the language type. Then it uses the `if` combinator to say if the identified language is not English, call `myWatsonTranslator/translator` to translate the input message (in `payload`) to English. Otherwise, call `en2shakespeare` to translate English to Shakespeare English. This sequence is wrapped in a `try` combinator to catch any error in the process. Short inline functions are used to quickly check a property value, rename data based on the requirement of an action, and generate an error message. - -All action nodes in the graph are gray at this moment because we don't have those actions deployed yet. - - -## Using IBM Watson Language Translation service -We use a built-in OpenWhisk package for using IBM Watson Language Translation service. To do so you need to have a valid [IBM Cloud account](https://www.ibm.com/cloud/) and a Language Translation service instance under your namespace. The service offers a lite plan that is free of charge. Here we will quickly walk through how to get the service credential and set up the Watson Translation OpenWhisk package. - -If you already have the Watson Translation OpenWhisk package setup, change `myWatsonTranslator` in the composition code to the name of your translation package and redeploy the app. If you see `languageId` and `translator` in the graph become blue, you can move directly to the [next section](#creating-en2shakespeare). - -_Tip:_ You can edit an exiting app using the command `edit appName`. - -Follow the steps here to get your Language Translation service credential: -1. Go to your [IBM Cloud dashboard](https://console.bluemix.net/dashboard/apps) -2. If you see a `Language Translator` service offering in your list, click on it and go to Step 5. Otherwise, click on the `Create resource` button at the upper right. -3. Search for "Language Translation" and click on it. -4. Select the free lite plan, then click "Create" at the bottom to create the service instance. -5. You will be at the Language Translation service homepage. Click on the "Service credentials" tab at the left pane. -6. Choose a service credential that you'd like to use form the list. If you don't see any credentials, click "New credential" then "Add" to add a new credential. -7. There is a "View credentials" option that you can click to expand. You'll see a `username` and a `password`. We will use them to set up the Watson Translation OpenWhisk package. - -Now go back to Shell and enter the following command to set up the translation package with your credential: - -```bash -# in Shell -> wsk package bind /whisk.system/watson-translator myWatsonTranslator -p username MYUSERNAME -p password MYPASSWORD -``` - -Replace `MYUSERNAME` and `MYPASSWORD` with your username and password. This command creates a package under your namespace called `myWatsonTranslator` from the built-in `whisk.system/watson-translator` package, and binds your service credentials to it. You can now try to invoke an action in this package to test if things are set up correctly: - -```bash -# in Shell -> action invoke myWatsonTranslator/languageId -p payload "bonjour" -{ - "language": "fr", - "payload": "bonjour", - "confidence": 0.799347 -} -``` - -_Tip:_ You can read more about using OpenWhisk packages [here](https://github.com/apache/incubator-openwhisk/blob/master/docs/packages.md). - -## Creating en2shakespeare - -`en2shakespeare` is a typical example of turning a web API service into an OpenWhisk action (cloud function). It uses the `request` npm module to send an http request. Here's the code: - -```javascript -var request = require("request"); -function main(params) { - var options = { - url: "http://api.funtranslations.com/translate/shakespeare.json", - qs: { - text: params.text, - api_key: params.apiKey - }, - json: true - }; - return new Promise(function(resolve, reject) { - request(options, function(err, resp) { - if (err) { - reject({error: err}) - } - resolve({ - payload: resp.body.contents.translated - }); - }); - }); -}; -``` - -In Shell, enter - -``` bash -# in Shell -> new en2shakespeare -``` - -Copy and paste the above javascript code into the editor and hit `Deploy` to deploy the action. - -Now, enter `app get myTranslateApp` in Shell and you should see all the nodes blue. We can now run the app. - -_Note:_ `en2shakespeare` uses an API from [Fun Translations](http://funtranslations.com/). The API allows some free calls without providing an API key. You can subscribe this API with Fun Translations and change `params.apiKey` in the code to be your key. - -_Tip #1:_ OpenWhisk Node.js runtime provides [several built-in npm modules](https://github.com/apache/incubator-openwhisk/blob/master/docs/reference.md#nodejs-version-6-environment), including `request` that we use here. You can also create a [zip action](https://github.com/apache/incubator-openwhisk/blob/master/docs/actions.md#packaging-an-action-as-a-nodejs-module) that uses any custom modules you'd like. - -_Tip #2:_ You can edit an existing action using `edit actionName` - -## Running the app - -```bash -# enter in Shell -> app invoke myTranslateApp -p payload "Mieux vaut prévenir que guérir" -{ - "payload": "Prevention is better than cure" -} -> app invoke myTranslateApp -p payload "hello world" -{ - "payload": "Valorous morrow to thee, sir ordinary" -} -> app invoke myTranslateApp -p payload "3.14159" -{ - "payload": "Sorry we cannot translate your text" -} -``` - -Checkout the `Session Flow` and `Trace` tab of a session to look at the execution path and trace of your app. You can use `session list` to see a list of recent sessions, and click on a session to view its detail in the sidecar. - -## Connecting the app to Slack - -Now we have the main functionality of the bot programmed, we need to connect it to Slack. To create a new Slack bot, you need to go to your [Slack API app page](https://api.slack.com/apps), login and choose `Create New App`. You will be prompted to give your app a name and select a development workspace. Here I call my app `Composition Bot` and select my personal workspace. - -|| -|:--:| -|Create a new Slack app for our bot| - -At your Slack app's main page, follow the steps to setup the chatbot: - -1. Go to `Features > Bot Users` and `Add a Bot User`. I have both display name and default username be `composition_bot`. Turn on `Always Show My Bot as Online`. Press `Add Bot User` to add the bot. -2. Go to `Settings > Install App` and click `Install App to Workspace`. Authorize Slack to add the bot user. -3. GO to `Features > Event subscriptions`, turn it on, go to `Subscribe to Bot Events` and add the `message.im` bot user event. This event is fired when our bot receives a direct message. Scroll to the top of the page. You'll see an empty `Request URL` text box. - -Let's go back to Shell now to create a new app called `slackTranslationBot` - -```bash -# in Shell -> compose slackTranslationBot -``` - -Paste the following code to the editor, and hit Deploy. - -```javascript -composer.sequence(p => p) -``` - -`slackTranslationBot` currently only has an echo function that will return whatever the input is. Now, let's create a URL endpoint for triggering `slackTranslationBot`. - -```bash -# in Shell -> webbify slackTranslationBot -https://openwhisk.ng.bluemix.net/xxxxx.... -``` - -The `webbify` command creates a URL for invoking a cloud function or composition. Copy of that URL, go back to the web browser and paste it to the `Request URL` text box in our Slack app's `Event subscriptions` page. Hit `Save Changes` at the bottom of the page. Now, try sending a direct message to our `composition_bot`. - -|| -|:--:| -|Send a test message "hello bot" to the slack bot| - -In Shell, enter `session get --last` to view the most recent session that was from `slackTranslationBot` as it just got triggered. View the data returned by Slack. According to Slack's [documentations](https://api.slack.com/events/message), the message is stored in `event.text`. Also, if a message is generated by the bot itself, there'll be a `event.subtype` that has the value `"bot_message"`. We do not want our bot to reply to itself, so we will add a condition in the composition code to handle that later. - -The last piece we need is to create an action that can send a message back to our bot. Go to `Features > Incoming Webhooks`in the Slack app page. Turn the feature on, and add a new webhook that enables our app to post to `@composition_bot`. We can post a message by making a HTTP POST request with data `{"text": "our message"}` to the webhook. Let's create an action to do that. - -```bash -# in Shell -> new sendSlackMsg -``` - -Copy the below JavaScript code and paste it in the editor. Remember to replace the value of `url` to be your webhook URL. Hit `Deploy` when you're done. - -```javascript -var request = require('request'); -function main(arg){ - return new Promise((resolve, reject) => { - request.post({ - headers: {'content-type' : 'application/json'}, - url: 'http://xxxxx', // replace this with your webhook url - body: JSON.stringify({text: arg.text}) - }, function(error, response, body){ - if(error){ - reject({success: false, input: arg.text, error: error}); - } - resolve({success: true, input: arg.text, result: response}); - }); - }); -} -``` - -Now let's edit the `slackTranslationBot` app. - -```bash -# in Shell -> edit slackTranslationBot -``` - -Copy and paste this code to the editor, and redeploy `slackTranslationBot`. - -```javascript -composer.if( - p => p.event.subtype !== 'bot_message', // ignore the messages sent by the bot itself - composer.sequence( - p => ({payload: p.event.text}), // rename data for the next action - 'myTranslateApp', // do translation - p => ({text: p.payload}), // rename data for the next action - 'sendSlackMsg' // send a message back - ) -) -``` - -Here we reuse `myTranslateApp`, and use some inline functions to rename the data for Slack. You can imagine reusing `myTranslateApp` again if we want to build the same bot for other messaging platforms like Facebook. - -## Testing the Slack Bot - -Let's test it by sending another test message to our slack bot. - -|| -|:--:| -|Now we have a translation Slack bot| - -Congratulations! You now have a Slack bot that can translate the user's message. The bot is completely serverless, meaning that you never pay for an idle bot (only pay per use), and the bot scales automatically. - -You can use `session list --name slackTranslationBot` in Shell to look at your bot's execution history. - diff --git a/docs/tutorials/translateBot/finishedBot.png b/docs/tutorials/translateBot/finishedBot.png deleted file mode 100644 index 9314b85ef7f0eff0306a0bcd951e0268a78bb56f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58568 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 iYQWq6AHMz!9LEyVpHuOj3;yUQi#J@5I>`tCn) zf4IF?Pj^?|#(g)Dz z&kB;CKa(jq*qVZ@OaK6h;P^y16=g}>zTJ3AO3FGR8l_LRepvgHme3IU`V^GD-!MLr z70pMB!p!=Gz|gnQ8EPYvg@$NUG5WPL2W8P58g>T^a!CSoZ|Qea9d|}fmzy1Ty>~}a zFJS@O5)Be@!6ksG55t(^FpnQGF=CVQ`T$TWSr8Ik86yMO_hMoJ5E^2Oor$iE0CMZf zB?+VF+Sg7TRVL;{C;$dL&-c`!0Y6VHz;ZGL#x8`=p1;fQWH<7Dks^$u&}^Z8DkZtt z+R`}XEh4JR;NXkEG$bF$_z|2!h%CyPU&Fh3-P}?pQODnOe9;^zjG0j~N4`JdU(A=4 zS@jR%L@_FLgvQ=9Ceh}8TsW#zOxPu-M}Y9tQKa&?d2J?oZ8bKL65C-3h#$la6p?gH zsL&R3DT*tOVt%LmgMzG7xa0l$;8Xr`PvWkVHZ}{>@mrcZR|Nr)cH4 zTh)dEMqm1Ie}4b0=J!O#MZxO?KDvbL@V?vAiJ>Vry&L@)70(xgXc|L@5)$)hH0lXK z?>SGB&=(0G9r>%kah?@fD{9KE8Qy@xy{XMdsF|cJiaLyVHaI@?;wdNK*)@cfBJjCd z?2BpDv<-AK2bZ9`v6VN;veku-UDRj>9&IMBI_|b;Z-4!U3>xf{FhCy?zKoWPFb_)D zQcsr@Zyz4giVPOy17{V$NI|h_!vEIcxUIG}!$2%%NI|Ow<{$ess=e_8oqG{V< zB?7zWoA&*1{Yw)Z32df774LdQ(^5Zo!9{=BPa#9V$8UHdb!qQuuwKy;;kjA-Wi)<~ zVKo4g;#K_ZL>?Qtzma_6+xWOamF;hb`_q?tT>dN)sZ$g)Y>~E zf_fSC_S-|YOPcQ?fY1{-{1f*!pqWSbuu=8Vb@2m5$$*P-T$$v}d+n#aLgV}`c3!cR zrCZ+Z79}yZbJF8`d(PKWhu=Rquf*l8XkDN!yXA~<{?ZLsJO2aJaO)WO^s1@&h|HZeD~*Y}GQZdd|miMsN@(@7!ecz*?6{4Db6~ z7^b>MNiuRKYxTa?wHfq}I(@U>Ph~8G2Q*@s%RHJI^|0-MQ2|%3YgWCL8`M=8KA6@- z!Q6T_J^84RSpbu}d~+x-u#09_7?BU#89;yxO$HjB43^Sw-!A>046!5we#cKV3op(u zUY~LPU4tL7KI%Lwia+o8J30T$byjmIu5Pa;^_FhLanw~`VQ68AcgWcki$M^EAsQ4Y zLG+v7p~(#-uwsHJDL_GJ(PWO%za(gtBCJFjC}#RA`|Y>b9neAIC*Pu?SQT6T^eb9hW`%c_Nu%6lx;jHg9FP;`OWlv=Tb!+*KB-HVY$W!1;fbGxQ z_4+%_C*IZI+uwTd?0!t$DeH3j=os%n-;%!>eu6Q;-N4%*dMapvKMfKg_cxbw@?Ena z|Cr7ls3Ep21C+2LZ@_E~f}+HbOf{ChpcIXo&jTub1VMpF_p$Z~ic_zIg%!Jnx`p3M zyq6R%QYcc$u2SE~`@!+O5W(LVyM}flok(~m#w=Dn$~A_tUwvR@OE`q?SK6jzaCV+D zj^eB`io&QOiNY!k9UTE}3$2_Q77de%P9<34+|RIZQ@n&=CgeaqT`FE7QQ1{FwaB&D z)|@>Be z`1MS@Vq67}Q#@C{uF|g@uWX!iTAF#K`E}b>ygJ=W-8%zPdcon`;hF^T1k~)jcz8Ww z-G;`jYAh&hHXj8*2cQRw3-&}1$#`4A{TIuygh(9uQjx=~S=n;=MVVuvW29r%Mdw9S zXFFp0^Z{Nr=Z3wsseQs+fnFmdGns*;9;1`}oEEhf#TG{=*S#+j#N$(Qh_jgc*5iD+ zbA@B$w-fSndb!?8opU}m>n3C@8b)@5>paT-`$NOV6=oSGH-rZS0eDhKjf4#ZCozTDDrYHPmMvFs_gcAK+K6DK4d5b4mw=?t8E~)`Dw4m^zz| z4c8BA?!fGD?4UB36*nzknwo0h=M!RKY~VvoZ|YIoxN z(O%MJVas7jb%kTHe)!stuzO_8+E+VwN!-=!7I@op;_WsMHU=MEgE_lBA#Hz*!s}*; zWmt_JXApmpsWh&%{zAMOuxfQmciJb=E1;99D2RF4ns&=Z_HhG4T(`-a zryLG1r#Iwpu!FyEQA?V2sDCwi2~4(UiyT%;|B&Wv(lB#mQk#hbjs3(5m)Vm%1)Q@x z$!Si%^xU=1j2xCvUTfxba#Uh`9V8zQyNBEJCTQJsp`lQzHv*bSQjL^zsoAOke_+%{pIy?{9<~$oIXw6 zN>fsYR>#dU{ei0{=5w79DnsMa;l&Zg!e%!reSvp)o=Yrxw zl0X6(NEw*%n(}m5-jf}e8rej`V>f-ZS73By^r2qj_-OHk_p7eBm!a3=d2nAUA&?;A z+4OPgM69QG5R-sfEiEsNftSarWPMsFwy5~jX>q?|2Y=*tj54j+-sNIp)-ijRDGim^ zyWm&j_B6~GVmR&!GfC%`d+|xl<@O@IoO;Cb$<<@E+V1RPDU4_RAxiofY-li&NxPy*rN_oWPZx7FuQSB6!U zck(lWT4iVa;B2+0WA`={VAR3Tzw@k6@-S!buHzMLO~ zC>uTFB;OvVHf_CgC$wOKH$-xQ-Kr}C zY|)$B0B{Xe z|Ku=#WMX0dr|vgW;Ga}p1rXT8N<#!>ZDQm2)`kEF7c20u^8Z)P|FrloO3nYF|HlY^3j z7mFR)*G69FaKikoGa)b;5RK#=>NmI_P{c>R6#yXd(|&L6_qWdt-@kI#N#1o~>V5lH zN#0c`2r%ypMFbquUv&Q|2$1*uA0jl8Hv<}aeg7_!n}p?`1~z;Fz;ojNH1-!!)^C0^ zpTggQo8Yd0)em|0)AfJ2+VG9I6#`^LyaxS-==m>GZ!C9VuKkC>|FHl6nR=7W{}Yl@ zgJ0*l4G}C*X6B{S_4>_I?0x3TZu9l@L=KdOR2kB;95hq0V# ztIh|bG_5udt%C*qMt0|2)WY)<0dLq07z-(Ngx)#F3buSM{;$uP`^AJ6u@7Z>SHZix zGu9{-)*8uA^LV5AD>`DZ2gk?ddZR&&|Dew)32qSujKcR)yI<$nu}0L4-`9->i9Zu0 z_bDEAXPc!GVS2pQ333K$h)h9A6)tPvB}y4ly;sYL$QX;Wq=A?_%i;#Yq!?g=pUCcu zW0C@?4R)=1?>2O~+|1mZ+bnKc=c<;{G8L$FnIx z{WFPqd!ejhfP!tC2TlhdJxL?i^q5}4&}9&T1)Bm(0$#lIM$h0iR!M&Zg}+XPh~wrH zgB}zTyheJTQC@*B39&6@p-6liA)}XYYf1F4G`Zdco0){$PSJ>+bX(B-laa8(jOp6d z+{rlNwZxV}TMJ0lZ&Z9geAkhnD79rWV@O(8%j#yria~1f>M0+cOXeU9gVv)CM9m=B z-Q%BX*%wvOuwPK?p}Blj$bNqO=e2)3}6kChXc@+B5;pF01E-o7$$hXnUKwU%A)v z=dj_AM>EbS&Q2!?$-|qPLun2u2N(xprSN++6rSV!t(!J{<<5kb0AnwOx+!pqmy>rI z6yYl#au!dQOE}xjwvwG6&z89PO#RDId&@CkSh5h3Q|NTNKDVQ3#j6qag1uvNLN#AiN2fr&9AYOF&K*AZ`19DssO4ju)+uF&3lVg@8*WoQ&_e$E zv;~#3Y+1FBzi;K`m)$DszOJ!1GLR{8#BP_SYXDL)s-j#yW+1m~6O0F;ApYCeMaaypbD2(LU6mE*} zb@$lgY=U^Yt)s-!rOT3zBF0z!z~m)Hdnh_*^w-MQ*5mdRe_)=4M&+ne&t0_*1kcE>_5+1Z^Q7E4a5tEFbl zwW3{BF)u2qEhP|KYn0Of+uC5|ui5;L$98R)R5u zo{m_$w>)4S!SkDOK-qS?H@0`lfHg3mp5IhWeQ^*l=3aLBktYGw+4(wem4~lTGxFa2 zK=ajJ4c5t|%ZOYKlE#D`j)YP(f730$oe}x0=<95m=AanCKOnAOg*t`-3fx@uzO(T! zE8oT^?GWUscoHLMKgB@2Kx&5KxZ_lYJu2hu?r~#q)z+*o5p5__{_@GDET+8W_XP)J zHLq0=)n2G1CJdRswS%nBdmgsD7n=OR3;a-xwqCRmSXi5eB-yD+Se`V6jJMzn`+0hI#m;j8vFD_&JBLkoOH z>`?aYj)Rs|ZcrjVs3P-qHRAeZIRuBQt;PrQIjo!aA4I8qXhcL~)ag1V)jHyXhpObv zbeH^K#ut9!P>t0Dq2!RK0Gg^=Lun%W9LA6LYir$HBo2?x8TowOK8Ie|wTmpg&)}DL z2BEWZN(+5%H$J!-7JFWhAs2MqkqQ1^V1NQr>%~C?l}}z5;}PZ(M{%=O3wuq}7u(Nt zgN}UZF94%tCs1q-Vr{DH!v2k=ayt$KYIH$eF&QSyE|}CR{_R&1+C>Kix828JuX^)& za^__9PdJ!G5A>9uqpf$?klT-dxqQc*t@P!V%9{LmT#(B`0OEJ4Q9cqU4d+LnCO~{A ziKbSU2h$_)!`PBvXstw@*6ky48rI>@Bob6=03Qb1n&c4?x_;aIVYh zoGt7so(Flz*yBHIUugvstG{WRoDC%yXbO(|*Q$(i3-OWgk2?f*+4N zjDG(Rd)R`^eq(*U$-Y9)&tKbc#^xF{P7^{Ql&eBk#L<%Lt|aRlJ!h8l002J7kR$)? zZoR3(M?hrxh5_0&L>xL%*KZTTd-}K^73CAHV@~6-V>{I)7Cx@KYGgS|l~*!CtQ`GC zIpod@^^R;Y<}(~fFO zE}u&Nl3wi3%~}+ut?g#!h8>(U*?$S{PCS0=!K8kD)=l>B|X85_*;tdq7JVe!v|e+)SX~XB|B< z?^k-n^5b*?a%X6z{EIA8WVZm`V_ZC=YO<4s)VuEbRNMM=s-fNBHa*xh1wv~)8h!h4 z2~B|CITo>^p2d|R(!soSeeidC7uKwvWZuJ@MaC^oY%vw;!<4k=z;eYqH=bCnQr-8O zdBmRJ-3TOqm~SExh|Yz{n%^lLagTQA{1SGZe)oByH^Yl zVB<>G@Qm2=VmdqjU1?a|)T*LpB~?F0n7B4UHL<{#1$16egKw(%5>8n<@)5hd|Yr#6TK^KXZ9^sw{=H#nKyi zBGsc#Y!Qf&VUp`fL9bvGjRE(uKpbKIY=ShH&N6t{ZHQGBiZX_F21#UEzXU^cbYQS5 zNsgR+si`~q1$?I3}00Nqc9i{(lfa`J?zO>oV){C)19O1C_23(hH zB>vEN;37ldT1wVW-bwzMx%1)WYqkzq-L3-KSVnm@mr~3llZ6Z7_9p4lD~YYYLlOGc zw{K=?q&WD(4_oXj968cch`==PlFa}4F3CEyq1G*c>A^`V{JWb^U#l9N1b|P!A|k3u zPV7C&_4`mONo?C;a+Jm})S zG2PT+^SuTX$-qpv=~h-3GksR%Rm9iGbp-3wj*o3GQ@}A&ElrPf>?Jq5r8GP*O-+}7 zQPgAHcota*0#*)Gq${)|s@3>VLC{~l$)4{Y+5ZI@YH{$eDCg#*5R&0nA8 z&5no{Jb&I)YpK*l9^Tf)tC@zcQZvf!(rg$PXOPz5KcLd!l{n4LR~tul?cZ@%Wy);81;+^H1t_k=gl4?&=! z8mOG~ldoBtQBE{m>GZFz!>mVh{jcSb7^p##)<=fmu7K5j`Arxv?-FeFQU^2q+_e-BFg zo4?z3p%lTi1&aNsO?&iYDAZ^$3v2Qjs({V?5x&^|nR$vkG4!E7Gh9OzhJ?z#ox-Pp z2)XDOezHET&px5fEL?;6`R1azK`szxAXPiaETMdc*0gJ{K-^?L8pZ}HXk4>P27g6y zNhP;On%MGKZ#G_x4Lc~>!e&597iT-!CNWgtB(&IUl&RQk@CqrW>?54SEM7~<5j*2# zqz?6x3Gu~YS*_eai041yhgl2MI@B|}GyQ#n@Y%3C6qJ&|k|TdG$Gb?>m2|O+myYA* z8kpf+e_8tScil4EzJ$>wthv4z)QrV?`^{<-xPWlR2}#1Gs~HrW8H3V$tI)G1lk2rO z)}{e#k2=^4UlI{8MSR%oKDe+rpI(C}wuaEer<%33E8V8p+bDa!dDzw&FLowhqikRL1= zp~NNFI+q)Y=aMf9xds4Ph~UG1QiGYa`$`ke+=0>!L`xOQpc;C>GqRh_O24kfx253< zaDzir9l?ONUb0AFUn(f$=02;gZJ81ynV5J;E%eKvV0eN7W>F`=3kmQF8 zi-n#8%XLRUf@|m66sCoNXKyF^+q5ThKo-BJpw{%rUH@R|3RG-4Shh$yNx_Kwfqu=L z-9qyr`Z0x>Fx(M*CZX`R+?_(;7Gc3nKqvS(MPGd11Rxpa2u*>yOt0_wo{uim10kR9 zJr`y!aOa-Nr&#Q(KsY3H6dWJe5u4XOO}~wxJc`Tk{9Fa`*lu9A!sWxy1eeVKYc^-3;82=G!7<6v~^^XT{I6r^XGkrF9wV&2wKF? zXA|qq8JVQgI;Nu!UE!no%X=@IRip|l_ZW+dSv@|%MoK!mJcAFG*4K`L9oCxA;)aB> zF|g?5?KjkWIyC> z<5EGO#uPvN&HVq~1jtebjtg`-mRL*Uik#Ue zL$rmMC*4Ae;Z65hF~Xx~p3o`-N1QdkdY-u~RbPj)yDtS7nT2K{Bismv0evo`S%TDA zdtD<2)yT%#`g~Aazf?b3P^8isM%T#WLO>n~3PnNzq^rfhOvxr2EhB)*lw7{I2_e#6 zt8y`n@H9cgQND1SYvAbGpb)I@Zz8^ z%DPhAbKFv2gCODie82Vc5M8bB%H)K9oBfvUaEl0FymWk^mq?!~Ho^Hfh;;O&(p3K% zC`i)LOY>C@0V`!~^}>yzPMf7^TekaxG7r+nUtO7k=)Z+$qe@H{ov;rb8@Q@IBb*IH zr;z8ws2-dc!nAd<L=~f4H8Nyj$6?RP+4K)d^7PDsAU_A85@cb&y3GR2=T`mkk2Fp0Fj=A z|HjfguvMbkcPqSpub>+TmsHfdnWEE~UQ@Jyd_?xzJkVnCPw5F#O>SyRid0#3j0H{xKF=GwowcVx{XEM z#DBLHy#i~mt@k5q^;b7L`4oOVZN&)*O4q=JF3!wbh=dtg&mqfJd3Uw^Lr@ngZm8kd zG=QUa_@^4q$bwh;NnOTvGvZLUpR~!Pzz5ZRyd__8n|KUXH(3-*bD6RZj2{#qlH5aRO!tqWl_3gkL$^M}c6}zxBxIpZFx|?iowcPIek4 zYJXh%DGeFl#BUO{Q~%29L18@jKv-A@u~Q&V_^{xzjap|PoLyNfKAUc#DXD(XNon5_ z=Oyvc3;p8HkV50|sJ;qj3{E#V>R$GyP2KGjH~^BRJ!}Ag29|+=S40I4Bd9Cnb`9J= ziA9bdhQ{w;@12`ry}$6Se%rzAk8eTqY#ph+R0$urRxrpPr5F zFuKP-5fnmcZQ!6((fB!z;7b^6r0Mm zQIbwH!NR7>^`_TxfIs)_BQg{kFls2Ny0U$g%XA^o*dZj1aI&-c`)K2>$p!qx=1sK_ zwd0!!h!joV*QI=FXh0R@5)}T@Rdys8gqX#4s7NZ|rQI>^(pCOjk)#X7CjfUHcB$Tr zr0X5u$NYFN^wa+aKk-S-+15W&FZk%{y*CgYTOyNof-nT&emrBH=Y6ODGZ63m{oS;- zap13^+(zQemVndi9>_)m;fvvly5Kic7Nj4T6?|lfYPB&X+Z(TWRKkdSH;pbTJS+Td z;l1Ctw4(`ZQ5z=oCCH5F){_R%EM`ZHyXhF)=k{1XB7Se1@SEQk3isrb|K0gP`YTq~Cpk0& z$Pk9rr|`!YJMt`XfT5J)A?&hLi4k{Up7XCc@5LRJSGK*gUj$F^fLc2~3aSVCL-Xe- z6+^)(z!i<#L`;q=OaYxW;mD%5_vnF2S8U*_8tEqYU%xfcgr<}z8A|H~?b=f6$RE~y z`Uypu8lK;&${X1cj`iG+eiCF{jCIxR5uvAs>Ht2ws-S{ppJWht*G(dCs;0g4T+G3=?tsw zek6?evVD4tEgd$oyzfPkl@P2@C_z39Ge+ADbRAInX@!e(yG?Snwoc>6s#EsmK5%^t zHn+dL1ztJ0v4h5&;WN+%=PI6o2rV|fcDM@|ANkZ8Fj*;^I`m^@pY(TKH zB=M=fgUY}(hhi0gvLZe=KqEEM=DkfcGbB6tn5^lNJhPnawI6&qCKb8Y!WBOD3LD$K>oA>Tn)oY+P2gaANgIZ^nyC>lB%<Y2lW9`ht<ytP>ZYmR+)co#t@NIKOntc@Q2<$yhE#@-s}t`2vsd-+%hiRkGS%g4_5upY6ghEP|%Qw4cuR;<+4T$WnS84ZlkM~|GrSAW_a!fB8qS)iw6^;<+i?B5ZEM*ylN*a|S~XVOr_2d}K*+l}+~ z#{uYGD?aQC6ofLQ`2{-*TX#QECzmDtboTUGkj$zpt|srQMpA%{z^Kp|E?rkFgcN3% z23FqcN6{W^mMmHNop+M3@Q~yHxGQW9;RuqPLmndq<`t%bf+AJ{rGBWeao6$#{9>U< zGsA}vsoS7@tmo$Ch;2ouLEia60r7Tv@@Ix3RywN zuQLT_mHYJd8Nzy!x~5XppjI^3_@VD0#rmIGN-=c4)D?qvoy`jR2;k=FE?N`~N-`5q1Fi6xoiEks9|`qJ-ykDl^e(XCzi zd~W@c#(wzmHM!Tr^kF*TF|S5A)0iHBy87-9=F|$|0DQMAu9>e)<)dHAtd^cSDjHYa zA>7qweNk(_XhWcWt|0{`iR+)b!xAHv;S6MFoD;K>O4-pW#9b}TtQFoi;UPZVcT&X-V4 zVd?oW*g_jW=nnf4fURo6pMk6Efn&5)&wUd|1s!GQb}=)J!Z+@2OFuDM=hwxb5>9X*w7PZgZ=%Atvb`W*Y=JFc?Ug7-Pe zo6%e*fV%Ac`V2A;dc>Uja&UMk?YJ|n=|P(1@4hO~W#kHq_pkCSc<;VEE|OTjWWXNK zcTzfHc9ow#n;h+u#Lrl6cFR3q%_~5YTk5L;RePivuFKRybFFt#&+asoiImTfw*b7; zMvy>5dpo;qT;(%j)!CqV{T-nparalBNPNo8G!wAA7$U0(+qTsrO2ip^$T+2oS)jQ!#{CfxMyhJy zi*_w0>D_R1W$GXroz!QkI_tS4DL1=?V)Y_dk`?F@Wg%P z&YYn6G-TSlyKrhR=iY_3c%{`O3({`gZg6%%zngS=mCn($6dr9lpsgEg66=sq5$6EQ z+CU1yFEC8pC@k?Yxv+FPp-|Lg&%iq`y0BPgWuP*V#lz+^KZnT`8~R2LBfV;Rq2L}H zwixL$b3D80hTEF%hdB=pm%@s-UDw+LcI#EkBWTlBmzw?tQ!$G&gZRYPMZ zy{^N+hnMubvp~V5)vB>W^+j6hG&{qG`98tqq=I?#T;wVAK+=SUMT^q-hDIvdFJ2=Y zpwo6eP1pT$TQBK{u1D0Op=eDW)MfiVV*0|S0FZUf0F|Xit<{Shvl>h*Q+h7sC3+X)DHD^zRKVm8~^TS?6`Q_Okd0_ ztnO|-;Do@{d5w~+i32FZYL&^iV~0SHfx|x}o7fGgj6>=u$Q#3=SoeIcs5wZsg5=wq z6oXYYr(Nv1xi&aVw5t9fFo({;N}R}nINJn;zj%&f(mL-q7KiU6?vP*EKP9L&_DugU zv2qxQCbx8~4O&dI9=XG63}pXiBLc2reu-c6J`dF^VE(#KUysP$vOcZ+Vz3tep_}E9 zf#Bv>2AkPReuX-C^-?d+rg=MIarFzcn?3Jd*4WH;Jx?taWQJ%c4z82;4UqIVbc zx@PJt-E3P&BkCF2MzM>|y^A9h&zrlSj$*{sTA5LE-op8vgMXwZI#Zglc^m^HiWbh{ z)1e571V`0S`q?$hJTD8!32^1jtpktWb3!uhWu20BtpAwW}P{UDE{YW7ky?Orwy6C*&7@1h6iUf{aURUx;Hk#sY%T2bP zo-M8H3*CZzGxI`@q>9(41k*jj@HpOSdw=&eHD>84*G0i=nYH;x6jDR3pRk0$tNl{p#k_{Q$_Dd2?Mspq<_aeYUYcJr+D&iNNIa?7CvAwPNV zoU(5y9OYirQc!@}K4%tayliHXh$>Ww1Ul!$&lxl`R~=7jb>EI-XwZu>6bnT708F5! zZ|!ccN9Cn`INwjtkEiQbjjYe_RBi>I|7^6sSQa92R=QswPPX5!9!6+riR^qPeKF@f z|0&oyTmu+m{_1A@5F;9P*Q!5w1sCYWd|Wd$O1!bffqeFK(Vshs+i~{c_P7&aU9(DG zxMg$D`+?22>g55nWZjs2)%uHk50RP929kxgH+$i5SnhCPb2FTCvH#Uxmrl=aL-eIp zSWpKN!@W-M_r#g+Y~Qn z(O5N$C3AGVLskQG`XC2Q@xcb>hHsHSrM8$?Z{Vr)^Xt=Bf+X*_w*wAkb5PsgfA~Sl zX8F>>k*O?%escvN$xdx@e^SdD{;lAYwG(q=Dxz29e~M1v0~_X7B`dfNB?1uIiY^Q@ zuuU$vT&0{+G#AF4!+;1QE9k;OnO{+Nkp@2h5Gby@aNIRVy%@c9*Q()AAw10}cwG{o zisRwC1I=B4WI!9`WCbNJ=aI3DCA9{Nj$_nIuF`8|1-4(Va@r@6xmNeWOdv?0E9xLX zFV1uM)WD5%kP)E<@Ap~Ct{&ULT>)=}hwDo3-zV0%>&=$yFHZaXbA^PsE6FxmU^6Xl z)+iDl%bvPlW#Ln5wOo>s3wDIB{GK$K=l;QGPsg_2@@AQi6r;3=$eYpOuea9P#|$brCT7;!%Cgq#*Y>q(}#zGf)&@b74p>986y=#cY zskoYa^IH`3WOB3R-R!=VL2D(+kl)t6@)S|(V2#*wXtrqo1G@9LzH^)#=9&WCtN?wxO7GIr_Om@mqM{*AHoR`8V+g7i01nme1NK@7 ziqarGWlHjf^P3%)k;SG=7eB8i3TubHhsZ} z)pQQVq4gwnkilxvz=$YI1~H|zup+kL_-vHjt2D9T1Vp&iksQq(*hhp@r-NE0W_-(k zb9IXRV+aa3#L<+1P^Rf)25f)1wv|cLvEVZaC$Z`3shpGK(u;~{eJNu%RJ_hd&)P-i z6X3H3dbQ^VGbDEA_ym4H_rY)(3jT5tgPWi3vaI-vmk|P0=xgoBMgAZn4ucHWny2Hl z?$>Sl8#!&;_WDEkGeF+kA$Gx{&_~>*lsfH0>q|gJq2Tk{q068QAY+oSlzEM_%h4yj zt}U5SWEFH1R`-0g-(XruEz5Qm3wMA-1GXZKW5mv6W?C0DfrH}&lrp3b44y@i61E5; zuR3`WG;OYn{OqfS2*G}DrqOG{Ut`#nw}5&W`V2=VB-Ww^-2q;>hWK1(_SzjN^AkR7 ztK|!Y&CYgz)VY4DPJ^aqkqAgzKYd~Gh8B`=R?ts?=i`#Nn4z9zqb6n#={T6nChw{c!7%hFvJLCJtH+NRRV z4ytOKjRVUH*(rv$w&$Cr{NskD(XUlI_q!^5+5KtGHw*g-skXAUrejjC=SODEM2P&a zPCwvH4-bCM8s5Ft3CfP2{MBH&U#BcD@4DjEIAgte47{fGn6(_2+89{O${?M+WNu>7 zHP3eVvDbR?Fn=ZT*uCX6Yl5D6_!joF9rLKaMenM9Yxd#tVt8nZn!vp`*{tCHvQnCB z;pXg`@oKEoc!6s5A$NFf^YrWOV+&s-cxwl9cK6NhgxWv#e)V{mE)>)r^8D%IaLheG zri_S%pWy~79KWapxhpS-zoJ8AljB7IfMlKgVl_uC3UAm_MilT32k z)aN#{zMge`NxFYAR4L)lnO^p_xO`=29ToeMelh9NBUUt=Ch;a&;YgvEIw|ufxZ)TZ?dg;Tu+op}Y z#2C1DN;Q5S_H`=r`G+e8#=hGe-`a^YB=D)db3fd+X#4*0@fUMsO+CofZRv5*y?Ed& zpZ05m1yr5k9DieV)i!LfK?9@;%DFVP=P2P%~`r6BoG1zPf1Fo7IX3 zU}ZiZ?Gg(yD1wlLe)?uUJGpOBkT#24!wFtRU+oIM{<^pI8cLnQbX{ZgditGNGFPVH zTe*6E)0ltTal0a*?{(BE5G}{|eD%TVoO$5Q4$G=L=ER&su4_0yaXmGgLe{Gy-8D+A zIxiCEr+Yqa?5v)K`RzlQ5pR|eMsgk`o(F~cbOo)TG??yj;p1vz+y3gmpBMX5P!cco`Y?x?m^8cTF-X2= z>-k$7^QFE5_6~^mQ{c?^meD=}wdM8YbnI#@c=vwvb#blJ+E;Kdi#f0Lv_qT+_!YFmIn`sTEl|B?zX6WD?|Fc*EgBYiI?ybtN%?dGVU9QdI~j%PlFHZeS-I( zhsC*$jZWYCYDrdRuYKvMUBTOANsENBht+&n`**~nGBL5o>*MO-q2t@^i0ZtW z9GWDJIWas8|uMH}}2N3;gQX6KGOH?IUFsWJmK)yHIsb zCkrGgmT1W*0iH`v7<4&(A&?AzWReUWeTlN>YZ*hqsJo#%+Xxtlj$j4NexP|q1dTPHCwA(_)Ug>n7K(>(%t{zJU}Hwic|kX@S#;yM5G2D+fc z+SBZ7!R44O3DX>T0_U3N<<+B6WCofE?NSn#Z3Xk}HkMZQCsV7ZgdeSH{+Kb!+GtVT-EC0|c8Eaxjp43UgrTAcZU&-YCC=@~!vM`z>_s0I1YcW#m$9?9tVZou z6MgNyOnwbK*Kor0kl-MsTB^XYdl+VLhP;v2?)qoo9+Y23J>}YF#Kx^9vtgx&U21ZrqN22~5o+VYd#M6QacJRNRA{6S<7D z@QQj3>C&rhhuh8)*a{_ATe$hxP^t~nwviW2f-TCYV)8O~zld~wbxBszW9yDl*mKlJl=uY%jO^3}cH3?q5Db0eNqTY7%ncfQO-f2ARFe?!{kuAbQxJ8u5e7&qJVzC3ji{v*y%1b2r{NYD_1 zySq2;a69|#ckgrVU%2-Zqic*R>M2>ZYOOhEEmPgyVU*xEBT+ZO2zLpGvxI~?F9oVK z=3h-52;NcJl^`3%HM5p8#0pp32-yX(Fs>xz*v=%QU{;l!Yt#nsKF?FoqgswwkGp#y z7^R=AwnHRZ|MZN=y}O)w_(;-9Rqq+AS&};yjWc$M5p-*{*3Rh5BC+Ck9T#-Zu;^q< z^|1UDpve>fJmSl{iEitdG#K9P%52U4^_gnxHlsdP2^6!ssl?TJi}Kz}b7bDFxd>BD zr=A|Vovf>IaZL9Z7$>ilF(tm##ZGGB|1pml)o%2dN}U4}{xTLodEB~f{$#r31@r4L zM2tfpjjQu4ztB0!9roNzv4siiznyFZa_+`9VBng72mbOE%U1^TeXBH+@iJKr&*W5p z@4A?Z#}7E&eJ~lT6KDHX`(uPKO7r!UxBJIHt-O*v-kmQ_PlhY`NVpBI4}wirbbEYG zKz++lUS1KD6{!~tO*Kr_DRgYV`FJET{+sAKX&75gt;{Prr{f$cfF2HBcDdd)9> z)B9A~7-K8GpRvns@tF8wphV@x!&#o;?B%h)%`>&wFSfMEFxjVzTFvV@BJLTA5m z+>;X3Wo^e#Ja3r?LSd*%;Z=a=zI)tdJRICF3%lqYD>LP9 zB~CD7u!VVpk&zGjJ?bK`0PNHB)m?zF`-}?io12BO`6BN4GtQz7Zue}>yDi-7-X5?& znrccFaeY9Fy{QjdOdH3-g1FTX|9Wkn28GjE#V@DzJ4Ec}sW9*U+|~p0>1?uE?Roaz zr&O#bm8Fql3At*&MaQwe$9+lt?D(ULvCaT|X0$JT zPUfRW>nGC$$m>(rzyP9I#+|b!gU!-{K(n*%yP$|dX2~1nN3Y8ti+OsW=Aily^$`J2 z?L*=LUiwJ6uKs89yYQa4(!0l)>L*R#CeG)sjHs|}iQ^9fN`VJfG)aM{>ojf8mmdh= z;M>tS4avLRIAis~DZ)b4KMi5?bYpwZAbR+I?An?LYRg+);cJe_fRU}@+rfd0fyu}Y z$ObE*Kz}LMfg#3znH^C;=>e=q!r$N*;nW5SE>%^nCAQ|1JR&}@xIL3v>@c4{NtjW) z6^+GpeT_TQ4>{k(-FRr`V6+n3v>muzyJ;h1zpnDqFmHO|f9?{a>-*o5#|O7)Hb%pbJBpIZPiKwQ)AU1g&xY3wWhU}1s4i5OcV%0N zqt#Hojf4B;NprWC1!frn*0Yv$s-@pJ97d04fqFhQ1Y;M|;z(?0)oDaf`@Z%4q~23g zkN$_zc&d9U0@}m>ig*8f^?C2!P_+)M$LjQF z81mZ=OV_oeXA8+4I!i$4E_^d|PkIUM*oh|h+T}QxPv;4;tWk|*7P448&j=}%wwS>dJ6IM*ASpBiRM4tWue>!~J2w_;B^ z-4|0PW>A{2?)w`}RZ=boiH8gjbJ+P4{LU)X7h`k8DQY*Z`*gYS(y;4Z-el(5pSv3U zxjhP))WSXRP>3vGJPQ$bwlOz?_0YXjyNQ%|DAO!7oa=rb^mHd#7&re0GHNUFFmV3K zu*38x2J7lYTKAg1z%eoRvRJ?tpHW(l8RF8_^+@#<FIH!M55pgo7ZNAGU7u!6Y}{g9j#mZK8ckwF~AsTb$Um?!nQxW?-B#8N9Mma6xd0dX3rRxqm>)x~m+Jmx zmPzbQp~B7GD@nb<0UAXJlZj@ zvpW>T0a|rPBmfFv9d~b5-Y_+Llg$J_ZVgac5PQsmM{Gp$L#jK)Spaq%=z~KhCJMua zNZP4bCmNG=X}nLr^d~UHMK?SYRGCHXd}0?X6^`*n)59)#o6C z0<)0LX*0BN*md#^HJnkZ99fggw6nGPYX@|!L#UYsUXvOufQ@H+nC+wRo~?B6cj3Tv z_v5hp58NQVX)2EiZYFVU;$WKl74&(H$3x>wMBrhiVLK`BU{e4C-e5j4@ZFX~tqufv z^6G9rlHA5m5o_6dHdMpDd2!cKYtwn??5cbmv<&pfzzPz3622i?KKVg3w)S&4$84fr zol zr78BispqApC13KU5205HnlsZrYb00^63G3hVoyIGe=Y@`^s)WA4eXA$&jf zaZ@oaTEK{P?(OtSBQ_jfq!T6&mEzjOO_lVY)J?_uEdLp;O9^~VJ8);|Tq;#pc?&n{ zk2ar1q)|H_4eh@bp_L>&`cb|R#shGqXA9ZRVo^=FY1sGqS;;IF*8){qXnZgNaaGXk6Lvewf^BZzi(0u+{dftS*Au4}plBvc#sLf^+)Tn>I&Y85*&C?zvf6 z?!c2MJyUu})F-HjxqN~xf>>hr0AojHa6g;YfV z@iQ__&GuQ1@_|T?oMn+~t*3|Ww^~(M=rF#Fl1Bk=gx9HN|M42+0efBG&ffo}%AW@v zR629!Uf-|i=>p1tHKvwqGYY7e4$D#Jkj+wSYr56!m z&N)@~;;-J?AHLIp4_yXA%!cErOrlIa9 ztG;Q{M9ggPf{z{KZ9MYCI&V7F=eAsM z7;Uv&fC}C~ojO1lM|p`ZPALJ?U|(4+goD1GS(jQE87JXTBU8S==ohWGy_3$ORIlY< z|^7~KE+MmcP<4Q|FgTl7^NPc=C5Mc5_v?NrcUzBD^p99o2O>=^<7dU1dxq zOH{gY&9CuuzBrQGuOxq)X!+^cbP-o1e&mQW^)VCI;$u)i=QSgDIq6$B%Nbke1ZT1o z%g2WyiyMcwtv$zsy^qHe_@AdDVPeZCmp@!60+uMhUnRsnZij{L;fU_Mx35m?XbFT) z0=+Ni_8E6|^X}z3A97fWaD%MhNSc&X8Z#JI7+S_pR}o4qANy~|pLZV97)VkaQl8&{ z_IbTLa{_zGy7dWE7so@Qk68~>9(QKg~qAy18Z>DF<7SJZPxi2m*W=S3x_EGk)Un7=J#qcWM znt?aI;k*0opnwk4CV!lu`<~hhui)V8&1!FtLlEk_e90nQ;p&}Ev<}xYiO-euPPSw3 zbMKG@_PxBQ-g!T|ELcw`IW=ykdMt(xSCkp5f@ij0O`cW;y)SQju;cbau;WU=_N|m} zfpp10Ci3j_*IG=U3L>NT64G+L8LwHL%PMs=V2U2=vR8%Q_5)K$EZ&tmKM5vV6^ben z!q7oTu}mBZocjtk#*zt&g;n+bJ^4bNBm?i@uOTqqsWNpkm=wFF5yTQ?H<0i`Dn1X* znjXoZpOEpiQL-Up@~k0+I9?Xv@wVh%G|x}nusF!IdjwUwMDI3bQItI$eBpP3+8#)l zPzWS5XlWY%353Z8X$Y^%(ZC0ygrRTmsG2nYVx?TKraYdt&r4fo(}1+mUah_I!4KWn z@VtI5_33Z{l6-O!7nE&*OJ_8Om}$E-CBihNQ=^*FL|gnuoRGEd8&21(w<Bo~T})5`F<<$jP_FryP&5Hl>(ZqCHg4&T_Yf zSjhu$1G$=qtwKlQbhAW~Hg=XDi>d#lp?LohL(rJU=a)yL_f}}Qpc{n{jSd@9a+uOY zn|xmPfB*{ok7A&gFjm|UM|Jn(t^0=njp5~t4MT61wgOv+7)$Y2G?o#|vN)L>)3)yz zguCVMK_LRJ{tE1}j(eM5*v~l1b(jGoU(YYc<{j8q@RhXB?rVDpUyZJm-_~h>b$ZC0K!0y%tM>_ zH~LJP64P{`Km7syE8m^9wP!DEYj}O{EgBVi5pb6mA|{h5$N})3I4M2-JRdtEXRSJV zN{4JyiL~Bu?41S3eg+qXa!(p|Ny2>Oo^^orfVdAakb2Gvc>45MU0Gh&zc3crh!sJ3 znu8IQRNZo_BB`7a{MP8ls&ihQU(}!@W4r|wG=jD4^jT!xG9n+=I3(L`q{uPY=6BpF z6!7?&dyeFwJN1C^bbhvx*g|+m3M4Bw>9O$C_|%S@{t_^iA|Jlb*0QYJKo3PTDo%f1 z%3OdzbXd%JEqnP+o&s=XOliJNkO)O_$6TY0&M#jYG!Hf8MRvC%rUNf!bjs&KleHUo zZQUKfZ0_^%3mg?8HAW$G-%S8M)4ah+fftW?{HHU5^F7BPp%TNMq^>nf3mcWp&_Z z45E6CR+W~v3-qE^n0@1s@*b$ao60)N6~?YDC&QhLKNaZ{ua;$A++4fPtj(%&wKjC| zeQM)u@-EEFI@=QJtj+zNfWyj6^|S(KaC&=_l~d~P+8JG5mWAWq!#3R4m&H$+eWrsASyuJ}4KU&d6o_F`(j&=%nx>^i&p zMO8o8H-3YC%Pb?*xPBiX`JDGY;4Ka=ENr(T(SQgJ=*8iEX<(iKbN@ATNcs7+X^$8P zZqWR(Z{n%F@3U7vqPbYIC||+X5ZfPntWK0Mzu}icgn@o`T~jff?J_ zmsohCjb;aJkwRVX@-W8rDo3P!AOW-{_hxU?H&+$!YaSzzSK>#~bNsSj+-vPt1>cPq zU76;&n7Z4x*{|l!*z5IG;$D zFN4aF;qY`Hzz8nK%dx?d3ekb`iXBZOCfph6)LVoF4wh_Ao+qYF9OkgSa>3?Qi~9W_ z=dj?Rut!b-Zz{s39c@Uw8d}1V6#jDTksA9v(vnjHm6R<0`TWO4?G4s9q?U;nnb1D= zN|(X}i2pmjQ(7WT@e?!Cx7j9>yFR8<^X@zA&&aGdW3TC=Kfd27oSgV)uShx=17 zlq!$aGNP=lF+ups?qp3Kk?`h@nh+& z!FTjrgdZRvHdC+r3)_0b{^f02*=*HZ;&4S4Hw`g*QfdKlv*4)W*AixN)HZSiS4h~l z{~OM@AsOn;ddrUW<|K;u#Fd6}8mhPG=FOVOchKP_p!+16xnh~EFT}I?PV3-I>^BqE zZ&J*fGcE89e6I-`USpYzYi5DS1|u;gi7T*bnup=s&J~yQUi1Uw<-QWaq;X-ozb_at z^GF@7Zn+2{BRHcb@N6)JAEfM$V8N4#h$Y+OT)a!w@Ok>s|%pb0Lsusvt=g?kf|ebp_60u{gGC z6%f3|g!|$QBefXri2h7Cc^`WTXOMT|Eq4M@e=I3YKv(n+=uN^X;!DnI@ z!{yyjf77VQ8b%k^wyOtI8QG*R!3jo*^iFx1yU|uyJ8MsG0ATjx_Q@{;8H%#9!fHbrr>?YHXJY$jF(nuXAo~>czqDLvOa~bHw)Mb(gGlyWc^fN3qLX`QuMBfzgcRZd)6lKvP=tyHUgcXK1A>?waxizGM!V7 zTG)05Ft0>zCiT3(czj2u}M64S?E*;XiaC-R=DYhVNpmwWn%r1Ow1T2|S`dW?;tkYr>cc`N0~4pOj*u4 z5>Z%^YsfWKZa!=y1PxkyaNOIl06@2zk*G2bOms#;xlgu6%)h=da4L5Iz(t1iH2<(o z+yC;i2hEI;_=KY(KNYtDp2fpHHN|0uX-%_@56Y&dOhL z6yV4aJvYYWaTB^>>kU%W=`z9qOe6V9#B ztat4`qF8u#bK!4#TkrM~6DEQ(IaQk4s{w*|V%2VvYEyH-0{|4+n`6IltKO-eiVYbw6yL~O7K;!vU|1qEY1)1uvW}kOvuXj~7ZPo9>DIEo4YHCy zn2-5I?JTz|8dfTBOL9-7tv0EQaO4V|%C1P^V_~8m&PNOngB;>n#|w3>Owf;p`jH@t zon-z|+$qCy<`6zRLussR-eiTU`u1ukhbT}!P%!K)5f3H7^^JA)LJf&wy*67F$Q;wgxZ~9f6Hg5R=4Wn`s9PgXOJu^6jc1BVs@e^dXt#!_3cMi)~|AV6cA3QrdVr+-k}TP znnaxx9U%u;_=kQF0-Tk1c9?7}rWC(uc>cj=qDk+kVXGP=t|lxBJt1Fq=Z)*gr2AN% z0M$QwLaV_Mi=c8M_)Bk0OP0Ftgg}X8jb24fXi0@v(Vn_syuMh&Pa;xQZg)ue#0Rv2 z-d8=vpGbadBH%EV3Ydx6VH=Miv;U&iZc%QXqL$>Fw-G^C22<^+p z`=@(Uo54*$>M6Js629tLCM?{V8T8^SA=D_7^Lnhr%sg{%ZAIqPLDP+`JZ8Z{>O*Bh z>t4iPaDCzEmpfi59y!YvjD@5jc}3*FSMwmtcTS*?m&ydN*gckQ&tP&SN;0BRiE%xv zCR(2zhp0VM>-k^Rd^Pnm)`vl`$b6nE(_MDWy8?t>Zz$tU%mbMoVppd3pBn)9XZC6$+sDMvT(G zbzVLbf)P52vSEtjO2W@*wL>vLR7kQC@cET$(ZR$kwF`w#YvyvpoCB3yB52Qd$R_c{ z7Y+w!Lt3Yu;`K3D3R($|WH1?vrL~z{qffX7*Y@E3QbRTnkM<*P`f4(&oFoOCmBrBNePo4fVzK4JgA z`^45hDi!6$hA5Q2gJ5EC@;zz?%MLO=K7l z8;a}?B&Af&6`kyPU$cVVgZfSp&q%`q!j_d-fb(5pK)2limuxO9p8e3eOWy1V%*@$! zo@IZ~g;_5iN(4pjVIx!0i~O>eKc7#9udCnBTPYugCX*^Z(9_iEeP zv=3wSVvr55a+sgE_Lks|K*zb53yBrq?4&BEXq~JIttl)27By?*(%wH407(JoK+)@x ze>!gJaQ7S84R2&`5hd|wDKN_`h=CNmS{%m&a82i zKIXneDYXOafH)C4mVYRuy`XX|c!RGRR1T&9Ez)|DPRYOT3cuFh+!M{(ackneZ@91STGqr-e{^@D``YHN$v`^%uWRnwir zPG$nX|89+|5KUugti|JQCYgVHrJBLQNB`XBLW9{l4FIY+tD?E5l0eRfZ1fBO_*CH^ zCDT6`f5EV?(?|fH3kmFCXijh>J*^VoU34Wa5?cF4dlfyEpSlD6=JvKBmiqBv`3scX z+v33DZ(;|gxim$=H{A`Q?N#|Nx6Df0WYPfG@Lp%>(^9JEN^%kXzh}goSXwh}Wl%F` z?tZPCU2Le5oviwZp+Enq*_B)ZCZj{7ugrFTni(hgaCrac)bd44TZ#KK0MZH_o=lE6 z5|NyP3S4`SJ36xtp%z-4;XtUS2mm+tU$n))_EzIW$^;k(h{sxxKE8NFwZDre6lc-8VlmHSJ`m-z|&z zdp%g8_BCdjVnmtySJGR*nYh#0b#y@ztct0lbC_4*Eqagd>i?!{kI`K{A z+M?u+9CqhR-hLgiiE-3=7bJx-9)n7RB9Ax2f0ozJzZ%BE%Fs~oXfnYobSV0YR<)8U zYe{6(c@cBh;KW&?_%)K$9wzIHyGlmo!AjX*V$AWzn_Sdm|2f5`SU8|ErpR1J0;a$lQk{5Z7`|czg&RZ8E z;>A%Oxp?tklwu$`E4tO9=}5dqi1BZ2-l(fMuP5b;^F+=!{j>B!F-)`JG zLTao@$UhP-vfw`kFa{a~p@kQjMG55%vRpEOx;C{qkYE#%MzmzDx2L;2m+FM^L(K*) z_kdP0BW)Qb(ZPakdU-Js^wCWG-N~Xo6lK5@ZA#d(Z;mkXi}UH)M{cOL4C#PUgx(Kb z0*ENuN_YSw0E#&hotv?v5wA)D19u{43W^@GxADHd0h_pvw+gYkPP@uaw2kwt zE3rQrf{olUxL75<9$s@H8|=DIJhsKb`@dB{QQXZ*$?Cn)ThvyP+?g(-Z$^2|G5-%!eIx`0lkx?6 zI=c0WFp%sd`8(-~6pk4>H4If`7fHz*kzbhPEuuZ)`l=vY4JV(~{X8FN6C z=p+Nk0-y}J0JZPQ&f=c-%Y~uE{jVd?G6g^l4FyEQ&~)XINZo8OOyeC<7?D`MCV}yv zlMrAw&@#^#_NUE{Pg46L$-v{+A2~cBWiC#SX7;0+8p(_6ds%(I!jK4#pqAI03gYF>d#J$WD|UbX^SC=A#oNC zmTN%K#Dkem8Ak&T#@NIOZvL%h@oN6Bh;~nMD&Uz00RU);p57p;DOH>j=Z~RgjVS^o zY?P<+jNe8n6Q5-!PT~D}T=%eHb;YFt>dVc#4SMhCu;5#5b}C{$Ka%AOpmqfAKRQG& zrjf*%C!_WrRpDGXD%c`+wFH2C=XDI_i=j$dxwgU^`%KY|oe1k1S!#fsHQGFqsz}~` z%we+M=th|ugv0o^#Has=tp7`DqsFfFMKBI9iT4?U$N+i`j8xN}y;|S!qMv@0mmScb*4eTYb zMEs9bC2a2CZ?GL9>Hgx6^s_RJQIg{9{_?Kq4)kPLfjMub;GpkbVMK>@=gHRqAbWA` z7|2ufG^M$CHHk|#l-VLdp}KphDi+{ky&_c&6vDx&fK9nS4xJE7eNcZrt5F#^b^07m z7nqdSfWbR>!SB-ID;t{zBXV-GEmvRBQ3z9^3Z|5Y4vIQyla$iomMuJkx;a;@CeZxH zXZ@F)PaFwnbDQ#ttYsK0>nRdA+ovEYrii^p#yEujq?WaYfl6n9ec4#(_rw(3&SBxL zAvyRk&mNX98dL6aw##mvB}Eq+hxIyBo4VQLIb>49>R_p%$|X0j}18s<54E z=}-AWB4Z&27|>VDR{LQN!U_96wuz1j@;>AR(^;IUFKxZ)-U0#Idh*6fk#VLNQl(aV z72s~fsbSPqoM<>lTP--6(gnjqEi7kkK)f!)_#fMWIJiMz;~w1*;%oyX;yt+yAfp<0 z0va5>uwTLPQx(00arOAK#6S2xIh;z=G~~+IS#`$O<4NPN^pSI{mD>Lyn2FSQ%AtWk>_;+l>MKB-FmJ&&3rUd z=C_A2@RES?^(5l7$nU74sAJ62P!*~h-UJo#@eGC(!Z4)5F2qHnwGfFQxz-B8wUE5oH+579soWX;oa;I&d}^N;|2M?NVcsz#9hLn8Mu$f)r8||jf+E2i4~>UumSF(L*#3}lalg?%4&R0lq2P&jxds+kCh*A=;iySmp6agp{`8uT3qGLU=N`m@KoSQG$ zmy$)^j}f|bv=YVrUvWolI2I1hZBf=KjwLc45&%Cw*f4|$8V&e#u9Se^&w5sbb)&O9 z&)YfrVJhxyt0Z_iHz}N}i!NpnGOiZNQ1!J%gRE#EAs0(7y(z>S%~Xqd7KG4q7@J$3gJP9sUulqXqv#h$A8H1A`8huzVI`j2Z-Zw3HBi%!Lz3S2V`V z>4PM-W8X)r9?MOx*3-1^Fq+4$Qcz-%LO#8)OB$qOh=exPi#}rqbN!A6lS@T4l^T;L zkpkA>#ra+**JkxbjQ`o0ylk6N>G@p}i;in4tE*Co#5wEI6kH*dU>&phLgX3`l5iW! z<&%=2O>MMSq-iAB^fWLshU#~S!v4>GLATR~SwWe8M@D?eqtlXU962*Ll z=Nyv~;N4%&p#^x`AC;K}MdREX1;SgRb70_?z8}?{7xhiFb9fv+%S!AE2BSlu_}uwY zS{Sc*nfK{bbDXrMpV_Tw<0>0m{#f1-s8*j3JiaqxS^9SX1Tmy^e{aa&6xE!u=VwL9 zUu_CWeNw`wNJ&d&dluFqg;%B+a}W<3y(1~YkJ>wbT5I69*3KFABNe%Z<-$HX+1k+q zMi0#R(ipQklWjB@OKxq*G%!NQo1htpS?BLE)6_=1`^pX_EREhkKY($&3YAn`DivYU zgp_#lT8@wVHg=EV_$JB+t^>r5vi>9A`TI<29*E1u(AE*ytRGNi~mgWef?_kZ;CUO}N=1+L&Jzh32$GaA?ZT_c3*rxY5w`dY@n{q(=@8olxZ<3Vi?Zz}Rj{(W2g z`-D+NAsQ0AqHta2pUQu0H1;8$T6)auQ+{$Euk(OFgp@|wmn z+5V?}M1xY9h%#kD;ZF7cRy{=nGJye}5}bo>m=ER)~?kRQ%tnH=$61+)+1fyE|%+yAq$oML|Ka`ITOa;On(+wXDYql;qCwPjc{TJY7r= z4cCw0@R>MwHtzoUk~8~0PMr65eG6Z@$ote?UuPkcU*>*?5cB8abuCd7_o{&4zC7d1L;1b5!*DesFDl z16=Of{V?T^pfB2-Br;$zO%T0TIq3`MG=NS?<4j=ieQ1AY|_Bpv>Y;_m8i zXkWRH45JWqdMTSr?GX6tAynipd#l(Xg$;lD!QxX49DK8Z#|M8zyN5u|eg0U*y^=v% zEi>p$O`G1YjuF}%OgZZ+xqW>N-~MIxaO>B+INIDSvK~F&dHnNX^=dgts3a#a_2%*J z*jalM@+aV?h{q<1vx(&>pKmZvd2LOVtKR1TVV|~!h0KRoBs*K(>ESD(xLM!gBww?8 z6`x0SjY&SLp5ENw6su>Q4R=31I?|N;oY@plABvxC;XkZT+hmcAH*31|Rd)c{v_>T# zuY16!JG6Z6JA9t_hg_~qw6W9|9c6mET31ProYKg&V4=l{MK$k350j|!>LVwvt{s_b z1=C~SLl2wNjphT_d8hgqmX`_{r)ZQbMJGWs8yF+RhUSnZKi97j%HvEi>Q9eeKFd*e zpzbQx!aE7M>sNeqY9@tOsg+Uyr|beR`-S zq&5h@S`z!?_(S}1X0b!SC;zIGKghDCyY6ffe|@@4Ju5x%;fP~+lIx@`*krrBis!iN zF4vHhY0z!+Qot|LGhihEbl?)=r7fBK9BBYAcg`c0j|C@t!B-V`ybgkSC9vjNi=W$E z(qUyD^biyI{ocZ0D0NzqX81f1AukhdgOG^1=t7e;b$_k+zMn4Qm0+$q_J~y+wji$L zX{q7DlS|uZw%1bY($(5yP2hv?c*}tOR+>d%tvt_4*W+BdjpOXnU?Ycd#|*!#`E@?{ zY2oerjReIX6(Iz<>3{A^xbCMha82r|#LPAtX9t+`tdFSPHeYo%1hMR%lsBvs8gwfs zF_}~Xrkmzn#NM9`FAkHHPNV~qn)#Py@T@bKyz^8@Z^sd<(AfzkqFBY? z9KKqgC>#H^Y3P0#m;v6!u16sEeV45Q`Y%(bEP@^&sMx+8{o&isYrojL{$*;v`bj!; zd?s=811xck;n?&3CvjRvD7yhisv801_P5yaTng@PGW>;%<9N%X1v9u|jeWg0>)k0X zMQ(Xj+t@+FxQ5So%ik?UQB#<&_8Gx1&B&0j3a|8><}%FE$PwKdXK>Q-P?z%tST)WZ zEj+;x?+cXZmy@7wDs#+kU}$n!3jSPvxCE$p3;q**J zvvYTc&C5SqxcrWi3@sLaTKavk4uw}(bW1OYHII0^`Y*P56su+M{+vuU8o3&gd}{dm z9*d4I1+k09E6mz^54!G-7}r|UuvWiu^6Ltjqc&kv1P)&Z^fJYExZQN!KU^)3kp>MJ zXLKCTq`nN_lzGnmEt+>cB@vc$0zv$1)sHp)2q5TIVN%vi-v*UW&|Lejgqy~Z>NeSX zo!Wev!0S~-ie5U3hZrw-NnRjt`(abo75Y8Ni0Y7P`bNZ4bhz#1!R*$B5RejmTqY1T0O7%w*z zS7L_z>Wy9}LS%{w!_S)6DKb0Q>uk$5!}E|UQcdgJ`RAvUt!bSuO|~faUitgjOck-x*j|~_?!-uV4Wnzzc*>-^*bWA*PX2ShH>fB zNabM}+g(>*mh2-|Z)>5&{IIN7ovqWp>SRK_J??%AHlp<~Z?LQNcrPJk%23AliaOxDSL@lgtf%P*n|i6- zdX-7GT-Eb~I7vYe>VmCRn3mU4V;`ENjVw#W9VDmm>brdX(Mcalebgbh}xu8vG2oeoGu?ZNG5RlZRzK8#g)>>zAh%k9|qt z>J>&l=<-|rJP3U@S`v_8;g>8^t50Ax5XH4;?VwkEsP%pr#92~DO85^Y}BWWgbT8Ds@H^87jS%rgL;2Dt9zA?XW<1ybiAmcVk4yG zlAl|{XQXL!eH|h>F|)Zk&l5}CKAsV{)`kpE$Cu2#&W<9>Be z6)RF4+j`QwUoiN4gKQxB(#0>(?<}iBwgdNS$*;Lg>x+z@$Wg?I#GPq$lWU`ek)HVD zwbfDLgP7M5`2D(P_TUPsXCmn8QuNb9_Rh8 zb{!RBe7`+TXh#X2gJSpNu!FMIe9jfRe*Z%YWL>hdlc6R$HIEi`drRf zttP1}>I)_B-dHkcU!^{u{mSOUi<&15kxlFOipvuCAh(x`S%l0P^RCB-K9wldXH;H3 zZ;B?$bj1$bek~uRYOIFr@UTk4VG3RwuY_XA?(z@erqw1_-e)@uxbiO`&^@2|!*_XE z!6hjz%ASY5>ZMGDW_Ph$>v7vN{vZ%~hwA(`4vI>F|m)Q@4cH(@#TI ziNvV1xBHen6A{0D5-6=5HeV!v6mDB~!(Am5weV@Y*%;Tfg5clYX)Edr^yE@GRP#t@ zPaZg_rk39I;EG%BO_o!<%j<#e$4T7A&-&L7Z<=*8Zg~TIS`_;2N;IetKp9NyTHlz0 z!{dqdk9}xEa-)6Z8j6fux4|f&b;DO3wKRd(-}u2N)>(^;Y|=HbzaM({N4=zFZw%my>tk2-pK#WCA+u@`zyW3DK;Hkucg*qOGDmPiP^k8by? z>kB6yP*Iur?X0Kz?-G?@@I|jBLCDY%B_HcZ&>*Y&!7H`fcE)Js_1=;nY9lCnZ!c## zv2$w{2rqLXr_oh!2VW22yipV>P>>)UxBBR3Gn@$#b?12Ti$jn}-G31Rd8+g7+!z}= zv?a+*GxIGIrZBT76?+Wh(DGK)#V3KAwV67SHq{=9-4rTp3DJEO7NPql48Fh2{IS!z z+WQ?^ig$_M!_X%blsDw}{e8>JZ#M*BtP5^@631zgIR_C5{3c=fj@axlbpumbKfE}2 zg;D!dRlljFltIw&Z_yr&Hpx%7&Q*52y>WS#%sZluj!~$V@$9_2-5=3$=gMPqxSEnc zp;NmhISzY+pQDRkBYa+)Ogj?v4!IuBuG42mji%Y|vlX7{c=!#hE=X^9vBNQFUEj*x zhoNz57?lknw8^Xtr|e!kOjNw)k={SK**-fIzwawtF0(>AZhz_t0MWn=EWq0t`JAQt z<;Al>-EQH(Pey-b3;l~?3d}!hBy4iBXC@>~u`1nd0 z9eJR-bH!)A`FO+rXL|a_C#{pup$B5uKS?o%F|B&Z2j$;jKMVZcBNv^;Sgws6Lxudh zys|0z+m3oUioNgNuDRGr*U8dPLdmku{oh?%{60a6#6q)4U7yaYX#!t48%|-x_Mxv@ z^VC`o=+N2I%n7>P5Ku;cV`b?mAT{^?sF*(U%yGQ9QRKd+r-IGzWR1~gtx);$Va%&@e50eimmtLY);$iQ~z4KC-|L}4ai$ai}ZLd5CUi3swf4!=cWp^JECVmPJ z6?AX<~6K*h!Bjr3J%;2Ynt~z8(uJ+cd^qU z8-Igwj1|R8BCDkS|FHL#O>uSKx_1%?5=gM%?!ny~cZUe>E{z9hJV4_P!QDa#ZjHOU zySuwI&ePe?-sir*z&W*F{9jQui`li-lxxj3#&28;|1^W-LZW!<#?|N6{~b2{oNJ0} zmn?TiOjBswS(d{x?4)hde$`Y2(QT?kimFk8Vj>8QjUpqi%Y4$Bl!_o20C|JyDCe-y zub!a7oE8*MVyn#(IZO}K*d1^p)D*CSikd9Pc&im*{77~R1W&y2MNq)b(#tF< znZeZ^X1No6KQLmXZZ;?<09R*}E7vd1rx*^yUYfPGUhPS2EI577xes*tt+0yo{i4ef zdMU|2-1Ve3;L4cSn)>a-PN7H3v@w#+SL*tc(+`42ow3yN&DD-n^1j6fow41I$G(Up z7bgYjk^-t^i)E_&-GRAle~L=aC*)Ym-^|;F$kE2wG;>z3{`ppvGjZ05r3~24Kb$>1 z`OR4wzom=VS`PieFB{H~8tED)g!z&D_N{r^{E$3l(UC!{9~lCd^)#IU5P4vs#u{ZI z&DB@EER4BH{)go^pnI6qT5wk*WXK zieaMcWtQqi33Bt&D?;p}26%hW*x7JomSEmG;ZcS#D_K!eXJ_*vWULjQL=K{uFv&Qo*7V#n-0<84W}>avOprdsOJ9gCd)mN= z`Y!U1T2@Fe)VQ!3r=`1lJM8UkUtaZA75EjU!R2@- z9&N?Y_y&wz=4NT)OAwFdlw)1gL<{hGSi#2y@;$eC%z2zP3cm}N083A~tvq3}&>lPk zAJ=H%MLWcIOP#OSARiPc4ATV(oynrUBcs7h43>q5X}+f+@mV=lOvi~y_+YQM7=hKz z;Bc`aHO>#R!7N(}77J}@I^U5v)uRy~h@@`zfL>1s-S1@un*jU|B~amE@AT4L&M&w$ z-ZDh{bR3`Bk!5d&{ADRx2EA+5U8ZxbJ_bL1gZ)FI!0EwmzSmYv?_*-@{ZZyo@}9rV z?kGI!!L;38d~dUNc3FLUQd0u6?m;Wjb-nI`Sk5R1vwjO;ga3&HfIo%*(>Mf(?XgdW zE}H%Hg&Yt;kp7v>1+5*}blMI<#zcQvlYiQb(4S%&zm2C~$A~al3P>iR+^AV~vsrW- z-4-%IaZS{3Y6ZOHC+e+F@80OGQ}t}Wc39JWtxmI3-Y=vL4r&OYnJHQeq19I=^)#`83QHTR(kXOsk*z1ov`qbF=_Vl&i8>2TnK@)^YGY6< zR^VRzIe8~5OHYsyr)(KpUOdR$I$<4zK}n&`i|Me~NVCX=e0foepGSpl*daP8y1Px9 z@`u%Mdl%sY|F-L@4{40TRD~YNW=}*^9nMYnYENYZK}?r2hzyp=%n2skl0S4By@b^z zT;#EM1~zaLr{LSme|rSeCIn7q7DzBb4+0*O}sZJ(8#U)y-BDVGhweF_8OJ9Unc~3)&1)lF|ZpZ(W9z=Bzw9 zP}dwFNwN!Cf4SoZnl4%;+aMTCU|OPNk38S58Wp-c5F`C49f3!O;`7Vf+veb!XX#`7 z-{B80P;l!lBDIMOWKl@UTlN@z)5S9HEyZfTiF2xsw||+K85$U54uXZp9%~C8lke}i zraU8Q^IAn0VCL)OXah9)>$02%w}`_DOr!6OOle;u()jo@utO}DoTr*AUx?Ki(7%ab z3g6OpW(5WUhw^~(BS(F(-?gn2;x2vvnbr^w8MM9 zSFJs?Mbd+;&hvkFKEM?Fc{szc^lYpm8z>W;7@W8oj!!E2bDtIf%%-7yKK^ik`OA>t zsROS}0VZlRi@!O&J0_bw9{V#=3zRe0#5V-D zKF@Bzh{3LqxF&#~Hu6^Qj})7Z&C%16+Jf66;)?uu)b(?;oe~owBsmDOGOKW{&HBJF z&IxlX$VdMtll$y*|BaK62Tx)J`=@y-fCcH+nt55|MmHhj$ca!n*%sfJkk|F}EQV#} zQ+T&5XwLA=x`2X&s-I=*bZT;>9CY>^c5JyMP^AdESh3(6x7;`4Fa%#~6Viq+`{^-- zgeL^3B&(H-R@wd@QF&*Fj2fg2`vkIvxl3Jj|D&Qw^^x#H_qO^sog`(Og|7$pMxUAU zPFg@dhcng&Cc-l`{Zd3EKAJ{BhJo)%4ShNk8-wZs1Y$&|)&c?z`ZUc7y4YMLCQT!% zUFS`4&;NV^(9Lcq?y;N{E2d=P49tFY(lI;=9jy7H%=N<}sPsb47 z!@eQtfk2m*N9Ad;Qb9^M?itQ|V5!=%Qa5+>Hhl2q?7Crmm1*B8Gc?IbWsJ!2&i&+5YHjKruj+w2cI zLrv6Q(QL9)}L4O5^!pt}z^sn3YJ3G5z z{}FmW-t>6EkdeyXDzHuk6^#-!;yng@lMOtJrWJiHEi2OEu-PkJ_p0$Ch0_w4r0~Rm z>dKVdN-YV}D6Ddnu&rC?pRATOq?$50P>81Y$*M6qA&&qdr!bT@4bTXmi7ZK==qlX# zViPj(zz@GBfN#B3j_>7i%Y!dcP=m}lhJCX6+yD-WMyAbNnscJ|Hrqod#0ziue(F#~ z6nyumM9n7zYvSul#CNK19i0O7fz5iVc8VE$*CF@UgailS=qMJM&Cv4+>icq75Kp3c z*5Z!2W$QEHTI_=Zwa{2Y{)^4#LElaFFwO+Or$%0CB}3HfZ(M*65nbS*pYv^A#v$vO z7PvUnUB5(;NIdSg69Z{)p6IphSH>|Eep_6HDDO}$f`dE}mpn2t7IC!UeQn2)D2<#< zXk9b%bB>s^(l4=2{%4edp(ed~5#5N4eh#@uZ&!T)%G}6kjMWlUu*g*i5F|l;bX>8a zi1o4cHRD6EC}DWJjbuE{_m`z4lDP!#Ahr?KEUA7HG}1p@UPPRZOH9q|6Jums=BlED%WMZq-=BE62nwxay9luJUjh1mLJ0$};{ zQi9UmJU>k;zH5LN2wXU;b3Bi|ib4d1k%y0#GFSd^?5BJ-d%(9m-C)-;Ya04WbrKnb ze5%eKxMx+(2v_eBBj4uPcIwS_|d40@atU}GP27!nka23l!GO(L#AK>ik#h>R8+E~2sA=+l7r5iy?^7AuXmC~S7r9K#Ur zi74Q01kRO{YhXVJE{@9R>eQo$g2+Gq7NOVEnkNHHp>3Kk1m6#*2nu|}g;MT6U8cHQ z2Eb!E8JyShasr+o?~XPC#)6CcKF2E{p_#6GANifDA|jN0?{fZl(Ff6X2fRnq)Sxr>0K}GG{<1tI2DlKmHJq1X=kK3+Oxq zSi&Uhp$F60Cxy<}NLP0ZhsHh8Qogk(Zp}rM?n8$-{`0LoC^|Au1-tY_wCt--I_#KW zur|vY_?AE7lW;(r|2zeN5lqAljtHTZ15q6m!-cg{m#k-3JgRa!13_m|a zCG`0hxVQDswR9@=z0ZzlJ+IiJT6A!0Dm zkX%eV+qZQRY5<|CeBOFL&IzG>_*2MUGZ@ohQ&4;LeCy#<-9x)Ry2f&HB}z_D2OI?5 zTjI89ZfNlCgDhN#j4Al!!|rj)pOxT4l`m9yjfMH3injw~i6yBug0Py1mCyzAqBfR=m{2(xrBB2M%v(E}hZcoDC9hUq)W&9Z{Z~5)tUso;chPF|jy|BbI;3-H!N8WHMQhG8|WlDAChG($n+2pJU*N=&?2I5cng@r zLZ&Jonm$r;Er==YADb=c+P6HV4fvcRp@GBT7?U|eay!Uvy4KnSg5ebT$gauxG?dlM zW~iYs-{Htmu2`V%Uh#J=lU`z1^f!)?f_Uf0wFP*3Es1)b?Foa|KrE7ru4C`MN%1?2 zfL#;ztsetSwR01Fa(Txw)*8BR$eRy#89w7_E%}u6ZEh@)N(sDk)H@Beu(vbq=e<3(}{lFn(Vcg zR;OB27cVvyP4zoQn_nMH54B@6EIhU*xMXlTRPwm353>O^u0+$i<{GwV76FgC-WAWE zPoJMos)K$uaLR#*FavzBFi1X|!a@5!8~fyXxv$K~e|YcRFE8;}mEy>IP98+Wc)CPT zB?9m{)6s3dM@)q!If;k&R7Zn)c#IfXm^&yD_J7I7O*YMGG}ST+9ZnS|9A_=$v?LHKJ?H|G75K5s#bn-UX+4!xCIEBKh2fm>IJ@K`nD1WcbY+d=W!R?4g2C0ydKx zHf)`YrasOTeI@MULER0^k(#g6BX z-n-M?!~MqH%~j*oCn4z;%SK{s;^EY% z4W%9ZuyjFs7PG{#>{CRbynY%uh@He|LzZ%}4Z?fhHpiB$Gw$&6HxjmYO!s9dg2yFl z><0qF7{rE<&|e|^*~X_Idp(;ZTs=HBvJd{S2P%#xIMp+f!eJhXtD%Cd%!Wxai^OW+ z*EF2?DZ>`KoeN=DF8)J}6=X9?U<3x{+5tMm&Atb!o5-6SCE-TY>4v&kHmf5P?HilC z_5GFW_xqV6zA&eMf4Zpl{oc+61!OEBogX>b>NqBBg97lgUoD=f!hlx&%{M-q53@)V zYPGhyPVIL#ly5>Em~;)JaZkAgFyeZD$50lVG0Z<&Wa8@K8Q0c!efeY*Ynoam6>+e0 zHK|-RUf*d%W$J%+hFYwHFB5E};7N}QW|`kblHY}$C)!|%L)PuV#9A%huj@dc%IN`) zZy%2p6x~Kf(#y^$7=pHUUlfnBOj1uZ3FGlL_P~!HaGCHIF>OX{Y&H+;tRDlSvBX2Z zS>0VA&WWo|aP(H--F#lv~tV$-CpGCUlo?^DOo;^)Fw1o)6jmnB2#dG2Lc$$!O3kPdq^ z<=jnHj69X=^&yM2Jit7T+Bh@*Q>)_n{oc57*Ylt6YmtiNo2=R-;lBBzV{(}kz0D#7 z$>pe`BrMnWLMAyz{P)Y^$lST4WRavpfD z4?{gRc-rh3!*$8ET;nGKV9?^kG>I0WB$+AvBLNzq&9=3~e86pM^8Is20LK_F3R6ZF z^4{1vg*?(Yrc%aLU@aHnsZcXc$d3(@kf4{;>m2M+%IZc7TAC()=3m4yFG5dg+J7lZ z96KgOj6V7|K;aBJJ+mV_%9HYuVw}$d>~SDrNBh0{3`2okaE;aUggeVdL->y{@FNcv zO%n}4ItDke3pO{DdK~@=HCEE`m9zs<2W!;xmEQ=v1@r2W1jd`C*ViGSm}S>fDca!Z zt@|&?9`cLu~p$eOTS{_hF30UO@vN44Ydl` ze=*1G@ivew+{Y&iTBv;4&3%f;zwXusTpZ*K>Z4!ae zxq6&&YM=kXZrT4*yfl0J&Hw6(`gEd@s3r@VlDvOLz~n!J2QNpwPWOq`4E9y5H;sxpv4qc$y`Im@?hnP-u8S*24Nq#R zT~3GM&phb2+tAiwrA6DjOi)t%;WO)M@zb)9e2teYyS7a>oT)6=QL&vj+slAS&2FT2 z>O~_^{qyvg;}?mnF67aL)n{%>Aw5GOt>>!b^XpNw`IOb67>{EMD^isiB5iN;$%X|X zGZ^tYTj6tm%`$1T^akb2@RJL7dXz93U0=eWh|?jV{z5e^QFYP2{rCF3lR>CNwd`_G z!D26-i{7`%gWt`UPchZc`9!|YUlLLpX;|2%2aiqkEcAzuDs>O2JW9~hu}ISmg>-9H zzW@F8fa6N9{KLW~n{ReU8M%bNa2%OzO~JxdifP9*Ykr zZq)OT=Y!MwpYEdgQ}OrsR~bUJp?nH@!9XO2JpU8VS+nWl3q7-`x6;({$4l6UL*q~% zgGoIN4`H|dD4By6Pvtx??W#6w>p_&1+34a5q{!ULd)6{2#rjY^7=$#@)VxRQG^Zz! zBYggAE1I{#nz}U;1JMkm zx$dK6x~1?x_}xDjHNT9QJqB5uZH1txN<8 zh=5$?+{4DI?=Flj$pGQAOo1b8o5C+EP0nsMPM!gkcW?A(4w9MI@1$*u9Y;B<_JZ_> z*DJ%uMR%$?ZCNDbg`Y;kGa3hGD&}K6QdE!sn3lApj7!1GfzJTYbGgaqJ7pl# z907s76wK{2)k12Jdmp1aeFze0|$BF@d!Oyl`PX3kjI~X)1%vyudLaLHNN4{zE$7?m3b&=Se&?-Cr`^TH{QWlDdR6!4!L9w^Q{{`{Au`( z2XwWyu+Q3`yo#Uo7z3p?0_I;kQn6WNO~)2$=Fmh_=# zgHOUsd7o^fr+p?a*73zCp7EET{M+>ygt_aPel><{Fs*Y3*6Fkcy>>wSeX}|8=-h|t zVauRX43>I5c{txRtc<~4Puq;N^N2!-9X?0NC7Y}pLGj}@ntUuPulMZ{*z-TI)?Rr=5@_-cmG0q zZN0g)W;aVFf2VLc7mPl>^+GL94Z+!)PfkkH&9UAoBpd1WwII4QbuUuuuC%KNUvRe~ zXy)m>)@^_CbQn+}-hmTRQkM%}T9>FQiq(m= zTG4*lr8($|CE=HE5Yni!@~}dmF=phVi`?jWbzyxQA-(gkWLnVL z^T^XMd=+Rh$=ds25cTCpVQo6wLiIRh$*$d~G=e4lX_5NdaF zK?!iKY_!Cc+Cz)yoSx?W1lm4lykAkRicYF>Ep;qiANY=>I1|e}Z<_hE@5RK~-ULjw zGOn`iy(le3M=|No=+N5KJH=REyU(BcNTE8`pCVQ`@tHu08C#CKu`D^H27Z)ZSJ_{e z8Qp5@tyCPNl2BmbK9gNP_AB6`HNg$on%nH2aU(CP-IyoJ68ez)-;G7JaG@RmHrI_B zfAm0XBD``@IrWoj2b!ut5uh?WC!eZL8|?Dq?8k25XBuuQQo?(9W6?pXCImJ$Au%9L z2i5fR!3EMrXvuo{JOi-Nz~_58Fnbz9c{0qzA%O{c&ia0|@uH=f!RD?77-x|Cy?Ra* zf}?<0FITXT5H5(v(8{z32GU*p$xerE4(x&g*ZaerTV)$JLK5~h5@q#)ptDk!$2DRP zm80&J#|^~GLDH8w=y8hswjw(>V9KZMr|FIdzVP|4#=>=2dVaE5`H`56yW|CHQLQO9 zadpBVjuQ#GsY;aTBnL`LyTL(2RkPH;juw^13bv~(YOUVj#@g^^l(sZmuWpMN#Y?}%OBq5K_NYe+7rGgfAsC!1Bb*8q%wSd z@*VeUB1}W{50J-GJm<%6pd1+~Oz>v@FO^TIngo*8|JE-di|A%9Wj;kG15KUIo?N?-ToW% z*4cRZ#G}=sLlT1%zRmLATc@%<-BPS-K7v~JhtW<&5;5O0Ho_@%kgXklMPGav^)gZe zH?=y0e>9D?G_>3Ee>uk@2`_(8(qr6mmHY|;DZNj8yB)&r5Y%t5U&hn3U$!gn(>yw> z@3w-HpDDU$glu=6PEO+de1#^T%3le#6r0oFk?U!=4C~?V$&eOnGJLr&Xgiv1v@bqX zYxQHAjjs~DH;UqX$mvWBn32|vVe?YyE%dA4IedtqxEi{2)g#Y5mR%rQPq))QLdXz zzg}h;T7>H7?O*nlou0X)lfHSn%Be))xJ7J>S-{0-F?&C)YODU#=aixIz_YQ0o9A>; zZ6&6%K{82$;mWI5>1S=4&iIn!=kDLVmK>g?_#CGK4+6fWEja#=wXS{%uYt8>?qLu0 znV9MA5!E|*pDg2z(Pf94Dq7s}Cf z@g})WM}$pAOfmV2Ou4G{PLgJQTW#*v@)($x2JVhVu_tOS$X7IYZJkKcVRRRFU{m zHM|qvBU{2eYQ>g(Voz!|hf?rnxl3Sib zd(PjxkpRMpklQ>;)9kb(gvLdJT^X}m5PR?sf3Lc=RD6iN{nn=ulu%d^?i^k0>Sas} zZqSSM!uSmRn#IEJ$%bP_)Nm93Hn1YCrPHW1fYGHCogFjkOeN?ta1@K_#np_~q04PE zR?7u7BmlWp`~oSvt)tM_qO*4(30tSGt5LsUvdJpE?VzZ z$G;=L3v~IUX@oi=Eu+i&$DE6My@P-~$<8`+@ku(RzH-<(T%lTtBo2A!AaQ5042?@z zr-|jpHStKl4+~EiaBThHHIXkZ4Ls-T=d z>^hG@;%&_c51qe^44q4%e19y~M6lA?y?khXK_QtxoeOO8#{HcE8NV_)7i4Wbtvy(1~eYW;zg2LFp60;h0M+Dc+&?)205G zQfN=b2M_XU%IAtm0FfmFt?@GEss`eGqtrcx#9n)JORzTYDZf_?XH(Sku}e@HArIL= za|#irX<%C;HV#N7P}Hd(B~z<}5dJD&iHq_gk%AIzzAxxdu}`_6489@wq+JI#RHY+< zca#I+l|!43nXIK*)ux&XNMo9?Vb=T1nAj(nSTm}heS4HapX*06xn)4*OdUN)Zr}W* z(i!0llFGRx9?7@zBd2Xl6onf5Q%Bx{rdKxFRyW zt;o#J!g|a$#x{!h-Sk7LV)D@ZM!55ftiMoY(d?qB_MQ(diAmA?UH6?!e&)M&6b~UN z;YrqVH`B*+Yx||^@>cXLIM|1Ttdz(^PxVv<7?ZtL8CLEhEi#`giv)!WVKiItqPJ90|^~fIwhbuVRw*QW^Mpu7;Uuu5-0>jmK%!-qL~))`$&Q?)<%52Ix{(K>!4I~} z-2V1ht*wRULSoKb(+>}`?oUAXd*8iXsfbB)jx=gp+hSTPiG*|~F*smYySVzeNU$mC zyVJD$Vwo33UEmk^cQ7XucW zyH!p0zN&y8mzA8<16pU?A}D`lsB{MK+q^AuPs6yS>RhOa0PaOlU4P=}pb-)74;!4o z@(TNo1ms1ct|*pO;`Mc+>N}pP?E)2tE*hCX>^8;_H`UWBE7R#=h^4&%w?_5`6+l5@ zgge*oYBs>({xC)Vh1+9UZ%*G12z!ZSl4?M5K?YJXerlUCOH8LEIBwR)Xm zBg8Y~Yw3Z1C^ewbyA@SJz-Yc=b37cW{zZBl$f@dUK_$;KLGi^txDfaVBk>=nFv>hs02IgkB$IukD- zq=O1)z5V95=c?-wllQQ^28nI-1_1-RtM~kCuU~Ua{M8>!^KFd#`Q5yM&PWnL6_kDs z+(~@?Um%dPp$*cEufOxZU=)yVt{}6ixwJo$<)D8y36)5fM8TDR)JoFKQ8X67hJjN= zpx#E8qT_JN8&2b{a^6oPzkFBSTtPu;RPrDsS7C{!-y$~4#I%~H9l&Zf7n%2@Pkjr9 zsONQ6G{YuHqdBBLT+&yWR&0`# z9`P0o>=-X#qNp?8PW^?6ZYM)|5^Yf`RUcDazHy$46W7!HQ#mZEv5HkJ4*jOmYBTCwmN* zJow4<24-4g(oP7c{T_VF@uVcc86b_K31+qv%hHiqmNjy1sxjM{1doWyT}754 zU6LKo4g%ZtZr<>e22Bvw;&g@sD+vG1=~Lu%QvCz41O8?GytB(s;ZUcSh>1ke5HsxT zwsxGCfNJF+o>GiHv>APaM`s6JeSs1?2S-hMY70*dOFp=cPl=VRCz==E!Ddh2nWkaX zt{jHoAOjNCYWxoc{m5xZEM+Xo0qT)YOC-B(RA)}BaYr~`xfkYyOvZhPE?Ko`$}2KG zNgWLAS(ii|FiF&Q>o_OvFl)H57-Q`A%e*^Hy;+9A=5<#AksEh1+6^W61*Y4z5(_jN znue=Ew+{@fRidEB*Ee(Q0-BJz@$UczV`3T<+v3h21VM;mG(#~JkxAT$R~S)hmR)OV zsjCL~i5DQRnB_Mv@7s)G%UFJigZO10i=Nq^ov|av&*m9&Wj-bq{v`PuiafimTT4IR z0yc(Ht<8s9N5WikB3@qyH~QDU_Lrx}Qm3#8^FLb??4eJn!vu15V{#&!nmC6PxzBMJ z26a;T<80Z^_qtTj;Pi(EWH}(w>p{9%S)UY8zw#x%HR{@LSY4T5?GUF`6TDrvjJhRS zLRjaatw2J{bKXs*)gH#_ahb#G#xzgsyo)kRP#$w|0Z|eD^;;m4^V>>x$%Au^cXJJS2atc_0qJh;F!=KJb zwG!Aij^X-^ir6jU)QZ8<2OHt;Puh9D^b2KESawAB3=3kw=;#S0&?6Q!_T>6F0cCO1 z)Q;|`OgF#Ph!#u!mz*$fMPCvQ`$4UAKf?NJ;Ujyz!!fdJfs)vWl_oVv;rP#nipX*l zAYJA1bz!(OygC@~xbi7sCpDF_x1qKR2fd76CVa6c?AnvJb&XYYq0Gx`JW9KXNnFNh zO#ToJA8kC#u+mrc_N%4@O=vS#k@vmFIk}1vI7ph}Lth1&QmyaQqc*3G69jRNiIsft z#zHNR7ikom-5yKwCsPB9U9ladb>O#zS00Lz)8T8f0n+jMX|tH6vvWM@^p@jIS-$5e z2O3kAu6-`A*u2N?)AWt?Ll`i81coyaPkM;n1eYszwRk7N)G4nU#}7}axNQz6Y+CAf znW`}*5T#u32d}suD(IZ~U4!qUgymze_x-u!XYLJXU|8a`sj(1;vg{DqLUcpdmykwJ zH90C1r5mY7tenP^mqig8bc7=VjerRe5E-$>S~+%S)s|@p+y>Pox62*)saYCQlWtBF zxHKZzT!)M%5%wI)Gu*-Z6hFstB^pQq9M$n*8ip05h^{O*LN;a)W@OS<8E~&>Df3$= z&^qrK_H7vs$^bkSRXRTLWt!t>DpF+>W!jKRhi)^J$U05*x3qcI)W*b%?OtBS%Wv6d z1o80>)nxRGRi10aUxv`LM%9u(1XXh z7VxXty&W>XpmOep38Md*Wi8`$T>vn5p#<0)=%oBf6)sYL!^e!%DR!i$OCeYG=+28hpzUO!TV0oQVi@8 zM5z$%wj5b2y5M*H&U;taxZFr&D=Dy7J8OJ`v|jXkBLm^Lw`Q|2DV?Tuf)WzOt|ZAyr~$* z`Dk9$dD?#bDaTa&22Vd2k7!2!T&jC4<(a^2>UiTZ8c_+?8_sP&L2V~g5Z7j{hackE zNx>Brea!bJuA#yM~Q@Bk<<=ENrHk|2ThWg{=%Kh4H4R8yQQ8s zMQ(Q$4~xOI%%!MtR9&xX&9^F?B01Byj&fKXR>Uj_RPuxHJ1a3^fci)4+Rm(q^VN5n zg?R+!18-|`NxEX(#Aw_io5_4~AS*%+F*W)>Zej5NxDaviAXj{;nYvmmYP^juFvsCy zW(h792^&bU;t!QrvA+Fw*BW~JuQwiK1rs}Wy*|&)(;tT8`bI%<^+|M7PqO%Je3k9> z^>K*W`MBY?U2E^6tQn}NVhA~*f$_5TSeZGcy`TuH7R(#<_HqOm&v!b#vQgLv9;&wl^&U4)LT2h} zQUHk@-n6=m9i3HrxCO1=luy`3B0i>K-kf9l^{rIMXn5>}SiI$K@q#7N#G9{D(9eFo zR37`^45YXB2uAZ#EKlm=Gw_~tuj-r2`E*Z)Jj>;oRSUE~AK;j7x&E?P&BVb4%39gH zcUZ93;xFyRV*P&p9q;ftp@qZ@h}z!$B_0}WZqm57h-bW9JAn&RgYKt17IxR$2MPyo zW`=_>@NE*-UKk8a22@cdc+y<(NzICCQjUI;JP6hO%-s~_e|HGAhnGt`<2|JUSSuxd z0B3pqn6ElbJ4%qa-IRRMf&sF~$5xsp_oJ!pBpb?Z2ssRt3VuA?fU(jhBgKvp|A?#h zHjT%fuD6$)0v<IbXaI`M+K9RsR+j-56(CQaf`B5@*nkju9Ur-N zR4&{TT?TGJK&QuFj1Vhiju^Mi8Q}-}XS9V-M~tIJ)&Un6Js?;4_7B#6VmidY=cm)w z9m;ueM7xnP3JT|@T*RZ{mKTj>Ju-(JofaLxJdvi~C|vC;Kwyy74bp2@h8`$x2nJOi zlJ6PY8Z*{=94G~--8a+6XDx3P<3<$*^W+bWVXUR4o1$lkDXSW`A9d0qxvdLQyB0O%-J6| zuGQ~J9sE1)5A`QV$IXm={MWvB2uRF7Ye?Q0rMe?bp7!5*e|^FOqbs7X)F64m^`?Umu@=Gi z`aMWLdDq+hgEncB4E#H~+DWYGrB&cBk-TBp@jJ&=?^OPXf? z#^r|g`b7@)10Sv*Q7F` zQ|S3KFsN4(NPOHq`$AKYwH10M^06X{>`F)@mpnUyKBOmtBYMutpQ$IN=A61rGZRbXuiy}8ygF@yYr019pgW8MO8l_cml zywuQcFfBVgstw^TZ9_M~EFX4;xp|YZq3kMZn4gkX{1Lgz2JHA_m_y7gO@qERh>XSL zk!47G(7>7h#NuECNst{O6>8?3b&I$71X=RD432C2Qo=%jPs5EQ)_~wKck@V>f`MSq zNgo1cZ~f?4+5Ee4{Lh{GX2?l|Yx*&p+K6fG@&L(U8@CF3hZnjvBzhwz*yLh>GlJvU zy!={P3t=;TyWY=)GWlY{#<&lS0HIobM4l=6!YJR@gxw`8Kz>IsBtGgvaP_{ZhzH)@ zAH>;B$;WJSX4haND`asJT;beDvY2@5LE^~_bH}=tRHudFzJD+puT=Z^-dQ#Zs}yFa z)|&5k_Bbm#v-<^J?wzj&xFGK!cl*D1BbCocKM6X-A3v%Am3YP9!f9duH4!9*AxZnj z>O`)U*I@Y@$MHxiN=1fa!;wM)n}>v<<`gLy(nNvr2^-v-{)DN?Wh@AssOUu6$z8?v zg_#FZ1M-Wu$pI&Ip(a*4!X~`QSO3+)h*E_f3C#f*T=SzM84G}>7yHV>s&5;8yfswh z0I8aUd$x&s1$ad(7{llM7`pi(vZn350Dk+hfUb6($;B*ZXxlHaNFf;@6?5&r_+RXm z$6pAF#ED7uAI{1#90oiQ!IgIZ%LVb|uWzHrP>saD_$f9R@#TnGhg0wmD^)KIqq|Pn zW-LN8|1Zvrh!RF<_5QGS_|L_O{Qq-7_Mega&zk$c zyCK$IUcGwt@)9%0WAy5k$g97#|3|uS)4p!cdjB#vhlH6XYRHL*z++>e04o{^u^St) zC4o4Pq_Q_wWmy1}E$M&|5Hfea{gv6=YP>2&E~$tlArlBomXU(T#q zNL_4ixTygSp3XJa|Lk%D7+{*q}QIlLc( z+ia7Lo`ggIj~nt12f`p1zJlo|wq0|5uZ*K8L6damTE{k1*Ca2V;VF!N1lU3>>kC$f z3UBzIKzDe)>J;?1mOhf8wQ|B73@TN}Xe*?)piKYlXjuWGK}%P5VCNSbnC#>Jtda#6H79~@d?6r#m)y0HNVMR}bcW#`PJ zD(qwNzNvqekPYjNv{#XlzXEK{y}zasA*m%7%~p9OHjr{(m2#HU;vifBmcAj6_>Lsh zh;oB>VTQ9O{6E*cCLAeJKm*vO!l^K!b!Y1Q|Co9Ut~R5sZMTjV3GT&lI`lXduS8(IRC#wbQ!fp3YGob5~gxuPm2Vz0n9-%cW zE08;VFZAP&@5ryNUdSMC(k6o3Z&d)c-_?qpJBu-Lz(3WBv(qgfETm$QA?CX zUJSUFTD3LVhuHJS-CI`A{y#STDsKc>U<@@i0N&{_w_`#WibS8|Tr7CU7^Ly3m)F2pVO|} zy8^uusD;6d2@h|O=b{_aCfa9s+* z1IbR(M#@N#@$j=^RwPi%Q*F~0fWHpb?`F6{Vn1CUCoAiyOqy^=L1fAZsRwc}u8GB{ zyZObB2i9qK!qP}i4I9P5rqWcM#@QSAw8G$XsM|x^e(6?eWOA0>)rFcGyX$ZBiM<1f z{m-9kE%sX#z0(kh9Q^vj^Z`oz&)J*{*BE%jXRX4_zQ7N&s%jj6OCwwNqL>nslT8Xs zUb%{EQyz(V+R_l&w`f_3A+O|sn$^n0ndBohNDv+aItbmQ|Ca^lZZ?!j5YKyQ;k;~$ zr(zl%f6H}nBuF5zI4p37hK9DJ5v)ythgukA`cdQP2VdrZ7vn{-~oUS#*1QpCW#5T>-MIPM?}QxbD)~0YhxQo>E1V z>M2#k33F7rik^-*YP-HVA(TePz59Mo_qcs-5(K|V*u+CaFDfk$aZ;AU*%Wx0M2e!H zj?BFD3OU3IT#!mXlmG4TY_?pN2~@4L6uc6~4oIGDb9*fY4A-&trfFyDl_W@Af3GVh zP!W&R?I<(`k>xNla`64TEVyP7F%StmZd_|6#Gg{*o}l8MK>=?`+!MUljE|FEw0#nB zy7ZpduUSp${;>GIHsF56Tj=>j6EvlSsG^<}-)yD9wL+wR;?z@14DYlT_{e}l5R2NoGbP`mz-V=inFMs|%q!fEY2KRnEq@#<1+jr{NNh&8*w~!ec`S z;hEw~bx86fb~h|L1MYg%2f59nJ7uN?;xh~ANxw;fS5X_axBtuP@LuJn!Ex0!8=WYj zT0+dT)DqHJSot6t>)i?q)|{#sbom@lu9~hx>m5@M9-X`wMa`yyWm9Nb`XCLEK?V*z zZdHMLDd3Tdbg5DI-8&D3lB2OHQo+V~_C6cv7G6e6C$3y{Z`IV6TOl-DgUrGi^|(fY zd;SeWl44LUF?p#)7+>h<`^3ERkJ(1~G3qQTVr9_}-A#C(3_?YA)q z+K>Jsvl+v-`l~0kblR3Gxb;T?=hfPzj$0qu5aWraTI7^0%1A$Fz znq)18DjKn=yKY)q%3_aOvRr-vq37 z@Zep{=s9e(EN^H$vthbKjzG`(Zz$P{f{GIdxz`Q{u1o7lbCKh8Ad;(PM;g;aCKtgJ zXTtY-Rp$W7?AB9hJ1)TeNsB{Ah&c4u^m)RYs&qrAg+ppS3gl%O6UO*N-T0qZNzi^8 zMg4}!BZtmNgeUe|LIWDxCyM1|viOUK%f$`!)A|;Zcz)t+2VvKVI5&B0Eu=RB954nG zzQxYX#S4A`rI9!wdhw`cCO3WP2&W;r-f{)eC%=aSUo4@Z8vTyKJYy4WHi@pd#y3eA z9ohKgy3~M7(YBVU;6%T6<2m8X2iYPB14F2a)~JG^<{5iJ{};`L^InapT{#FGQWcuf z_Jf>>ssesR7=udQzpNFAPV6-%E`0tCS(WXJibj}d@cnj|72A2iV2%iSU<-IJjT?MT zm{^~Q*oF5rK>H@k<#GGB;Q>kTeH2h;5{0dxHEwuUb~O{u;2^E1?-`DHcW@-3v|YpdW>|k$V4@4c6PmJA z!6!ehuFfkE!8jls5qG;f<~M)DHOMxJ<3|;inw`kz!*u95XZ>f(k50}VvGjK`5@j{r zq~#Kj~1`84(?{YB(!Z9ztTH4mEK1`RSSrTCwc^ufX;g8gCLuII~{7tya$HXP?InU>~ zd*z4aNx`jSZ%}BX{8QBJ`JTyB(A$qpCSCl-{NIL!5zLkZP`W(?-zPTAp7%}1pYCjJ zv!R$wPlU;MCb6+_Fv{_K^QDDw)d{=r4Lq&GGAnK4$mfqja3@xJU5!3jKyWakV@4_d zF8e5Fz$kEuF6|{k6Ook=BTep?gCDnRejW$NL!b$=bbNW5ToW6r*HOg){ZBt zWo~V+xlHZ3Bw>y%Oi%$i85VyR<0#ePHwmU}EKVfbf4#%-`o#pZB4F0PNk<-Ffq}hQ zi-&0lic`ZWD9wR940vdnE*9C?y4gq(KxBv9kQ)$t&!gxU=bTEOOm279TsUx+VT9`24Xu=XqSe-Z*dNGv?4It>&4DC36~peTv5n zn2BjRj^Dhvvtio~L*XOpn{lRyjPze~y0;74Y0{&c6H}#I`-Hu~Van_-)Yeney2UA; zW9n}cA`M#9b?BL}-LmP3Xer_`-WtgMT@zs-ZL_hJ*Sa5Yy@l|IwQ^st-sK#hoE&mn z)PKD!ZENEd%i8mx8Vo_e6xK`=o1p0%FqC16aFnR9F0e*M1lGJE|8A7lp5JS?KrV!u_m^!I**_Qmc@#^MR*a~2!zETzw}2qp`t5h z!#z9>8Md>KU6^5sZb~9{z`Lsx>Y|foC6PyTht6A#IRR^!Rgjo8^mU-3qG$227`t(H zYAxO2EFe0r)7JE37LgaqDB9Il1KZDFOyD5Y84={xhH?_0Y9|L_|5vT}kYj zR76!M=J%OTLXH?gdbnE)FcP$hHhQ8I677G0+`uEpqD<0)b8gRoqI}tR`!Tl%dE)_0 zSgXV)YLf1|g=W^jt1eKizBw zXYEDF9kgyMg{%b}&4xUX`7ae5)uXU@G;o-WsqF=uBRt>-O0zMz=MXIc;fLSUo#&H2 zd)khhFYk-$%8~N}o(8?OJq=3Cq?yaN#u5qqA-o9Q1Q5O{zIW?(sjkU=Z@HAQ|5r0a zdeR2Jy5%20h<}g?WX{r+BbN-wkH*S2aM$=Wdu0{+~AuuFZZ^l>`3n#7m84diXnOcAggfG zcHp~f&>-}&ep+bxon{@raBZ@E)tmP0KKR{1=~?naLaS$60Me1uTf!{+vKr|)-F_i2 zMu-a7lEJ?$)#7Y_?(amsb@A?%sEIlY5Jgxg7&P=T3cs(xd6yG?)mY6J-g|VR1wL&5 ztLsGnY~1HUU5%!eA5gH|#hYj7Z;|7ll}W$23Ga{RET(oZp$tYc8J-a&oc&;rE<<3{ zgo0Bu?0(sVq77(sH9br); z8Be~Rxp=7NdwIDCrQ*WX8;)7V-c}R2D`iO{{&TP-JeB}`dp}uk7SDUKM?WiS` zm>apw$G`N=;cE%>i2tVmRK=TUWbQ(*9B2a=4m!ZKPqoskdDw+PIlm6<49SqxJa+E&aVK0nO*p|@n zU3}Jg+PNQsN91^9=fN#_x$4mIwqr13eQ?5!Twg^anXOGpBhQN4FUBzRd~(4K}#f!Ad@z{#uu6#BT}*5j(? zKf*rSLnIFD$sMQ7^hNflRg&{)WD^9NZx!Z@)$exG4P);`snm*_pcFHN3R$jdbGOxc z+TV)eg`rw+s&Y{>z4lM|Zq#!uMt*kRlYPTu($I;XNPk@SSf3fcq-A^b*vJhlLJXrJ zfJ59z%~GBNsP2#N7m1B&ydwqwv=8gGl;*k=moR~@9($hGE!G6Kr~sEPEmh9Yi+1$Nn;Zs4M*DhIw-ETq6K$4ENQZVMqz-ZYFl)Et z*7iJ=QrhDm5GX8ExBRkao=aYuYF@Fa?fJ?KGOoaFNne2O1FP(GF$57Cl6pUish0Qp zKxMw&4y+SwmPjxYy8D;!=HsPuVME7py&QU?ofq@%BeGSB`vENhOdTLa3uIB5J#dr! zP=h>0Y!g8!6|~1BK7Kfqi-$}l#E&-xyroeTfJqeJCTCC&L(IlUP4qyN_{e76xeFom zbAN)c@>rY!3E6#aoy=pSNLr}k?2o=9bhI4@d}D#s)Y0AStVLJD`(uSybct?rM7x89 zMeyP*n$XCmL9K^-`L*ji4^KOLj?PRWZTH;tF?vdP%zS;>%&bZOY@f*A0UXS&O)wJG zPd$+{_Gdl-`E8Q$LqyT-tp1E^Pvp11yXgksU--s`O04O->`&V1lxf!bT5A|+Lt?t_ z$xX7meu~`v_B(%NANv70(C@H<{)0wgT6I(ULB@>WR-VtPb=!|NKKBiiTDpRgst;6$ zEgRnbIr*)b?#piR<{|cnE>ncPB~=|0-iyOtv&L<&k_2)>|Qvpn*eBthPWt$__rHFlmBL5XdHBa8~U zAj|9Jd!(e-we=!a<9djM6cn28TUeYW?3-{%~vWnLg2`>zN~0H$8@7k=sx}>xx2#bvB6I5$+^cH>M`E$#$%to`Ks} znH(;qlt>2$2d(wFHXpK@`K(y*M9)X*`8*bN_CNH;uF^g`Mz!1TcWH5aR9ZD0JH!7#N_K-3wlxFzM8+P-)JxBl1WcV(k1okj=fIZi_|tu}y1 zD9p0DDu4u*NYJjOPNONwjQ1OWKH-7-I32wjK0?FuBvV( zqK?Y*x|6X143qkFdVS!V*o^4xq~%l~-xQ1`T9=ojJZggGyG#nBZ4c!Vc94JupsmSD zcD#SqTqcKP=yQKYE%LZEAWL4=u^xyE!M#7sVd1#_L{@W>%wr9@!n&A6 z&&n{vJJ^hZ18rr{H7J52$7>D637v*4>2Esgypnjq8nRc{A7{Hq7rU@G($zMc=fkDL zYW)&XVHU*$=WC9Nmjj=Sw-9PtKr_q0=e~~6pRxm~S`Y)TUGzyw--qXBO7aPU5Jr#EtKbX(7_gN*-%o1o@eY2CH(}lCClX zxeu%*&zgGvL@w7iDewUU2{J>6|MbxH$ueh?;94LF5U)fuH8HstsFdsFCW0Iqmg_+{ zv6WM}`1R7IZi$|StH$vsR^IpE8pb3#3NFTL85HC6udin&NIn-*M^x3cIo<*k%I%z! z@)@(SfKRyQYIHJy^fZxNI=^ryv)g1#hOKxJ&@7%)S=R9wFBHm{b;)$<3s>)ilPK)? zy(_3IeZxSb`W{b|2I1`8XvDhCEd)P709E^4=JDuNbY^}tS6YyfJn6GmL*rOAQaXOC zg30acpI?{CZY7JgN`nSJ!e1#gX{S1!=xkA{%c z^kYkt#~#c*H=1wnMe-Tfb`9|=w3HTE>5O1UDhr;rnmBHu4D%(P#$A>197{AZZRvya zMj+J9+W6rAtb7U_eZx4!2}$?fG8zuD4qPHn>>$HA>%7-?Jtt2%LLebPBkWu0TG zRY4Sn-N&KIL%h-O5g_(pl-z{1n00e$^c-a4evugm#|Pu~_7+!BNk7_GXSL=Cj#znT z)}Vsc&%3`;c~2fOV>E2l+G%wGCJlXu0co@#)t7oxzgwGEhNyr(=Pe0xFmU5amQGcn z0Jl9zqgDT7C8?0B01Ug^4CccALtArw5}9vas`iw}*% z;CmCOsNk8ENG3`-)Yl&)uoq6B_Kp&0B{PZ+@xvgPCi_sZc{xA+$ujmYCm-gkrqUaW zfj!z=6w2hOtVbjd$!A|{yTh?WX}(xN9x}+-kA#$Lag#Wt+Y0|3Gme4}IEd+rbY+Cc zXP~SpuNeh}24#wr9;g&;T!lo+*<4ucVt0|<_VGm1a5%Q*R~X3HaDI+)2lU;utvjyI z40G(qSd7u_b$+*)R6424FMJp_gVKD&1{m_F1R&?9hP?Wkn;T;Nr|a4uY8oCcmPIG> z6fxQ}s}f{%(zy${s6~#q^>}>Gmjx7r3QNpC%qJ^xqlFWo%^>~hS-k+%L-EM^o=>}K z*FP3BNT*%aq}R zAP7yC60OFPkCn|}l=z1{hmOa|rba22DRIs_;mdj4qCeJcwti*L_I-0_ogosPKY_|y zQfV7nx+e&WQ}&l{s6O<-gU(lU?26hNR|LLkIbE-M7;clt>6h{JQB#oOIOItA;`M(;+f(=4|?L2WaVq#T+4w z-Y$2hOYFwyy@Xw_lRM0276#?VVyog#o$ha6*NFLvq3Yq1-}l>_+bQ;m>13fs%d#I` zA9yCCoTsJvBxbCW?KZiAzT1x|L@S!KV#7eMg?+EpFP2ST3?Be=?O?YpSmfBlQHs)H z$&yAkJRBlDfA1<4h{=2X2cSh+l53#(A%?OXTf5mq<&eCy1-9y))3Q!u6*C|{ z8;bqEp&y`yK7YC>Fohl>cvjI3y>3IBoC~>izg`XueE@FN12{Y&Ya)fPBxMt@;s9#g z?leg@d_jQ>q+ooov`fPIq=b{l@3OZk+8#-hxv|g) zZ(68=pZ5kMW!@K8U-G7fN*C4^=Y()$|FSSM&sviM;7;q<#KK3slRl|dl_VuwJXDlz z;`^h^HZCW+8tSyOX)B?`fB$YLj{Unaq^z~n`=ooW4`-p1-I-~8Mcvma%23;&JF~)S z9La?^iAcfi+3%X8o;LPq)=uJDJp-Sd=>1#b#B{9Q3{jyvN&9zxBkmdkNQ_Kl+bCDy+@yA{CLD6fl2Do30o-Nr59ay_OHb?a-WR+YPR!*rk4CIv$YB|pvnxI>u!j{kt zkv152&w?*@<}HSa?mg(^lgsU_=%ge^$kL)htiz+ALC_bKGFLGAGWlk@XXhIwEOP$H zzuQwW+}53G+q{YUf$s-QwUO5ZFvMME^}_mP?WIGuR)DTzO4$KR$|FMjk^au z7qd*R`+jpYXLfCCS-%iU@}_}cD2L9!mh;Z7@7#dQ5MJ}6`)Zc2c=hgYmA*OR9|8{g z|5?Ct0Y=%FlR7O==00kEkDZqv3l7A5LuhjRhBCF9Y(v5D8{Y$Dc1*>LS7y4cfm>g7 zfwL$wmTu52o=ctYjBTm5 zMJ9@l8$h+==c&S`KLZHkM%h3MwP!AH=h&beLiR%18}*m}ga6vi2Ys4~u4zjbYQPT~ zakSp-ltAyKTBOtbZ(Y}Ge+&`-7SAT!_^~F>2H%y52& zfO%5Oko7Yz3_Hkq#i|-jOn2`mcv2xOC~(aLtgv^&@19=@cvC+fHDFyWf=^U`MR|wg zWWj+8smZJ9M)4%!QNEuk3`Jw}m@d!(l;u)mU6-4%9$r>kWVD7BcGd zD&9PNbs2u_RYc}fSg?H*{aFt?j|Xqis+AI!SZnV^i2|!AlRLPxsTnMz@C|wE`;p#@ zNMF*OM)XZ=fp=KB+72m-(RHuaQgnd54_-1V=jiu2Y0fQiC#wYY88T%066#FY1!HT^Z#fFmACgvZ)Ze;nni55>gvq9GJ&@&{&cEFKkPZF7wom4J z_dY`xD~yeaAn;BVwZd*5&nrQa(@g|rN&`2pJ(o3)fT?`$frh83xXvnrO#tcsLUSy# zXSI)-FK5RD`v_!vwAxaO9T{aNF@|^C@*Ft9NfwQ_iD0G|kGR?x5D*|RagdKGi&@A) zyX}d7%~Du8(bn~GJ;JOk%NirWIb|WHEw*Z|cN@ye@r6FasR03VX$OB|BY^)s^33lO6if%2; z9i&~#1Ae!)QO{&H%@)X8ix7M=0J-+mK><^YK-LS%e(7WOH-dW&?3QBGEUf;_1{x7c zB2Tdedl;?B9b0qDkc7n4AbN)$Qnv03^s5aU3!3^R3-w;Ay~DqS`*kOrN0wX3xsWRA7c=n6m*onL>nws!&SRgMX4F)$e0sA$NTzCB?Z&NJHeTr zjTgzvirhd%!@$SD7DdccM+dKXie*(q)N?08Ra)*%GWcXxj+NIii&F{JS5{*yj+bM- z=YBGqu2$CO4eZYcptC(o10w{;u>V0jOqUm>V8dhMF*{W=!AHTM4uDU#8uCKX@6-y1 zc3vmIc+t*I?*cn0T#LDi&R9vNhJKJ*aJEXvgv1(ALnP8X;@F7WCd==g3EJ>)=vbKG zkTbku`g-pyOlIY*BtxFBb@Wxb*~TunCmG(D=BYd>8da#6;g}rxDb@A8>Tjs`yYXzk zjR;@bSvUfpZ9MZUu{zg%t}}odmY9rll!DuvTG(HW_gTGf&K1SY^flJMAXxX~Hk#IY zv*l2cgGF&%IxeKt!rXK-LL9UIh*|aH?(0`>Yk3;ErhD@h+pmEG$Sj!pO5yP`0gfBpA~!tB#_NWaqxwu#dPc(||%<0E>pvTgE2IDz>7 zZC_p6+_b~==e6rii5>QWf=J#d#8^5~?-nY6NU*CFF z+98gQy|qmDk}8uKS#8tTT7#~SKOF4wZ0x$AdqVeX#Iw4Jj|r_OJ0+w(`o)$ORcHzT zO@9#6_k{rgx^o&41x)j|>2w;?{TM<6I&Z6K$s6%ycYfih<#89Q=Ak8Nccz4BR#AyP z4D@}>{Hd$s@vpsQ(oE`3^VbMsS9Q?L4TPTc5HrGVnL=E>q_KX_htO*b8!>+<1RAV| zz$3`T#FBTz8AJ95w&RA+m4r-?mE63r_e+W_H1Qj@#f#eW+^Q|b_>EUZm*Px^Gsy!5 zdm+{bGN3EkqVl>NfqYX>HLkBF^*^bi5<7OxdKDs_FK2Jd3$d0bwhHybPLMShDVb>w zMO(dD87+4+o2u{!F`%-CNzpZpqziob+XW1NHs>}p3WtXJiV}&pOMkp?1w)pE9EaBz zsd^8j-nm>v$jP0-L59_}0^o}(6-O;0d*O#NW}x%@{b|5A%08uR;{d3(*4KHctCJJT zY4?5r-JdW^QRCWNV5cM#bq$hCyLl57xo<<#Qzxx80VqJ>_o;f~fyH>&%l{C~(_w{s z1oE+2#(C&9=BID0rQ0Cx2Zd;zqj-rLb&j%mlJRPj-T1_lmNjEEy@3I{6El1K-m;Lv z0QpC?sy%6DVpZYYk6R4J#G|WOIks&1X=jCMIyRrk7yvaQ`KNs%$^1q{Op}w0{d&Fa(SFSBhZeIvXWE1tefv{(4g#V?_ z4$$G z<@Z7o?>(+mat!-@+1%hGQYE%A-bR)>M4N@`+XJ>>f3{%Cz3F=vb7LueEV-u}qFubo zo3|M#n#S*v?k~hf>vst~W@yG4s){ti2W7N}D>=4?(pK%lkto`bFv80B*$I>!d0^U$ zBsL~kd2T}H(u?T?TZNL*6HTLA1huBtPtW$@Wd6l6`VP6_SlAVuzY^(mXe(aWS;z+4 zueTFvn%b-)8qUnG=nW6#K7!KHjcogxp;vP&KyaQ+m@dV+fZI{pBAtqj-Rfm7J>Jif z4Kb=>OKZ8KzPrYl#rY(gNS&?J5Xqo1AEgdrD+eWAZtvjA&+kp%IBIsB-9h zV2qR?nCG6S9wh36=kddp?T?j?qA2{IUYoR#hde#KxO*Qb{PR&B`M0rsqP+055W@j7 zm_~vcEm-xf0-ym9n;MD??{%QJLgfq*GTB6?xm*Ka?46=`;lPX(Sai)$n)uvGNyUw& zSPwJQ`E%JygO$3`9sK?>wVPUe_^JAyH>?qJ$=3xayeqmVRwd!@@1HCuCt!1_c4y+( z#1}Yiyt5(isgrZ~d~XU#FY0WS`v;Mz6mbP}cRGk%e;1U2GFv$QVBa%&yC=0$4d0`mv z^wzn)gFWy&+S3Zvakmx5J6E}~=pQdPo;lF^@3@eZu4yhtAiT?&`nX*5rDc8j;??h| zJAfz$xR?zF8tT|ov2V*+^kVMROUfB)B}Vq8pxxaP;?Fu7k`9%dmf`NuNm*IXm6v6~(Z%yYUrgie#GVH67*E9`<8YW{ zs=jNlB~Jk-Vjx03L-wWH|1_5r;)sU=%#tx1ZQ-3>dVK6Gt-6h0_eNLwTnQsog-sZD zXVLgyA*`%9&O1*TZI=Aqg`s5*_QbqXmqdNr^&Ec`odK#1+Ap(fs*A^K99uuqV6+|7 zGfKKG`;I@K=%zTWlIx#qvGzr${0dGKF-4kJd!w)YMbt)_CBqxZe(w?`nVsjxhmyw* zXAg~GsQOwcTF(BC0`jVuBN&URUX5v|z-RxG&(N&ZhwSe1WcU@)*I!90kkkwDGn8s4 zSd(81Bg~28PGR&XPsCNDOb8pnEq6w7n zO05pYH~H&<;=}gwoq0m=U*Y*iMoDBH?&nn0^zmCe*5>Al##9Y&ZaQ`-Q*tI8-IC&x zh;dU`q-T`4z(!CY`i2F8nqj567k~T3uQvw>t@u(}SXL?oY&^Lr|5+>WROs%5*eot+ zM8X;h1swy1COm|KndpASktCJ;&j0=%(FUo^S5ks z$t2F6SBd_KIFPOTW_CXA?hI0!rR`G1LffY>h7-|EA9!l}Ut#(HV!O#L>n#En{vgA! zMd1(pF5vUHqQuNRtHS1>UQ}q0tSH%F07_$NtDpOq`ssbx>ieO<*A0Zmr$KC~ZN6f> zP}tcA+FE+j%ylf&q@VB~s8t`equ_;N_)qA@@KeF>yttn)>p4xYj$dyi1jg`Bd}CXR zC=3-bdZO6q6+cp(r1OIz#vZ~Ph3kD<9cP-ZVK9pg-jHE?m&6F#!s6yv+f)2_i-zu$ z#l&vHky@`K<5scAh<_|8F=SKj(yiDaPJ_5~`XJgXK!wI<*u{?^b-EK#dwb2a^xreg z0;~piKOU9e;0C@I|EFU&E3pwXW?_o|{Plv>^*(|Cvh7q4{T#j~}hx+bQk2>D2d$0)wn&uP5;3G|n9FN&7_*p1w^q>?ce|`mNG_UvzvZCZEmT33-NWup7oVAS6lHK7&5IOGX?E|6kDshHjAo`pI4^RF z>B^Xr&V3r_GcpZ7IP z!Duuz@q3+LQy2D?bCi%4v$jMpOi(wzQJ<@B)DFY6I0oajm(Jl03Fx{FiWajM7ZY5H+CzwrM z&D9}8y8Mjs1&J|H{%d`71=5j~my`EnRe0(*EE%~El-T;2+w{k>g*;(8R63!=42}k) zKnC^8udW-#^xbTrq0sboWTf-65N&D50la=E^taowW#i&@1wDD6qKW&!!`o=B2B!SX zyuc6lrfnxxUv&wzP?U5>{u7n|?ZRiOS5DHNJ5;Dd302>zG)$jFXB(j3d?i$Gjhg~@aFeI$j}umWYF?lycCEauSla-9eP5w3xl=PzZh}e%qEyR z!y|N=vh*z#{^-V4>%MwS(>-eZ@8^A^!ZQ5#fz*X&GpAKEf2t^foJxT6P!N7QSOW?k zCXKI{0*VVM#8HYhE>55I5o=f-|=JvUhTYUFWtf+x}fX?t|xq}1;Q?suxe`+*VW&NbN!P3L$0GmljQ*u4}z zlOZh~IQIBK@$yGqwS&@dP1GH|s}w7Wyh^;*#wOo<0+@jkLuhH-6$M5CaF!k5Zd zQQncl+byfVI*YQWtdHjKUwvk{{AAV|H2N+;M{fjua{N+!izZ}P>U|EiBkWc7eJzyt7=66%Jh#uGkd-xBb7#Z zzBC1S(Ps8)-g-10y@6M_mIITowLc|Y)_d0({nqIB{%K=T&1An?8^9Wb(GvNye(tTt zRNY@>eG9SrHD+yWl;kz`jks_bRId-74}gldU)ZG{AC)YOW_QZ8g{eaE>GPO!=5a^) z;qrtfc#$_UmcBU~5uAJ5{5uK3><4MtTDiIV(zyx9U>Bl7R(mdb7jzl5J`I5TT4*5{z>{4HimjJGWD65y8Z|8N#jt&<(r}fdHvYuX?Tx~Z&18OBGOiQdVu$vt~O+ejfgjOe&9$!2(Jnb4! z3A`L1P99Ljt?j-7aB3^8pSTl0stB;C&oZZ{#po7?uUlIm&RQe1uekp=qn+41&`l?Z zNhODPXwQlTE6l#V#p$CS5a$M}&v(i{`w1xW!%RQP*yhAc0thmKi_6+;!bCSKtHpLm z%zbo}X+m-VL{esqtt@sKkC%L-uloyB~kTT`|eMVd85-w`LkjN@20*eOqINVIO5Z#T>md zTj*1;Xzi}vamz+@t_DW43RC!;HjyMH<4kyYAIzTJcQ(Fk+E86JtdjdbH;2Gy-2dbm z2zu0x6mmRPrdA&{D+?u1Ek8FZa#8U!CKQSSsu!KaoT=|8#&oqx+>EdqAg7hXu27P^ z!!7n~Yo?5N9d2$E{q$Jp`HM3wp6xSZbeR1@tq4Hxl9_uYd-nq%QE?)UFY&S!RL9)6 zZCo!}CW3uwpyLlR(xc%;)2!-?Bv^|GVr=gqv@+WVhrlI3);XkMM6;)VOA@_qC-|3h zUwR*8+)P{b|5V`X9ZWa)DLm))?IOTPCAp4pl+Q0to`7igFNueHQxPuS;uS|AhJ zL{q)1AmTasD2{lv$I6(T0wzQ; zL{erPeijkFWunVkSsktntwUAnx#A$tcpwTIKcD+;v}f+Ym^1!Jy}!BB_D0*3yH`mw zH5Z@KnVo0aSBPfn&G<4K<0!5sQ~y0o#)zDp z*v9fx;X-K0aAw9EACq@zf%scxnH!tYhI`u!9v0LCJE0)tmta^%x;^$6`|Nc!Zwb%zx6*gqKhc4T5=uwkkvD4Mku%L|vV!%DJ(nTejL zU^fK+JG*#2m6-boV+f7Rm02d+fb>%c_od?B?VH?s4w{L;p$~5%uAX=VRbn!tJWSQe zgazbXK6~Gl@@qf}N}}(og)kgA^^NC|7v{funUNi)J<13v5uZMr3jeyb;s=!cl3*$7 zvOGu}Vd9T#EklPDw(|F851fC8j7=bpDrRM)CejZM)8C)<0@it$gRy%r4(2$#FDy-6 z3(RD=Wq<*b=J}s$;=%;ldy38RFU8Q!JlYDElS{(VvJ-V0aWV_A>N+3n zLF1qSOcB3egnSA|Q{NZcAmGSOeDZ3=!H_%}1%KIt5;*&W(Wj=NF|-|8!Q;%?C_?M~ zJpkT=wLCV)=rT}TEFq3n-H*n=40B7}Gb0Wf7zk(%%1B|W`0;~xSV>Wl^8jN!q>-bmFUD}p{Q-eVVITb>d>ay z(P=IJMAAllHj7(N6EJi~O^4r16BQl5#{7Eq+RUGnO(v3$jJ&;_F-oH#YDUY82$v`t zGX^nP03ZWZC6Swo^$kh2|M(=>yZSqDtv0mm##Pc;5Rs!4Rl(l2A-$dIC)QFOtqUKI7*_g z<7p#t2H(@=NITytdraULT#dwx47_X7_gKYwiyPt4e()J6a=H9|W%17T;db9}Glpx5 zHyiQ9B6PLtkzcw#&#@MO&`^wD_|tsDv2U%hS{C6rJFKjQ9oiHQcU}j0aLMdoJP&-m zB>Z3KJwog)dLVDoYf7Lo0|N^aui@?a{?y5s83u`fwC#a!G#4wlGJ zu}65Z87DR+7jrT^WyVcIS2wt(ZGPEN#KHFg$KLM=&HU?R$;bA<;va!WoVuKq4QL#I zzFnFbr@9CR^@YY$kYzhgs=6Ct7lhEZ=iFVZ*%({+@wXph1X?1#DNH*@ihQ)HM)OE>J_H(mfaZaH>#cQbSN&Q!mjN8!z89y_?%lP~|mB5%(a7^5B# z4J&d^a{L*AZhusw_z_3goUew#FwiHjpS?-v@6};0T?Dwzwz{F<2oe28q-1l1Q+NF~AVi+7WAS>Q!I? z+KJydPyt2MrV(>W^u`@_(lEqOiOqenTjYOk(dYjR%4^pPFbjzlQr`ha&6!!NUGa~6 z_q$sDE{Q8~sBs*rs)(QOUu?{DcsQtibGbd+ZH$?3fU0u~*6VpVS;!>&MGg*U{hEis zFIeWLdjjY>QI7GQshCk2gU-9Z zQ>|`i+@7jhaa7Zv1?GM#yAk{-kNhjEMUWl4BN0b$&mvgVNxC%)sEkc!WzQ!;j4ge` zukt>wJArC78ogu@+4cNgfVAmGR}e>xa50y^wtclENkF4MeS8YM8sF%knuBoo4 z>gk9#)9Dr;?cew1-VeE~tPg1{w><~>7M;E+(QKKlucj=vS5u3tgjKxsCFeFYjuH+z z=#9f3P-0^zRFVCv%RSI}l=5xNuZzX5vGxG1J49o$T}m12m;E7<5KpdMLBJMeK_Swq zB7@9D7+w8pEe&f9S?>;m@V?ztbZp@4oVAY9;<#p1Ck{;y)?rP3Etq4feu+|D%u}Xc z?oIz#lP&3@$4pwcHO(iRv$c-Or&&QQ>YOnv(-`bAh*1=sJ^m0+8o7iS1xF368g;!j z2)5{SB?txbU4gh*i%z2i@XC)He?03?#!=(~>#m@7l@2>wA|x?RT{*|?kq$Ro&oAgg z*I!zgSOy#f{n3bn0hnPt(*GZ5dSG%C2fcuf9wLCU1nh2zJ-faPlv)W;)4*88QN z;2qIl&!S5Pok=ESS7OW}a#ejJxyS{W@Fb_IL7%lmV&^bX*X-GD3$lx%b-MlU@7+O# ze5r1aH#}P5qjwn)563#Ec$)IO;d4LZ;7-l26HBMTM@vB%&{6Ux{G!osaY#VdqH8r2^v; zaPiiTfn~{6uuMko`IY&62r`zcNn}sP5bL5Oe7o|f1kMo48c$wY)tZx@A1(!a{&Jc) z9}rK{*eB6OflI+3q?pWKWX*;!_r(i{_3^F%IdO)!8D4|~b6*}GqLSw9vkroB=vf?p zF{nKJ&~NpGa9^_7^i98WG?FqeHGHU-(ECR+l54Z_i}%_?@seH#apy7G9IsZ;lO)o#%tn zxiH7!e~Vim5H}VHIgMeI><048Tg$-a$#|v@{?bQoh~+J}Z<-nQ=6)`6%R=bk#l!qR z!V%Pxpq0?I639b8>3<*5`ITCj&q;&o#N&RZgVN_n<|m8dL9p~O$4#z%gvgvO+FeK} zKDwgnv|%DG(C52F^TlJ&^?9A4DiuWZb0D1WzC7c_OP2H0%`SC)BVcn95bxXbUGp=3 zA649&)b9BW-vF&-aTFu;iQt-jlBO*57?NMVAYHvt6k~o#>0Li&Xy+-lL-(`}1rvg> zxTQj#rNF?$^qLCT^74i1tDL%IVumVTOXY3Z};e<(&BKca*c8rkw!8_ zzuIlZX>2qdw{myR&4;Mgw{FD;&AN6XT25$5FYi3krQ+5E%3xo)D0M<#6=$3@q2Fw$CRwotGnY<#2zM! zbdL@4B}&>b)jiwk1f@^B`}8612>1&N_ttxFodvX7uC% z6iC(I2h*nnW@1oQ9>ktKrb$~y)C=Vu0@d`30w+?GEPU_h6ZAd(Cf*58gw|ahcc3q` zJI&62kWTnRyn}K4+hDWXp0M@nq{`#~>2Y+5${A;z`dpHlT|1@0!LNK}Epl%^dk9+U z+Y1^skgs7XV`e%@M`H#1NhV7|eX;ulZji^`RLLH@Uw=iNHU3Eba*Km(C?R;V*}K5F z3qmdcjtsZUQ24As&Q|rvwtGZVl5%l&KxKF1P*LBE<~Mm!PdjU0pSZ; zJ)3JQTvd9&&hKZ;z$I3N7;zvsyx;6N()JADAmGzpLT-?o#l5*HOY0c;YpJGpXBgH3 z_1i`qMd7oO-4&b!eSaXSv$w>u^z6uO!mbNPBMI*=R~C!ac|@>8lIYV~!`1TL$!JGJ zqQ_z5z;Jb@j%kVP^lWRmVrzg%sy50~-{p|gzogfL`Veq! z+dETiSv|0_Im5DnGcB~=B91M)9nV0}#LS#$4cshQmnxm=_x3DV!?Zf`(gcnuQ-?|x z)UogqDJvEYdeR0PbEK@rz3+&p4cR%E#;3L?ti0d-;hlt$iv9lN;B<9CuAs0-8q&2m z?qvyAZCuHYi^Q`Y1#Fek*Jv}~-UM$95+uE76DlIBkAd})91@=xHcov&?d0M~Wm)e` zH-EP5q?vWB3ZUQqx?atf1ak(cje003^x9p`yT%7)cJ-13XL|D`XBV;P-RwyF7j7Fo za{~Ke<7g<)P@ug+!ZYnA=1nXdT$YiKu%hn?Wu18>S!Wp^Hf z^0CPiY>FYZ0M8$;IpJ%n<_)2KglqW6U!s#(Ez<201swkb3mnG9YgU_K{w`8{UG?Bt-=6lX;F zdH{LJFwcjnZ48H*C|r5yJUt_MS(UEy(vps4$kJ@5=pX&0(mmsp!Lkp(qgk60xkhd9k<#@JMjy|1L};@ zCVE`AD2s4ZkOVc2_>Dx0h%W*AZUx3{Hmp)+Ve=**PzL1_n5^yg5!a%=TD5kV<%kkU zJ-^(Hr5%gBp$X%MU-5eS+6Q68SphQnh+X!sCx+JVj_)!su?9MCLFqu%EJB8|EhTuF z)a$xdZ9m+JDMH{D|98bRI~^167@kwEQ!K2vrTd^7St4-}NMR53lStW};!YH3tI=T7Cr4LD-K*7v+b z70?p0;x!~|XJBmm>Cl*&-M%`1DtCV~QLb5A(ut9tVZzv5k}ap8uNvy=#`b#o6UQiM z(^=_YP+{O%OLONA<)&P6pz`6Q0r1^K#6skwQV!YoGZWlPTM4kK)sCG}19S4fz?phx z;p}QumsYs+F+Dvsl}Rc9Y_K2nNcp;U+pOvs^IChQZJf=X_4lDklblBVK3HWut*m{{6JNl~CPJ!39O~ z#RQamS${xJ_TSk=yl3Mf=5$#hf$htu(GIF{u~~`F=WnV^36S4Wl=2~gwkWB{WLSJt zWFYZ~JjJw>xb(r1q~>A*pNKKpaN~v|n zLVFFDF!!ZEA(6oY#bsQG<;+M1Y{VHDoZ242A;@DfHx}cv7V)gN3fdqn5*v04IOQd# z#xeDegNeFpmXsuq5;1+B@5!4|F1XHD{6Xo~Qr07IK~wlFnZjti*Q>1p#AD2d3f}gF zj-xUk^xLa0dac7Qta~HLp_fTC3xZ`5vT2^(S|({{1dkr=Cp|SyEj4z!h$BkUq?Qh6 zGQLw+D<0O)znLWJ4=)QYW%u-h9>4uC*_w}biYnYYQ1sgo3Wze&8m1u@o9u1&nCACUP!*vP zJEssRZ1W?2L)a%e%@4u+Wr8Gbs5?HS%gO%f;@r|=848owsz2AzGRqo+aWkX_Z+5wJ zjg2=VaHg(J^x#``bUGY0i3x`jpn(T8Z)CzPTsG^0${oaruVqa9`({BRT8N4=;66?9 zfgzcSe@Ei?vI=PYVh{KMU{=HGUmn+KPFsC zo$~4?T9zSElvmZ3L0Bn4UA2m0Q(Bv0jogbxqVsLc`^2QE0WCel!D)|^^IUn>y9x8j z7gL6-1)^q@eTC?%+2Nm^#W*obH0z&B#$8;y55Ku@E+8!4%ZsFm7ziC!##ZeY>OG-6 z$;2Qf=OLGJL2AfOoo8@lg`_#X2{q~I7J{RDe+j^i+Ir7z4M7gB5TnFKQlR!7D`%qR z=NIn>jKV@GB_q_@C1>ePY7?*+vU=iCr9Hwyw}&;fO7Ht&Q2Z8c{C-iMynOr6O6Gt} z324RRP7SMXeh)@v=YfO3x~5M^qJ!e9+;?`xzQ=lK8VE3;prrx% z9M2>_GX6FS4JPB1gCEEF>6$RIsq#Pey^4>yjzOUi$$GP|tyCV98Y>lz<)r3E5!MY9 za-B{BysE&KS4T(t-c-aPxG8k=s|iVTuwk>^w%=^C{2R~vU7~ZsWdyyHgdlYKRl{nv zzEif?(Na#^-8c6Y)gb+0T8WykM;v?Rgp!L2bt#)DAVXtJ5_02bzmB7*H>JawWkG&0 z%J*j*lw*bESvW!4l)f}n6j*`?>TK#yEE$n0ZM5se224*mBp^|f}AZE4xKs1w1I+F=tE7y0;MmIUd+VQ zaPCmGlw_J3uA(S77y98T7N|4c`9t^aJ^ed2yY1BS4~f^&XSjC579^v`&^cOWhFpUH zUi-v{**50egM-(qDj#)5#z9=5gzkUxx+!r_Ypfb#;Nm&gjiXbh8cDD)-mPQi?lk1) z{u2|P40IzH4#O_*;v2r+?ULhKBbMBycxOZrpmVEd^b>WXZcr#zbW z9$U5>>Y9p+-=(>>?m2p1q#dgcrQK>`GZG3x5;KTv+e>vS=NUar{oIT%7i_u#Tz>o< z{%DT(u{*$1Dp7FeRojMqINUo9onLv_vVGQ%eLGyKl9TyE(s8%92vIf-Q;2ng$O)3j zE2k>^35}jFZX1?8ai`JvBOG45v|g1utjb%fX zdWjiU*%S(K3!fL7+fZXF)qs_pcUUTLdu@bqKd7EDE)8)nt=3oBN1vq9AF;g_dYPr( z){(;;e!+dd(V!(^Rn~g+d>tX*OL^1lgOmO>MdPuGsnAGi{92dRU#p!OS;JR!q00pV)6+v-+A!Z z<}w?V8mpLgAU!-O>Rs7{s>O;7c&K9#+EcWDT@}S#KMa?T~ALzDdOUOVk(G(4C;ENEesL}xvy+)z19^jsbK&Kym+YkAr&?^ zwf(%*K7iCY(9LOh0dVRvobQfVyBQzN@`##uac!=tKQyihy@H%ZA#|aa{u;S>MdCb| zL)_wUlBYz>wc_r0RpZsv9!A{cGHLFZzgno0--z_6Cx|Wp%On!AN^Hekd8<_IhiZW% zU^S3KQg;8V4!V!=eC7J8yg}FbR}}7kdV~M$O&7B#LFJ0;eyNA=*0hir=KW8wVa zt?$AoODZT_a*Aw zC~^^}&2Wj|Q6XJnvuWtDEbf9hAz_3rv#e zuzJhW;J8B}(K$u&r-Hf+^_I&0LsRz}X19@TM8=aen5)goS2R1)%iCU$3il*_^F^Mk zpB)i*wDFE^p@h47dORx^`~0J6kZYx*(HB?YCgDy(we#_x$f2`mzDV4S89D%jzbvDU z1r`*Te&!v7Y2LKz!<^vnuBjfenx#YHe4C*+2}~o7g!XJX!Hw+7-I1E7rkyWi(GDlJ zz@qeatLM$im}g)M>@{;|=o~?Q#;^QL{Y(4dct+i;emlaE`*rhe6M;RSUbHCTP&0DF zo%^$=GI7ZG^!Bgt#m%wMjZledQ`fWzo3N9rsZU_C=it#8q)lyD;s&)s^U#vpmAFm6 ziegijka^N;k|UqNr38&qZ7dJH%Qi!1A$19)q0QmZ2IpECVo732=BN9jWg&h49?|Lx zg4KAYr0wuIk1uyyGb1j?tv@=^Q)=$u3^HsE?s8n3dmHv2X_nY+8C=-o-8bhSCcfX6 z=(<#ir?beJZe8I!`6H5qY8iP7C6<3^E$|G%ZQXEmd3il`cVkfc%w|C;XK4X>+3sw+ zWj)|itz-Ue59Xrh2=U{b0a4S7tCf`{_W|9p>T^*czVo%)AB#$lT5{6Fsk)zfW9Tzzt(Rx+#TQCGaOM}p$IRBuqJ?wD(5WW7|Jw@*LwZg z1z?<+fw&voxH3NnCgU^Bd&IUF7n<|VTV}1(^bb3ZWjnDQscBMGt8L#mFHng2stv$j z));Is>chM)wHoFO%zJ{NN&GHlBTlF2#TVj9Q~12%j=u&kbhyJil{ptIbbqfmTDE6M z>0mdF9_rtn{Jt0hrj|myh)J7sSB7m&h8D3=Dg@ zi%;ZtYkw{zlC&59wng^bkA|#G1&X)-&u{zu=c0r{(Efe+3nF&<7dXW=-I5pB|33V? zbKd{g`TrC9|GC1Ap8A*`&e!<4`1~)O&8&pemV+r|2z9(oJ}*cCxQ;%wxHrVinwOlZ zHU6v1=h)8~$)Om0STxJ)xQu#>D)sw3|7mTqOy&ao$OV=SB!))OW}Vzp<3AM_3=^q) zm9GD=$87^}5(|bkglqiIQpxOtYkUh+fJLR{V}bc8{Lx*Et_b#>7Y*FFp|FoL#Tw<* z6n!&COf8$=(QqD5B0Oi;s)YVq96U3OKBl*!1V=Nij~Vao6?u)D`C(rk_!(z>Ai$#B zwK@;`cj)-uHkbk{Hxb2)*^)iG1@r($=bvQCbN>Al~KZW<_p4ltFfPMRDv-pk@O4y@L74mnW0f1c@_MmHv zaYQJ({X4X`y{a1>?;vzmY+byv`yD!u{ z{&w>X=*IljukJ$$pL}~OweNo>PQ)Hj2DZ7F0JQ6pS@g%ugGaG}Zr-*n)~Ct9IKoTi z{=PXa8t|5>cgjG!XsQ=~yGa%k@yVx4B&v%kfg7fB#bm z7+&u6ZnCB4uU~^{L>~NBJMUe_B=NqL%>4+Vf;J|!UNZfWO(Z%nXgbe+IhkDSjJfra zy~5Y&gF4whe=WXtBp{_=mG2-BU6*MsPq8bYQolere^p`B2N1S$YIIzr44qI_m)4Yu z4-I=l0oh-%;Zl;d#jMAc_)5r~Bry&brGo^L8YJKWZN&cabH2uM3BaneDRw9FBR<&v zxOio!DtLzhGC@T(u#PN=P0wpAB1Z z?0FYjOOjDM2N-pxLLbk!|!EV zM9k+Dz2@q=(g^qMZOX65+nLt*H_+2Q8vc7iLZuWsm2dSwu9g=L8~4lBH1e(x4dBq% z@x>3wT!TNBQbUhgpFFRArPwwaMF>s<7_Nz=$l|$C^#K#Rx)WjWs*~Q!z198Z zbmvVBn$7vnSh!gxgD_km?)@&nCg)!bBkdTncRQ%;Sp-<0mDOPtLpolqY;cp*DORA; z53xJq#YpKZ4@WL#KYr-?(0FF6pJ@5ez^ki^f%C2haZS}mDBHwoq;gGi!nhnZy2Fa= zRW^zuDs4fJB`9c`fG*dW>Wvncx9pL4-P=n`*8{weO)t=Rep)x5bO+t7r6#f(`MX`t znG%Z=2Ch+r^JK4|QB=NXwBmj4vf@$a29VV^VGA&7oP@ral=BHdoCk=W@raYa0yX?V z<9@pT`!G5p;bnVf0rqn|DsFY<6M*uj`)wK@r?wM-xgFKa=!GoH!&Jq}Z}#nQMyA|> zQvOAN7I9Z*w1m>I%3`XBR_-UxBaqWT5jA-~Zy6B=wmTc*mX2z65Z4ZyccG76kn`CF zCNV@AZWY|7ayK_-1UFKmRkf7nvaIH+BXQWT83& z+_{lZGK_=xzxQsPS)cHSj9W_ z;Q+k{ZKI0K!?jCbI#9DCC}(5rkM_JS6%$jt+DxhX(Vxf$|E4Hb*`M>%7o4YFi*8 zof6lc{w@pV!n#U$8eb)&Y?*Ag5X&C!QyS)O6R;9W= z?&Yxr4v3tqpIs+-XzY;|sf2iK52b9Axb9@_m{CG4Tr46m1%w~_6p3lxvWH?kb?M(E zm>l$TYQyZFkWy;Y`X&`lpC?YgL+D_^N2-W_okR^a)5!q%wP}+jzTy+64S6Gw?9|R0 zhS=Hf3W~D=ZVJ;|k2+?vFEZ(y%uMbUbN*!VitF^qK=!!xGVmxCV)VlLW?0m|O21&hNHnX|crLtAb}& ze@ZGv8}CZP(uqA;JPe%?y|L0X1Hj z(f9fxzAev-$PZ>Txqwx&jq4@(UHp83F5we`MpTKzO=xbzEK=Qml;6pBy{nROt6E6W zyq)d_{?+r^Q6Zmp%yC3;`*D>%(k%4Jy$(H{nT7>$)XeCryg`NO*BPS*dMV8o8d1IFd9e-ZpUr8S%IIJ&mydkKoQ|ee_1R z2?ra52NyL9(}0hmT*o_xgNVyvlEA(L1>17da?XE)GFBlcOmj_+=^$48S==N{A(e*} z^a}D_n%GHImh3%K7*&sAkA(O;Y;RfwViI-qjDjyrkMM!$S>J z;ZWBXLN5we09LvHOu?X)r!F}3h0!$?A&rja0LCZ^Fd-!R;H%MB_;vy#(kzUi?Mgpl zuuu*PTo96NKUooiDHbE5e5Zn$!h`=ae^MUw_P|%Ig|ac!ahhZ$nBpdZvi|9XFTk-Y zUkO^teMx!-ZV0raSJ&LaQ&uR!xDCqONwTP#!ax+hpn zyR0QvDah~9*aIsy%c~)C?RuzHg6F2xS3Sb(ga{8#g4!IJl_{{@!%paoWDJ8npWsPzV6|ReX?4cWFJe9)%6hUh;t07HKk;l#q7; z!%HZYUw4qo9n4GU0?bgXc!c=EHO-h%Kt-AP}OU>(;ImtV&fw%|5| zAQMiDMv`mqLU@Eva?uU|Fy?_Kv)i$&kBcGL6Qw$affdXa5Y zQ8YOYOe5Bqc&L%?7Hk$?H2Sx6?L~>zMxT)PKQJQDQ#@)HdUe#Iw*{MV4Yaq$c1e6M8n;NcA- zUa(V2VEbEFROBcI|D3HonRy@D6>z=2??A!D=gyEGfc+|+=L0>>Yc`q21(toSbgV~Y zN7Z&T))rg(6}=$!N+G38_FQTmjo5$#!zmL;ST)vDcis55lX96gb6K9sg@Pp^HTFW^h(W z_+x0XYMFYaoo0Z}O9z}mU?#vpcXAjGGzed_@;NBXM=mXi@xtg(Q+3m@v@%2O>gn|K z7#BJRWNu$e8Ma4qflmPP@=&fqu67mXj9gd$0sJB`H$673`v?wQ8aw%^9pYGR%{!{} z2;+5Xh39BQ=5TCc4It$5Y5E4oW56{dN|Qb@DwKd}LVR2Sf9iA4lz25Y>YVBXIop8& zFQ3G-x3RuA_9ttZP-6zd-cy(WGCX&Ozl3HG2ZlYJX&A1+&^bj90h`d(q9Z@zg~RLd zmg4T##fq5MObnrkCTsfrC|>fxFp*p?%QNEP`FXBV>tcDPAI%;9!i~2G#6orb0qN=^ ztWC!_S*=ekP4ZRW*E|04U22HVQmNh);WP2KmKl|>8kP0O^yX;mn8Gktv(z#8kn4-) zyMyS&LLvN|TG5zW_eH0x}q>&ipD;jACw-hchSx_9k!2XVALawww zDn8fRvv8EcMB}!eemU2g0)hs#wGx(7!NB#-t{29dX*;TY6i7q;$nbJJshCnN?T69J z6ZWItA2*L+_#qA^V=+*;Z=g0KV$e22+NbCwS~0kE;Cz!jwW3{&Bx`Y!m$<)9U<(F2 z?0Q$@?|ir^BOMhqd;M0Zf=<>LM8K%mkt@%l8e!b#l3dy_j){oZSk})lRZxVdQf8FH zya;T>Vm}%XMf!Qssr-+=h$E$MO3V3%;S*C~5{9%y^1SwHbWL6*rvtHmiAoV4x6zQI zc(;wmwTy@k;tJAykH=2PpZ?Tgr?F@;_fo07a$?tRE7`=rsE02Q&i^%rEFw!;^XEL) zJOQxkrbk5@>WlBX>h84keS;Av?ie=YUqkR2?z-_=oG!v{kBqKx3%6o(rvN@L2-G%W8BrJc(E*v%R zWex?7%m6kn9U3O#ZA3Xa@0v!!t&P~%Fv1U3O5)(q+57QtyV}=8P78YT*LC=|VpU4^ zg38xMPYi@uaZge|Nw@}n0uN*E;cwGL<=HuF-_-9&m>fIPOLS0via37 zIvVJK5DUlYrZ3s^?`%XW<+)jv9@N%GO0OJjWuz29v|DfyP7suGRurW$&S>6DM^hT6lyLh#Ge2D9iblYRw6NQZWumfu!Idn0Xq@q<3_ zq~f%iV*B`Zs{5x$J2aG(uo&<%9ayF1YV>ctOw;74iXPd5LkA9#(-g=O(#F59T0v|b zx>l$%xry52P==}Q>Dw?7{-QA1(s!r|{BBqsW8PY42LB*W1q8-?q{;=N&JvHs_uS1)BHL{-1C$gxShV25B3FAh*Ky|&zn zsV=`}yC&noB$Cbc=|z1GF2s^XA!mzjLB8sUB*}&oUuDG#Gs@Ee|05A7;~HR0`?7$D zm}$VkH==LLz%23@MpgB5C$aMS5JPiXp{?T)!%CnVPDwhgkiV~=GSCR(3kkHZO5y$f zdaR?8jO_+>^~Er`e-%#v#`1|Y&FEOi*OXKHwU6D$2$hmdsLgXs0=_~=E))yMT(oazBu z%O2}l_X(i4>crbuCKZb55LcyO^4S?IWG*+UIjuZwa?R6Q>?3U1^z&`6EVib9NJk^m zw`VZ1`|8JP@*1A8BL~x764nSulW>gZ8jHK?3?#t z+g@{5oA1cOF}yX$ZNH%5wUI7c2A@UKCL;;gp9<;(b+-k7$9D*qhVMrr*@Ma09g`Jf zZLL#er%^it9(JvzKk1wz1w6X!Jt7gDS+tiq9?TZ{s7zC({b0Fpwy?%UQq7MqRI~DK znm4j`1l%GAgp!^9hLWe3v>$voBF;1tyqb!w`l*+`^Bnv1WMWd0-@m1>UiUdRYi_W} zYYXD0<~Y?ch|*NpHkZm#to9|sOrEVg2I3Qx)?h{*$&@jBdt*scc^WI(kgQb$eBjg; zLYj1PNw|T~?%<70D5e|7H_iFdGs`tB9L+Z25JPf8Oxw6+vI?JU`Qp*tCDY*u&lTH>>#JU<)~yNX5Ci3ztN3did!|9P2R~}G77dXKyEOL zlY-8^w5%qblg@!dZ?&~a4f@&9dS7;PxQ;web3gDo5%Q?a{6~C_dMv4-5v-Sr)d2|f z0pQu`8B0?jZl0F3X(2o9vwgEYEtpxxPi}|P5l7cfbr{T}CroJih%I$_1e|F%ui97w>A_lItzV3JR5CMgoTO4+QUuK zokd4{Gqk&9e49tf3+~xt>7>R%%)1x^@Nkga2y(F{gRDv=tho$FfUj~FNt z3SbE+GRs18uuR)&*sy*Yq>A(^*2$Js0 zCsX#x6y3p~BIge1MN*2+i4fxBB+cUwk4_~Rh%ki0D}9A-M67|}6cxFU(xu&&=3+TWp!84#gd^Kcy&K=nZ4=tY{#ruJLJ<$co~!gx%O`(Iu)551 z&6=XIh&5ZNnN(F{fB()MfWZ3_TKT5bee$uQ<8?%QeHZZ^K0-%eI8h+5Pz`l$?WXr- zrkvI(V?gRQ+#<;)8?gmC0JF!OVUYnKnxWz27U@PX<7j}ML>`fMYtJeBQF z6>F%V)dm9iA6>SFlfvI;w6M$?R~rB->&5vRFCxjiy{&{sa&iAp9y)^G1d!56HY|t> z{^DlDzd_c=hko0J%gamUxSj~%IpT^Z&%6;=6=FcNdr))hzwlPNY^L?a-jo+|9fx-t zkX6%)U|6%kk7dI#s|#M|32>D@Tvl{v*)3tqFL~%FGrCZbDIh=b1CB= zAa0Z$i9;9m<)-M^bA(a5y8gupv&YGq&1P>Das00M41h~Dn&fi+oluF)4{(agu?QNp z<0=nGbZshv?AGLeTRB67gseV0L*-uFq!vC?pjqEMKM-`bt?Rg4XaG(pu4|{pxd_36-t?5&#@T0rkhTQKtIu&K{tXD(HgN^nYXq z1oxUKE#J`xmMIJrsCAS#;`Uq> WmhW^Zxv5G>U+9Np~YHDBX>el$7ARIrn{@ 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%0D^YOtmoFw&Y}RceTb;(piO>3g>6 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 diff --git a/package.json b/package.json index 7dad465..3c7029f 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,18 @@ "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", "scripts": { - "test": "mocha" + "test": "standard && mocha" }, "bin": { - "compose": "./bin/compose" + "compose": "./bin/compose.js", + "deploy": "./bin/deploy.js" }, "files": [ "bin/", "composer.js", + "conductor.js", "docs/*.md", - "samples/", - "test/" + "samples/" ], "repository": { "type": "git", @@ -26,17 +27,19 @@ "functions", "serverless", "composer", - "bluemix", "openwhisk" ], "dependencies": { "minimist": "^1.2.0", "openwhisk": "^3.11.0", + "openwhisk-fqn": "^0.0.2", "semver": "^5.3.0", - "uglify-es": "^3.3.9" + "terser": "^3.8.2" }, "devDependencies": { - "mocha": "^5.2.0" + "mocha": "^5.2.0", + "pre-commit": "^1.2.2", + "standard": "^12.0.1" }, "author": { "name": "Olivier Tardieu", diff --git a/samples/demo-conductor.js b/samples/demo-conductor.js deleted file mode 100644 index 6b6df45..0000000 --- a/samples/demo-conductor.js +++ /dev/null @@ -1,105 +0,0 @@ -// generated by composer v0.4.0 - -const composition = { - "type": "if", - "test": { - "type": "action", - "name": "/_/authenticate" - }, - "consequent": { - "type": "action", - "name": "/_/success" - }, - "alternate": { - "type": "action", - "name": "/_/failure" - } -} - -// do not edit below this point - -const main=function({Compiler:e}){const t=new e;function n(e,t){return e.slice(-1)[0].next=1,e.push(...t),e}function s(e){ -return 0===e.length?[{type:"empty"}]:e.map(r).reduce(n)}function r(e){const t=e.path;switch(e.type){case"sequence":return n([{ -type:"pass",path:t}],s(e.components));case"action":return[{type:"action",name:e.name,path:t}];case"function":return[{ -type:"function",exec:e.function.exec,path:t}];case"finally":var o=r(e.body);const u=r(e.finalizer);return(c=[[{type:"try", -path:t}],o,[{type:"exit"}],u].reduce(n))[0].catch=c.length-u.length,c;case"let":o=s(e.components);return[[{type:"let", -let:e.declarations,path:t}],o,[{type:"exit"}]].reduce(n);case"mask":return[[{type:"let",let:null,path:t}],o=s(e.components),[{ -type:"exit"}]].reduce(n);case"try":o=r(e.body);const p=n(r(e.handler),[{type:"pass"}]);return(c=[[{type:"try",path:t}],o,[{ -type:"exit"}]].reduce(n))[0].catch=c.length,c.slice(-1)[0].next=p.length,c.push(...p),c;case"if_nosave": -var a=r(e.consequent),i=n(r(e.alternate),[{type:"pass"}]),c=[[{type:"pass",path:t}],r(e.test),[{type:"choice",then:1, -else:a.length+1}]].reduce(n);return a.slice(-1)[0].next=i.length,c.push(...a),c.push(...i),c;case"while_nosave":a=r(e.body), -i=[{type:"pass"}],c=[[{type:"pass",path:t}],r(e.test),[{type:"choice",then:1,else:a.length+1}]].reduce(n) -;return a.slice(-1)[0].next=1-c.length-a.length,c.push(...a),c.push(...i),c;case"dowhile_nosave":var l=r(e.test);(c=[[{ -type:"pass",path:t}],r(e.body),l,[{type:"choice",then:1,else:2}]].reduce(n)).slice(-1)[0].then=1-c.length,c.slice(-1)[0].else=1 -;i=[{type:"pass"}];return c.push(...i),c}}this.require=require -;const o=r(t.lower(t.label(t.deserialize(composition)))),a=e=>"object"==typeof e&&null!==e&&!Array.isArray(e),i=e=>Promise.reject({ -code:400,error:e}),c=e=>Promise.reject((e=>({code:"number"==typeof e.code&&e.code||500, -error:"string"==typeof e.error&&e.error||e.message||"string"==typeof e&&e||"An internal error occurred"}))(e)) -;return e=>Promise.resolve().then(()=>(function(e){let t=0,n=[];if(void 0!==e.$resume){ -if(!a(e.$resume))return i("The type of optional $resume parameter must be object");if(t=e.$resume.state,n=e.$resume.stack, -void 0!==t&&"number"!=typeof t)return i("The type of optional $resume.state parameter must be number") -;if(!Array.isArray(n))return i("The type of $resume.stack must be an array");delete e.$resume,s()}function s(){if(a(e)||(e={ -value:e}),void 0!==e.error)for(e={error:e.error},t=void 0;n.length>0&&"number"!=typeof(t=n.shift().catch););}function r(t){ -const s=[];let r=0;for(let e of n)null===e.let?r++:void 0!==e.let&&(0===r?s.push(e):r--);function o(e,t){ -const n=s.find(t=>void 0!==t.let&&void 0!==t.let[e]);void 0!==n&&(n.let[e]=JSON.parse(JSON.stringify(t)))} -const a=s.reduceRight((e,t)=>"object"==typeof t.let?Object.assign(e,t.let):e,{});let i="(function(){try{" -;for(const e in a)i+=`var ${e}=arguments[1]['${e}'];`;i+=`return eval((${t}))(arguments[0])}finally{` -;for(const e in a)i+=`arguments[1]['${e}']=${e};`;i+="}})";try{return(0,eval)(i)(e,a)}finally{for(const e in a)o(e,a[e])}} -for(;;){if(void 0===t)return console.log("Entering final state"),console.log(JSON.stringify(e)),e.error?e:{params:e} -;const a=o[t];void 0!==a.path&&console.log(`Entering composition${a.path}`);const i=t;switch(t=void 0===a.next?void 0:i+a.next, -a.type){case"choice":t=i+(e.value?a.then:a.else);break;case"try":n.unshift({catch:i+a.catch});break;case"let":n.unshift({ -let:JSON.parse(JSON.stringify(a.let))});break;case"exit": -if(0===n.length)return c(`State ${i} attempted to pop from an empty stack`);n.shift();break;case"action":return{action:a.name, -params:e,state:{$resume:{state:t,stack:n}}};case"function":let o;try{o=r(a.exec.code)}catch(e){console.error(e),o={ -error:`An exception was caught at state ${i} (see log for details)`}}"function"==typeof o&&(o={ -error:`State ${i} evaluated to a function`}),e=JSON.parse(JSON.stringify(void 0===o?e:o)),s();break;case"empty":s();break -;case"pass":break;default:return c(`State ${i} has an unknown type`)}}})(e)).catch(c)}(function(){ -const e=require("util"),t=require("semver"),n={empty:{since:"0.4.0"},seq:{components:!0,since:"0.4.0"},sequence:{components:!0, -since:"0.4.0"},if:{args:[{_:"test"},{_:"consequent"},{_:"alternate",optional:!0}],since:"0.4.0"},if_nosave:{args:[{_:"test"},{ -_:"consequent"},{_:"alternate",optional:!0}],since:"0.4.0"},while:{args:[{_:"test"},{_:"body"}],since:"0.4.0"},while_nosave:{ -args:[{_:"test"},{_:"body"}],since:"0.4.0"},dowhile:{args:[{_:"body"},{_:"test"}],since:"0.4.0"},dowhile_nosave:{args:[{ -_:"body"},{_:"test"}],since:"0.4.0"},try:{args:[{_:"body"},{_:"handler"}],since:"0.4.0"},finally:{args:[{_:"body"},{ -_:"finalizer"}],since:"0.4.0"},retain:{components:!0,since:"0.4.0"},retain_catch:{components:!0,since:"0.4.0"},let:{args:[{ -_:"declarations",type:"object"}],components:!0,since:"0.4.0"},mask:{components:!0,since:"0.4.0"},action:{args:[{_:"name", -type:"string"},{_:"action",type:"object",optional:!0}],since:"0.4.0"},composition:{args:[{_:"name",type:"string"},{ -_:"composition"}],since:"0.4.0"},repeat:{args:[{_:"count",type:"number"}],components:!0,since:"0.4.0"},retry:{args:[{_:"count", -type:"number"}],components:!0,since:"0.4.0"},value:{args:[{_:"value",type:"value"}],since:"0.4.0"},literal:{args:[{_:"value", -type:"value"}],since:"0.4.0"},function:{args:[{_:"function",type:"object"}],since:"0.4.0"}};class s extends Error{ -constructor(t,n){super(t+(void 0!==n?"\nArgument: "+e.inspect(n):""))}}class Composition{static[Symbol.hasInstance](e){ -return e.constructor&&e.constructor.name===Composition.name}constructor(e){return Object.assign(this,e)}visit(e){ -const t=n[this.type];t.components&&(this.components=this.components.map(e)) -;for(let n of t.args||[])void 0===n.type&&(this[n._]=e(this[n._],n._))}}class r{task(e){ -if(arguments.length>1)throw new s("Too many arguments");if(null===e)return this.empty();if(e instanceof Composition)return e -;if("function"==typeof e)return this.function(e);if("string"==typeof e)return this.action(e);throw new s("Invalid argument",e)} -function(e){if(arguments.length>1)throw new s("Too many arguments") -;if("function"==typeof e&&-1!==(e=`${e}`).indexOf("[native code]"))throw new s("Cannot capture native function",e) -;if("string"==typeof e&&(e={kind:"nodejs:default",code:e}),"object"!=typeof e||null===e)throw new s("Invalid argument",e) -;return new Composition({type:"function",function:{exec:e}})}_empty(){return this.sequence()}_seq(e){ -return this.sequence(...e.components)}_value(e){return this._literal(e)}_literal(e){return this.let({value:e.value},()=>value)} -_retain(e){return this.let({params:null},e=>{params=e},this.mask(...e.components),e=>({params:params,result:e}))} -_retain_catch(e){return this.seq(this.retain(this.finally(this.seq(...e.components),e=>({result:e}))),({params:e,result:t})=>({ -params:e,result:t.result}))}_if(e){return this.let({params:null},e=>{params=e -},this.if_nosave(this.mask(e.test),this.seq(()=>params,this.mask(e.consequent)),this.seq(()=>params,this.mask(e.alternate))))} -_while(e){return this.let({params:null},e=>{params=e -},this.while_nosave(this.mask(e.test),this.seq(()=>params,this.mask(e.body),e=>{params=e})),()=>params)}_dowhile(e){ -return this.let({params:null},e=>{params=e},this.dowhile_nosave(this.seq(()=>params,this.mask(e.body),e=>{params=e -}),this.mask(e.test)),()=>params)}_repeat(e){return this.let({count:e.count -},this.while(()=>count-- >0,this.mask(this.seq(...e.components))))}_retry(e){return this.let({count:e.count},e=>({params:e -}),this.dowhile(this.finally(({params:e})=>e,this.mask(this.retain_catch(...e.components))),({result:e})=>void 0!==e.error&&count-- >0),({result:e})=>e) -}static init(){for(let e in n){const t=n[e];r.prototype[e]=r.prototype[e]||function(){const n=new Composition({type:e -}),r=t.args&&t.args.length||0;if(!t.components&&arguments.length>r)throw new s("Too many arguments");for(let e=0;ethis.task(e))),n}}} -get combinators(){return n}deserialize(e){if(arguments.length>1)throw new s("Too many arguments") -;return(e=new Composition(e)).visit(e=>this.deserialize(e)),e}label(e){if(arguments.length>1)throw new s("Too many arguments") -;if(!(e instanceof Composition))throw new s("Invalid argument",e) -;const t=e=>(n,s,r)=>((n=new Composition(n)).path=e+(void 0!==s?void 0===r?`.${s}`:`[${s}]`:""),n.visit(t(n.path)),n) -;return t("")(e)}lower(e,n=[]){if(arguments.length>2)throw new s("Too many arguments") -;if(!(e instanceof Composition))throw new s("Invalid argument",e) -;if(!Array.isArray(n)&&"boolean"!=typeof n&&"string"!=typeof n)throw new s("Invalid argument",n);if(!1===n)return e -;!0!==n&&""!==n||(n=[]),"string"==typeof n&&(n=Object.keys(this.combinators).filter(e=>t.gte(n,this.combinators[e].since))) -;const r=e=>{for(e=new Composition(e);n.indexOf(e.type)<0&&this[`_${e.type}`];){const t=e.path;e=this[`_${e.type}`](e), -void 0!==t&&(e.path=t)}return e.visit(r),e};return r(e)}}return r.init(),{ComposerError:s,Composition:Composition,Compiler:r} -}()); diff --git a/samples/demo.js b/samples/demo.js index f5e3805..2b0c20f 100644 --- a/samples/demo.js +++ b/samples/demo.js @@ -1,5 +1,5 @@ /* - * Copyright 2017 IBM Corporation + * Copyright 2017-2018 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,6 @@ const composer = require('@ibm-functions/composer') module.exports = composer.if( - composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), - composer.action('success', { action: function () { return { message: 'success' } } }), - composer.action('failure', { action: function () { return { message: 'failure' } } })) + composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), + composer.action('success', { action: function () { return { message: 'success' } } }), + composer.action('failure', { action: function () { return { message: 'failure' } } })) diff --git a/samples/demo.json b/samples/demo.json index 1ecf1d8..b01f72e 100644 --- a/samples/demo.json +++ b/samples/demo.json @@ -1,33 +1,143 @@ { - "type": "if", - "test": { - "type": "action", - "name": "/_/authenticate", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function ({ password }) { return { value: password === 'abc123' } }" + "composition": { + "type": "let", + "declarations": { + "params": null + }, + "components": [ + { + "type": "finally", + "body": { + "type": "function", + "function": { + "exec": { + "kind": "nodejs:default", + "code": "args => { params = args }" + } + } + }, + "finalizer": { + "type": "if_nosave", + "test": { + "type": "mask", + "components": [ + { + "type": "action", + "name": "/_/authenticate", + "path": ".test" + } + ] + }, + "consequent": { + "type": "finally", + "body": { + "type": "function", + "function": { + "exec": { + "kind": "nodejs:default", + "code": "() => params" + } + } + }, + "finalizer": { + "type": "mask", + "components": [ + { + "type": "action", + "name": "/_/success", + "path": ".consequent" + } + ] + } + }, + "alternate": { + "type": "finally", + "body": { + "type": "function", + "function": { + "exec": { + "kind": "nodejs:default", + "code": "() => params" + } + } + }, + "finalizer": { + "type": "mask", + "components": [ + { + "type": "action", + "name": "/_/failure", + "path": ".alternate" + } + ] + } + } + } } - } + ], + "path": "" }, - "consequent": { - "type": "action", - "name": "/_/success", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'success' } }" + "ast": { + "type": "if", + "test": { + "type": "action", + "name": "/_/authenticate", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function ({ password }) { return { value: password === 'abc123' } }" + } + } + }, + "consequent": { + "type": "action", + "name": "/_/success", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function () { return { message: 'success' } }" + } + } + }, + "alternate": { + "type": "action", + "name": "/_/failure", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function () { return { message: 'failure' } }" + } } } }, - "alternate": { - "type": "action", - "name": "/_/failure", - "action": { - "exec": { - "kind": "nodejs:default", - "code": "const main = function () { return { message: 'failure' } }" + "version": "0.7.0", + "actions": [ + { + "name": "/_/authenticate", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function ({ password }) { return { value: password === 'abc123' } }" + } + } + }, + { + "name": "/_/success", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function () { return { message: 'success' } }" + } + } + }, + { + "name": "/_/failure", + "action": { + "exec": { + "kind": "nodejs:default", + "code": "const main = function () { return { message: 'failure' } }" + } } } - } + ] } diff --git a/samples/node-demo.js b/samples/node-demo.js deleted file mode 100644 index f223cc4..0000000 --- a/samples/node-demo.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017 IBM Corporation - * - * 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. - */ - -// require the composer module -const composer = require('@ibm-functions/composer') - -// define the composition -const composition = composer.if( - composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), - composer.action('success', { action: function () { return { message: 'success' } } }), - composer.action('failure', { action: function () { return { message: 'failure' } } })) - -// instantiate OpenWhisk client -const wsk = composer.util.openwhisk({ ignore_certs: true }) - -wsk.compositions.deploy({ name: 'demo', composition }) // deploy composition - .then(() => wsk.actions.invoke({ name: 'demo', params: { password: 'abc123' }, blocking: true })) // invoke composition - .then(({ response }) => console.log(JSON.stringify(response.result, null, 4)), console.error) diff --git a/test/composer.js b/test/composer.js new file mode 100644 index 0000000..a5f8d6b --- /dev/null +++ b/test/composer.js @@ -0,0 +1,416 @@ +/* + * Copyright 2017-2018 IBM Corporation + * + * 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. + */ + +/* eslint-env mocha */ + +'use strict' + +const assert = require('assert') +const composer = require('../composer') + +function check (combinator, n, p, name) { + if (n === undefined) { + it('variable argument count', function () { + for (let i = 0; i < 5; i++) composer[combinator](...Array(i).fill('foo')) + for (let i = 0; i < 5; i++) composer[combinator](...Array(i).fill(() => { })) + }) + } else { + it('argument count', function () { + for (let i = n; i <= (p || n); i++) composer[combinator](...Array(i).fill('foo')) + }) + it('too many arguments', function () { + try { + composer[combinator](...Array((p || n) + 1).fill('foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + if (n > 0) { + it('too few arguments', function () { + try { + composer[combinator](...Array(n - 1).fill('foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + } + } + it('combinator type', function () { + assert.ok(composer[combinator](...Array(n || 0).fill('foo')).type === name || combinator) + }) +} + +describe('composer', function () { + describe('composer.action', function () { + it('argument count', function () { + composer.action('foo') + }) + + it('too many arguments', function () { + try { + composer.action('foo', {}, 'foo') + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + + it('too few arguments', function () { + try { + composer.action() + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Name must be a string')) + } + }) + + it('combinator type', function () { + assert.ok(composer.action('foo').type === 'action') + }) + + it('valid and invalid names', function () { + let combos = [ + { n: 42, s: false, e: 'Name must be a string' }, + { n: '', s: false, e: 'Name is not valid' }, + { n: ' ', s: false, e: 'Name is not valid' }, + { n: '/', s: false, e: 'Name is not valid' }, + { n: '//', s: false, e: 'Name is not valid' }, + { n: '/a', s: false, e: 'Name is not valid' }, + { n: '/a/b/c/d', s: false, e: 'Name is not valid' }, + { n: '/a/b/c/d/', s: false, e: 'Name is not valid' }, + { n: 'a/b/c/d', s: false, e: 'Name is not valid' }, + { n: '/a/ /b', s: false, e: 'Name is not valid' }, + { n: 'a', e: false, s: '/_/a' }, + { n: 'a/b', e: false, s: '/_/a/b' }, + { n: 'a/b/c', e: false, s: '/a/b/c' }, + { n: '/a/b', e: false, s: '/a/b' }, + { n: '/a/b/c', e: false, s: '/a/b/c' } + ] + combos.forEach(({ n, s, e }) => { + if (s) { + // good cases + assert.ok(composer.action(n).name, s) + } else { + // error cases + try { + composer.action(n) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith(e)) + } + } + }) + }) + + it('valid and invalid options', function () { + composer.action('foo', {}) + try { + composer.action('foo', 42) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + describe('composer.function', function () { + check('function', 1) + + it('function', function () { + composer.function(() => { }) + }) + + it('string', function () { + composer.function('() => {}') + }) + + it('number (invalid)', function () { + try { + composer.function(42) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + describe('composer.literal', function () { + check('literal', 1) + + it('boolean', function () { + composer.literal(true) + }) + + it('number', function () { + composer.literal(42) + }) + + it('string', function () { + composer.literal('foo') + }) + + it('dictionary', function () { + composer.literal({ foo: 42 }) + }) + + it('function (invalid)', function () { + try { + composer.literal(() => { }) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + describe('composer.value', function () { + check('value', 1) + + it('boolean', function () { + composer.value(true) + }) + + it('number', function () { + composer.value(42) + }) + + it('string', function () { + composer.value('foo') + }) + + it('dictionary', function () { + composer.value({ foo: 42 }) + }) + + it('function (invalid)', function () { + try { + composer.value(() => { }) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + describe('composer.parse', function () { + it('argument count', function () { + composer.parse({ 'type': 'sequence', 'components': [] }) + }) + + it('too many arguments', function () { + try { + composer.parse({ 'type': 'sequence', 'components': [] }, 'foo') + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + + it('too few arguments', function () { + try { + composer.parse() + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('combinator type', function () { + assert.ok(composer.parse({ + 'type': 'sequence', + 'components': [{ + 'type': 'action', + 'name': 'echo' + }, { + 'type': 'action', + 'name': 'echo' + }] + }).type === 'sequence') + }) + }) + + describe('composer.task', function () { + check('task', 1, 1, 'action') + + it('string', function () { + composer.task('isNotOne') + }) + + it('function', function () { + composer.task(() => { }) + }) + + it('null', function () { + composer.task(null) + }) + + it('boolean (invalid)', function () { + try { + composer.task(false) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('number (invalid)', function () { + try { + composer.task(42) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('dictionary (invalid)', function () { + try { + composer.task({ foo: 42 }) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + describe('composer.let', function () { + it('variable argument count', function () { + composer.let({}) + composer.let({}, 'foo') + composer.let({}, 'foo', 'foo') + }) + + it('too few arguments', function () { + try { + composer.let() + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('combinator type', function () { + assert.ok(composer.let({}).type === 'let') + }) + }) + + describe('composer.repeat', function () { + it('variable argument count', function () { + composer.repeat(42) + composer.repeat(42, 'foo') + composer.repeat(42, 'foo', 'foo') + }) + + it('too few arguments', function () { + try { + composer.repeat() + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('combinator type', function () { + assert.ok(composer.repeat(42).type === 'repeat') + }) + }) + + describe('composer.retry', function () { + it('variable argument count', function () { + composer.retry(42) + composer.retry(42, 'foo') + composer.retry(42, 'foo', 'foo') + }) + + it('too few arguments', function () { + try { + composer.retry() + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('combinator type', function () { + assert.ok(composer.retry(42).type === 'retry') + }) + }) + + describe('composer.if', function () { + check('if', 2, 3) + }) + + describe('composer.if_nosave', function () { + check('if_nosave', 2, 3) + }) + + describe('composer.while', function () { + check('while', 2) + }) + + describe('composer.while_nosave', function () { + check('while_nosave', 2) + }) + + describe('composer.dowhile', function () { + check('dowhile', 2) + }) + + describe('composer.dowhile_nosave', function () { + check('dowhile_nosave', 2) + }) + + describe('composer.try', function () { + check('try', 2) + }) + + describe('composer.finally', function () { + check('finally', 2) + }) + + describe('composer.empty', function () { + check('empty', 0) + }) + + describe('composer.mask', function () { + check('mask') + }) + + describe('composer.async', function () { + check('async') + }) + + describe('composer.retain', function () { + check('retain') + }) + + describe('composer.retain_catch', function () { + check('retain_catch') + }) + + describe('composer.sequence', function () { + check('sequence') + }) + + describe('composer.seq', function () { + check('seq') + }) + + describe('composer.merge', function () { + check('merge') + }) +}) diff --git a/test/conductor.js b/test/conductor.js new file mode 100644 index 0000000..c9ce3ed --- /dev/null +++ b/test/conductor.js @@ -0,0 +1,591 @@ +/* + * Copyright 2017-2018 IBM Corporation + * + * 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. + */ + +/* eslint-env mocha */ + +'use strict' + +const assert = require('assert') +const composer = require('../composer') +const conductor = require('../conductor') +const name = 'TestAction' +const wsk = conductor({ ignore_certs: process.env.IGNORE_CERTS && process.env.IGNORE_CERTS !== 'false' && process.env.IGNORE_CERTS !== '0' }) + +// deploy action +const define = action => wsk.actions.delete(action.name).catch(() => { }).then(() => wsk.actions.create(action)) + +// deploy and invoke composition +const invoke = (composition, params = {}, blocking = true) => wsk.compositions.deploy(Object.assign({ name }, composition.compile()), true) + .then(() => wsk.actions.invoke({ name, params, blocking })) + .then(activation => activation.response.success ? activation : Promise.reject(Object.assign(new Error(), { error: activation }))) + +describe('composer', function () { + let n, x, y // dummy variables + + this.timeout(60000) + + before('deploy test actions', function () { + return define({ name: 'echo', action: 'const main = x=>x' }) + .then(() => define({ name: 'DivideByTwo', action: 'function main({n}) { return { n: n / 2 } }' })) + .then(() => define({ name: 'TripleAndIncrement', action: 'function main({n}) { return { n: n * 3 + 1 } }' })) + .then(() => define({ name: 'isNotOne', action: 'function main({n}) { return { value: n != 1 } }' })) + .then(() => define({ name: 'isEven', action: 'function main({n}) { return { value: n % 2 == 0 } }' })) + .then(() => wsk.compositions.deploy(Object.assign({ name: '_DivideByTwo' }, composer.seq('DivideByTwo').compile()), true)) + }) + + describe('blocking invocations', function () { + describe('actions', function () { + it('action must return true', function () { + return invoke(composer.action('isNotOne'), { n: 0 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + + it('action must return false', function () { + return invoke(composer.action('isNotOne'), { n: 1 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: false })) + }) + + it('action must return activationId', function () { + return invoke(composer.async('isNotOne'), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) + }) + + it('action name must parse to fully qualified', function () { + let combos = [ + { n: 42, s: false, e: 'Name must be a string' }, + { n: '', s: false, e: 'Name is not valid' }, + { n: ' ', s: false, e: 'Name is not valid' }, + { n: '/', s: false, e: 'Name is not valid' }, + { n: '//', s: false, e: 'Name is not valid' }, + { n: '/a', s: false, e: 'Name is not valid' }, + { n: '/a/b/c/d', s: false, e: 'Name is not valid' }, + { n: '/a/b/c/d/', s: false, e: 'Name is not valid' }, + { n: 'a/b/c/d', s: false, e: 'Name is not valid' }, + { n: '/a/ /b', s: false, e: 'Name is not valid' }, + { n: 'a', e: false, s: '/_/a' }, + { n: 'a/b', e: false, s: '/_/a/b' }, + { n: 'a/b/c', e: false, s: '/a/b/c' }, + { n: '/a/b', e: false, s: '/a/b' }, + { n: '/a/b/c', e: false, s: '/a/b/c' } + ] + combos.forEach(({ n, s, e }) => { + if (s) { + // good cases + assert.ok(composer.action(n).name, s) + } else { + // error cases + try { + composer.action(n) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith(e)) + } + } + }) + }) + + it('invalid options', function () { + try { + invoke(composer.action('foo', 42)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('too many arguments', function () { + try { + invoke(composer.action('foo', {}, 'foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('literals', function () { + it('true', function () { + return invoke(composer.literal(true)).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + + it('42', function () { + return invoke(composer.literal(42)).then(activation => assert.deepStrictEqual(activation.response.result, { value: 42 })) + }) + + it('invalid argument', function () { + try { + invoke(composer.literal(invoke)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('too many arguments', function () { + try { + invoke(composer.literal('foo', 'foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('functions', function () { + it('function must return true', function () { + return invoke(composer.function(({ n }) => n % 2 === 0), { n: 4 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + + it('function must return false', function () { + return invoke(composer.function(function ({ n }) { return n % 2 === 0 }), { n: 3 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: false })) + }) + + it('function must fail', function () { + return invoke(composer.function(() => n)).then(() => assert.fail(), activation => assert.ok(activation.error.response.result.error)) + }) + + it('function must throw', function () { + return invoke(composer.function(() => ({ error: 'foo', n: 42 }))).then(() => assert.fail(), activation => assert.deepStrictEqual(activation.error.response.result, { error: 'foo' })) + }) + + it('function must mutate params', function () { + return invoke(composer.function(params => { params.foo = 'foo' }), { n: 42 }).then(activation => assert.deepStrictEqual(activation.response.result, { foo: 'foo', n: 42 })) + }) + + it('function as string', function () { + return invoke(composer.function('({ n }) => n % 2 === 0'), { n: 4 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + + it('function may return a promise', function () { + return invoke(composer.function(({ n }) => Promise.resolve(n % 2 === 0)), { n: 4 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + + it('invalid argument', function () { + try { + invoke(composer.function(42)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('too many arguments', function () { + try { + invoke(composer.function(() => n, () => { })) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('deserialize', function () { + it('should deserialize a serialized composition', function () { + const json = { + 'type': 'sequence', + 'components': [{ + 'type': 'action', + 'name': 'echo' + }, { + 'type': 'action', + 'name': 'echo' + }] + } + return invoke(composer.parse(json), { message: 'hi' }).then(activation => assert.deepStrictEqual(activation.response.result, { message: 'hi' })) + }) + }) + + describe('tasks', function () { + describe('action tasks', function () { + it('action must return true', function () { + return invoke(composer.task('isNotOne'), { n: 0 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + }) + + describe('function tasks', function () { + it('function must return true', function () { + return invoke(composer.task(({ n }) => n % 2 === 0), { n: 4 }).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + }) + + describe('null task', function () { + it('null task must return input', function () { + return invoke(composer.task(null), { foo: 'foo' }).then(activation => assert.deepStrictEqual(activation.response.result, { foo: 'foo' })) + }) + + it('null task must fail on error input', function () { + return invoke(composer.task(null), { error: 'foo' }).then(() => assert.fail(), activation => assert.deepStrictEqual(activation.error.response.result, { error: 'foo' })) + }) + }) + + describe('invalid tasks', function () { + it('a Boolean is not a valid task', function () { + try { + invoke(composer.task(false)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('a number is not a valid task', function () { + try { + invoke(composer.task(42)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + + it('a dictionary is not a valid task', function () { + try { + invoke(composer.task({ foo: 'foo' })) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + it('too many arguments', function () { + try { + invoke(composer.task('foo', 'foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('combinators', function () { + describe('sequence', function () { + it('flat', function () { + return invoke(composer.sequence('TripleAndIncrement', 'DivideByTwo', 'DivideByTwo'), { n: 5 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 4 })) + }) + + it('nested right', function () { + return invoke(composer.sequence('TripleAndIncrement', composer.sequence('DivideByTwo', 'DivideByTwo')), { n: 5 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 4 })) + }) + + it('nested left', function () { + return invoke(composer.sequence(composer.sequence('TripleAndIncrement', 'DivideByTwo'), 'DivideByTwo'), { n: 5 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 4 })) + }) + + it('seq', function () { + return invoke(composer.seq('TripleAndIncrement', 'DivideByTwo', 'DivideByTwo'), { n: 5 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 4 })) + }) + }) + + describe('if', function () { + it('condition = true', function () { + return invoke(composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement'), { n: 4 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 2 })) + }) + + it('condition = false', function () { + return invoke(composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement'), { n: 3 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 10 })) + }) + + it('condition = true, then branch only', function () { + return invoke(composer.if('isEven', 'DivideByTwo'), { n: 4 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 2 })) + }) + + it('condition = false, then branch only', function () { + return invoke(composer.if('isEven', 'DivideByTwo'), { n: 3 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 3 })) + }) + + it('condition = true, nosave option', function () { + return invoke(composer.if_nosave('isEven', params => { params.then = true }, params => { params.else = true }), { n: 2 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: true, then: true })) + }) + + it('condition = false, nosave option', function () { + return invoke(composer.if_nosave('isEven', params => { params.then = true }, params => { params.else = true }), { n: 3 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: false, else: true })) + }) + + it('too many arguments', function () { + try { + invoke(composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement', 'TripleAndIncrement')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('while', function () { + it('a few iterations', function () { + return invoke(composer.while('isNotOne', ({ n }) => ({ n: n - 1 })), { n: 4 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 1 })) + }) + + it('no iteration', function () { + return invoke(composer.while(() => false, ({ n }) => ({ n: n - 1 })), { n: 1 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 1 })) + }) + + it('nosave option', function () { + return invoke(composer.while_nosave(({ n }) => ({ n, value: n !== 1 }), ({ n }) => ({ n: n - 1 })), { n: 4 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: false, n: 1 })) + }) + + it('too many arguments', function () { + try { + invoke(composer.while('isNotOne', ({ n }) => ({ n: n - 1 }), ({ n }) => ({ n: n - 1 })), { n: 4 }) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('dowhile', function () { + it('a few iterations', function () { + return invoke(composer.dowhile(({ n }) => ({ n: n - 1 }), 'isNotOne'), { n: 4 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 1 })) + }) + + it('one iteration', function () { + return invoke(composer.dowhile(({ n }) => ({ n: n - 1 }), () => false), { n: 1 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 0 })) + }) + + it('nosave option', function () { + return invoke(composer.dowhile_nosave(({ n }) => ({ n: n - 1 }), ({ n }) => ({ n, value: n !== 1 })), { n: 4 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: false, n: 1 })) + }) + + it('too many arguments', function () { + try { + invoke(composer.dowhile(({ n }) => ({ n: n - 1 }), 'isNotOne', ({ n }) => ({ n: n - 1 })), { n: 4 }) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('try', function () { + it('no error', function () { + return invoke(composer.try(() => true, error => ({ message: error.error }))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) + }) + + it('error', function () { + return invoke(composer.try(() => ({ error: 'foo' }), error => ({ message: error.error }))) + .then(activation => assert.deepStrictEqual(activation.response.result, { message: 'foo' })) + }) + + it('try must throw', function () { + return invoke(composer.try(composer.task(null), error => ({ message: error.error })), { error: 'foo' }) + .then(activation => assert.deepStrictEqual(activation.response.result, { message: 'foo' })) + }) + + it('while must throw', function () { + return invoke(composer.try(composer.while(composer.literal(false), null), error => ({ message: error.error })), { error: 'foo' }) + .then(activation => assert.deepStrictEqual(activation.response.result, { message: 'foo' })) + }) + + it('if must throw', function () { + return invoke(composer.try(composer.if(composer.literal(false), null), error => ({ message: error.error })), { error: 'foo' }) + .then(activation => assert.deepStrictEqual(activation.response.result, { message: 'foo' })) + }) + + it('retain', function () { + return invoke(composer.retain(composer.try(() => ({ p: 4 }), null)), { n: 3 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { params: { n: 3 }, result: { p: 4 } })) + }) + + it('too many arguments', function () { + try { + invoke(composer.try('isNotOne', 'isNotOne', 'isNotOne')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('finally', function () { + it('no error', function () { + return invoke(composer.finally(() => true, params => ({ params }))) + .then(activation => assert.deepStrictEqual(activation.response.result, { params: { value: true } })) + }) + + it('error', function () { + return invoke(composer.finally(() => ({ error: 'foo' }), params => ({ params }))) + .then(activation => assert.deepStrictEqual(activation.response.result, { params: { error: 'foo' } })) + }) + + it('too many arguments', function () { + try { + invoke(composer.finally('isNotOne', 'isNotOne', 'isNotOne')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Too many arguments')) + } + }) + }) + + describe('let', function () { + it('one variable', function () { + return invoke(composer.let({ x: 42 }, () => x)) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 42 })) + }) + + it('masking', function () { + return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, () => x))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 69 })) + }) + + it('two variables', function () { + return invoke(composer.let({ x: 42 }, composer.let({ y: 69 }, () => x + y))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 111 })) + }) + + it('two variables combined', function () { + return invoke(composer.let({ x: 42, y: 69 }, () => x + y)) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 111 })) + }) + + it('scoping', function () { + return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, () => x), ({ value }) => value + x)) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 111 })) + }) + + it('invalid argument', function () { + try { + invoke(composer.let(invoke)) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + describe('mask', function () { + it('let/let/mask', function () { + return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, composer.mask(() => x)))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 42 })) + }) + + it('let/mask/let', function () { + return invoke(composer.let({ x: 42 }, composer.mask(composer.let({ x: 69 }, () => x)))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 69 })) + }) + + it('let/let/try/mask', function () { + return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, + composer.try(composer.mask(() => x), () => { })))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 42 })) + }) + + it('let/let/let/mask', function () { + return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, + composer.let({ x: -1 }, composer.mask(() => x))))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 69 })) + }) + + it('let/let/let/mask/mask', function () { + return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, + composer.let({ x: -1 }, composer.mask(composer.mask(() => x)))))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 42 })) + }) + + it('let/let/mask/let/mask', function () { + return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, + composer.mask(composer.let({ x: -1 }, composer.mask(() => x)))))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 42 })) + }) + }) + + describe('retain', function () { + it('base case', function () { + return invoke(composer.retain('TripleAndIncrement'), { n: 3 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { params: { n: 3 }, result: { n: 10 } })) + }) + + it('throw error', function () { + return invoke(composer.retain(() => ({ error: 'foo' })), { n: 3 }) + .then(() => assert.fail(), activation => assert.deepStrictEqual(activation.error.response.result, { error: 'foo' })) + }) + + it('catch error', function () { + return invoke(composer.retain_catch(() => ({ error: 'foo' })), { n: 3 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { params: { n: 3 }, result: { error: 'foo' } })) + }) + }) + + describe('merge', function () { + it('base case', function () { + return invoke(composer.merge('TripleAndIncrement'), { n: 3, p: 4 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 10, p: 4 })) + }) + }) + + describe('repeat', function () { + it('a few iterations', function () { + return invoke(composer.repeat(3, 'DivideByTwo'), { n: 8 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 1 })) + }) + + it('invalid argument', function () { + try { + invoke(composer.repeat('foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + + describe('retry', function () { + it('success', function () { + return invoke(composer.let({ x: 2 }, composer.retry(2, () => x-- > 0 ? { error: 'foo' } : 42))) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: 42 })) + }) + + it('failure', function () { + return invoke(composer.let({ x: 2 }, composer.retry(1, () => x-- > 0 ? { error: 'foo' } : 42))) + .then(() => assert.fail(), activation => assert.deepStrictEqual(activation.error.response.result.error, 'foo')) + }) + + it('invalid argument', function () { + try { + invoke(composer.retry('foo')) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith('Invalid argument')) + } + }) + }) + }) + }) + + describe('compositions', function () { + describe('collatz', function () { + it('composition must return { n: 1 }', function () { + return invoke(composer.while('isNotOne', composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement')), { n: 5 }) + .then(activation => assert.deepStrictEqual(activation.response.result, { n: 1 })) + }) + }) + }) +}) diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 8d72a4f..0000000 --- a/test/test.js +++ /dev/null @@ -1,559 +0,0 @@ -const assert = require('assert') -const composer = require('../composer') -const name = 'TestAction' -const wsk = composer.util.openwhisk({ ignore_certs: process.env.IGNORE_CERTS && process.env.IGNORE_CERTS !== 'false' && process.env.IGNORE_CERTS !== '0' }) - -// deploy action -const define = action => wsk.actions.delete(action.name).catch(() => { }).then(() => wsk.actions.create(action)) - -// deploy and invoke composition -const invoke = (composition, params = {}, blocking = true) => wsk.compositions.deploy({ name, composition }).then(() => wsk.actions.invoke({ name, params, blocking })) - -describe('composer', function () { - this.timeout(60000) - - before('deploy test actions', function () { - return define({ name: 'echo', action: 'const main = x=>x' }) - .then(() => define({ name: 'DivideByTwo', action: 'function main({n}) { return { n: n / 2 } }' })) - .then(() => define({ name: 'TripleAndIncrement', action: 'function main({n}) { return { n: n * 3 + 1 } }' })) - .then(() => define({ name: 'isNotOne', action: 'function main({n}) { return { value: n != 1 } }' })) - .then(() => define({ name: 'isEven', action: 'function main({n}) { return { value: n % 2 == 0 } }' })) - }) - - describe('blocking invocations', function () { - describe('actions', function () { - it('action must return true', function () { - return invoke(composer.action('isNotOne'), { n: 0 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - - it('action must return false', function () { - return invoke(composer.action('isNotOne'), { n: 1 }).then(activation => assert.deepEqual(activation.response.result, { value: false })) - }) - - it('action must return activationId', function () { - return invoke(composer.async('isNotOne'), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) - }) - - it('action name must parse to fully qualified', function () { - let combos = [ - { n: 42, s: false, e: 'Name must be a string' }, - { n: '', s: false, e: 'Name is not valid' }, - { n: ' ', s: false, e: 'Name is not valid' }, - { n: '/', s: false, e: 'Name is not valid' }, - { n: '//', s: false, e: 'Name is not valid' }, - { n: '/a', s: false, e: 'Name is not valid' }, - { n: '/a/b/c/d', s: false, e: 'Name is not valid' }, - { n: '/a/b/c/d/', s: false, e: 'Name is not valid' }, - { n: 'a/b/c/d', s: false, e: 'Name is not valid' }, - { n: '/a/ /b', s: false, e: 'Name is not valid' }, - { n: 'a', e: false, s: '/_/a' }, - { n: 'a/b', e: false, s: '/_/a/b' }, - { n: 'a/b/c', e: false, s: '/a/b/c' }, - { n: '/a/b', e: false, s: '/a/b' }, - { n: '/a/b/c', e: false, s: '/a/b/c' } - ] - combos.forEach(({ n, s, e }) => { - if (s) { - // good cases - assert.ok(composer.action(n).name, s) - } else { - // error cases - try { - composer.action(n) - assert.fail() - } catch (error) { - assert.ok(error.message == e) - } - } - }) - }) - - it('invalid options', function () { - try { - invoke(composer.action('foo', 42)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - - it('too many arguments', function () { - try { - invoke(composer.action('foo', {}, 'foo')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('literals', function () { - it('true', function () { - return invoke(composer.literal(true)).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - - it('42', function () { - return invoke(composer.literal(42)).then(activation => assert.deepEqual(activation.response.result, { value: 42 })) - }) - - it('invalid argument', function () { - try { - invoke(composer.literal(invoke)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - - it('too many arguments', function () { - try { - invoke(composer.literal('foo', 'foo')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('functions', function () { - it('function must return true', function () { - return invoke(composer.function(({ n }) => n % 2 === 0), { n: 4 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - - it('function must return false', function () { - return invoke(composer.function(function ({ n }) { return n % 2 === 0 }), { n: 3 }).then(activation => assert.deepEqual(activation.response.result, { value: false })) - }) - - it('function must fail', function () { - return invoke(composer.function(() => n)).then(() => assert.fail(), activation => assert.ok(activation.error.response.result.error.startsWith('An exception was caught'))) - }) - - it('function must throw', function () { - return invoke(composer.function(() => ({ error: 'foo', n: 42 }))).then(() => assert.fail(), activation => assert.deepEqual(activation.error.response.result, { error: 'foo' })) - }) - - it('function must mutate params', function () { - return invoke(composer.function(params => { params.foo = 'foo' }), { n: 42 }).then(activation => assert.deepEqual(activation.response.result, { foo: 'foo', n: 42 })) - }) - - it('function as string', function () { - return invoke(composer.function('({ n }) => n % 2 === 0'), { n: 4 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - - it('function may return a promise', function () { - return invoke(composer.function(({ n }) => Promise.resolve(n % 2 === 0)), { n: 4 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - - it('invalid argument', function () { - try { - invoke(composer.function(42)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - - it('too many arguments', function () { - try { - invoke(composer.function(() => n, () => { })) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('deserialize', function () { - it('should deserialize a serialized composition', function () { - const json = { - "type": "sequence", - "components": [{ - "type": "action", - "name": "echo" - }, { - "type": "action", - "name": "echo" - }] - } - return invoke(composer.util.deserialize(json), { message: 'hi' }).then(activation => assert.deepEqual(activation.response.result, { message: 'hi' })) - }) - }) - - describe('tasks', function () { - describe('action tasks', function () { - it('action must return true', function () { - return invoke(composer.task('isNotOne'), { n: 0 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - }) - - describe('function tasks', function () { - it('function must return true', function () { - return invoke(composer.task(({ n }) => n % 2 === 0), { n: 4 }).then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - }) - - describe('null task', function () { - it('null task must return input', function () { - return invoke(composer.task(null), { foo: 'foo' }).then(activation => assert.deepEqual(activation.response.result, { foo: 'foo' })) - }) - - it('null task must fail on error input', function () { - return invoke(composer.task(null), { error: 'foo' }).then(() => assert.fail(), activation => assert.deepEqual(activation.error.response.result, { error: 'foo' })) - }) - }) - - describe('invalid tasks', function () { - it('a Boolean is not a valid task', function () { - try { - invoke(composer.task(false)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - - it('a number is not a valid task', function () { - try { - invoke(composer.task(42)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - - it('a dictionary is not a valid task', function () { - try { - invoke(composer.task({ foo: 'foo' })) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - }) - - it('too many arguments', function () { - try { - invoke(composer.task('foo', 'foo')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('combinators', function () { - describe('sequence', function () { - it('flat', function () { - return invoke(composer.sequence('TripleAndIncrement', 'DivideByTwo', 'DivideByTwo'), { n: 5 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 4 })) - }) - - it('nested right', function () { - return invoke(composer.sequence('TripleAndIncrement', composer.sequence('DivideByTwo', 'DivideByTwo')), { n: 5 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 4 })) - }) - - it('nested left', function () { - return invoke(composer.sequence(composer.sequence('TripleAndIncrement', 'DivideByTwo'), 'DivideByTwo'), { n: 5 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 4 })) - }) - - it('seq', function () { - return invoke(composer.seq('TripleAndIncrement', 'DivideByTwo', 'DivideByTwo'), { n: 5 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 4 })) - }) - }) - - describe('if', function () { - it('condition = true', function () { - return invoke(composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement'), { n: 4 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 2 })) - }) - - it('condition = false', function () { - return invoke(composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement'), { n: 3 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 10 })) - }) - - it('condition = true, then branch only', function () { - return invoke(composer.if('isEven', 'DivideByTwo'), { n: 4 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 2 })) - }) - - it('condition = false, then branch only', function () { - return invoke(composer.if('isEven', 'DivideByTwo'), { n: 3 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 3 })) - }) - - it('condition = true, nosave option', function () { - return invoke(composer.if_nosave('isEven', params => { params.then = true }, params => { params.else = true }), { n: 2 }) - .then(activation => assert.deepEqual(activation.response.result, { value: true, then: true })) - }) - - it('condition = false, nosave option', function () { - return invoke(composer.if_nosave('isEven', params => { params.then = true }, params => { params.else = true }), { n: 3 }) - .then(activation => assert.deepEqual(activation.response.result, { value: false, else: true })) - }) - - it('too many arguments', function () { - try { - invoke(composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement', 'TripleAndIncrement')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('while', function () { - it('a few iterations', function () { - return invoke(composer.while('isNotOne', ({ n }) => ({ n: n - 1 })), { n: 4 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 1 })) - }) - - it('no iteration', function () { - return invoke(composer.while(() => false, ({ n }) => ({ n: n - 1 })), { n: 1 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 1 })) - }) - - it('nosave option', function () { - return invoke(composer.while_nosave(({ n }) => ({ n, value: n !== 1 }), ({ n }) => ({ n: n - 1 })), { n: 4 }) - .then(activation => assert.deepEqual(activation.response.result, { value: false, n: 1 })) - }) - - it('too many arguments', function () { - try { - invoke(composer.while('isNotOne', ({ n }) => ({ n: n - 1 }), ({ n }) => ({ n: n - 1 })), { n: 4 }) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('dowhile', function () { - it('a few iterations', function () { - return invoke(composer.dowhile(({ n }) => ({ n: n - 1 }), 'isNotOne'), { n: 4 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 1 })) - }) - - it('one iteration', function () { - return invoke(composer.dowhile(({ n }) => ({ n: n - 1 }), () => false), { n: 1 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 0 })) - }) - - it('nosave option', function () { - return invoke(composer.dowhile_nosave(({ n }) => ({ n: n - 1 }), ({ n }) => ({ n, value: n !== 1 })), { n: 4 }) - .then(activation => assert.deepEqual(activation.response.result, { value: false, n: 1 })) - }) - - it('too many arguments', function () { - try { - invoke(composer.dowhile(({ n }) => ({ n: n - 1 }), 'isNotOne', ({ n }) => ({ n: n - 1 })), { n: 4 }) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('try', function () { - it('no error', function () { - return invoke(composer.try(() => true, error => ({ message: error.error }))) - .then(activation => assert.deepEqual(activation.response.result, { value: true })) - }) - - it('error', function () { - return invoke(composer.try(() => ({ error: 'foo' }), error => ({ message: error.error }))) - .then(activation => assert.deepEqual(activation.response.result, { message: 'foo' })) - }) - - it('try must throw', function () { - return invoke(composer.try(composer.task(null), error => ({ message: error.error })), { error: 'foo' }) - .then(activation => assert.deepEqual(activation.response.result, { message: 'foo' })) - }) - - it('while must throw', function () { - return invoke(composer.try(composer.while(composer.literal(false), null), error => ({ message: error.error })), { error: 'foo' }) - .then(activation => assert.deepEqual(activation.response.result, { message: 'foo' })) - }) - - it('if must throw', function () { - return invoke(composer.try(composer.if(composer.literal(false), null), error => ({ message: error.error })), { error: 'foo' }) - .then(activation => assert.deepEqual(activation.response.result, { message: 'foo' })) - }) - - it('retain', function () { - return invoke(composer.retain(composer.try(() => ({ p: 4 }), null)), { n: 3 }) - .then(activation => assert.deepEqual(activation.response.result, { params: { n: 3 }, result: { p: 4 } })) - }) - - it('too many arguments', function () { - try { - invoke(composer.try('isNotOne', 'isNotOne', 'isNotOne')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('finally', function () { - it('no error', function () { - return invoke(composer.finally(() => true, params => ({ params }))) - .then(activation => assert.deepEqual(activation.response.result, { params: { value: true } })) - }) - - it('error', function () { - return invoke(composer.finally(() => ({ error: 'foo' }), params => ({ params }))) - .then(activation => assert.deepEqual(activation.response.result, { params: { error: 'foo' } })) - }) - - it('too many arguments', function () { - try { - invoke(composer.finally('isNotOne', 'isNotOne', 'isNotOne')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Too many arguments')) - } - }) - }) - - describe('let', function () { - it('one variable', function () { - return invoke(composer.let({ x: 42 }, () => x)) - .then(activation => assert.deepEqual(activation.response.result, { value: 42 })) - }) - - it('masking', function () { - return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, () => x))) - .then(activation => assert.deepEqual(activation.response.result, { value: 69 })) - }) - - it('two variables', function () { - return invoke(composer.let({ x: 42 }, composer.let({ y: 69 }, () => x + y))) - .then(activation => assert.deepEqual(activation.response.result, { value: 111 })) - }) - - it('two variables combined', function () { - return invoke(composer.let({ x: 42, y: 69 }, () => x + y)) - .then(activation => assert.deepEqual(activation.response.result, { value: 111 })) - }) - - it('scoping', function () { - return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, () => x), ({ value }) => value + x)) - .then(activation => assert.deepEqual(activation.response.result, { value: 111 })) - }) - - it('invalid argument', function () { - try { - invoke(composer.let(invoke)) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - }) - - describe('mask', function () { - it('let/let/mask', function () { - return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, composer.mask(() => x)))) - .then(activation => assert.deepEqual(activation.response.result, { value: 42 })) - }) - - it('let/mask/let', function () { - return invoke(composer.let({ x: 42 }, composer.mask(composer.let({ x: 69 }, () => x)))) - .then(activation => assert.deepEqual(activation.response.result, { value: 69 })) - }) - - it('let/let/try/mask', function () { - return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, - composer.try(composer.mask(() => x), () => { })))) - .then(activation => assert.deepEqual(activation.response.result, { value: 42 })) - }) - - it('let/let/let/mask', function () { - return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, - composer.let({ x: -1 }, composer.mask(() => x))))) - .then(activation => assert.deepEqual(activation.response.result, { value: 69 })) - }) - - it('let/let/let/mask/mask', function () { - return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, - composer.let({ x: -1 }, composer.mask(composer.mask(() => x)))))) - .then(activation => assert.deepEqual(activation.response.result, { value: 42 })) - }) - - it('let/let/mask/let/mask', function () { - return invoke(composer.let({ x: 42 }, composer.let({ x: 69 }, - composer.mask(composer.let({ x: -1 }, composer.mask(() => x)))))) - .then(activation => assert.deepEqual(activation.response.result, { value: 42 })) - }) - }) - - describe('retain', function () { - it('base case', function () { - return invoke(composer.retain('TripleAndIncrement'), { n: 3 }) - .then(activation => assert.deepEqual(activation.response.result, { params: { n: 3 }, result: { n: 10 } })) - }) - - it('throw error', function () { - return invoke(composer.retain(() => ({ error: 'foo' })), { n: 3 }) - .then(() => assert.fail(), activation => assert.deepEqual(activation.error.response.result, { error: 'foo' })) - }) - - it('catch error', function () { - return invoke(composer.retain_catch(() => ({ error: 'foo' })), { n: 3 }) - .then(activation => assert.deepEqual(activation.response.result, { params: { n: 3 }, result: { error: 'foo' } })) - }) - }) - - describe('repeat', function () { - it('a few iterations', function () { - return invoke(composer.repeat(3, 'DivideByTwo'), { n: 8 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 1 })) - }) - - it('invalid argument', function () { - try { - invoke(composer.repeat('foo')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - }) - - describe('retry', function () { - it('success', function () { - return invoke(composer.let({ x: 2 }, composer.retry(2, () => x-- > 0 ? { error: 'foo' } : 42))) - .then(activation => assert.deepEqual(activation.response.result, { value: 42 })) - }) - - it('failure', function () { - return invoke(composer.let({ x: 2 }, composer.retry(1, () => x-- > 0 ? { error: 'foo' } : 42))) - .then(() => assert.fail(), activation => assert.deepEqual(activation.error.response.result.error, 'foo')) - - }) - - it('invalid argument', function () { - try { - invoke(composer.retry('foo')) - assert.fail() - } catch (error) { - assert.ok(error.message.startsWith('Invalid argument')) - } - }) - }) - }) - }) - - describe('compositions', function () { - describe('collatz', function () { - it('composition must return { n: 1 }', function () { - return invoke(composer.while('isNotOne', composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement')), { n: 5 }) - .then(activation => assert.deepEqual(activation.response.result, { n: 1 })) - }) - }) - }) -}) diff --git a/travis/runtimes.json b/travis/runtimes.json new file mode 100644 index 0000000..f565907 --- /dev/null +++ b/travis/runtimes.json @@ -0,0 +1,30 @@ +{ + "runtimes": { + "nodejs": [ + { + "kind": "nodejs", + "image": { + "prefix": "openwhisk", + "name": "nodejsaction", + "tag": "latest" + }, + "deprecated": true + }, + { + "kind": "nodejs:6", + "default": true, + "image": { + "prefix": "openwhisk", + "name": "nodejs6action", + "tag": "latest" + }, + "deprecated": false, + "stemCells": [{ + "count": 2, + "memory": "256 MB" + }] + } + ] + }, + "blackboxes": [] +} diff --git a/travis/setup.sh b/travis/setup.sh index 138c3a6..2b69f5b 100755 --- a/travis/setup.sh +++ b/travis/setup.sh @@ -14,13 +14,13 @@ git clone --depth=1 https://github.com/apache/incubator-openwhisk.git openwhisk cd openwhisk ./tools/travis/setup.sh +cp $SCRIPTDIR/runtimes.json $WHISKDIR/ansible/files + # Pull down images docker pull openwhisk/controller docker tag openwhisk/controller ${IMAGE_PREFIX}/controller docker pull openwhisk/invoker docker tag openwhisk/invoker ${IMAGE_PREFIX}/invoker -docker pull openwhisk/nodejs6action -docker tag openwhisk/nodejs6action ${IMAGE_PREFIX}/nodejs6action # Deploy OpenWhisk cd $WHISKDIR/ansible @@ -32,13 +32,9 @@ $ANSIBLE_CMD initdb.yml $ANSIBLE_CMD wipe.yml $ANSIBLE_CMD openwhisk.yml -e cli_installation_mode=remote -e limit_invocations_per_minute=600 -# Deploy Redis -docker run -d -p 6379:6379 --name redis redis:3.2 - docker images docker ps -cat $WHISKDIR/whisk.properties curl -s -k https://172.17.0.1 | jq . curl -s -k https://172.17.0.1/api/v1 | jq . From 200673799952c4cfb9911af1b3f49bc99f2745bc Mon Sep 17 00:00:00 2001 From: David Grove Date: Mon, 1 Oct 2018 18:49:35 -0400 Subject: [PATCH 26/94] remove IBM copyright; scancode fixes (license, trailing whitespace) (#67) --- .travis.yml | 17 +++++++++++++++++ README.md | 19 +++++++++++++++++++ bin/compose.js | 2 -- bin/deploy.js | 2 -- composer.js | 13 +++++++------ conductor.js | 13 +++++++------ docs/COMBINATORS.md | 21 ++++++++++++++++++++- docs/COMMANDS.md | 19 +++++++++++++++++++ docs/COMPOSITIONS.md | 23 +++++++++++++++++++++-- docs/README.md | 19 +++++++++++++++++++ samples/demo.js | 13 +++++++------ test/composer.js | 13 +++++++------ test/conductor.js | 13 +++++++------ travis/setup.sh | 18 ++++++++++++++++++ 14 files changed, 168 insertions(+), 37 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d444b3..cf0f091 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + language: node_js node_js: - 6 diff --git a/README.md b/README.md index a86afb2..da2d59b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ + + # @ibm-functions/composer [![Travis](https://travis-ci.org/ibm-functions/composer.svg?branch=master)](https://travis-ci.org/ibm-functions/composer) diff --git a/bin/compose.js b/bin/compose.js index 8821eba..f0aa334 100755 --- a/bin/compose.js +++ b/bin/compose.js @@ -1,8 +1,6 @@ #!/usr/bin/env node /* - * Copyright 2017-2018 IBM Corporation - * * 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 diff --git a/bin/deploy.js b/bin/deploy.js index bbd9bce..9dd6f86 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -1,8 +1,6 @@ #!/usr/bin/env node /* - * Copyright 2017-2018 IBM Corporation - * * 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 diff --git a/composer.js b/composer.js index e86af89..106269f 100644 --- a/composer.js +++ b/composer.js @@ -1,11 +1,12 @@ /* - * Copyright 2017-2018 IBM Corporation + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 * - * 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 + * 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, diff --git a/conductor.js b/conductor.js index bac9641..0764018 100644 --- a/conductor.js +++ b/conductor.js @@ -1,11 +1,12 @@ /* - * Copyright 2017-2018 IBM Corporation + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 * - * 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 + * 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, diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index b4d29fc..28540e9 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -1,9 +1,28 @@ + + # Combinators The `composer` module offers a number of combinators to define compositions: | Combinator | Description | Example | -| --:| --- | --- | +| --:| --- | --- | | [`action`](#action) | named action | `composer.action('echo')` | | [`async`](#async) | asynchronous invocation | `composer.async('compress', 'upload')` | | [`dowhile` and `dowhile_nosave`](#dowhile) | loop at least once | `composer.dowhile('fetchData', 'needMoreData')` | diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 17e0e19..dabe630 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -1,3 +1,22 @@ + + # Commands The `compose` command compiles composition code to a portable JSON format. The diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index b06b331..8a19717 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -1,5 +1,24 @@ + + # Compositions - + Composer makes it possible to assemble actions into rich workflows called _compositions_. An example composition is described in [../README.md](../README.md). @@ -91,7 +110,7 @@ actions as illustrated in [demo.js](../samples/demo.js): composer.if( composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), composer.action('success', { action: function () { return { message: 'success' } } }), - composer.action('failure', { action: function () { return { message: 'failure' } } })) + composer.action('failure', { action: function () { return { message: 'failure' } } })) ) ``` Deploying such a composition deploys the embedded actions. diff --git a/docs/README.md b/docs/README.md index 0cf3e8b..1abced5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,22 @@ + + # Composer Package The Composer package consists of: diff --git a/samples/demo.js b/samples/demo.js index 2b0c20f..12c632f 100644 --- a/samples/demo.js +++ b/samples/demo.js @@ -1,11 +1,12 @@ /* - * Copyright 2017-2018 IBM Corporation + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 * - * 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 + * 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, diff --git a/test/composer.js b/test/composer.js index a5f8d6b..eca428d 100644 --- a/test/composer.js +++ b/test/composer.js @@ -1,11 +1,12 @@ /* - * Copyright 2017-2018 IBM Corporation + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 * - * 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 + * 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, diff --git a/test/conductor.js b/test/conductor.js index c9ce3ed..da3324d 100644 --- a/test/conductor.js +++ b/test/conductor.js @@ -1,11 +1,12 @@ /* - * Copyright 2017-2018 IBM Corporation + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 * - * 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 + * 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, diff --git a/travis/setup.sh b/travis/setup.sh index 2b69f5b..2ee033d 100755 --- a/travis/setup.sh +++ b/travis/setup.sh @@ -1,4 +1,22 @@ #!/bin/bash + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + set -e # Build script for Travis-CI. From c96dca0b596df391d2a26041122fbaf21ab03b6f Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 1 Oct 2018 21:12:27 -0400 Subject: [PATCH 27/94] Update description and keywords. Drop semver dependency. --- package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index 3c7029f..0b03c0a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@ibm-functions/composer", "version": "0.7.0", - "description": "Composer is an IBM Cloud Functions programming model for composing individual functions into larger applications.", + "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", "scripts": { @@ -23,7 +23,6 @@ "url": "https://github.com/ibm-functions/composer.git" }, "keywords": [ - "ibm", "functions", "serverless", "composer", @@ -33,7 +32,6 @@ "minimist": "^1.2.0", "openwhisk": "^3.11.0", "openwhisk-fqn": "^0.0.2", - "semver": "^5.3.0", "terser": "^3.8.2" }, "devDependencies": { From e45360fc56c50519d5285d8897a3c36041dd7bdd Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 2 Oct 2018 10:07:58 -0400 Subject: [PATCH 28/94] Update composer version in demo.json --- samples/demo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/demo.json b/samples/demo.json index b01f72e..d02055d 100644 --- a/samples/demo.json +++ b/samples/demo.json @@ -110,7 +110,7 @@ } } }, - "version": "0.7.0", + "version": "0.8.0", "actions": [ { "name": "/_/authenticate", From 79860c7b9f970440ea8149f0159feae9e23ce7fb Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 2 Oct 2018 10:27:19 -0400 Subject: [PATCH 29/94] 0.8.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b03c0a..ddb8069 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.7.0", + "version": "0.8.0", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From 8566d07fb7b48db5dd54b0f2ead931e535b6693e Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 3 Oct 2018 09:16:46 -0400 Subject: [PATCH 30/94] Import fqn code --- bin/deploy.js | 2 +- composer.js | 2 +- fqn.js | 46 ++++++++++++++++++++++++++++++++++++ package.json | 1 - test/fqn.js | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 fqn.js create mode 100644 test/fqn.js diff --git a/bin/deploy.js b/bin/deploy.js index 9dd6f86..ec1343c 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -18,7 +18,7 @@ const composer = require('../composer') const conductor = require('../conductor') -const fqn = require('openwhisk-fqn') +const fqn = require('../fqn') const fs = require('fs') const json = require('../package.json') const minimist = require('minimist') diff --git a/composer.js b/composer.js index 106269f..ed3ef97 100644 --- a/composer.js +++ b/composer.js @@ -17,7 +17,7 @@ 'use strict' -const fqn = require('openwhisk-fqn') +const fqn = require('./fqn') const fs = require('fs') const util = require('util') diff --git a/fqn.js b/fqn.js new file mode 100644 index 0000000..44836f7 --- /dev/null +++ b/fqn.js @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +'use strict' + +/** + * Parses a (possibly fully qualified) entity name and validates it. + * If it's not a fully qualified name, then attempts to qualify it. + * + * Examples: + * foo => /_/foo + * pkg/foo => /_/pkg/foo + * /ns/foo => /ns/foo + * /ns/pkg/foo => /ns/pkg/foo + */ +module.exports = function (name) { + if (typeof name !== 'string') throw new Error('Name must be a string') + if (name.trim().length === 0) throw new Error('Name is not valid') + name = name.trim() + const delimiter = '/' + const parts = name.split(delimiter) + const n = parts.length + const leadingSlash = name[0] === delimiter + // no more than /ns/p/a + if (n < 1 || n > 4 || (leadingSlash && n === 2) || (!leadingSlash && n === 4)) throw new Error('Name is not valid') + // skip leading slash, all parts must be non empty (could tighten this check to match EntityName regex) + parts.forEach(function (part, i) { if (i > 0 && part.trim().length === 0) throw new Error('Name is not valid') }) + const newName = parts.join(delimiter) + if (leadingSlash) return newName + else if (n < 3) return `${delimiter}_${delimiter}${newName}` + else return `${delimiter}${newName}` +} diff --git a/package.json b/package.json index ddb8069..ae5ac70 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "dependencies": { "minimist": "^1.2.0", "openwhisk": "^3.11.0", - "openwhisk-fqn": "^0.0.2", "terser": "^3.8.2" }, "devDependencies": { diff --git a/test/fqn.js b/test/fqn.js new file mode 100644 index 0000000..1c7afe3 --- /dev/null +++ b/test/fqn.js @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* eslint-env mocha */ + +'use strict' + +const assert = require('assert') +const fqn = require('../fqn') + +describe('fqn', function () { + let combos = [ + { n: undefined, s: false, e: 'Name must be a string' }, + { n: null, s: false, e: 'Name must be a string' }, + { n: 0, s: false, e: 'Name must be a string' }, + { n: 42, s: false, e: 'Name must be a string' }, + { n: true, s: false, e: 'Name must be a string' }, + { n: false, s: false, e: 'Name must be a string' }, + { n: '', s: false, e: 'Name is not valid' }, + { n: ' ', s: false, e: 'Name is not valid' }, + { n: '/', s: false, e: 'Name is not valid' }, + { n: '//', s: false, e: 'Name is not valid' }, + { n: '/a', s: false, e: 'Name is not valid' }, + { n: '/a/b/c/d', s: false, e: 'Name is not valid' }, + { n: '/a/b/c/d/', s: false, e: 'Name is not valid' }, + { n: 'a/b/c/d', s: false, e: 'Name is not valid' }, + { n: '/a/ /b', s: false, e: 'Name is not valid' }, + { n: 'a', e: false, s: '/_/a' }, + { n: 'a/b', e: false, s: '/_/a/b' }, + { n: 'a/b/c', e: false, s: '/a/b/c' }, + { n: '/a/b', e: false, s: '/a/b' }, + { n: '/a/b/c', e: false, s: '/a/b/c' } + ] + combos.forEach(({ n, s, e }) => { + it(typeof n === 'string' ? `'${n}'` : `${n}`, function () { + if (s) { + // good cases + assert.strictEqual(fqn(n), s) + } else { + // error cases + try { + fqn(n) + assert.fail() + } catch (error) { + assert.ok(error.message.startsWith(e)) + } + } + }) + }) +}) From 5f7468b4e58564495d6f983c72e8254996b45936 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 3 Oct 2018 09:20:16 -0400 Subject: [PATCH 31/94] Include fqn.js in npm package --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ae5ac70..9983f1f 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "bin/", "composer.js", "conductor.js", + "fqn.js", "docs/*.md", "samples/" ], From 8403e587ed73097b4794096e7afa7b166012f912 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 3 Oct 2018 10:43:47 -0400 Subject: [PATCH 32/94] 0.8.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9983f1f..a9710a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ibm-functions/composer", - "version": "0.8.0", + "version": "0.8.1", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", "homepage": "https://github.com/ibm-functions/composer", "main": "composer.js", From 94fe7415270a6718dddc5f535f38364589a70f4f Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 3 Oct 2018 16:19:46 -0400 Subject: [PATCH 33/94] New url --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index da2d59b..dfefd99 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,12 @@ # --> +# Notice + +Composer is now part of the Apache OpenWhisk incubator project. The Composer +code is now hosted at https://github.com/apache/incubator-openwhisk-composer. +Issues and pull requests should be filed against the new repository. + # @ibm-functions/composer [![Travis](https://travis-ci.org/ibm-functions/composer.svg?branch=master)](https://travis-ci.org/ibm-functions/composer) From 9e8c961c221fa19cd787c44b7cf45eebac99c96e Mon Sep 17 00:00:00 2001 From: Nikolai Baudis Date: Fri, 12 Mar 2021 15:29:16 +0100 Subject: [PATCH 34/94] Revert "New url" This reverts commit 94fe7415270a6718dddc5f535f38364589a70f4f. --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index dfefd99..da2d59b 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,6 @@ # --> -# Notice - -Composer is now part of the Apache OpenWhisk incubator project. The Composer -code is now hosted at https://github.com/apache/incubator-openwhisk-composer. -Issues and pull requests should be filed against the new repository. - # @ibm-functions/composer [![Travis](https://travis-ci.org/ibm-functions/composer.svg?branch=master)](https://travis-ci.org/ibm-functions/composer) From 674e91a517ecd9d1caa1f2500f161c266e6cbca4 Mon Sep 17 00:00:00 2001 From: David Grove Date: Wed, 3 Oct 2018 11:30:13 -0400 Subject: [PATCH 35/94] Project boilerplate files --- DISCLAIMER.txt | 1 + NOTICE.txt | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 DISCLAIMER.txt create mode 100644 NOTICE.txt diff --git a/DISCLAIMER.txt b/DISCLAIMER.txt new file mode 100644 index 0000000..65d2a55 --- /dev/null +++ b/DISCLAIMER.txt @@ -0,0 +1 @@ +Apache OpenWhisk Deployment on Kubernetes is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 0000000..e6d7bdb --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,5 @@ +Apache OpenWhisk +Copyright 2016-2018 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). From 28e2415bc5ffd071cd378bce8ba51179fae49d88 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 4 Oct 2018 10:54:56 -0400 Subject: [PATCH 36/94] more boilerplate: fix DISCLAIMER; add CONTRIBUTING (#2) --- CONTRIBUTING.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ DISCLAIMER.txt | 2 +- README.md | 7 +++-- 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..cf5d5b2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,71 @@ + + +[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) + +# Contributing to Apache OpenWhisk + +Anyone can contribute to the OpenWhisk project and we welcome your contributions. + +There are multiple ways to contribute: report bugs, improve the docs, and +contribute code, but you must follow these prerequisites and guidelines: + + - [Contributor License Agreement](#contributor-license-agreement) + - [Raising issues](#raising-issues) + - [Coding Standards](#coding-standards) + +### Contributor License Agreement + +All contributors must sign and submit an Apache CLA (Contributor License Agreement). + +Instructions on how to do this can be found here: +[http://www.apache.org/licenses/#clas](http://www.apache.org/licenses/#clas) + +Once submitted, you will receive a confirmation email from the Apache Software Foundation (ASF) and be added to +the following list: http://people.apache.org/unlistedclas.html. + +Project committers will use this list to verify pull requests (PRs) come from contributors that have signed a CLA. + +We look forward to your contributions! + +## Raising issues + +Please raise any bug reports or enhancement requests on the respective project repository's GitHub issue tracker. Be sure to search the +list to see if your issue has already been raised. + +A good bug report is one that make it easy for us to understand what you were trying to do and what went wrong. +Provide as much context as possible so we can try to recreate the issue. + +A good enhancement request comes with an explanation of what you are trying to do and how that enhancement would help you. + +### Discussion + +Please use the project's developer email list to engage our community: +[dev@openwhisk.incubator.apache.org](dev@openwhisk.incubator.apache.org) + +In addition, we provide a "dev" Slack team channel for conversations at: +https://openwhisk-team.slack.com/messages/dev/ + +### Coding standards + +Please ensure you follow the coding standards used throughout the existing +code base. Some basic rules include: + + - all files must have the Apache license in the header. + - all PRs must have passing builds for all operating systems. diff --git a/DISCLAIMER.txt b/DISCLAIMER.txt index 65d2a55..aa67e53 100644 --- a/DISCLAIMER.txt +++ b/DISCLAIMER.txt @@ -1 +1 @@ -Apache OpenWhisk Deployment on Kubernetes is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. +Apache OpenWhisk Composer is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. diff --git a/README.md b/README.md index da2d59b..6cf928d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ # --> -# @ibm-functions/composer +# Apache OpenWhisk Composer [![Travis](https://travis-ci.org/ibm-functions/composer.svg?branch=master)](https://travis-ci.org/ibm-functions/composer) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) @@ -44,7 +44,10 @@ This repository includes: ## Installation -Composer is distributed as Node.js package. To install this package, use the +Composer is distributed as Node.js package. The package is currently named `@ibm-functions/composer`, +but will soon be available as `@openwhisk-composer`. Until we have our first official Apache release of +composer, please continue to use the latest release of `@ibm-functions/composer`. +To install this package, use the Node Package Manager: ``` npm install -g @ibm-functions/composer From 2bccc91b8ccc7682b0df658513eca320c83e03d8 Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 5 Oct 2018 07:22:26 -0400 Subject: [PATCH 37/94] Scancode (#3) * enable codescan in travis --- .travis.yml | 2 ++ travis/scancode.sh | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100755 travis/scancode.sh diff --git a/.travis.yml b/.travis.yml index cf0f091..5ec856f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,5 +23,7 @@ services: env: global: - IGNORE_CERTS=true +before_install: + - ./travis/scancode.sh before_script: - ./travis/setup.sh diff --git a/travis/scancode.sh b/travis/scancode.sh new file mode 100755 index 0000000..900d465 --- /dev/null +++ b/travis/scancode.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements; and to You under the Apache License, Version 2.0. + +set -e + +SCRIPTDIR=$(cd $(dirname "$0") && pwd) +ROOTDIR="$SCRIPTDIR/../" +HOMEDIR="$SCRIPTDIR/../../" +UTIL_DIR="$HOMEDIR/incubator-openwhisk-utilities" + +# clone OpenWhisk utilities repo. in order to run scanCode.py +cd $HOMEDIR +git clone https://github.com/apache/incubator-openwhisk-utilities.git + +# run scancode +cd $UTIL_DIR +scancode/scanCode.py --config scancode/ASF-Release.cfg $ROOTDIR From 8cf1b91cc6ca48e0dffcc9179d0c8ef49a25fe83 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Fri, 5 Oct 2018 11:51:17 -0400 Subject: [PATCH 38/94] Update travis link in README (#4) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6cf928d..22b112a 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ # Apache OpenWhisk Composer -[![Travis](https://travis-ci.org/ibm-functions/composer.svg?branch=master)](https://travis-ci.org/ibm-functions/composer) +[![Travis](https://travis-ci.org/apache/incubator-openwhisk-composer.svg?branch=master)](https://travis-ci.org/apache/incubator-openwhisk-composer) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) From 68f4a3625652db04f42ff0201a07b8de8ef607b3 Mon Sep 17 00:00:00 2001 From: Bertrand Delacretaz Date: Tue, 9 Oct 2018 17:18:34 +0200 Subject: [PATCH 39/94] Mention missing IP clearance (#5) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 22b112a..a997871 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) +Note that this module **cannot be released** until the IP clearance at https://issues.apache.org/jira/browse/INCUBATOR-222 is done. It shouldn't have been imported here before that, but it's probably ok to continue working here until that's fixed. + Composer is a new programming model for composing cloud functions built on [Apache OpenWhisk](https://github.com/apache/incubator-openwhisk). With Composer, developers can build even more serverless applications including using From 0b6a646f22181a31aee16e84ba2665d0cd546d59 Mon Sep 17 00:00:00 2001 From: David Grove Date: Sat, 20 Oct 2018 18:18:43 -0400 Subject: [PATCH 40/94] INCUBATOR-222 is resolved; can remove disclaimer (#6) --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a997871..22b112a 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,6 @@ [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) -Note that this module **cannot be released** until the IP clearance at https://issues.apache.org/jira/browse/INCUBATOR-222 is done. It shouldn't have been imported here before that, but it's probably ok to continue working here until that's fixed. - Composer is a new programming model for composing cloud functions built on [Apache OpenWhisk](https://github.com/apache/incubator-openwhisk). With Composer, developers can build even more serverless applications including using From 81b80e6d349965cbd4a61976d748cfaca8c1284f Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 23 Oct 2018 16:37:56 -0400 Subject: [PATCH 41/94] LICENSE to LICENSE.txt to match openwhisk conventions (#7) --- LICENSE => LICENSE.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENSE => LICENSE.txt (100%) diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt From cf485b9064872c2379d66cec220ca55bcffef1f4 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 15 Nov 2018 13:19:43 -0500 Subject: [PATCH 42/94] Rename npm package to openwhisk-composer (#8) --- README.md | 9 +++------ package.json | 8 ++++---- samples/demo.js | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 22b112a..384ab96 100644 --- a/README.md +++ b/README.md @@ -44,13 +44,10 @@ This repository includes: ## Installation -Composer is distributed as Node.js package. The package is currently named `@ibm-functions/composer`, -but will soon be available as `@openwhisk-composer`. Until we have our first official Apache release of -composer, please continue to use the latest release of `@ibm-functions/composer`. -To install this package, use the +Composer is distributed as Node.js package. To install this package, use the Node Package Manager: ``` -npm install -g @ibm-functions/composer +npm install -g openwhisk-composer ``` We recommend to install the package globally (with `-g` option) if you intend to use the `compose` and `deploy` commands to compile and deploy compositions. @@ -60,7 +57,7 @@ use the `compose` and `deploy` commands to compile and deploy compositions. A composition is typically defined by means of a Javascript expression as illustrated in [samples/demo.js](samples/demo.js): ```javascript -const composer = require('@ibm-functions/composer') +const composer = require('openwhisk-composer') module.exports = composer.if( composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), diff --git a/package.json b/package.json index a9710a4..058f1f0 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "@ibm-functions/composer", - "version": "0.8.1", + "name": "openwhisk-composer", + "version": "0.9.0", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", - "homepage": "https://github.com/ibm-functions/composer", + "homepage": "https://github.com/apache/incubator-openwhisk-composer", "main": "composer.js", "scripts": { "test": "standard && mocha" @@ -21,7 +21,7 @@ ], "repository": { "type": "git", - "url": "https://github.com/ibm-functions/composer.git" + "url": "https://github.com/apache/incubator-openwhisk-composer.git" }, "keywords": [ "functions", diff --git a/samples/demo.js b/samples/demo.js index 12c632f..9454bbc 100644 --- a/samples/demo.js +++ b/samples/demo.js @@ -15,7 +15,7 @@ * limitations under the License. */ -const composer = require('@ibm-functions/composer') +const composer = require('openwhisk-composer') module.exports = composer.if( composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), From 11044c7d798485dbc084ad4bbf73abe0daf39114 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 20 Nov 2018 13:30:57 -0500 Subject: [PATCH 43/94] Fix openwhisk-composer module resolution in compose command (#9) --- bin/compose.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/compose.js b/bin/compose.js index f0aa334..b581700 100755 --- a/bin/compose.js +++ b/bin/compose.js @@ -39,7 +39,7 @@ Module._resolveFilename = function (request, parent) { try { return _resolveFilename(request, parent) } catch (error) { - return require.resolve(request.replace(request.startsWith(json.name + '/') ? json.name : json.name.substring(0, json.name.indexOf('/')), '..')) + return require.resolve(request.replace(json.name, '..')) } } else { return _resolveFilename(request, parent) From 9e472473291498a3c8794163012ded81824fd4e6 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 26 Nov 2018 15:34:23 -0500 Subject: [PATCH 44/94] Skip OpenWhisk build in Travis (#10) --- travis/setup.sh | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/travis/setup.sh b/travis/setup.sh index 2ee033d..17ebb48 100755 --- a/travis/setup.sh +++ b/travis/setup.sh @@ -23,26 +23,21 @@ set -e SCRIPTDIR=$(cd $(dirname "$0") && pwd) ROOTDIR="$SCRIPTDIR/.." -IMAGE_PREFIX="composer" WHISKDIR="$ROOTDIR/openwhisk" -# OpenWhisk stuff +# Clone OpenWhisk cd $ROOTDIR git clone --depth=1 https://github.com/apache/incubator-openwhisk.git openwhisk -cd openwhisk -./tools/travis/setup.sh -cp $SCRIPTDIR/runtimes.json $WHISKDIR/ansible/files +# Install Ansible +pip install --user ansible==2.5.2 -# Pull down images -docker pull openwhisk/controller -docker tag openwhisk/controller ${IMAGE_PREFIX}/controller -docker pull openwhisk/invoker -docker tag openwhisk/invoker ${IMAGE_PREFIX}/invoker +# Configure runtimes +cp $SCRIPTDIR/runtimes.json $WHISKDIR/ansible/files # Deploy OpenWhisk cd $WHISKDIR/ansible -ANSIBLE_CMD="ansible-playbook -i ${WHISKDIR}/ansible/environments/local -e docker_image_prefix=${IMAGE_PREFIX}" +ANSIBLE_CMD="ansible-playbook -i ${WHISKDIR}/ansible/environments/local -e docker_image_prefix=openwhisk" $ANSIBLE_CMD setup.yml $ANSIBLE_CMD prereq.yml $ANSIBLE_CMD couchdb.yml @@ -50,13 +45,13 @@ $ANSIBLE_CMD initdb.yml $ANSIBLE_CMD wipe.yml $ANSIBLE_CMD openwhisk.yml -e cli_installation_mode=remote -e limit_invocations_per_minute=600 +# Log configuration docker images docker ps - curl -s -k https://172.17.0.1 | jq . curl -s -k https://172.17.0.1/api/v1 | jq . -# Setup +# Setup CLI WHISK_APIHOST="172.17.0.1" WHISK_AUTH=`cat ${WHISKDIR}/ansible/files/auth.guest` WHISK_CLI="${WHISKDIR}/bin/wsk -i" From 14801e2ee40b88ec9dc29ddeff3ab57c8915542a Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 27 Nov 2018 11:39:41 -0500 Subject: [PATCH 45/94] Prefetch docker images (#11) --- travis/setup.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/travis/setup.sh b/travis/setup.sh index 17ebb48..e7bdd1b 100755 --- a/travis/setup.sh +++ b/travis/setup.sh @@ -25,6 +25,11 @@ SCRIPTDIR=$(cd $(dirname "$0") && pwd) ROOTDIR="$SCRIPTDIR/.." WHISKDIR="$ROOTDIR/openwhisk" +# Prefetch docker images +docker pull openwhisk/controller & +docker pull openwhisk/invoker & +docker pull openwhisk/nodejs6action & + # Clone OpenWhisk cd $ROOTDIR git clone --depth=1 https://github.com/apache/incubator-openwhisk.git openwhisk From ba2fe51f93127c71bb6b3453897108c40cdea8bd Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 28 Nov 2018 14:06:55 -0500 Subject: [PATCH 46/94] Fix incorrect path handling in fsm synthesis (#12) --- conductor.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/conductor.js b/conductor.js index 0764018..a70f5a7 100644 --- a/conductor.js +++ b/conductor.js @@ -153,7 +153,11 @@ function main (composition) { function compile (parent, node) { if (arguments.length === 1) return [{ parent, type: 'empty' }] - if (arguments.length === 2) return Object.assign(compiler[node.type](node.path || parent, node), { path: node.path }) + if (arguments.length === 2) { + const fsm = compiler[node.type](node.path || parent, node) + if (node.path !== undefined) fsm[0].path = node.path + return fsm + } return Array.prototype.slice.call(arguments, 1).reduce((fsm, node) => { fsm.push(...compile(parent, node)); return fsm }, []) } From c815bf6c625cd48de640afc21e2879eb2b6fa7b0 Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 4 Dec 2018 01:24:47 -0500 Subject: [PATCH 47/94] add disclaimer paragraph to bottom of README.md (#14) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 384ab96..c3554aa 100644 --- a/README.md +++ b/README.md @@ -142,3 +142,7 @@ Compositions are implemented by means of OpenWhisk conductor actions. The [documentation of conductor actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) explains execution traces in greater details. + +# Disclaimer + +Apache OpenWhisk Composer is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. From 0fd5cc49289cf81aa8d1e35dcca64b459551afac Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 6 Dec 2018 20:25:55 -0500 Subject: [PATCH 48/94] Rename $resume parameter to $composer (#15) --- conductor.js | 14 +++++++------- docs/COMPOSITIONS.md | 6 ++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/conductor.js b/conductor.js index a70f5a7..aca9fb1 100644 --- a/conductor.js +++ b/conductor.js @@ -182,7 +182,7 @@ function main (composition) { }, action ({ p, node, index }) { - return { method: 'action', action: node.name, params: p.params, state: { $resume: p.s } } + return { method: 'action', action: node.name, params: p.params, state: { $composer: p.s } } }, function ({ p, node, index }) { @@ -208,7 +208,7 @@ function main (composition) { }, async ({ p, node, index, inspect, step }) { - p.params.$resume = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack) } + p.params.$composer = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack) } p.s.state = index + node.return if (!wsk) wsk = openwhisk({ ignore_certs: true }) return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) @@ -303,19 +303,19 @@ function main (composition) { // do invocation return (params) => { // extract parameters - const $resume = params.$resume || {} - delete params.$resume - $resume.session = $resume.session || process.env.__OW_ACTIVATION_ID + const $composer = params.$composer || {} + delete params.$composer + $composer.session = $composer.session || process.env.__OW_ACTIVATION_ID // current state - const p = { s: Object.assign({ state: 0, stack: [], resuming: true }, $resume), params } + const p = { s: Object.assign({ state: 0, stack: [], resuming: true }, $composer), params } // step and catch all errors return Promise.resolve().then(() => { if (typeof p.s.state !== 'number') return internalError('state parameter is not a number') if (!Array.isArray(p.s.stack)) return internalError('stack parameter is not an array') - if ($resume.resuming) inspect(p) // handle error objects when resuming + if ($composer.resuming) inspect(p) // handle error objects when resuming return step(p) }).catch(error => { diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index 8a19717..045d248 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -58,6 +58,12 @@ the sequence is not executed. Moreover, if the sequence is enclosed in an error handling composition like a `composer.try(sequence, handler)` combinator, the execution continues with the error handler. +### Reserved parameter name + +The field name `$composer` is reserved for composer internal use. Compositions +and composed actions should not expect or return parameter objects with a +top-level field named `$composer`. + ## Data flow The invocation of a composition triggers a series of computations (possibly From 3c762d6bbf21f8018041f66ec1f9ebc7d4619d2f Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Sat, 19 Jan 2019 17:06:50 -0500 Subject: [PATCH 49/94] Add parallel, map, and dynamic combinators (#16) * Add parallel, map, and dynamic combinators --- .travis.yml | 1 + README.md | 55 ++++++++++++++-- composer.js | 8 ++- conductor.js | 150 ++++++++++++++++++++++++++++++++++++++++++- docs/COMBINATORS.md | 70 ++++++++++++++++++++ docs/COMPOSITIONS.md | 8 ++- test/composer.js | 16 +++++ test/conductor.js | 45 +++++++++++++ travis/setup.sh | 3 + 9 files changed, 344 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5ec856f..051e253 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ services: env: global: - IGNORE_CERTS=true + - REDIS=redis://172.17.0.1:6379 before_install: - ./travis/scancode.sh before_script: diff --git a/README.md b/README.md index c3554aa..9fa0af1 100644 --- a/README.md +++ b/README.md @@ -65,12 +65,12 @@ module.exports = composer.if( composer.action('failure', { action: function () { return { message: 'failure' } } })) ``` Compositions compose actions using [combinator](docs/COMBINATORS.md) methods. -These methods implement the typical control-flow constructs of a sequential -imperative programming language. This example composition composes three actions -named `authenticate`, `success`, and `failure` using the `composer.if` -combinator, which implements the usual conditional construct. It take three -actions (or compositions) as parameters. It invokes the first one and, depending -on the result of this invocation, invokes either the second or third action. +These methods implement the typical control-flow constructs of an imperative +programming language. This example composition composes three actions named +`authenticate`, `success`, and `failure` using the `composer.if` combinator, +which implements the usual conditional construct. It take three actions (or +compositions) as parameters. It invokes the first one and, depending on the +result of this invocation, invokes either the second or third action. This composition includes the definitions of the three composed actions. If the actions are defined and deployed elsewhere, the composition code can be shorten @@ -143,6 +143,49 @@ Compositions are implemented by means of OpenWhisk conductor actions. The actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) explains execution traces in greater details. +While composer does not limit in principle the length of a composition, +OpenWhisk deployments typically enforce a limit on the number of action +invocations in a composition as well as an upper bound on the rate of +invocation. These limits may result in compositions failing to execute to +completion. + +## Parallel compositions with Redis + +Composer offers parallel combinators that make it possible to run actions or +compositions in parallel, for example: +```javascript +composer.parallel('checkInventory', 'detectFraud') +``` + +The width of parallel compositions is not in principle limited by composer, but +issuing many concurrent invocations may hit OpenWhisk limits leading to +failures: failure to execute a branch of a parallel composition or failure to +complete the parallel composition. + +These combinators require access to a Redis instance to hold intermediate +results of parallel compositions. The Redis credentials may be specified at +invocation time or earlier by means of default parameters or package bindings. +The required parameter is named `$composer`. It is a dictionary with a `redis` +field of type dictionary. The `redis` dictionary specifies the `uri` for the +Redis instance and optionally a certificate as a base64-encoded string to enable +tls connections. Hence, the input parameter object for our order-processing +example should be: +```json +{ + "$composer": { + "redis": { + "uri": "redis://...", + "ca": "optional base64 encoded tls certificate" + } + }, + "order": { ... } +} +``` + +The intent is to store intermediate results in Redis as the parallel composition +is progressing. Redis entries are deleted after completion and, as an added +safety, expire after twenty-four hours. + # Disclaimer Apache OpenWhisk Composer is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. diff --git a/composer.js b/composer.js index ed3ef97..66f500f 100644 --- a/composer.js +++ b/composer.js @@ -285,7 +285,10 @@ const combinators = { mask: { components: true }, action: { args: [{ name: 'name', type: 'name' }, { name: 'action', type: 'object', optional: true }] }, function: { args: [{ name: 'function', type: 'object' }] }, - async: { components: true } + async: { components: true }, + parallel: { components: true }, + map: { components: true }, + dynamic: {} } Object.assign(composer, declare(combinators)) @@ -303,7 +306,8 @@ const extra = { retain_catch: { components: true, def: lowerer.retain_catch }, value: { args: [{ name: 'value', type: 'value' }], def: lowerer.literal }, literal: { args: [{ name: 'value', type: 'value' }], def: lowerer.literal }, - merge: { components: true, def: lowerer.merge } + merge: { components: true, def: lowerer.merge }, + par: { components: true, def: composer.parallel } } Object.assign(composer, declare(extra)) diff --git a/conductor.js b/conductor.js index aca9fb1..ac595a4 100644 --- a/conductor.js +++ b/conductor.js @@ -83,10 +83,79 @@ class Compositions { // runtime code function main (composition) { const openwhisk = require('openwhisk') + const redis = require('redis') + const uuid = require('uuid').v4 let wsk + let db + const expiration = 86400 // expire redis key after a day + + function live (id) { return `composer/fork/${id}` } + function done (id) { return `composer/join/${id}` } + + function createRedisClient (p) { + const client = redis.createClient(p.s.redis.uri, p.s.redis.ca ? { tls: { ca: Buffer.from(p.s.redis.ca, 'base64').toString('binary') } } : {}) + const noop = () => { } + let handler = noop + client.on('error', error => handler(error)) + require('redis-commands').list.forEach(f => { + client[`${f}Async`] = function () { + let failed = false + return new Promise((resolve, reject) => { + handler = error => { + handler = noop + failed = true + reject(error) + } + client[f](...arguments, (error, result) => { + handler = noop + return error ? reject(error) : resolve(result) + }) + }).catch(error => { + if (failed) client.end(true) + return Promise.reject(error) + }) + } + }) + return client + } const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) + function fork ({ p, node, index }, array, it) { + const saved = p.params // save params + p.s.state = index + node.return // return state + p.params = { value: [] } // return value + if (array.length === 0) return + if (typeof p.s.redis !== 'object' || typeof p.s.redis.uri !== 'string' || (typeof p.s.redis.ca !== 'string' && typeof p.s.redis.ca !== 'undefined')) { + p.params = { error: 'Parallel combinator requires a properly configured redis instance' } + console.error(p.params.error) + return + } + const stack = [{ marker: true }].concat(p.s.stack) + const barrierId = uuid() + console.log(`barrierId: ${barrierId}, spawning: ${array.length}`) + if (!wsk) wsk = openwhisk({ ignore_certs: true }) + if (!db) db = createRedisClient(p) + return db.lpushAsync(live(barrierId), 42) // push marker + .then(() => db.expireAsync(live(barrierId), expiration)) + .then(() => Promise.all(array.map((item, position) => { + const params = it(saved, item) // obtain combinator-specific params for branch invocation + params.$composer.stack = stack + params.$composer.redis = p.s.redis + params.$composer.join = { barrierId, position, count: array.length } + return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params }) // invoke branch + .then(({ activationId }) => { console.log(`barrierId: ${barrierId}, spawned position: ${position} with activationId: ${activationId}`) }) + }))).then(() => collect(p, barrierId), error => { + console.error(error.body || error) + p.params = { error: `Parallel combinator failed to invoke a composition at AST node root${node.parent} (see log for details)` } + return db.delAsync(live(barrierId), done(barrierId)) // delete keys + .then(() => { + inspect(p) + return step(p) + }) + }) + } + // compile ast to fsm const compiler = { sequence (parent, node) { @@ -148,6 +217,23 @@ function main (composition) { const fsm = [{ parent, type: 'pass' }, ...compile(parent, node.body), ...compile(parent, node.test), { parent, type: 'choice', else: 1 }, { parent, type: 'pass' }] fsm[fsm.length - 2].then = 2 - fsm.length return fsm + }, + + parallel (parent, node) { + const tasks = node.components.map(task => [...compile(parent, task), { parent, type: 'stop' }]) + const fsm = [{ parent, type: 'parallel' }, ...tasks.reduce((acc, cur) => { acc.push(...cur); return acc }, []), { parent, type: 'pass' }] + fsm[0].return = fsm.length - 1 + fsm[0].tasks = tasks.reduce((acc, cur) => { acc.push(acc[acc.length - 1] + cur.length); return acc }, [1]).slice(0, -1) + return fsm + }, + + map (parent, node) { + const tasks = compile(parent, ...node.components) + return [{ parent, type: 'map', return: tasks.length + 2 }, ...tasks, { parent, type: 'stop' }, { parent, type: 'pass' }] + }, + + dynamic (parent, node) { + return [{ parent, type: 'dynamic' }] } } @@ -208,7 +294,7 @@ function main (composition) { }, async ({ p, node, index, inspect, step }) { - p.params.$composer = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack) } + p.params.$composer = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack), redis: p.s.redis } p.s.state = index + node.return if (!wsk) wsk = openwhisk({ ignore_certs: true }) return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) @@ -225,6 +311,31 @@ function main (composition) { stop ({ p, node, index, inspect, step }) { p.s.state = -1 + }, + + parallel ({ p, node, index }) { + return fork({ p, node, index }, node.tasks, (input, branch) => { + const params = Object.assign({}, input) // clone + params.$composer = { state: index + branch } + return params + }) + }, + + map ({ p, node, index }) { + return fork({ p, node, index }, p.params.value || [], (input, branch) => { + const params = isObject(branch) ? branch : { value: branch } // wrap + params.$composer = { state: index + 1 } + return params + }) + }, + + dynamic ({ p, node, index }) { + if (p.params.type !== 'action' || typeof p.params.name !== 'string' || typeof p.params.params !== 'object') { + p.params = { error: `Incorrect use of the dynamic combinator at AST node root${node.parent}` } + inspect(p) + } else { + return { method: 'action', action: p.params.name, params: p.params.params, state: { $composer: p.s } } + } } } @@ -232,6 +343,29 @@ function main (composition) { return p.params.error ? p.params : { params: p.params } } + function collect (p, barrierId) { + if (!db) db = createRedisClient(p) + const timeout = Math.max(Math.floor((process.env.__OW_DEADLINE - new Date()) / 1000) - 5, 1) + console.log(`barrierId: ${barrierId}, waiting with timeout: ${timeout}s`) + return db.brpopAsync(done(barrierId), timeout) // pop marker + .then(marker => { + console.log(`barrierId: ${barrierId}, done waiting`) + if (marker !== null) { + return db.lrangeAsync(done(barrierId), 0, -1) + .then(result => result.map(JSON.parse).map(({ position, params }) => { p.params.value[position] = params })) + .then(() => db.delAsync(live(barrierId), done(barrierId))) // delete keys + .then(() => { + inspect(p) + return step(p) + }) + } else { // timeout + p.s.collect = barrierId + console.log(`barrierId: ${barrierId}, handling timeout`) + return { method: 'action', action: '/whisk.system/utils/echo', params: p.params, state: { $composer: p.s } } + } + }) + } + const internalError = error => Promise.reject(error) // terminate composition execution and record error // wrap params if not a dictionary, branch to error handler if error @@ -288,6 +422,14 @@ function main (composition) { if (p.s.state < 0 || p.s.state >= fsm.length) { console.log(`Entering final state`) console.log(JSON.stringify(p.params)) + if (p.s.join) { + if (!db) db = createRedisClient(p) + return db.lpushxAsync(live(p.s.join.barrierId), JSON.stringify({ position: p.s.join.position, params: p.params })).then(count => { // push only if marker is present + return (count > p.s.join.count ? db.renameAsync(live(p.s.join.barrierId), done(p.s.join.barrierId)) : Promise.resolve()) + }).then(() => { + p.params = { method: 'join', sessionId: p.s.session, barrierId: p.s.join.barrierId, position: p.s.join.position } + }) + } return } @@ -315,6 +457,12 @@ function main (composition) { if (typeof p.s.state !== 'number') return internalError('state parameter is not a number') if (!Array.isArray(p.s.stack)) return internalError('stack parameter is not an array') + if (p.s.collect) { // waiting on parallel branches + const barrierId = p.s.collect + delete p.s.collect + return collect(p, barrierId) + } + if ($composer.resuming) inspect(p) // handle error objects when resuming return step(p) diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index 28540e9..d3d9cd2 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -26,14 +26,17 @@ The `composer` module offers a number of combinators to define compositions: | [`action`](#action) | named action | `composer.action('echo')` | | [`async`](#async) | asynchronous invocation | `composer.async('compress', 'upload')` | | [`dowhile` and `dowhile_nosave`](#dowhile) | loop at least once | `composer.dowhile('fetchData', 'needMoreData')` | +| [`dynamic`](#dynamic) | dynamic invocation | `composer.dynamic()` | [`empty`](#empty) | empty sequence | `composer.empty()` | [`finally`](#finally) | finalization | `composer.finally('tryThis', 'doThatAlways')` | | [`function`](#function) | Javascript function | `composer.function(({ x, y }) => ({ product: x * y }))` | | [`if` and `if_nosave`](#if) | conditional | `composer.if('authenticate', 'success', 'failure')` | | [`let`](#let) | variable declarations | `composer.let({ count: 3, message: 'hello' }, ...)` | | [`literal` or `value`](#literal) | constant value | `composer.literal({ message: 'Hello, World!' })` | +| [`map`](#map) | parallel map | `composer.map('validate', 'compute')` | | [`mask`](#mask) | variable hiding | `composer.let({ n }, composer.while(_ => n-- > 0, composer.mask(composition)))` | | [`merge`](#merge) | data augmentation | `composer.merge('hash')` | +| [`parallel` or `par`](#parallel) | parallel composition | `composer.parallel('compress', 'hash')` | | [`repeat`](#repeat) | counted loop | `composer.repeat(3, 'hello')` | | [`retain` and `retain_catch`](#retain) | persistence | `composer.retain('validateInput')` | | [`retry`](#retry) | error recovery | `composer.retry(3, 'connect')` | @@ -425,3 +428,70 @@ composer.seq(composer.retain(composition_1, composition_2, ...), ({ params, resu compositions asynchronously. It invokes the sequence but does not wait for it to execute. It immediately returns a dictionary that includes a field named `activationId` with the activation id for the sequence invocation. + +The spawned sequence operates on a copy of the execution context for the parent +composition. Variables declared in the parent are defined for the child and are +initialized with the parent values at the time of the `async`. But mutations or +later declarations in the parent are not visible in the child and vice versa. + +## Parallel + +Parallel combinators require access to a Redis instance as discussed +[here](../README.md#parallel-compositions-with-redis). + +`composer.parallel(composition_1, composition_2, ...)` and its synonymous +`composer.par(composition_1, composition_2, ...)` invoke a series of +compositions (possibly empty) in parallel. + +This combinator runs _composition_1_, _composition_2_, ... in parallel and waits +for all of these compositions to complete. + +The input parameter object for the composition is the input parameter object for +every branch in the composition. The output parameter object for the composition +has a single field named `value` of type array. The elements of the array are +the output parameter objects for the branches in order. + +The `composer.let` variables in scope at the `parallel` combinator are in scope +in the branches. But each branch has its own copy of the execution context. +Variable mutations in one branch are not reflected in other branches or in the +parent composition. + +## Map + +Parallel combinators require access to a Redis instance as discussed +[here](../README.md#parallel-compositions-with-redis). + +`composer.map(composition_1, composition_2, ...)` makes multiple parallel +invocations of a sequence of compositions. + +The input parameter object for the `map` combinator should include an array of +named _value_. The `map` combinator spawns one sequence for each element of this +array. The input parameter object for the nth instance of the sequence is the +nth array element if it is a dictionary or an object with a single field named +`value` with the nth array element as the field value. Fields on the input +parameter object other than the `value` field are discarded. These sequences run +in parallel. The `map` combinator waits for all the sequences to complete. The +output parameter object for the composition has a single field named `value` of +type array. The elements of the array are the output parameter objects for the +branches in order. + +The `composer.let` variables in scope at the `map` combinator are in scope in +the branches. But each branch has its own copy of the execution context. +Variable mutations in one branch are not reflected in other branches or in the +parent composition. + +## Dynamic + +`composer.dynamic()` invokes an action specified by means of the input parameter +object. + +The input parameter object for the `dynamic` combinator must be a dictionary +including the following three fields: +- a field `type` with string value `"action"`, +- a field `name` of type string, +- a field `params` of type dictionary. +Other fields of the input parameter object are ignored. + +The `dynamic` combinator invokes the action named _name_ with the input +parameter object _params_. The output parameter object for the composition is +the output parameter object of the action invocation. diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index 045d248..342b4f6 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -25,13 +25,15 @@ _compositions_. An example composition is described in ## Control flow -Compositions can express the control flow of typical a sequential imperative -programming language: sequences, conditionals, loops, structured error handling. -This control flow is specified using _combinator_ methods such as: +Compositions can express the control flow of typical imperative programming +language: sequences, conditionals, loops, structured error handling. This +control flow is specified using _combinator_ methods such as: - `composer.sequence(firstAction, secondAction)` - `composer.if(conditionAction, consequentAction, alternateAction)` - `composer.try(bodyAction, handlerAction)` +Parallel constructs are also available. + Combinators are described in [COMBINATORS.md](COMBINATORS.md). ## Composition objects diff --git a/test/composer.js b/test/composer.js index eca428d..ce0fc0c 100644 --- a/test/composer.js +++ b/test/composer.js @@ -414,4 +414,20 @@ describe('composer', function () { describe('composer.merge', function () { check('merge') }) + + describe('composer.parallel', function () { + check('parallel') + }) + + describe('composer.par', function () { + check('par') + }) + + describe('composer.map', function () { + check('map') + }) + + describe('composer.dynamic', function () { + check('dynamic', 0) + }) }) diff --git a/test/conductor.js b/test/conductor.js index da3324d..90b936e 100644 --- a/test/conductor.js +++ b/test/conductor.js @@ -33,12 +33,17 @@ const invoke = (composition, params = {}, blocking = true) => wsk.compositions.d .then(() => wsk.actions.invoke({ name, params, blocking })) .then(activation => activation.response.success ? activation : Promise.reject(Object.assign(new Error(), { error: activation }))) +// redis configuration +const redis = process.env.REDIS ? { uri: process.env.REDIS } : false +if (process.env.REDIS && process.env.REDIS_CA) redis.ca = process.env.REDIS_CA + describe('composer', function () { let n, x, y // dummy variables this.timeout(60000) before('deploy test actions', function () { + if (!redis) console.error('------------------------------------------------\nMissing redis configuration, skipping some tests\n------------------------------------------------') return define({ name: 'echo', action: 'const main = x=>x' }) .then(() => define({ name: 'DivideByTwo', action: 'function main({n}) { return { n: n / 2 } }' })) .then(() => define({ name: 'TripleAndIncrement', action: 'function main({n}) { return { n: n * 3 + 1 } }' })) @@ -114,6 +119,28 @@ describe('composer', function () { }) }) + describe('dynamic', function () { + it('dynamic action invocation', function () { + return invoke(composer.dynamic(), { type: 'action', name: 'DivideByTwo', params: { n: 42 } }).then(activation => assert.deepStrictEqual(activation.response.result, { n: 21 })) + }) + + it('missing type', function () { + return invoke(composer.dynamic(), { name: 'DivideByTwo', params: { n: 42 } }).then(() => assert.fail(), activation => assert.ok(activation.error.response.result.error)) + }) + + it('invalid type', function () { + return invoke(composer.dynamic(), { type: 42, name: 'DivideByTwo', params: { n: 42 } }).then(() => assert.fail(), activation => assert.ok(activation.error.response.result.error)) + }) + + it('missing name', function () { + return invoke(composer.dynamic(), { type: 'action', params: { n: 42 } }).then(() => assert.fail(), activation => assert.ok(activation.error.response.result.error)) + }) + + it('missing params', function () { + return invoke(composer.dynamic(), { type: 'action', name: 'DivideByTwo' }).then(() => assert.fail(), activation => assert.ok(activation.error.response.result.error)) + }) + }) + describe('literals', function () { it('true', function () { return invoke(composer.literal(true)).then(activation => assert.deepStrictEqual(activation.response.result, { value: true })) @@ -291,6 +318,24 @@ describe('composer', function () { }) }) + describe('parallel', function () { + const test = redis ? it : it.skip + test('parallel', function () { + return invoke(composer.parallel('TripleAndIncrement', 'DivideByTwo'), { n: 42, $composer: { redis } }) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: [{ n: 127 }, { n: 21 }] })) + }) + + test('par', function () { + return invoke(composer.par('DivideByTwo', 'TripleAndIncrement', 'isEven'), { n: 42, $composer: { redis } }) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: [{ n: 21 }, { n: 127 }, { value: true }] })) + }) + + test('map', function () { + return invoke(composer.map('TripleAndIncrement', 'DivideByTwo'), { value: [{ n: 3 }, { n: 5 }, { n: 7 }], $composer: { redis } }) + .then(activation => assert.deepStrictEqual(activation.response.result, { value: [{ n: 5 }, { n: 8 }, { n: 11 }] })) + }) + }) + describe('if', function () { it('condition = true', function () { return invoke(composer.if('isEven', 'DivideByTwo', 'TripleAndIncrement'), { n: 4 }) diff --git a/travis/setup.sh b/travis/setup.sh index e7bdd1b..82ebf3f 100755 --- a/travis/setup.sh +++ b/travis/setup.sh @@ -50,6 +50,9 @@ $ANSIBLE_CMD initdb.yml $ANSIBLE_CMD wipe.yml $ANSIBLE_CMD openwhisk.yml -e cli_installation_mode=remote -e limit_invocations_per_minute=600 +# Deploy Redis +docker run -d -p 6379:6379 --name redis redis:4.0 + # Log configuration docker images docker ps From 5ffef65d593642a760a7c2bb1f3087b511067c09 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 11 Feb 2019 10:17:53 -0500 Subject: [PATCH 50/94] Updated doc to account for feedback on PR #16 (#20) --- README.md | 4 ++-- docs/COMBINATORS.md | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9fa0af1..238b23e 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Compositions compose actions using [combinator](docs/COMBINATORS.md) methods. These methods implement the typical control-flow constructs of an imperative programming language. This example composition composes three actions named `authenticate`, `success`, and `failure` using the `composer.if` combinator, -which implements the usual conditional construct. It take three actions (or +which implements the usual conditional construct. It takes three actions (or compositions) as parameters. It invokes the first one and, depending on the result of this invocation, invokes either the second or third action. @@ -168,7 +168,7 @@ invocation time or earlier by means of default parameters or package bindings. The required parameter is named `$composer`. It is a dictionary with a `redis` field of type dictionary. The `redis` dictionary specifies the `uri` for the Redis instance and optionally a certificate as a base64-encoded string to enable -tls connections. Hence, the input parameter object for our order-processing +TLS connections. Hence, the input parameter object for our order-processing example should be: ```json { diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index d3d9cd2..9a157d2 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -451,6 +451,13 @@ every branch in the composition. The output parameter object for the composition has a single field named `value` of type array. The elements of the array are the output parameter objects for the branches in order. +Error results from the branches are included in the array of results like normal +results. In particular, an error result from a branch does not interrupt the +parallel execution of the other branches. Moreover, since errors results are +nested inside an output parameter object with a single `value` field, an error +from a branch does not trigger the execution of the current error handler. The +caller should walk the array and decide if and how to handle errors. + The `composer.let` variables in scope at the `parallel` combinator are in scope in the branches. But each branch has its own copy of the execution context. Variable mutations in one branch are not reflected in other branches or in the @@ -475,6 +482,13 @@ output parameter object for the composition has a single field named `value` of type array. The elements of the array are the output parameter objects for the branches in order. +Error results from the branches are included in the array of results like normal +results. In particular, an error result from a branch does not interrupt the +parallel execution of the other branches. Moreover, since errors results are +nested inside an output parameter object with a single `value` field, an error +from a branch does not trigger the execution of the current error handler. The +caller should walk the array and decide if and how to handle errors. + The `composer.let` variables in scope at the `map` combinator are in scope in the branches. But each branch has its own copy of the execution context. Variable mutations in one branch are not reflected in other branches or in the From 7dca6e6799a8c79fb5336ef85d8fa8bc9d3e210d Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 11 Feb 2019 16:26:00 -0500 Subject: [PATCH 51/94] Proper handling of ssl certificate validation (#21) --- .travis.yml | 2 +- README.md | 21 +++++++++++++++++++++ conductor.js | 8 +++++--- docs/COMBINATORS.md | 9 +++++++++ docs/COMMANDS.md | 4 ++++ package.json | 2 +- test/conductor.js | 13 ++++++++----- 7 files changed, 49 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 051e253..d3a6dcc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ services: - docker env: global: - - IGNORE_CERTS=true + - __OW_IGNORE_CERTS=true - REDIS=redis://172.17.0.1:6379 before_install: - ./travis/scancode.sh diff --git a/README.md b/README.md index 238b23e..f12aadb 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,27 @@ The intent is to store intermediate results in Redis as the parallel composition is progressing. Redis entries are deleted after completion and, as an added safety, expire after twenty-four hours. +# OpenWhisk SSL configuration + +Additional configuration is required when using an OpenWhisk instance with +self-signed certificates to disable SSL certificate validation. The input +parameter object must contain a parameter of type dictionary named `$composer`. +This dictionary must contain a dictionary named `openwhisk`. The `openwhisk` +dictionary must contain a field named `ignore_certs` with value `true`: +```json +{ + "$composer": { + "openwhisk": { + "ignore_certs": true + } + }, + ... +} +``` + +This explicit SSL configuration is currently only necessary when using parallel +combinators or the `async` combinator. + # Disclaimer Apache OpenWhisk Composer is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. diff --git a/conductor.js b/conductor.js index ac595a4..fab979b 100644 --- a/conductor.js +++ b/conductor.js @@ -41,6 +41,7 @@ module.exports = function (options) { // try to extract apihost and key first from whisk property file file and then from process.env let apihost let apikey + let ignorecerts try { const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') @@ -60,8 +61,9 @@ module.exports = function (options) { if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST if (process.env.__OW_API_KEY) apikey = process.env.__OW_API_KEY + if (process.env.__OW_IGNORE_CERTS) ignorecerts = process.env.__OW_IGNORE_CERTS - const wsk = openwhisk(Object.assign({ apihost, api_key: apikey }, options)) + const wsk = openwhisk(Object.assign({ apihost, api_key: apikey, ignore_certs: ignorecerts }, options)) wsk.compositions = new Compositions(wsk) return wsk } @@ -134,7 +136,7 @@ function main (composition) { const stack = [{ marker: true }].concat(p.s.stack) const barrierId = uuid() console.log(`barrierId: ${barrierId}, spawning: ${array.length}`) - if (!wsk) wsk = openwhisk({ ignore_certs: true }) + if (!wsk) wsk = openwhisk(p.s.openwhisk) if (!db) db = createRedisClient(p) return db.lpushAsync(live(barrierId), 42) // push marker .then(() => db.expireAsync(live(barrierId), expiration)) @@ -296,7 +298,7 @@ function main (composition) { async ({ p, node, index, inspect, step }) { p.params.$composer = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack), redis: p.s.redis } p.s.state = index + node.return - if (!wsk) wsk = openwhisk({ ignore_certs: true }) + if (!wsk) wsk = openwhisk(p.s.openwhisk) return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) .then(response => ({ method: 'async', activationId: response.activationId, sessionId: p.s.session }), error => { console.error(error) // invoke failed diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index 9a157d2..336d7cc 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -424,6 +424,9 @@ composer.seq(composer.retain(composition_1, composition_2, ...), ({ params, resu ## Async +The `async` combinator may require an SSL configuration as discussed +[here](../README.md#openwhisk-ssl-configuration). + `composer.async(composition_1, composition_2, ...)` runs a sequence of compositions asynchronously. It invokes the sequence but does not wait for it to execute. It immediately returns a dictionary that includes a field named @@ -439,6 +442,9 @@ later declarations in the parent are not visible in the child and vice versa. Parallel combinators require access to a Redis instance as discussed [here](../README.md#parallel-compositions-with-redis). +Parallel combinators may require an SSL configuration as discussed +[here](../README.md#openwhisk-ssl-configuration). + `composer.parallel(composition_1, composition_2, ...)` and its synonymous `composer.par(composition_1, composition_2, ...)` invoke a series of compositions (possibly empty) in parallel. @@ -468,6 +474,9 @@ parent composition. Parallel combinators require access to a Redis instance as discussed [here](../README.md#parallel-compositions-with-redis). +Parallel combinators may require an SSL configuration as discussed +[here](../README.md#openwhisk-ssl-configuration). + `composer.map(composition_1, composition_2, ...)` makes multiple parallel invocations of a sequence of compositions. diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index dabe630..db45108 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -110,6 +110,10 @@ If the `--apihost` flag is absent, the environment variable `__OW_API_HOST` is used in its place. If neither is available, the `deploy` command extracts the `APIHOST` key from the whisk property file for the current user. +If the `--insecure` flag is set or the environment variable `__OW_IGNORE_CERTS` +is set to `true`, the `deploy` command ignores SSL certificates validation +failures. + If the `--auth` flag is absent, the environment variable `__OW_API_KEY` is used in its place. If neither is available, the `deploy` command extracts the `AUTH` key from the whisk property file for the current user. diff --git a/package.json b/package.json index 058f1f0..4069188 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ ], "dependencies": { "minimist": "^1.2.0", - "openwhisk": "^3.11.0", + "openwhisk": "^3.18.0", "terser": "^3.8.2" }, "devDependencies": { diff --git a/test/conductor.js b/test/conductor.js index 90b936e..157d885 100644 --- a/test/conductor.js +++ b/test/conductor.js @@ -23,7 +23,7 @@ const assert = require('assert') const composer = require('../composer') const conductor = require('../conductor') const name = 'TestAction' -const wsk = conductor({ ignore_certs: process.env.IGNORE_CERTS && process.env.IGNORE_CERTS !== 'false' && process.env.IGNORE_CERTS !== '0' }) +const wsk = conductor() // deploy action const define = action => wsk.actions.delete(action.name).catch(() => { }).then(() => wsk.actions.create(action)) @@ -37,6 +37,9 @@ const invoke = (composition, params = {}, blocking = true) => wsk.compositions.d const redis = process.env.REDIS ? { uri: process.env.REDIS } : false if (process.env.REDIS && process.env.REDIS_CA) redis.ca = process.env.REDIS_CA +// openwhisk configuration +const openwhisk = process.env.__OW_IGNORE_CERTS ? { ignore_certs: true } : {} + describe('composer', function () { let n, x, y // dummy variables @@ -63,7 +66,7 @@ describe('composer', function () { }) it('action must return activationId', function () { - return invoke(composer.async('isNotOne'), { n: 1 }).then(activation => assert.ok(activation.response.result.activationId)) + return invoke(composer.async('isNotOne'), { n: 1, $composer: { openwhisk } }).then(activation => assert.ok(activation.response.result.activationId)) }) it('action name must parse to fully qualified', function () { @@ -321,17 +324,17 @@ describe('composer', function () { describe('parallel', function () { const test = redis ? it : it.skip test('parallel', function () { - return invoke(composer.parallel('TripleAndIncrement', 'DivideByTwo'), { n: 42, $composer: { redis } }) + return invoke(composer.parallel('TripleAndIncrement', 'DivideByTwo'), { n: 42, $composer: { redis, openwhisk } }) .then(activation => assert.deepStrictEqual(activation.response.result, { value: [{ n: 127 }, { n: 21 }] })) }) test('par', function () { - return invoke(composer.par('DivideByTwo', 'TripleAndIncrement', 'isEven'), { n: 42, $composer: { redis } }) + return invoke(composer.par('DivideByTwo', 'TripleAndIncrement', 'isEven'), { n: 42, $composer: { redis, openwhisk } }) .then(activation => assert.deepStrictEqual(activation.response.result, { value: [{ n: 21 }, { n: 127 }, { value: true }] })) }) test('map', function () { - return invoke(composer.map('TripleAndIncrement', 'DivideByTwo'), { value: [{ n: 3 }, { n: 5 }, { n: 7 }], $composer: { redis } }) + return invoke(composer.map('TripleAndIncrement', 'DivideByTwo'), { value: [{ n: 3 }, { n: 5 }, { n: 7 }], $composer: { redis, openwhisk } }) .then(activation => assert.deepStrictEqual(activation.response.result, { value: [{ n: 5 }, { n: 8 }, { n: 11 }] })) }) }) From ba07fea1d7e3f73558481e80f8174912bf5549ee Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 12 Feb 2019 08:11:37 -0500 Subject: [PATCH 52/94] Add method and command to export the generated conductor action code (#22) --- bin/compose.js | 12 ++++++-- bin/deploy.js | 4 +-- client.js | 72 ++++++++++++++++++++++++++++++++++++++++++++ conductor.js | 52 ++------------------------------ docs/COMMANDS.md | 4 +++ docs/COMPOSITIONS.md | 10 ++++++ docs/README.md | 5 ++- package.json | 1 + test/conductor.js | 3 +- 9 files changed, 105 insertions(+), 58 deletions(-) create mode 100644 client.js diff --git a/bin/compose.js b/bin/compose.js index b581700..e9b95ef 100755 --- a/bin/compose.js +++ b/bin/compose.js @@ -17,13 +17,14 @@ 'use strict' const composer = require('../composer') +const conductor = require('../conductor') const json = require('../package.json') const minimist = require('minimist') const Module = require('module') const path = require('path') const argv = minimist(process.argv.slice(2), { - boolean: ['version', 'ast'], + boolean: ['version', 'ast', 'js'], alias: { version: 'v' } }) @@ -51,6 +52,7 @@ if (argv._.length !== 1 || path.extname(argv._[0]) !== '.js') { console.error(' compose composition.js [flags]') console.error('Flags:') console.error(' --ast only output the ast for the composition') + console.error(' --js output the conductor action code for the composition') console.error(' -v, --version output the composer version') process.exit(1) } @@ -64,5 +66,9 @@ try { console.error(error) process.exit(422 - 256) // Unprocessable Entity } -if (argv.ast) composition = composition.ast -console.log(JSON.stringify(composition, null, 4)) +if (argv.js) { + console.log(conductor.generate(composition).action.exec.code) +} else { + if (argv.ast) composition = composition.ast + console.log(JSON.stringify(composition, null, 4)) +} diff --git a/bin/deploy.js b/bin/deploy.js index ec1343c..433bdc1 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -17,7 +17,7 @@ 'use strict' const composer = require('../composer') -const conductor = require('../conductor') +const client = require('../client') const fqn = require('../fqn') const fs = require('fs') const json = require('../package.json') @@ -85,7 +85,7 @@ try { console.error(error) process.exit(400 - 256) // Bad Request } -conductor(options).compositions.deploy(composition, argv.overwrite) +client(options).compositions.deploy(composition, argv.overwrite) .then(actions => { const names = actions.map(action => action.name) console.log(`ok: created action${actions.length > 1 ? 's' : ''} ${names}`) diff --git a/client.js b/client.js new file mode 100644 index 0000000..82fbae1 --- /dev/null +++ b/client.js @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* eslint no-eval: 0 */ + +'use strict' + +const conductor = require('./conductor') +const fs = require('fs') +const openwhisk = require('openwhisk') +const os = require('os') +const path = require('path') + +// return enhanced openwhisk client capable of deploying compositions +module.exports = function (options) { + // try to extract apihost and key first from whisk property file file and then from process.env + let apihost + let apikey + let ignorecerts + + try { + const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') + const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') + + for (let line of lines) { + let parts = line.trim().split('=') + if (parts.length === 2) { + if (parts[0] === 'APIHOST') { + apihost = parts[1] + } else if (parts[0] === 'AUTH') { + apikey = parts[1] + } + } + } + } catch (error) { } + + if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST + if (process.env.__OW_API_KEY) apikey = process.env.__OW_API_KEY + if (process.env.__OW_IGNORE_CERTS) ignorecerts = process.env.__OW_IGNORE_CERTS + + const wsk = openwhisk(Object.assign({ apihost, api_key: apikey, ignore_certs: ignorecerts }, options)) + wsk.compositions = new Compositions(wsk) + return wsk +} + +// management class for compositions +class Compositions { + constructor (wsk) { + this.actions = wsk.actions + } + + deploy (composition, overwrite) { + const actions = (composition.actions || []).concat(conductor.generate(composition)) + return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) + .then(() => this.actions.create(action)), Promise.resolve()) + .then(() => actions) + } +} diff --git a/conductor.js b/conductor.js index fab979b..0c22f14 100644 --- a/conductor.js +++ b/conductor.js @@ -19,68 +19,20 @@ 'use strict' -const fs = require('fs') const { minify } = require('terser') -const openwhisk = require('openwhisk') -const os = require('os') -const path = require('path') // read conductor version number const version = require('./package.json').version // synthesize conductor action code from composition -function synthesize ({ name, composition, ast, version: composer, annotations = [] }) { +function generate ({ name, composition, ast, version: composer, annotations = [] }) { const code = `// generated by composer v${composer} and conductor v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n` + minify(`const main=(${main})(composition)`, { output: { max_line_len: 127 } }).code annotations = annotations.concat([{ key: 'conductor', value: ast }, { key: 'composerVersion', value: composer }, { key: 'conductorVersion', value: version }]) return { name, action: { exec: { kind: 'nodejs:default', code }, annotations } } } -// return enhanced openwhisk client capable of deploying compositions -module.exports = function (options) { - // try to extract apihost and key first from whisk property file file and then from process.env - let apihost - let apikey - let ignorecerts - - try { - const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') - const lines = fs.readFileSync(wskpropsPath, { encoding: 'utf8' }).split('\n') - - for (let line of lines) { - let parts = line.trim().split('=') - if (parts.length === 2) { - if (parts[0] === 'APIHOST') { - apihost = parts[1] - } else if (parts[0] === 'AUTH') { - apikey = parts[1] - } - } - } - } catch (error) { } - - if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST - if (process.env.__OW_API_KEY) apikey = process.env.__OW_API_KEY - if (process.env.__OW_IGNORE_CERTS) ignorecerts = process.env.__OW_IGNORE_CERTS - - const wsk = openwhisk(Object.assign({ apihost, api_key: apikey, ignore_certs: ignorecerts }, options)) - wsk.compositions = new Compositions(wsk) - return wsk -} - -// management class for compositions -class Compositions { - constructor (wsk) { - this.actions = wsk.actions - } - - deploy (composition, overwrite) { - const actions = (composition.actions || []).concat(synthesize(composition)) - return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) - .then(() => this.actions.create(action)), Promise.resolve()) - .then(() => actions) - } -} +module.exports = { generate } // runtime code function main (composition) { diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index db45108..adfb02e 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -39,6 +39,7 @@ Usage: compose composition.js [flags] Flags: --ast only output the ast for the composition + --js output the conductor action code for the composition -v, --version output the composer version ``` The `compose` command takes a Javascript module that exports a composition @@ -50,6 +51,9 @@ compose demo.js > demo.json If the `--ast` option is specified, the `compose` command only outputs a JSON representation of the Abstract Syntax Tree for the composition. +If the `--js` option is specified, the `compose` command outputs the conductor +action code for the composition. + # Deploy ``` diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index 342b4f6..7f72223 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -133,3 +133,13 @@ default parameters, limits, blocking invocation, web export. Execution and [limits](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md#limits) of compositions follow from conductor actions. + +The conductor action code for a composition may be obtained by means of the +`generate` method of the `conductor` module or using the `compose` command with +the `--js` flag. The conductor action code may be deployed using, e.g., the +OpenWhisk CLI. +``` +compose demo.js --js > demo-conductor.js +wsk action create demo demo-conductor.js -a conductor true +``` +The `conductor` annotation must be set on conductor actions. diff --git a/docs/README.md b/docs/README.md index 1abced5..e29a579 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,7 +20,10 @@ # Composer Package The Composer package consists of: -* the [composer](../composer.js) Node.js module for authoring compositions, +* the [composer](../composer.js) module for authoring compositions, +* the [conductor](../conductor.js) module for generating conductor actions from + compositions, +* the [client](../client.js) module for deploying compositions to openwhisk, * the [compose](../bin/compose.js) and [deploy](../bin/deploy.js) commands for managing compositions from the command line. diff --git a/package.json b/package.json index 4069188..d8989eb 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ }, "files": [ "bin/", + "client.js", "composer.js", "conductor.js", "fqn.js", diff --git a/test/conductor.js b/test/conductor.js index 157d885..9e89f01 100644 --- a/test/conductor.js +++ b/test/conductor.js @@ -21,9 +21,8 @@ const assert = require('assert') const composer = require('../composer') -const conductor = require('../conductor') +const wsk = require('../client')() const name = 'TestAction' -const wsk = conductor() // deploy action const define = action => wsk.actions.delete(action.name).catch(() => { }).then(() => wsk.actions.create(action)) From ff01897040158902b89d011b21ed8e9a5849748f Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 12 Feb 2019 12:07:57 -0500 Subject: [PATCH 53/94] Propagate OpenWhisk configuration to subcompositions (#23) --- conductor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conductor.js b/conductor.js index 0c22f14..2cf9845 100644 --- a/conductor.js +++ b/conductor.js @@ -96,6 +96,7 @@ function main (composition) { const params = it(saved, item) // obtain combinator-specific params for branch invocation params.$composer.stack = stack params.$composer.redis = p.s.redis + params.$composer.openwhisk = p.s.openwhisk params.$composer.join = { barrierId, position, count: array.length } return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params }) // invoke branch .then(({ activationId }) => { console.log(`barrierId: ${barrierId}, spawned position: ${position} with activationId: ${activationId}`) }) @@ -248,7 +249,7 @@ function main (composition) { }, async ({ p, node, index, inspect, step }) { - p.params.$composer = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack), redis: p.s.redis } + p.params.$composer = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack), redis: p.s.redis, openwhisk: p.s.openwhisk } p.s.state = index + node.return if (!wsk) wsk = openwhisk(p.s.openwhisk) return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) From 1d9a23989df540faa5c22fbc09ca6eec5ba3b6d3 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 12 Feb 2019 13:03:21 -0500 Subject: [PATCH 54/94] Add debug flag to generate method and deploy command (#24) --- bin/deploy.js | 5 +++-- client.js | 4 ++-- conductor.js | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bin/deploy.js b/bin/deploy.js index 433bdc1..c2b2519 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -25,7 +25,7 @@ const minimist = require('minimist') const path = require('path') const argv = minimist(process.argv.slice(2), { - string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file'], + string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file', 'debug'], boolean: ['insecure', 'version', 'overwrite'], alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w' } }) @@ -46,6 +46,7 @@ if (argv._.length !== 2 || path.extname(argv._[1]) !== '.json') { console.error(' -u, --auth KEY authorization KEY') console.error(' -v, --version output the composer version') console.error(' -w, --overwrite overwrite actions if already defined') + console.error(' --debug LIST comma-separated list of debug flags') process.exit(1) } let composition @@ -85,7 +86,7 @@ try { console.error(error) process.exit(400 - 256) // Bad Request } -client(options).compositions.deploy(composition, argv.overwrite) +client(options).compositions.deploy(composition, argv.overwrite, argv.debug) .then(actions => { const names = actions.map(action => action.name) console.log(`ok: created action${actions.length > 1 ? 's' : ''} ${names}`) diff --git a/client.js b/client.js index 82fbae1..2309e62 100644 --- a/client.js +++ b/client.js @@ -63,8 +63,8 @@ class Compositions { this.actions = wsk.actions } - deploy (composition, overwrite) { - const actions = (composition.actions || []).concat(conductor.generate(composition)) + deploy (composition, overwrite, debug) { + const actions = (composition.actions || []).concat(conductor.generate(composition, debug)) return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) .then(() => this.actions.create(action)), Promise.resolve()) .then(() => actions) diff --git a/conductor.js b/conductor.js index 2cf9845..be3fb45 100644 --- a/conductor.js +++ b/conductor.js @@ -25,9 +25,10 @@ const { minify } = require('terser') const version = require('./package.json').version // synthesize conductor action code from composition -function generate ({ name, composition, ast, version: composer, annotations = [] }) { - const code = `// generated by composer v${composer} and conductor v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n` + +function generate ({ name, composition, ast, version: composer, annotations = [] }, debug) { + let code = `// generated by composer v${composer} and conductor v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n` + minify(`const main=(${main})(composition)`, { output: { max_line_len: 127 } }).code + if (debug) code = `process.env.DEBUG='${debug}'\n\n` + code annotations = annotations.concat([{ key: 'conductor', value: ast }, { key: 'composerVersion', value: composer }, { key: 'conductorVersion', value: version }]) return { name, action: { exec: { kind: 'nodejs:default', code }, annotations } } } From c58a3f6712ea562a462e8ddf69c52396b477f298 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 12 Feb 2019 16:10:53 -0500 Subject: [PATCH 55/94] Add debug setting to control needle options (#25) --- bin/compose.js | 4 +++- conductor.js | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/bin/compose.js b/bin/compose.js index e9b95ef..e426d13 100755 --- a/bin/compose.js +++ b/bin/compose.js @@ -24,6 +24,7 @@ const Module = require('module') const path = require('path') const argv = minimist(process.argv.slice(2), { + string: ['debug'], boolean: ['version', 'ast', 'js'], alias: { version: 'v' } }) @@ -54,6 +55,7 @@ if (argv._.length !== 1 || path.extname(argv._[0]) !== '.js') { console.error(' --ast only output the ast for the composition') console.error(' --js output the conductor action code for the composition') console.error(' -v, --version output the composer version') + console.error(' --debug LIST comma-separated list of debug flags (when using --js flag)') process.exit(1) } @@ -67,7 +69,7 @@ try { process.exit(422 - 256) // Unprocessable Entity } if (argv.js) { - console.log(conductor.generate(composition).action.exec.code) + console.log(conductor.generate(composition, argv.debug).action.exec.code) } else { if (argv.ast) composition = composition.ast console.log(JSON.stringify(composition, null, 4)) diff --git a/conductor.js b/conductor.js index be3fb45..90e9e18 100644 --- a/conductor.js +++ b/conductor.js @@ -76,6 +76,17 @@ function main (composition) { const isObject = obj => typeof obj === 'object' && obj !== null && !Array.isArray(obj) + const needleOptions = (/needle<([^>]*)>/.exec(process.env.DEBUG || '') || [])[1] + + function invoke (req) { + try { + if (needleOptions) req = Object.assign({}, req, JSON.parse(needleOptions)) + } catch (err) { + console.err(`Ignoring invalid needle options: ${needleOptions}`) + } + return wsk.actions.invoke(req) + } + function fork ({ p, node, index }, array, it) { const saved = p.params // save params p.s.state = index + node.return // return state @@ -99,7 +110,7 @@ function main (composition) { params.$composer.redis = p.s.redis params.$composer.openwhisk = p.s.openwhisk params.$composer.join = { barrierId, position, count: array.length } - return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params }) // invoke branch + return invoke({ name: process.env.__OW_ACTION_NAME, params }) // invoke branch .then(({ activationId }) => { console.log(`barrierId: ${barrierId}, spawned position: ${position} with activationId: ${activationId}`) }) }))).then(() => collect(p, barrierId), error => { console.error(error.body || error) @@ -253,7 +264,7 @@ function main (composition) { p.params.$composer = { state: p.s.state, stack: [{ marker: true }].concat(p.s.stack), redis: p.s.redis, openwhisk: p.s.openwhisk } p.s.state = index + node.return if (!wsk) wsk = openwhisk(p.s.openwhisk) - return wsk.actions.invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) + return invoke({ name: process.env.__OW_ACTION_NAME, params: p.params }) .then(response => ({ method: 'async', activationId: response.activationId, sessionId: p.s.session }), error => { console.error(error) // invoke failed return { error: `Async combinator failed to invoke composition at AST node root${node.parent} (see log for details)` } From fc85802f8173d4991aa69998a18d6d0a8b39ccce Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 12 Feb 2019 19:17:43 -0500 Subject: [PATCH 56/94] Bump version number. Add changelog. Document debug flag. (#26) --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ docs/COMMANDS.md | 14 ++++++++++++++ package.json | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..04b9901 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,38 @@ + + +# Changelog + +## v0.10.0 + +* Add new [parallel](docs/COMBINATORS.md#parallel) and + [map](docs/COMBINATORS.md#map) combinators to run compositions in parallel + using a [Redis instance](README.md#parallel-compositions-with-redis) to store + intermediate results. +* Add [dynamic](docs/COMBINATORS.md#dynamic) combinator to invoke an action with + a name chosen at run time. +* Add [option](README.md#openwhisk-ssl-configuration) to bypass TLS certificate + validation failures (off by default). +* Add [API](docs/COMPOSITIONS.md#conductor-actions) to generate the conductor + action code from a composition. +* Add [control](docs/COMMANDS.md#debug-flag) over `needle` options and logging. + +## v0.9.0 + +* Initial release as an Apache Incubator project. diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index adfb02e..ca74c80 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -41,6 +41,7 @@ Flags: --ast only output the ast for the composition --js output the conductor action code for the composition -v, --version output the composer version + --debug LIST comma-separated list of debug flags (when using --js flag) ``` The `compose` command takes a Javascript module that exports a composition object (for example [demo.js](../samples/demo.js)) and compiles this object to a @@ -70,6 +71,7 @@ Flags: -u, --auth KEY authorization KEY -v, --version output the composer version -w, --overwrite overwrite actions if already defined + --debug LIST comma-separated list of debug flags ``` The `deploy` command deploys a JSON-encoded composition with the given name. ``` @@ -124,3 +126,15 @@ key from the whisk property file for the current user. The default path for the whisk property file is `$HOME/.wskprops`. It can be altered by setting the `WSK_CONFIG_FILE` environment variable. + +### Debug flag + +The `--debug` flag takes a comma-separated list of debugging options. + +The `needle` option activates `needle` verbose logging. + +The `needle` option enables overriding `needle` default parameters. +The specified `defaults` must be be a json dictionary, as for example in: +``` +deploy demo demo.json --debug needle<{"connection":"keep-alive","open_timeout":60000}> +``` diff --git a/package.json b/package.json index d8989eb..11f9102 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openwhisk-composer", - "version": "0.9.0", + "version": "0.10.0", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", "homepage": "https://github.com/apache/incubator-openwhisk-composer", "main": "composer.js", From 244d1a3a0c24bc7ea1cf7d80d7db2e0c1e235b83 Mon Sep 17 00:00:00 2001 From: David Grove Date: Sat, 16 Feb 2019 10:25:51 -0500 Subject: [PATCH 57/94] bump year in copyright notice (#27) --- NOTICE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOTICE.txt b/NOTICE.txt index e6d7bdb..b3b5bb1 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Apache OpenWhisk -Copyright 2016-2018 The Apache Software Foundation +Copyright 2016-2019 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). From 5d4ac0a616aed1994b5e89e1e2d3e032292f35f0 Mon Sep 17 00:00:00 2001 From: David Grove Date: Sat, 16 Feb 2019 10:57:19 -0500 Subject: [PATCH 58/94] add slackbot notification (#28) --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index d3a6dcc..7559d5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,14 @@ node_js: - 6 services: - docker + +notifications: + email: false + webhooks: + urls: + # travis2slack webhook to enable DMs on openwhisk-team.slack.com to PR authors with TravisCI results + secure: e87H+wvZkwk6LWi4BDNQY1JncgPJ88oOAIJksIl/4DgxjIiX/gak0gLZYfTIqmLSG9ips86qdsSm1d/qMd7EPlLrUcF/PPx5uiwjXbO3aDbgfA/kVkJkQtWFhVhAckmWNJbyJwQfrcFqguDdF+iBD16nMZBGljRSLWuz+gBOsb9gOvLM5wg5m9nZICsUgsdX/Mu4Ib4TdYAW5Sf+evp/5BhyvrycQ6UA+NCAGhQmzI/Tnf8X4zsz8q6OZxcHT8L5b2ucxxGqleplaMzBlir3ADQ7F8QWEIFj4aVmW7VHe2Bloi4g/03zb4nFFn+cFbw4LTZqtHAOZ5fzIMWmKrWWnRi5tOdea1UimWqZ33S2H/M0R6YYIlhdvZXGSAPgGEyfd/BsLtXFah4J8V3odJOHf2QTxPWLucJj3Sjhc9DDqXWo6d+bRP58VfS2HsRDb2pfC2zLCoUa8OMjqPdLVXIH6qbaCVX20KKkz3YNS1xsWmIRvnYaKOAFx4KQDX6o/UoER7gwEJOEgbmCqGIpvAaOsP55N7mGCfOK4m2J1kONsGHUbL2/13hA2AI66P6QS8ohb4JXS5d6F9JZljl/U95qOgT2avD6BtzpUGnMXL5pbUfNXFp+GBneBwzaEE22q6OPVd7PVrHmPFH2tzp3/fmkceeoxrDA45zyaZMevO9gcvM= + env: global: - __OW_IGNORE_CERTS=true From 06859394e05009002df66fa0bc4cc377166cfc2c Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 19 Mar 2019 18:05:54 -0400 Subject: [PATCH 59/94] Synthetize provide-api-key annotation (#31) --- conductor.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/conductor.js b/conductor.js index 90e9e18..9d73fe6 100644 --- a/conductor.js +++ b/conductor.js @@ -29,7 +29,11 @@ function generate ({ name, composition, ast, version: composer, annotations = [] let code = `// generated by composer v${composer} and conductor v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n` + minify(`const main=(${main})(composition)`, { output: { max_line_len: 127 } }).code if (debug) code = `process.env.DEBUG='${debug}'\n\n` + code - annotations = annotations.concat([{ key: 'conductor', value: ast }, { key: 'composerVersion', value: composer }, { key: 'conductorVersion', value: version }]) + annotations = annotations.concat([ + { key: 'conductor', value: ast }, + { key: 'composerVersion', value: composer }, + { key: 'conductorVersion', value: version }, + { key: 'provide-api-key', value: true }]) return { name, action: { exec: { kind: 'nodejs:default', code }, annotations } } } From 1ced1ea3893857101f6b29006030594caebe17c3 Mon Sep 17 00:00:00 2001 From: Lars Andersson Date: Tue, 19 Mar 2019 23:15:01 +0100 Subject: [PATCH 60/94] Update README.md to reflect new output from `wsk activation list` (#33) * Updated documentation to reflect new output from wsk activation list * Fixed scancode issue --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f12aadb..37626d3 100644 --- a/README.md +++ b/README.md @@ -103,12 +103,12 @@ OpenWhisk CLI: wsk action invoke demo -p password passw0rd ``` ``` -ok: invoked /_/demo with id 4f91f9ed0d874aaa91f9ed0d87baaa07 +ok: invoked /_/demo with id 09ca3c7f8b68489c8a3c7f8b68b89cdc ``` The result of this invocation is the result of the last action in the composition, in this case the `failure` action since the password in incorrect: ``` -wsk activation result 4f91f9ed0d874aaa91f9ed0d87baaa07 +wsk activation result 09ca3c7f8b68489c8a3c7f8b68b89cdc ``` ```json { @@ -121,20 +121,21 @@ This invocation creates a trace, i.e., a series of activation records: ``` wsk activation list ``` -``` -activations -fd89b99a90a1462a89b99a90a1d62a8e demo -eaec119273d94087ac119273d90087d0 failure -3624ad829d4044afa4ad829d40e4af60 demo -a1f58ade9b1e4c26b58ade9b1e4c2614 authenticate -3624ad829d4044afa4ad829d40e4af60 demo -4f91f9ed0d874aaa91f9ed0d87baaa07 demo -``` -The entry with the earliest start time (`4f91f9ed0d874aaa91f9ed0d87baaa07`) +

+Datetime            Activation ID                    Kind     Start Duration   Status  Entity
+2019-03-15 16:43:22 e6bea73bf75f4eb7bea73bf75fdeb703 nodejs:6 warm  1ms        success guest/demo:0.0.1
+2019-03-15 16:43:21 7efb6b7354c3472cbb6b7354c3272c98 nodejs:6 cold  31ms       success guest/failure:0.0.1
+2019-03-15 16:43:21 377cd080f0674e9cbcd080f0679e9c1d nodejs:6 warm  2ms        success guest/demo:0.0.1
+2019-03-15 16:43:20 5dceeccbdc7a4caf8eeccbdc7a9caf18 nodejs:6 cold  29ms       success guest/authenticate:0.0.1
+2019-03-15 16:43:19 66355a1f012d4ea2b55a1f012dcea264 nodejs:6 cold  104ms      success guest/demo:0.0.1
+2019-03-15 16:43:19 09ca3c7f8b68489c8a3c7f8b68b89cdc sequence warm  3.144s     success guest/demo:0.0.1
+
+ +The entry with the earliest start time (`09ca3c7f8b68489c8a3c7f8b68b89cdc`) summarizes the invocation of the composition while other entries record later activations caused by the composition invocation. There is one entry for each -invocation of a composed action (`a1f58ade9b1e4c26b58ade9b1e4c2614` and -`eaec119273d94087ac119273d90087d0`). The remaining entries record the beginning +invocation of a composed action (`5dceeccbdc7a4caf8eeccbdc7a9caf18` and +`7efb6b7354c3472cbb6b7354c3272c98`). The remaining entries record the beginning and end of the composition as well as the transitions between the composed actions. From b9c06ea0e4c2d80ed68b2434ace23be19898727e Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 27 Mar 2019 21:26:57 -0400 Subject: [PATCH 61/94] Add deploy --kind and --timeout flags (#34) --- bin/deploy.js | 11 ++++++++--- client.js | 4 ++-- conductor.js | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/bin/deploy.js b/bin/deploy.js index c2b2519..9374f99 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -25,9 +25,9 @@ const minimist = require('minimist') const path = require('path') const argv = minimist(process.argv.slice(2), { - string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file', 'debug'], + string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file', 'debug', 'kind'], boolean: ['insecure', 'version', 'overwrite'], - alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w' } + alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w', timeout: 't' } }) if (argv.version) { @@ -43,6 +43,8 @@ if (argv._.length !== 2 || path.extname(argv._[1]) !== '.json') { console.error(' -A, --annotation-file KEY=FILE add KEY annotation with FILE content') console.error(' --apihost HOST API HOST') console.error(' -i, --insecure bypass certificate checking') + console.error(' --kind KIND the KIND of the conductor action runtime') + console.error(' -t, --timeout LIMIT the timeout LIMIT in milliseconds for the conductor action') console.error(' -u, --auth KEY authorization KEY') console.error(' -v, --version output the composer version') console.error(' -w, --overwrite overwrite actions if already defined') @@ -86,7 +88,10 @@ try { console.error(error) process.exit(400 - 256) // Bad Request } -client(options).compositions.deploy(composition, argv.overwrite, argv.debug) +if (typeof argv.timeout !== 'undefined' && typeof argv.timeout !== 'number') { + throw Error('Timeout must be a number') +} +client(options).compositions.deploy(composition, argv.overwrite, argv.debug, argv.kind, argv.timeout) .then(actions => { const names = actions.map(action => action.name) console.log(`ok: created action${actions.length > 1 ? 's' : ''} ${names}`) diff --git a/client.js b/client.js index 2309e62..27fc471 100644 --- a/client.js +++ b/client.js @@ -63,8 +63,8 @@ class Compositions { this.actions = wsk.actions } - deploy (composition, overwrite, debug) { - const actions = (composition.actions || []).concat(conductor.generate(composition, debug)) + deploy (composition, overwrite, debug, kind, timeout) { + const actions = (composition.actions || []).concat(conductor.generate(composition, debug, kind, timeout)) return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) .then(() => this.actions.create(action)), Promise.resolve()) .then(() => actions) diff --git a/conductor.js b/conductor.js index 9d73fe6..74c84bc 100644 --- a/conductor.js +++ b/conductor.js @@ -25,7 +25,7 @@ const { minify } = require('terser') const version = require('./package.json').version // synthesize conductor action code from composition -function generate ({ name, composition, ast, version: composer, annotations = [] }, debug) { +function generate ({ name, composition, ast, version: composer, annotations = [] }, debug, kind = 'nodejs:default', timeout = 60000) { let code = `// generated by composer v${composer} and conductor v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n` + minify(`const main=(${main})(composition)`, { output: { max_line_len: 127 } }).code if (debug) code = `process.env.DEBUG='${debug}'\n\n` + code @@ -34,7 +34,7 @@ function generate ({ name, composition, ast, version: composer, annotations = [] { key: 'composerVersion', value: composer }, { key: 'conductorVersion', value: version }, { key: 'provide-api-key', value: true }]) - return { name, action: { exec: { kind: 'nodejs:default', code }, annotations } } + return { name, action: { exec: { kind, code }, annotations, limits: { timeout } } } } module.exports = { generate } From c4ea9adf2605ec5e0b6d394e73c93106974cf432 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 27 Mar 2019 21:27:14 -0400 Subject: [PATCH 62/94] Add compose --file and -o flags (#35) --- bin/compose.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/bin/compose.js b/bin/compose.js index e426d13..a9cd01a 100755 --- a/bin/compose.js +++ b/bin/compose.js @@ -18,14 +18,15 @@ const composer = require('../composer') const conductor = require('../conductor') +const fs = require('fs') const json = require('../package.json') const minimist = require('minimist') const Module = require('module') const path = require('path') const argv = minimist(process.argv.slice(2), { - string: ['debug'], - boolean: ['version', 'ast', 'js'], + string: ['debug', 'o'], + boolean: ['version', 'ast', 'js', 'file'], alias: { version: 'v' } }) @@ -53,7 +54,9 @@ if (argv._.length !== 1 || path.extname(argv._[0]) !== '.js') { console.error(' compose composition.js [flags]') console.error('Flags:') console.error(' --ast only output the ast for the composition') + console.error(' --file write output to .json file with path and name matching input file') console.error(' --js output the conductor action code for the composition') + console.error(' -o FILE write output to FILE') console.error(' -v, --version output the composer version') console.error(' --debug LIST comma-separated list of debug flags (when using --js flag)') process.exit(1) @@ -72,5 +75,13 @@ if (argv.js) { console.log(conductor.generate(composition, argv.debug).action.exec.code) } else { if (argv.ast) composition = composition.ast - console.log(JSON.stringify(composition, null, 4)) + composition = JSON.stringify(composition, null, 4) + if (argv.o) { + fs.writeFileSync(argv.o, composition.concat('\n'), { encoding: 'utf8' }) + } else if (argv.file) { + const { dir, name } = path.parse(argv._[0]) + fs.writeFileSync(path.format({ dir, name, ext: '.json' }), composition.concat('\n'), { encoding: 'utf8' }) + } else { + console.log(composition) + } } From f3a70a0312dea22da2bcb199236f186e0b61c308 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Fri, 29 Mar 2019 15:24:33 -0400 Subject: [PATCH 63/94] Improve write-to-file logic in compose command (#36) --- bin/compose.js | 24 ++++++++++++++---------- docs/COMMANDS.md | 23 ++++++++++++++++++++--- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/bin/compose.js b/bin/compose.js index a9cd01a..64aba12 100755 --- a/bin/compose.js +++ b/bin/compose.js @@ -54,7 +54,7 @@ if (argv._.length !== 1 || path.extname(argv._[0]) !== '.js') { console.error(' compose composition.js [flags]') console.error('Flags:') console.error(' --ast only output the ast for the composition') - console.error(' --file write output to .json file with path and name matching input file') + console.error(' --file write output to a file next to the input file') console.error(' --js output the conductor action code for the composition') console.error(' -o FILE write output to FILE') console.error(' -v, --version output the composer version') @@ -63,6 +63,7 @@ if (argv._.length !== 1 || path.extname(argv._[0]) !== '.js') { } let composition +let file try { composition = composer.parse(require(path.resolve(argv._[0]))) // load and validate composition composition = composition.compile() @@ -72,16 +73,19 @@ try { process.exit(422 - 256) // Unprocessable Entity } if (argv.js) { - console.log(conductor.generate(composition, argv.debug).action.exec.code) + composition = conductor.generate(composition, argv.debug).action.exec.code } else { if (argv.ast) composition = composition.ast composition = JSON.stringify(composition, null, 4) - if (argv.o) { - fs.writeFileSync(argv.o, composition.concat('\n'), { encoding: 'utf8' }) - } else if (argv.file) { - const { dir, name } = path.parse(argv._[0]) - fs.writeFileSync(path.format({ dir, name, ext: '.json' }), composition.concat('\n'), { encoding: 'utf8' }) - } else { - console.log(composition) - } +} +if (argv.o) { + file = argv.o +} else if (argv.file) { + const { dir, name } = path.parse(argv._[0]) + file = path.format({ dir, name, ext: argv.js ? '.conductor.js' : '.json' }) +} +if (file) { + fs.writeFileSync(file, composition.concat('\n'), { encoding: 'utf8' }) +} else { + console.log(composition) } diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index ca74c80..673035c 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -39,21 +39,29 @@ Usage: compose composition.js [flags] Flags: --ast only output the ast for the composition + --file write output to a file next to the input file --js output the conductor action code for the composition + -o FILE write output to FILE -v, --version output the composer version --debug LIST comma-separated list of debug flags (when using --js flag) ``` The `compose` command takes a Javascript module that exports a composition object (for example [demo.js](../samples/demo.js)) and compiles this object to a -portable JSON format on the standard output. +portable JSON format on the standard output or in file. ``` -compose demo.js > demo.json +compose demo.js -o demo.json ``` If the `--ast` option is specified, the `compose` command only outputs a JSON representation of the Abstract Syntax Tree for the composition. If the `--js` option is specified, the `compose` command outputs the conductor -action code for the composition. +action code for the composition instead of the generated JSON. + +If the `-o` option is used, the `compose` command outputs to the specified file. + +If the `--file` option is specified, the `compose` command outputs to a file +next to the input file with a `.json` or `.conductor.js` extension (if the +`--js` option is specified). # Deploy @@ -68,6 +76,8 @@ Flags: -A, --annotation-file KEY=FILE add KEY annotation with FILE content --apihost HOST API HOST -i, --insecure bypass certificate checking + --kind KIND the KIND of the conductor action runtime + -t, --timeout LIMIT the timeout LIMIT in milliseconds for the conductor action -u, --auth KEY authorization KEY -v, --version output the composer version -w, --overwrite overwrite actions if already defined @@ -93,6 +103,13 @@ definitions. More precisely, it deletes the deployed actions before recreating them. As a result, default parameters, limits, and annotations on preexisting actions are lost. +The `--timeout` option specifies the timeout for the conductor action. + +The `--kind` option specifies the kind for the conductor action runtime. By +default, the `nodejs:default` OpenWhisk runtime is used. The chosen runtime must +be based on Node.js. Other Node.js runtimes may or may not be compatible with +Composer. + ### Annotations The `deploy` command implicitly annotates the deployed composition action with From 7f3458d3cac62b4b9786b55f9ee3eb973427ac7c Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Fri, 29 Mar 2019 15:30:06 -0400 Subject: [PATCH 64/94] New revision + changelog (#37) Prepare for composer 0.11.0 release by updating package.json and ChangeLog --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04b9901..54e2b52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,13 @@ # Changelog + +## v0.11.0 +* Annotate conductor actions with the `provide-api-key` annotation. +* Add `--kind` and `--timeout` flags to `deploy` command. +* Add `--file` and `-o` flags to `compose` command. +* Update documentation. + ## v0.10.0 * Add new [parallel](docs/COMBINATORS.md#parallel) and diff --git a/package.json b/package.json index 11f9102..4afaaf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openwhisk-composer", - "version": "0.10.0", + "version": "0.11.0", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", "homepage": "https://github.com/apache/incubator-openwhisk-composer", "main": "composer.js", From 969a5edf6127e7871c876904367b99b4bc1eff5a Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 4 Apr 2019 16:01:43 -0400 Subject: [PATCH 65/94] rc-verify fixes (#39) --- LICENSE.txt | 5 +++-- NOTICE.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 8dada3e..d645695 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -178,7 +179,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" + boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE.txt b/NOTICE.txt index b3b5bb1..8cd1584 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,4 +1,4 @@ -Apache OpenWhisk +Apache OpenWhisk Composer Copyright 2016-2019 The Apache Software Foundation This product includes software developed at From 3a689740db3d65b87457fbf9ad95b0f93eded8f4 Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 23 Apr 2019 16:54:36 -0400 Subject: [PATCH 66/94] use long form license header (#40) --- travis/scancode.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/travis/scancode.sh b/travis/scancode.sh index 900d465..3bf9578 100755 --- a/travis/scancode.sh +++ b/travis/scancode.sh @@ -1,6 +1,21 @@ #!/bin/bash -# Licensed to the Apache Software Foundation (ASF) under one or more contributor -# license agreements; and to You under the Apache License, Version 2.0. + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# set -e From 23960913a281a643e36265c3ac658a7e9613335d Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 4 Jul 2019 19:21:24 -0400 Subject: [PATCH 67/94] use nightly tag to pull core openwhisk images from dockerhub (#47) --- travis/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/setup.sh b/travis/setup.sh index 82ebf3f..d0e6747 100755 --- a/travis/setup.sh +++ b/travis/setup.sh @@ -42,7 +42,7 @@ cp $SCRIPTDIR/runtimes.json $WHISKDIR/ansible/files # Deploy OpenWhisk cd $WHISKDIR/ansible -ANSIBLE_CMD="ansible-playbook -i ${WHISKDIR}/ansible/environments/local -e docker_image_prefix=openwhisk" +ANSIBLE_CMD="ansible-playbook -i ${WHISKDIR}/ansible/environments/local -e docker_image_prefix=openwhisk -e docker_image_tag=nightly" $ANSIBLE_CMD setup.yml $ANSIBLE_CMD prereq.yml $ANSIBLE_CMD couchdb.yml From 09015480a68dfcd2e65e45585c7bd187202ede11 Mon Sep 17 00:00:00 2001 From: Matt Rutkowski Date: Sat, 27 Jul 2019 19:47:13 -0500 Subject: [PATCH 68/94] Use correct ASF header for tool scripts (#48) * full header for tool scripts * ignore apache license header in 'bin' dir. * ignore apache license header in 'bin' dir. --- bin/compose.js | 13 ++++++++----- bin/deploy.js | 13 ++++++++----- package.json | 7 ++++++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/bin/compose.js b/bin/compose.js index 64aba12..4b95b4b 100755 --- a/bin/compose.js +++ b/bin/compose.js @@ -1,11 +1,14 @@ #!/usr/bin/env node -/* - * 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 + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * 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, diff --git a/bin/deploy.js b/bin/deploy.js index 9374f99..046dace 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -1,11 +1,14 @@ #!/usr/bin/env node -/* - * 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 + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * 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, diff --git a/package.json b/package.json index 4afaaf9..1369d04 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "license": "Apache-2.0", "name": "openwhisk-composer", "version": "0.11.0", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", @@ -58,5 +59,9 @@ "email": "nickm@us.ibm.com" } ], - "license": "Apache-2.0" + "standard": { + "ignore": [ + "/bin/" + ] + } } From b2db9c27a5190de97bb8f24501e25a2857a785fb Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 23 Aug 2019 10:14:53 -0400 Subject: [PATCH 69/94] tlp: remove incubator references and disclaimer (#49) --- CONTRIBUTING.md | 2 +- DISCLAIMER.txt | 1 - README.md | 12 ++++-------- docs/COMPOSITIONS.md | 6 +++--- package.json | 4 ++-- travis/scancode.sh | 4 ++-- travis/setup.sh | 2 +- 7 files changed, 13 insertions(+), 18 deletions(-) delete mode 100644 DISCLAIMER.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cf5d5b2..05d5ebe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,7 +57,7 @@ A good enhancement request comes with an explanation of what you are trying to d ### Discussion Please use the project's developer email list to engage our community: -[dev@openwhisk.incubator.apache.org](dev@openwhisk.incubator.apache.org) +[dev@openwhisk.apache.org](dev@openwhisk.apache.org) In addition, we provide a "dev" Slack team channel for conversations at: https://openwhisk-team.slack.com/messages/dev/ diff --git a/DISCLAIMER.txt b/DISCLAIMER.txt deleted file mode 100644 index aa67e53..0000000 --- a/DISCLAIMER.txt +++ /dev/null @@ -1 +0,0 @@ -Apache OpenWhisk Composer is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. diff --git a/README.md b/README.md index 37626d3..8fa12c8 100644 --- a/README.md +++ b/README.md @@ -19,19 +19,19 @@ # Apache OpenWhisk Composer -[![Travis](https://travis-ci.org/apache/incubator-openwhisk-composer.svg?branch=master)](https://travis-ci.org/apache/incubator-openwhisk-composer) +[![Travis](https://travis-ci.org/apache/openwhisk-composer.svg?branch=master)](https://travis-ci.org/apache/openwhisk-composer) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) Composer is a new programming model for composing cloud functions built on -[Apache OpenWhisk](https://github.com/apache/incubator-openwhisk). With +[Apache OpenWhisk](https://github.com/apache/openwhisk). With Composer, developers can build even more serverless applications including using it for IoT, with workflow orchestration, conversation services, and devops automation, to name a few examples. Composer synthesizes OpenWhisk [conductor -actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) +actions](https://github.com/apache/openwhisk/blob/master/docs/conductors.md) to implement compositions. Compositions have all the attributes and capabilities of an action, e.g., default parameters, limits, blocking invocation, web export. @@ -141,7 +141,7 @@ actions. Compositions are implemented by means of OpenWhisk conductor actions. The [documentation of conductor -actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md) +actions](https://github.com/apache/openwhisk/blob/master/docs/conductors.md) explains execution traces in greater details. While composer does not limit in principle the length of a composition, @@ -207,7 +207,3 @@ dictionary must contain a field named `ignore_certs` with value `true`: This explicit SSL configuration is currently only necessary when using parallel combinators or the `async` combinator. - -# Disclaimer - -Apache OpenWhisk Composer is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index 7f72223..9699038 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -126,12 +126,12 @@ Deploying such a composition deploys the embedded actions. ## Conductor actions Compositions are implemented by means of OpenWhisk [conductor -actions](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md). +actions](https://github.com/apache/openwhisk/blob/master/docs/conductors.md). Compositions have all the attributes and capabilities of an action, e.g., default parameters, limits, blocking invocation, web export. Execution -[traces](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md#activations) +[traces](https://github.com/apache/openwhisk/blob/master/docs/conductors.md#activations) and -[limits](https://github.com/apache/incubator-openwhisk/blob/master/docs/conductors.md#limits) +[limits](https://github.com/apache/openwhisk/blob/master/docs/conductors.md#limits) of compositions follow from conductor actions. The conductor action code for a composition may be obtained by means of the diff --git a/package.json b/package.json index 1369d04..8893761 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "openwhisk-composer", "version": "0.11.0", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", - "homepage": "https://github.com/apache/incubator-openwhisk-composer", + "homepage": "https://github.com/apache/openwhisk-composer", "main": "composer.js", "scripts": { "test": "standard && mocha" @@ -23,7 +23,7 @@ ], "repository": { "type": "git", - "url": "https://github.com/apache/incubator-openwhisk-composer.git" + "url": "https://github.com/apache/openwhisk-composer.git" }, "keywords": [ "functions", diff --git a/travis/scancode.sh b/travis/scancode.sh index 3bf9578..2c354bb 100755 --- a/travis/scancode.sh +++ b/travis/scancode.sh @@ -22,11 +22,11 @@ set -e SCRIPTDIR=$(cd $(dirname "$0") && pwd) ROOTDIR="$SCRIPTDIR/../" HOMEDIR="$SCRIPTDIR/../../" -UTIL_DIR="$HOMEDIR/incubator-openwhisk-utilities" +UTIL_DIR="$HOMEDIR/openwhisk-utilities" # clone OpenWhisk utilities repo. in order to run scanCode.py cd $HOMEDIR -git clone https://github.com/apache/incubator-openwhisk-utilities.git +git clone https://github.com/apache/openwhisk-utilities.git # run scancode cd $UTIL_DIR diff --git a/travis/setup.sh b/travis/setup.sh index d0e6747..ac48a00 100755 --- a/travis/setup.sh +++ b/travis/setup.sh @@ -32,7 +32,7 @@ docker pull openwhisk/nodejs6action & # Clone OpenWhisk cd $ROOTDIR -git clone --depth=1 https://github.com/apache/incubator-openwhisk.git openwhisk +git clone --depth=1 https://github.com/apache/openwhisk.git openwhisk # Install Ansible pip install --user ansible==2.5.2 From 68c156c92d7efc1ba98ad0e235705b7b10d6e825 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 13 Nov 2019 16:22:32 -0500 Subject: [PATCH 70/94] Only require redis in conductor code when running parallel constructs (#51) --- conductor.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conductor.js b/conductor.js index 74c84bc..7d163b9 100644 --- a/conductor.js +++ b/conductor.js @@ -42,7 +42,6 @@ module.exports = { generate } // runtime code function main (composition) { const openwhisk = require('openwhisk') - const redis = require('redis') const uuid = require('uuid').v4 let wsk let db @@ -52,7 +51,7 @@ function main (composition) { function done (id) { return `composer/join/${id}` } function createRedisClient (p) { - const client = redis.createClient(p.s.redis.uri, p.s.redis.ca ? { tls: { ca: Buffer.from(p.s.redis.ca, 'base64').toString('binary') } } : {}) + const client = require('redis').createClient(p.s.redis.uri, p.s.redis.ca ? { tls: { ca: Buffer.from(p.s.redis.ca, 'base64').toString('binary') } } : {}) const noop = () => { } let handler = noop client.on('error', error => handler(error)) From 212ce64188b4f763b7baa974d4cac844e8994913 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 13 Nov 2019 16:23:00 -0500 Subject: [PATCH 71/94] Update COMMANDS.md (#52) --- docs/COMMANDS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 673035c..a096aad 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -153,5 +153,5 @@ The `needle` option activates `needle` verbose logging. The `needle` option enables overriding `needle` default parameters. The specified `defaults` must be be a json dictionary, as for example in: ``` -deploy demo demo.json --debug needle<{"connection":"keep-alive","open_timeout":60000}> +deploy demo demo.json --debug 'needle<{"connection":"keep-alive","open_timeout":60000}>' ``` From fa6d103c35359baf91294cb74a64871ec52a6165 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Wed, 13 Nov 2019 18:34:24 -0500 Subject: [PATCH 72/94] Support setting all limits on conductor and composed actions (#53) --- bin/deploy.js | 14 +++++++++++--- client.js | 4 ++-- composer.js | 5 ++++- conductor.js | 4 ++-- docs/COMBINATORS.md | 16 +++++++++++++++- docs/COMMANDS.md | 6 +++++- 6 files changed, 39 insertions(+), 10 deletions(-) diff --git a/bin/deploy.js b/bin/deploy.js index 046dace..d0c3eb5 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -30,7 +30,7 @@ const path = require('path') const argv = minimist(process.argv.slice(2), { string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file', 'debug', 'kind'], boolean: ['insecure', 'version', 'overwrite'], - alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w', timeout: 't' } + alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w', timeout: 't', memory: 'm', logsize: 'l' } }) if (argv.version) { @@ -47,7 +47,9 @@ if (argv._.length !== 2 || path.extname(argv._[1]) !== '.json') { console.error(' --apihost HOST API HOST') console.error(' -i, --insecure bypass certificate checking') console.error(' --kind KIND the KIND of the conductor action runtime') - console.error(' -t, --timeout LIMIT the timeout LIMIT in milliseconds for the conductor action') + console.error(' -l, --logsize LIMIT the maximum log size LIMIT in MB for the conductor action (default 10)') + console.error(' -m, --memory LIMIT the maximum memory LIMIT in MB for the conductor action (default 256)') + console.error(' -t, --timeout LIMIT the timeout LIMIT in milliseconds for the conductor action (default 60000)') console.error(' -u, --auth KEY authorization KEY') console.error(' -v, --version output the composer version') console.error(' -w, --overwrite overwrite actions if already defined') @@ -94,7 +96,13 @@ try { if (typeof argv.timeout !== 'undefined' && typeof argv.timeout !== 'number') { throw Error('Timeout must be a number') } -client(options).compositions.deploy(composition, argv.overwrite, argv.debug, argv.kind, argv.timeout) +if (typeof argv.memory !== 'undefined' && typeof argv.memory !== 'number') { + throw Error('Maximum memory must be a number') +} +if (typeof argv.logsize !== 'undefined' && typeof argv.logsize !== 'number') { + throw Error('Maximum log size must be a number') +} +client(options).compositions.deploy(composition, argv.overwrite, argv.debug, argv.kind, argv.timeout, argv.memory, argv.logsize) .then(actions => { const names = actions.map(action => action.name) console.log(`ok: created action${actions.length > 1 ? 's' : ''} ${names}`) diff --git a/client.js b/client.js index 27fc471..2d53776 100644 --- a/client.js +++ b/client.js @@ -63,8 +63,8 @@ class Compositions { this.actions = wsk.actions } - deploy (composition, overwrite, debug, kind, timeout) { - const actions = (composition.actions || []).concat(conductor.generate(composition, debug, kind, timeout)) + deploy (composition, overwrite, debug, kind, timeout, memory, logs) { + const actions = (composition.actions || []).concat(conductor.generate(composition, debug, kind, timeout, memory, logs)) return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) .then(() => this.actions.create(action)), Promise.resolve()) .then(() => actions) diff --git a/composer.js b/composer.js index 66f500f..76b1965 100644 --- a/composer.js +++ b/composer.js @@ -358,7 +358,10 @@ Object.assign(composer, { exec = { kind: 'nodejs:default', code: exec } } const composition = { type: 'action', name, '.combinator': () => combinators.action } - if (exec) composition.action = { exec } + if (exec) { + composition.action = { exec } + if (isObject(options.limits)) composition.action.limits = options.limits + } return new Composition(composition) }, diff --git a/conductor.js b/conductor.js index 7d163b9..f72f501 100644 --- a/conductor.js +++ b/conductor.js @@ -25,7 +25,7 @@ const { minify } = require('terser') const version = require('./package.json').version // synthesize conductor action code from composition -function generate ({ name, composition, ast, version: composer, annotations = [] }, debug, kind = 'nodejs:default', timeout = 60000) { +function generate ({ name, composition, ast, version: composer, annotations = [] }, debug, kind = 'nodejs:default', timeout = 60000, memory = 256, logs = 10) { let code = `// generated by composer v${composer} and conductor v${version}\n\nconst composition = ${JSON.stringify(composition, null, 4)}\n\n// do not edit below this point\n\n` + minify(`const main=(${main})(composition)`, { output: { max_line_len: 127 } }).code if (debug) code = `process.env.DEBUG='${debug}'\n\n` + code @@ -34,7 +34,7 @@ function generate ({ name, composition, ast, version: composer, annotations = [] { key: 'composerVersion', value: composer }, { key: 'conductorVersion', value: version }, { key: 'provide-api-key', value: true }]) - return { name, action: { exec: { kind, code }, annotations, limits: { timeout } } } + return { name, action: { exec: { kind, code }, annotations, limits: { timeout, memory, logs } } } } module.exports = { generate } diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index 336d7cc..1294944 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -73,6 +73,9 @@ composer.action('hello') composer.action('myPackage/myAction') composer.action('/whisk.system/utils/echo') ``` + +### Action definition + The optional `options` dictionary makes it possible to provide a definition for the action being composed. ```javascript @@ -88,7 +91,6 @@ composer.action('hello', { action: hello }) // specify the code for the action as a string composer.action('hello', { action: "const message = 'hello'; function main() { return { message } }" }) - // specify the code and runtime for the action composer.action('hello', { action: { @@ -108,6 +110,18 @@ Javascript function, or as a file name. Alternatively, a sequence action may be defined by providing the list of sequenced actions. The code (specified as a string) may be annotated with the kind of the action runtime. +### Limits + +If a definition is provided for the action, the `options` dictionary may also +specify `limits`, for instance: +```javascript +composer.action('hello', { filename: 'hello.js', limits: { logs: 1, memory: 128, timeout: 10000 } }) +``` +The `limits` object optionally specifies any combination of: +- the maximum log size LIMIT in MB for the action, +- the maximum memory LIMIT in MB for the action, +- the timeout LIMIT in milliseconds for the action. + ### Environment capture in actions Javascript functions used to define actions cannot capture any part of their diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index a096aad..7b64e15 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -77,7 +77,9 @@ Flags: --apihost HOST API HOST -i, --insecure bypass certificate checking --kind KIND the KIND of the conductor action runtime - -t, --timeout LIMIT the timeout LIMIT in milliseconds for the conductor action + -l, --logsize LIMIT the maximum log size LIMIT in MB for the conductor action (default 10) + -m, --memory LIMIT the maximum memory LIMIT in MB for the conductor action (default 256) + -t, --timeout LIMIT the timeout LIMIT in milliseconds for the conductor action (default 60000) -u, --auth KEY authorization KEY -v, --version output the composer version -w, --overwrite overwrite actions if already defined @@ -103,6 +105,8 @@ definitions. More precisely, it deletes the deployed actions before recreating them. As a result, default parameters, limits, and annotations on preexisting actions are lost. +The `--logsize` option specifies the maximum log size for the conductor action. +The `--memory` option specifies the maximum memory for the conductor action. The `--timeout` option specifies the timeout for the conductor action. The `--kind` option specifies the kind for the conductor action runtime. By From d8374742e7839165476a17b0cd2658e317589223 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 14 Nov 2019 08:28:31 -0500 Subject: [PATCH 73/94] Avoid loading uuid when not needed (#54) --- conductor.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conductor.js b/conductor.js index f72f501..f37d152 100644 --- a/conductor.js +++ b/conductor.js @@ -42,7 +42,6 @@ module.exports = { generate } // runtime code function main (composition) { const openwhisk = require('openwhisk') - const uuid = require('uuid').v4 let wsk let db const expiration = 86400 // expire redis key after a day @@ -101,7 +100,7 @@ function main (composition) { return } const stack = [{ marker: true }].concat(p.s.stack) - const barrierId = uuid() + const barrierId = require('uuid').v4() console.log(`barrierId: ${barrierId}, spawning: ${array.length}`) if (!wsk) wsk = openwhisk(p.s.openwhisk) if (!db) db = createRedisClient(p) From a3e9fe034d2c4b5362e149aad66d6daf87006707 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 14 Nov 2019 13:53:06 -0500 Subject: [PATCH 74/94] Bump openwhisk-client-js version to 3.20 (#55) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8893761..4affc82 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ ], "dependencies": { "minimist": "^1.2.0", - "openwhisk": "^3.18.0", + "openwhisk": "^3.20.0", "terser": "^3.8.2" }, "devDependencies": { From 613e5507418700ef9ca49195262fbbd3822b39da Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 14 Nov 2019 16:05:46 -0500 Subject: [PATCH 75/94] Add support for bearer token authentication (#56) --- bin/deploy.js | 9 +++++++-- client.js | 22 ++++++++++++++++++++-- docs/COMMANDS.md | 30 ++++++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/bin/deploy.js b/bin/deploy.js index d0c3eb5..5fffccd 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -29,7 +29,7 @@ const path = require('path') const argv = minimist(process.argv.slice(2), { string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file', 'debug', 'kind'], - boolean: ['insecure', 'version', 'overwrite'], + boolean: ['insecure', 'version', 'overwrite', 'basic', 'bearer'], alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w', timeout: 't', memory: 'm', logsize: 'l' } }) @@ -45,6 +45,8 @@ if (argv._.length !== 2 || path.extname(argv._[1]) !== '.json') { console.error(' -a, --annotation KEY=VALUE add KEY annotation with VALUE') console.error(' -A, --annotation-file KEY=FILE add KEY annotation with FILE content') console.error(' --apihost HOST API HOST') + console.error(' --basic force basic authentication') + console.error(' --bearer force bearer token authentication') console.error(' -i, --insecure bypass certificate checking') console.error(' --kind KIND the KIND of the conductor action runtime') console.error(' -l, --logsize LIMIT the maximum log size LIMIT in MB for the conductor action (default 10)') @@ -93,6 +95,9 @@ try { console.error(error) process.exit(400 - 256) // Bad Request } +if (argv.basic && argv.bearer) { + throw Error('Must select either basic authentication of bearer token authentication') +} if (typeof argv.timeout !== 'undefined' && typeof argv.timeout !== 'number') { throw Error('Timeout must be a number') } @@ -102,7 +107,7 @@ if (typeof argv.memory !== 'undefined' && typeof argv.memory !== 'number') { if (typeof argv.logsize !== 'undefined' && typeof argv.logsize !== 'number') { throw Error('Maximum log size must be a number') } -client(options).compositions.deploy(composition, argv.overwrite, argv.debug, argv.kind, argv.timeout, argv.memory, argv.logsize) +client(options, argv.basic, argv.bearer).compositions.deploy(composition, argv.overwrite, argv.debug, argv.kind, argv.timeout, argv.memory, argv.logsize) .then(actions => { const names = actions.map(action => action.name) console.log(`ok: created action${actions.length > 1 ? 's' : ''} ${names}`) diff --git a/client.js b/client.js index 2d53776..2794e0f 100644 --- a/client.js +++ b/client.js @@ -26,11 +26,14 @@ const os = require('os') const path = require('path') // return enhanced openwhisk client capable of deploying compositions -module.exports = function (options) { +module.exports = function (options, basic, bearer) { // try to extract apihost and key first from whisk property file file and then from process.env let apihost let apikey let ignorecerts + let namespace = '_' + let token + let authHandler try { const wskpropsPath = process.env.WSK_CONFIG_FILE || path.join(os.homedir(), '.wskprops') @@ -43,6 +46,10 @@ module.exports = function (options) { apihost = parts[1] } else if (parts[0] === 'AUTH') { apikey = parts[1] + } else if (parts[0] === 'NAMESPACE') { + namespace = parts[1] + } else if (parts[0] === 'APIGW_ACCESS_TOKEN') { + token = parts[1] } } } @@ -50,9 +57,20 @@ module.exports = function (options) { if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST if (process.env.__OW_API_KEY) apikey = process.env.__OW_API_KEY + if (process.env.__OW_NAMESPACE) namespace = process.env.__OW_NAMESPACE if (process.env.__OW_IGNORE_CERTS) ignorecerts = process.env.__OW_IGNORE_CERTS + if (process.env.__OW_APIGW_TOKEN) token = process.env.__OW_APIGW_TOKEN - const wsk = openwhisk(Object.assign({ apihost, api_key: apikey, ignore_certs: ignorecerts }, options)) + if (bearer || (!basic && namespace !== '_')) { + // switch from basic auth to bearer token + authHandler = { + getAuthHeader: () => { + return Promise.resolve(`Bearer ${token}`) + } + } + } + + const wsk = openwhisk(Object.assign({ apihost, api_key: apikey, auth_handler: authHandler, namespace, ignore_certs: ignorecerts }, options)) wsk.compositions = new Compositions(wsk) return wsk } diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 7b64e15..2850e2a 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -75,6 +75,8 @@ Flags: -a, --annotation KEY=VALUE add KEY annotation with VALUE -A, --annotation-file KEY=FILE add KEY annotation with FILE content --apihost HOST API HOST + --basic force basic authentication + --bearer force bearer token authentication -i, --insecure bypass certificate checking --kind KIND the KIND of the conductor action runtime -l, --logsize LIMIT the maximum log size LIMIT in MB for the conductor action (default 10) @@ -133,17 +135,37 @@ specifying the OpenWhisk instance to use: -i, --insecure bypass certificate checking -u, --auth KEY authorization KEY ``` +In addition the `deploy` command supports the flags: +``` + --basic force basic authentication + --bearer force bearer token authentication +``` If the `--apihost` flag is absent, the environment variable `__OW_API_HOST` is used in its place. If neither is available, the `deploy` command extracts the -`APIHOST` key from the whisk property file for the current user. +`APIHOST` key from the whisk property file. If the `--insecure` flag is set or the environment variable `__OW_IGNORE_CERTS` is set to `true`, the `deploy` command ignores SSL certificates validation failures. -If the `--auth` flag is absent, the environment variable `__OW_API_KEY` is used -in its place. If neither is available, the `deploy` command extracts the `AUTH` -key from the whisk property file for the current user. +The default target namespace is the value of environment variable +`__OW_NAMESPACE` if defined. If not, it is the value of the `NAMESPACE` property +in the whisk property file if present. Otherwise, the default `_` value is used. + +If the `--basic` flag is set, the `deploy` command uses basic authentication. If +the `--bearer` flag is set, the `deploy` command uses bearer token +authentication. If neither flag is set, the `deploy` command uses basic +authentication only if the default target namespace is `_`. Setting both flags +is an error. + +For basic authentication, the authentication key is obtained from the `--auth` +flag. If the `--auth` flag is absent, the environment variable `__OW_API_KEY` is +used in its place. If neither is available, the `deploy` command extracts the +`AUTH` key from the whisk property file. + +For bearer token authentication, the token is either the value of the +environment variable `__OW_APIGW_TOKEN` if defined or the value of property +`APIGW_ACCESS_TOKEN` in the whisk property file. The default path for the whisk property file is `$HOME/.wskprops`. It can be altered by setting the `WSK_CONFIG_FILE` environment variable. From 77564d9463e5732255eae6de807801cee86289ba Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Thu, 14 Nov 2019 16:53:51 -0500 Subject: [PATCH 76/94] Document installation from source release (#57) --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 8fa12c8..ff5030a 100644 --- a/README.md +++ b/README.md @@ -207,3 +207,13 @@ dictionary must contain a field named `ignore_certs` with value `true`: This explicit SSL configuration is currently only necessary when using parallel combinators or the `async` combinator. + +# Installation from Source + +To install composer from a source release, download the composer source code +from the [Apache OpenWhisk +Downloads](https://openwhisk.apache.org/downloads.html) page, rename the release +tarball to `openwhisk-composer.tgz` and install it with command: +```shell +npm install -g openwhisk-composer.tgz +``` From 71a37c6408d7531e76a9b9c4ea52972201136914 Mon Sep 17 00:00:00 2001 From: Nick Mitchell Date: Thu, 14 Nov 2019 17:37:15 -0500 Subject: [PATCH 77/94] feat: add support for passthrough http optons on deploy (#46) --- client.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client.js b/client.js index 2794e0f..233b4a2 100644 --- a/client.js +++ b/client.js @@ -81,8 +81,13 @@ class Compositions { this.actions = wsk.actions } - deploy (composition, overwrite, debug, kind, timeout, memory, logs) { - const actions = (composition.actions || []).concat(conductor.generate(composition, debug, kind, timeout, memory, logs)) + deploy (composition, overwrite, debug, kind, timeout, memory, logs, httpOptions) { + function addHttpOptions (action) { + // the openwhisk npm allows passthrough request-style options + return Object.assign({}, action, httpOptions) + } + + const actions = (composition.actions || []).concat(conductor.generate(composition, debug, kind, timeout, memory, logs)).map(addHttpOptions) return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) .then(() => this.actions.create(action)), Promise.resolve()) .then(() => actions) From 1231bf9fc1999fd57e6057bf95bc2231283930c4 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Fri, 15 Nov 2019 08:13:37 -0500 Subject: [PATCH 78/94] Add support for setting the apiversion in the deploy command (#58) --- bin/deploy.js | 4 +++- client.js | 5 ++++- docs/COMMANDS.md | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/bin/deploy.js b/bin/deploy.js index 5fffccd..5a54691 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -28,7 +28,7 @@ const minimist = require('minimist') const path = require('path') const argv = minimist(process.argv.slice(2), { - string: ['apihost', 'auth', 'source', 'annotation', 'annotation-file', 'debug', 'kind'], + string: ['apihost', 'apiversion', 'auth', 'source', 'annotation', 'annotation-file', 'debug', 'kind'], boolean: ['insecure', 'version', 'overwrite', 'basic', 'bearer'], alias: { auth: 'u', insecure: 'i', version: 'v', annotation: 'a', 'annotation-file': 'A', overwrite: 'w', timeout: 't', memory: 'm', logsize: 'l' } }) @@ -45,6 +45,7 @@ if (argv._.length !== 2 || path.extname(argv._[1]) !== '.json') { console.error(' -a, --annotation KEY=VALUE add KEY annotation with VALUE') console.error(' -A, --annotation-file KEY=FILE add KEY annotation with FILE content') console.error(' --apihost HOST API HOST') + console.error(' --apiversion VERSION API VERSION') console.error(' --basic force basic authentication') console.error(' --bearer force bearer token authentication') console.error(' -i, --insecure bypass certificate checking') @@ -88,6 +89,7 @@ try { const options = { ignore_certs: argv.insecure } if (argv.apihost) options.apihost = argv.apihost if (argv.auth) options.api_key = argv.auth +if (argv.apiversion) options.apiversion = argv.apiversion try { composition.name = fqn(argv._[0]) } catch (error) { diff --git a/client.js b/client.js index 233b4a2..e1863a0 100644 --- a/client.js +++ b/client.js @@ -29,6 +29,7 @@ const path = require('path') module.exports = function (options, basic, bearer) { // try to extract apihost and key first from whisk property file file and then from process.env let apihost + let apiversion let apikey let ignorecerts let namespace = '_' @@ -44,6 +45,8 @@ module.exports = function (options, basic, bearer) { if (parts.length === 2) { if (parts[0] === 'APIHOST') { apihost = parts[1] + } else if (parts[0] === 'APIVERSION') { + apiversion = parts[1] } else if (parts[0] === 'AUTH') { apikey = parts[1] } else if (parts[0] === 'NAMESPACE') { @@ -70,7 +73,7 @@ module.exports = function (options, basic, bearer) { } } - const wsk = openwhisk(Object.assign({ apihost, api_key: apikey, auth_handler: authHandler, namespace, ignore_certs: ignorecerts }, options)) + const wsk = openwhisk(Object.assign({ apihost, apiversion, api_key: apikey, auth_handler: authHandler, namespace, ignore_certs: ignorecerts }, options)) wsk.compositions = new Compositions(wsk) return wsk } diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 2850e2a..6e37924 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -75,6 +75,7 @@ Flags: -a, --annotation KEY=VALUE add KEY annotation with VALUE -A, --annotation-file KEY=FILE add KEY annotation with FILE content --apihost HOST API HOST + --apiversion VERSION API VERSION --basic force basic authentication --bearer force bearer token authentication -i, --insecure bypass certificate checking @@ -144,6 +145,10 @@ If the `--apihost` flag is absent, the environment variable `__OW_API_HOST` is used in its place. If neither is available, the `deploy` command extracts the `APIHOST` key from the whisk property file. +The `apiversion` may be specified using the `--apiversion` flag, or, if absent, +the `APIVERSION` property of the whisk property file. If both are absent, the +default is assumed. + If the `--insecure` flag is set or the environment variable `__OW_IGNORE_CERTS` is set to `true`, the `deploy` command ignores SSL certificates validation failures. From 383e2ebe5473c9b66dcf1d737f5b911b2ff6aec4 Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Tue, 10 Dec 2019 16:28:15 -0500 Subject: [PATCH 79/94] Add example for dynamic combinator (#62) This example illustrates how to invoke an action from the current package (the package containing the composition). --- docs/COMBINATORS.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index 1294944..44cebb6 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -69,10 +69,14 @@ assumed. Examples: ```javascript -composer.action('hello') +composer.action('hello') // default package composer.action('myPackage/myAction') composer.action('/whisk.system/utils/echo') ``` +To be clear, if no package is specified, the default package is assumed even if +the composition itself is not deployed to the default package. To invoke an +action from the same package as the composition the [`dynamic`](#dynamic) +combinator may be used as illustrated [below](#example). ### Action definition @@ -532,3 +536,29 @@ Other fields of the input parameter object are ignored. The `dynamic` combinator invokes the action named _name_ with the input parameter object _params_. The output parameter object for the composition is the output parameter object of the action invocation. + +### Example + +The `dynamic` combinator may be used for example to invoke an action that +belongs to the same package as the composition, without having to specify the +package name beforehand. + +```javascript +const composer = require('openwhisk-composer') + +function invoke (actionShortName) { + return composer.let( + { actionShortName }, + params => ({ type: 'action', params, name: process.env.__OW_ACTION_NAME.split('/').slice(0, -1).concat(actionShortName).join('/') }), + composer.dynamic()) +} + +module.exports = composer.seq( + composer.action('echo'), // echo action from the default package + invoke('echo') // echo action from the same package as the composition +) +``` +In this example, `let` captures the target action short name at compile time +without expanding it to a fully qualified name. Then, at run time, the package +name is obtained from the environment variable `__OW_ACTION_NAME` and combined +with the action short name. Finally, `dynamic` is used to invoke the action. From ddf67c72bc9a4adbf9f194863105beb6622c0ecd Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 10 Jan 2020 11:00:47 -0500 Subject: [PATCH 80/94] add .asf.yaml to specify github metadata (#64) --- .asf.yaml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .asf.yaml diff --git a/.asf.yaml b/.asf.yaml new file mode 100644 index 0000000..513fb6d --- /dev/null +++ b/.asf.yaml @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +github: + description: "Apache OpenWhisk Composer provides a high-level programming model in JavaScript for composing serverless functions" + homepage: https://openwhisk.apache.org/ + labels: + - openwhisk + - apache + - serverless + - faas + - functions-as-a-service + - cloud + - serverless-architectures + - serverless-functions + - functions + - composer + - composition + - node + - node-js + - nodejs + - javascript From 477af79f705a50b0694eae4e172b22f444e28a0b Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 13 Jan 2020 13:03:22 -0500 Subject: [PATCH 81/94] Add webpackIgnore annotation on dynamic conductor dependencies (#65) --- conductor.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conductor.js b/conductor.js index f37d152..80495d9 100644 --- a/conductor.js +++ b/conductor.js @@ -41,7 +41,7 @@ module.exports = { generate } // runtime code function main (composition) { - const openwhisk = require('openwhisk') + const openwhisk = require(/* webpackIgnore: true */ 'openwhisk') let wsk let db const expiration = 86400 // expire redis key after a day @@ -50,11 +50,11 @@ function main (composition) { function done (id) { return `composer/join/${id}` } function createRedisClient (p) { - const client = require('redis').createClient(p.s.redis.uri, p.s.redis.ca ? { tls: { ca: Buffer.from(p.s.redis.ca, 'base64').toString('binary') } } : {}) + const client = require(/* webpackIgnore: true */ 'redis').createClient(p.s.redis.uri, p.s.redis.ca ? { tls: { ca: Buffer.from(p.s.redis.ca, 'base64').toString('binary') } } : {}) const noop = () => { } let handler = noop client.on('error', error => handler(error)) - require('redis-commands').list.forEach(f => { + require(/* webpackIgnore: true */ 'redis-commands').list.forEach(f => { client[`${f}Async`] = function () { let failed = false return new Promise((resolve, reject) => { @@ -100,7 +100,7 @@ function main (composition) { return } const stack = [{ marker: true }].concat(p.s.stack) - const barrierId = require('uuid').v4() + const barrierId = require(/* webpackIgnore: true */ 'uuid').v4() console.log(`barrierId: ${barrierId}, spawning: ${array.length}`) if (!wsk) wsk = openwhisk(p.s.openwhisk) if (!db) db = createRedisClient(p) From 26771802d5c793895dd67be902f92b38c8a3c4af Mon Sep 17 00:00:00 2001 From: Olivier Tardieu Date: Mon, 13 Jan 2020 14:11:47 -0500 Subject: [PATCH 82/94] Prepare for 0.12.0 release (#66) --- CHANGELOG.md | 12 ++++++++++++ NOTICE.txt | 2 +- package.json | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e2b52..3f8f7ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,18 @@ # Changelog +## v0.12.0 +* Running sequential compositions no longer requires the action runtime to + contain the `redis` and `uuid` modules. +* The `deploy` command supports additional options: + * `--logsize` and `--memory` to set limits for the conductor action, + * `--basic` and `--bearer` to control the authentication method, + * `--apiversion` to specify the API version of the target OpenWhisk instance. +* The `deploy` method supports passing through `httpOptions`. +* A workaround for Webpack has been implemented (dependency analysis of the + conductor code). +* The `openwhisk-client-js` module has been updated to version `3.20.0`. +* The documentation has been improved. ## v0.11.0 * Annotate conductor actions with the `provide-api-key` annotation. diff --git a/NOTICE.txt b/NOTICE.txt index 8cd1584..5a42896 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Apache OpenWhisk Composer -Copyright 2016-2019 The Apache Software Foundation +Copyright 2016-2020 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/package.json b/package.json index 4affc82..778ffc0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "license": "Apache-2.0", "name": "openwhisk-composer", - "version": "0.11.0", + "version": "0.12.0", "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.", "homepage": "https://github.com/apache/openwhisk-composer", "main": "composer.js", From b0f73d37eb24b80e232dfaa58adee4c2c2bdb557 Mon Sep 17 00:00:00 2001 From: David Grove Date: Wed, 12 Feb 2020 21:05:08 -0500 Subject: [PATCH 83/94] bump version of openwhisk-client-js to 3.21.1 (#68) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 778ffc0..a6e0a10 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ ], "dependencies": { "minimist": "^1.2.0", - "openwhisk": "^3.20.0", + "openwhisk": "^3.21.1", "terser": "^3.8.2" }, "devDependencies": { From 400a412da7722faddb62593e5edb7e60d72a4343 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 27 Feb 2020 10:56:32 -0500 Subject: [PATCH 84/94] change travis config from nodejs 6 to nodejs 10 (#69) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7559d5b..bfb4cd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ language: node_js node_js: - - 6 + - 10 services: - docker From e7f11b2639999afcf054353170bdff5e3371d105 Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 14 Apr 2020 15:40:19 -0400 Subject: [PATCH 85/94] replace last use of nodejs:6 with nodejs:10 (#72) --- README.md | 10 +++++----- travis/runtimes.json | 29 +++++++++++++---------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ff5030a..30c3aa3 100644 --- a/README.md +++ b/README.md @@ -123,11 +123,11 @@ wsk activation list ```
 Datetime            Activation ID                    Kind     Start Duration   Status  Entity
-2019-03-15 16:43:22 e6bea73bf75f4eb7bea73bf75fdeb703 nodejs:6 warm  1ms        success guest/demo:0.0.1
-2019-03-15 16:43:21 7efb6b7354c3472cbb6b7354c3272c98 nodejs:6 cold  31ms       success guest/failure:0.0.1
-2019-03-15 16:43:21 377cd080f0674e9cbcd080f0679e9c1d nodejs:6 warm  2ms        success guest/demo:0.0.1
-2019-03-15 16:43:20 5dceeccbdc7a4caf8eeccbdc7a9caf18 nodejs:6 cold  29ms       success guest/authenticate:0.0.1
-2019-03-15 16:43:19 66355a1f012d4ea2b55a1f012dcea264 nodejs:6 cold  104ms      success guest/demo:0.0.1
+2019-03-15 16:43:22 e6bea73bf75f4eb7bea73bf75fdeb703 nodejs:10 warm  1ms        success guest/demo:0.0.1
+2019-03-15 16:43:21 7efb6b7354c3472cbb6b7354c3272c98 nodejs:10 cold  31ms       success guest/failure:0.0.1
+2019-03-15 16:43:21 377cd080f0674e9cbcd080f0679e9c1d nodejs:10 warm  2ms        success guest/demo:0.0.1
+2019-03-15 16:43:20 5dceeccbdc7a4caf8eeccbdc7a9caf18 nodejs:10 cold  29ms       success guest/authenticate:0.0.1
+2019-03-15 16:43:19 66355a1f012d4ea2b55a1f012dcea264 nodejs:10 cold  104ms      success guest/demo:0.0.1
 2019-03-15 16:43:19 09ca3c7f8b68489c8a3c7f8b68b89cdc sequence warm  3.144s     success guest/demo:0.0.1
 
diff --git a/travis/runtimes.json b/travis/runtimes.json index f565907..5673232 100644 --- a/travis/runtimes.json +++ b/travis/runtimes.json @@ -2,27 +2,24 @@ "runtimes": { "nodejs": [ { - "kind": "nodejs", - "image": { - "prefix": "openwhisk", - "name": "nodejsaction", - "tag": "latest" - }, - "deprecated": true - }, - { - "kind": "nodejs:6", + "kind": "nodejs:10", "default": true, "image": { "prefix": "openwhisk", - "name": "nodejs6action", - "tag": "latest" + "name": "action-nodejs-v10", + "tag": "nightly" }, "deprecated": false, - "stemCells": [{ - "count": 2, - "memory": "256 MB" - }] + "attached": { + "attachmentName": "codefile", + "attachmentType": "text/plain" + }, + "stemCells": [ + { + "count": 2, + "memory": "256 MB" + } + ] } ] }, From 461eda5897e19a327efb666a696236cb51eb7483 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 5 Nov 2020 12:24:31 -0500 Subject: [PATCH 86/94] bump openwhisk-client-js version to 3.21.3 (#73) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a6e0a10..a91850d 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ ], "dependencies": { "minimist": "^1.2.0", - "openwhisk": "^3.21.1", + "openwhisk": "^3.21.3", "terser": "^3.8.2" }, "devDependencies": { From 856cc5b5b723e04020bf0df0e26133234872e1f1 Mon Sep 17 00:00:00 2001 From: David Grove Date: Sun, 13 Dec 2020 08:02:24 -0500 Subject: [PATCH 87/94] update for travis migration (#75) --- .travis.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index bfb4cd4..a99b4de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ notifications: webhooks: urls: # travis2slack webhook to enable DMs on openwhisk-team.slack.com to PR authors with TravisCI results - secure: e87H+wvZkwk6LWi4BDNQY1JncgPJ88oOAIJksIl/4DgxjIiX/gak0gLZYfTIqmLSG9ips86qdsSm1d/qMd7EPlLrUcF/PPx5uiwjXbO3aDbgfA/kVkJkQtWFhVhAckmWNJbyJwQfrcFqguDdF+iBD16nMZBGljRSLWuz+gBOsb9gOvLM5wg5m9nZICsUgsdX/Mu4Ib4TdYAW5Sf+evp/5BhyvrycQ6UA+NCAGhQmzI/Tnf8X4zsz8q6OZxcHT8L5b2ucxxGqleplaMzBlir3ADQ7F8QWEIFj4aVmW7VHe2Bloi4g/03zb4nFFn+cFbw4LTZqtHAOZ5fzIMWmKrWWnRi5tOdea1UimWqZ33S2H/M0R6YYIlhdvZXGSAPgGEyfd/BsLtXFah4J8V3odJOHf2QTxPWLucJj3Sjhc9DDqXWo6d+bRP58VfS2HsRDb2pfC2zLCoUa8OMjqPdLVXIH6qbaCVX20KKkz3YNS1xsWmIRvnYaKOAFx4KQDX6o/UoER7gwEJOEgbmCqGIpvAaOsP55N7mGCfOK4m2J1kONsGHUbL2/13hA2AI66P6QS8ohb4JXS5d6F9JZljl/U95qOgT2avD6BtzpUGnMXL5pbUfNXFp+GBneBwzaEE22q6OPVd7PVrHmPFH2tzp3/fmkceeoxrDA45zyaZMevO9gcvM= + secure: "bv5wMNLWLTTwn02xUNGqOSVgDfU2ZzZ6dPHjeoLdkaCkeZYmT15FmXQ7GQ78Cql293Om35nZHc2t54Kxzyq+BWkfKZXo6oF60wxZjaHunipc/+F3CMi+QjFEU7IwMoGom9HFZsTfoYeVPcCaXGKuVD/DMZHfE9TI7kM3/XsDJO+DbHDMxdE7OZUx1lfSNwCIXQrGdQ1w2S4QDnfVbQwmzZXvdzYr0RdVp8jCC4TD5GKr0rP3YemWSlUOO91heAJL217EUlbUr2jcr90x/GRjcPOocX7TobSdxiynk64cKJOODKiacwhHMBICSEKOiMvUelah9hFmmq40wm/oqnJkBzD7SoHCr/P47WjHu8GVW1obGzCldPHKAxTHc0zBS31H10nwYLV7Fo/z7qM0AEwikT7oqHizZVf1U1ywggrBAFrSb/LJBgdSPa4iXPr6t1phUYc+dZX20a4deNyFiHdFaprMNhSiOY6/NgD1Z+4wTFUzVTW96FdinfnjGsdwV46WPP7a7v3wf+bag6+pnT0i6uLFXwUvBmyuvvRYFGKf8UsqIZ2aZKqHZzOLofgdnd8I/0HRPk42aq7GJ1pyA7MXpVnH7MLWyLKk1nNXrsWTdsn8INwox9JaQ3JiefjOovnPKaEWBa6qTfQALkk9uj2gLNsZvqTx3iKSQn747VFGlY0=" env: global: diff --git a/README.md b/README.md index 30c3aa3..3629731 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ # Apache OpenWhisk Composer -[![Travis](https://travis-ci.org/apache/openwhisk-composer.svg?branch=master)](https://travis-ci.org/apache/openwhisk-composer) +[![Travis](https://travis-ci.com/apache/openwhisk-composer.svg?branch=master)](https://travis-ci.com/apache/openwhisk-composer) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) From 5eb331637716ac7c4c2bb6a25a18445af937ef2c Mon Sep 17 00:00:00 2001 From: John Bampton Date: Tue, 9 Mar 2021 22:08:01 +1000 Subject: [PATCH 88/94] chore: fix grammar and spelling (#78) --- CONTRIBUTING.md | 4 ++-- README.md | 6 +++--- docs/COMBINATORS.md | 12 ++++++------ docs/COMMANDS.md | 2 +- docs/COMPOSITIONS.md | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 05d5ebe..c782533 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ # Contributing to Apache OpenWhisk -Anyone can contribute to the OpenWhisk project and we welcome your contributions. +Anyone can contribute to the OpenWhisk project, and we welcome your contributions. There are multiple ways to contribute: report bugs, improve the docs, and contribute code, but you must follow these prerequisites and guidelines: @@ -50,7 +50,7 @@ Please raise any bug reports or enhancement requests on the respective project r list to see if your issue has already been raised. A good bug report is one that make it easy for us to understand what you were trying to do and what went wrong. -Provide as much context as possible so we can try to recreate the issue. +Provide as much context as possible, so we can try to recreate the issue. A good enhancement request comes with an explanation of what you are trying to do and how that enhancement would help you. diff --git a/README.md b/README.md index 3629731..35113bd 100644 --- a/README.md +++ b/README.md @@ -49,12 +49,12 @@ Node Package Manager: ``` npm install -g openwhisk-composer ``` -We recommend to install the package globally (with `-g` option) if you intend to +We recommend installing the package globally (with `-g` option) if you intend to use the `compose` and `deploy` commands to compile and deploy compositions. ## Defining a composition -A composition is typically defined by means of a Javascript expression as +A composition is typically defined by means of a JavaScript expression as illustrated in [samples/demo.js](samples/demo.js): ```javascript const composer = require('openwhisk-composer') @@ -73,7 +73,7 @@ compositions) as parameters. It invokes the first one and, depending on the result of this invocation, invokes either the second or third action. This composition includes the definitions of the three composed actions. If the - actions are defined and deployed elsewhere, the composition code can be shorten + actions are defined and deployed elsewhere, the composition code can be shortened to: ```javascript composer.if('authenticate', 'success', 'failure') diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md index 44cebb6..93ca4af 100644 --- a/docs/COMBINATORS.md +++ b/docs/COMBINATORS.md @@ -29,7 +29,7 @@ The `composer` module offers a number of combinators to define compositions: | [`dynamic`](#dynamic) | dynamic invocation | `composer.dynamic()` | [`empty`](#empty) | empty sequence | `composer.empty()` | [`finally`](#finally) | finalization | `composer.finally('tryThis', 'doThatAlways')` | -| [`function`](#function) | Javascript function | `composer.function(({ x, y }) => ({ product: x * y }))` | +| [`function`](#function) | JavaScript function | `composer.function(({ x, y }) => ({ product: x * y }))` | | [`if` and `if_nosave`](#if) | conditional | `composer.if('authenticate', 'success', 'failure')` | | [`let`](#let) | variable declarations | `composer.let({ count: 3, message: 'hello' }, ...)` | | [`literal` or `value`](#literal) | constant value | `composer.literal({ message: 'Hello, World!' })` | @@ -46,7 +46,7 @@ The `composer` module offers a number of combinators to define compositions: | [`while` and `while_nosave`](#while) | loop | `composer.while('notEnough', 'doMore')` | The `action`, `function`, and `literal` combinators construct compositions -respectively from OpenWhisk actions, Javascript functions, and constant values. +respectively from OpenWhisk actions, JavaScript functions, and constant values. The other combinators combine existing compositions to produce new compositions. ## Shorthands @@ -110,7 +110,7 @@ composer.action('hello', { filename: 'hello.js' }) composer.action('helloAndBye', { sequence: ['hello', 'bye'] }) ``` The action may be defined by providing the code for the action as a string, as a -Javascript function, or as a file name. Alternatively, a sequence action may be +JavaScript function, or as a file name. Alternatively, a sequence action may be defined by providing the list of sequenced actions. The code (specified as a string) may be annotated with the kind of the action runtime. @@ -128,7 +128,7 @@ The `limits` object optionally specifies any combination of: ### Environment capture in actions -Javascript functions used to define actions cannot capture any part of their +JavaScript functions used to define actions cannot capture any part of their declaration environment. The following code is not correct as the declaration of `name` would not be available at invocation time: ```javascript @@ -144,7 +144,7 @@ composer.action('hello', { action: `function main() { return { message: 'Hello ' ## Function -`composer.function(fun)` is a composition with a single Javascript function +`composer.function(fun)` is a composition with a single JavaScript function _fun_. It applies the specified function to the input parameter object for the composition. - If the function returns a value of type `function`, the composition returns @@ -313,7 +313,7 @@ if not. A _condition_ composition evaluates to true if and only if it produces a JSON dictionary with a field `value` with value `true`. Other fields are ignored. Because JSON values other than dictionaries are implicitly lifted to -dictionaries with a `value` field, _condition_ may be a Javascript function +dictionaries with a `value` field, _condition_ may be a JavaScript function returning a Boolean value. An expression such as `params.n > 0` is not a valid condition (or in general a valid composition). One should write instead `params => params.n > 0`. The input parameter object for the composition is the input diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 6e37924..34d9379 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -45,7 +45,7 @@ Flags: -v, --version output the composer version --debug LIST comma-separated list of debug flags (when using --js flag) ``` -The `compose` command takes a Javascript module that exports a composition +The `compose` command takes a JavaScript module that exports a composition object (for example [demo.js](../samples/demo.js)) and compiles this object to a portable JSON format on the standard output or in file. ``` diff --git a/docs/COMPOSITIONS.md b/docs/COMPOSITIONS.md index 9699038..5d32590 100644 --- a/docs/COMPOSITIONS.md +++ b/docs/COMPOSITIONS.md @@ -85,10 +85,10 @@ output parameter objects of `myAction`. ## Components -Components of a compositions can be actions, Javascript functions, or +Components of a compositions can be actions, JavaScript functions, or compositions. -Javascript functions can be viewed as simple, anonymous actions that do not need +JavaScript functions can be viewed as simple, anonymous actions that do not need to be deployed and managed separately from the composition they belong to. Functions are typically used to alter a parameter object between two actions that expect different schemas, as in: From 107a1637f248687c93c8f76cbbfcb411842e6524 Mon Sep 17 00:00:00 2001 From: Nikolai Baudis Date: Mon, 15 Mar 2021 10:37:44 +0100 Subject: [PATCH 89/94] Feature/Enable composer to deploy to IAM-based IBM Cloud Functions namespaces (#70) * first draft for enabling IAM * refactored iam-specific code fragments; adjusted gitignore; added prettier * several code changes and improvements * added correct license header; tweaked travis build config Co-authored-by: Enrico Regge --- .gitignore | 3 ++ .prettierrc.js | 23 +++++++++++ .travis.yml | 11 +----- bin/deploy.js | 2 +- client.js | 80 ++++++++++++++++++++++++++++++++------ ibmcloud-utils.js | 74 +++++++++++++++++++++++++++++++++++ test/cf-plugin-config.json | 3 ++ 7 files changed, 175 insertions(+), 21 deletions(-) create mode 100644 .prettierrc.js create mode 100644 ibmcloud-utils.js create mode 100644 test/cf-plugin-config.json diff --git a/.gitignore b/.gitignore index ef84937..ccccd20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ node_modules openwhisk + +package-lock.json +demo.json \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..924e13e --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +module.exports = { + singleQuote: true, + printWidth: 120, + semi: false, + trailingComma: 'none' +}; diff --git a/.travis.yml b/.travis.yml index a99b4de..6b32f6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,21 +17,14 @@ language: node_js node_js: - - 10 + - 14 services: - docker - -notifications: - email: false - webhooks: - urls: - # travis2slack webhook to enable DMs on openwhisk-team.slack.com to PR authors with TravisCI results - secure: "bv5wMNLWLTTwn02xUNGqOSVgDfU2ZzZ6dPHjeoLdkaCkeZYmT15FmXQ7GQ78Cql293Om35nZHc2t54Kxzyq+BWkfKZXo6oF60wxZjaHunipc/+F3CMi+QjFEU7IwMoGom9HFZsTfoYeVPcCaXGKuVD/DMZHfE9TI7kM3/XsDJO+DbHDMxdE7OZUx1lfSNwCIXQrGdQ1w2S4QDnfVbQwmzZXvdzYr0RdVp8jCC4TD5GKr0rP3YemWSlUOO91heAJL217EUlbUr2jcr90x/GRjcPOocX7TobSdxiynk64cKJOODKiacwhHMBICSEKOiMvUelah9hFmmq40wm/oqnJkBzD7SoHCr/P47WjHu8GVW1obGzCldPHKAxTHc0zBS31H10nwYLV7Fo/z7qM0AEwikT7oqHizZVf1U1ywggrBAFrSb/LJBgdSPa4iXPr6t1phUYc+dZX20a4deNyFiHdFaprMNhSiOY6/NgD1Z+4wTFUzVTW96FdinfnjGsdwV46WPP7a7v3wf+bag6+pnT0i6uLFXwUvBmyuvvRYFGKf8UsqIZ2aZKqHZzOLofgdnd8I/0HRPk42aq7GJ1pyA7MXpVnH7MLWyLKk1nNXrsWTdsn8INwox9JaQ3JiefjOovnPKaEWBa6qTfQALkk9uj2gLNsZvqTx3iKSQn747VFGlY0=" - env: global: - __OW_IGNORE_CERTS=true - REDIS=redis://172.17.0.1:6379 + - IC_FN_CONFIG_FILE=./test/cf-plugin-config.json before_install: - ./travis/scancode.sh before_script: diff --git a/bin/deploy.js b/bin/deploy.js index 5a54691..54524ca 100755 --- a/bin/deploy.js +++ b/bin/deploy.js @@ -46,7 +46,7 @@ if (argv._.length !== 2 || path.extname(argv._[1]) !== '.json') { console.error(' -A, --annotation-file KEY=FILE add KEY annotation with FILE content') console.error(' --apihost HOST API HOST') console.error(' --apiversion VERSION API VERSION') - console.error(' --basic force basic authentication') + console.error(' --basic force basic authentication. Note: this option can only be chosen for CF-based namespaces') console.error(' --bearer force bearer token authentication') console.error(' -i, --insecure bypass certificate checking') console.error(' --kind KIND the KIND of the conductor action runtime') diff --git a/client.js b/client.js index e1863a0..ad81eb8 100644 --- a/client.js +++ b/client.js @@ -22,9 +22,13 @@ const conductor = require('./conductor') const fs = require('fs') const openwhisk = require('openwhisk') +const ibmcloudUtils = require('./ibmcloud-utils') const os = require('os') const path = require('path') +const NS_TYPE_CF = 'CF' +const NS_TYPE_IAM = 'IAM' + // return enhanced openwhisk client capable of deploying compositions module.exports = function (options, basic, bearer) { // try to extract apihost and key first from whisk property file file and then from process.env @@ -32,7 +36,7 @@ module.exports = function (options, basic, bearer) { let apiversion let apikey let ignorecerts - let namespace = '_' + let namespace = ibmcloudUtils.getNamespaceId() let token let authHandler @@ -49,14 +53,12 @@ module.exports = function (options, basic, bearer) { apiversion = parts[1] } else if (parts[0] === 'AUTH') { apikey = parts[1] - } else if (parts[0] === 'NAMESPACE') { - namespace = parts[1] } else if (parts[0] === 'APIGW_ACCESS_TOKEN') { token = parts[1] } } } - } catch (error) { } + } catch (error) {} if (process.env.__OW_API_HOST) apihost = process.env.__OW_API_HOST if (process.env.__OW_API_KEY) apikey = process.env.__OW_API_KEY @@ -64,16 +66,64 @@ module.exports = function (options, basic, bearer) { if (process.env.__OW_IGNORE_CERTS) ignorecerts = process.env.__OW_IGNORE_CERTS if (process.env.__OW_APIGW_TOKEN) token = process.env.__OW_APIGW_TOKEN - if (bearer || (!basic && namespace !== '_')) { - // switch from basic auth to bearer token + // check whether there is a CLI argument that overrides the API key retrieved from the config or env + if (options && options.api_key) apikey = options.api_key + + // retrieve the namespace type + // we need to apply different authentication strategies for CF and IAM + const namespaceType = ibmcloudUtils.getNamespaceType() + + // + // check for IAM-based namespaces, first + if (namespaceType === NS_TYPE_IAM) { + // for authentication, we'll use the user IAM access token + const iamToken = ibmcloudUtils.getIamAuthHeader() + + // define an appropriate authentication handler for IAM authHandler = { getAuthHeader: () => { - return Promise.resolve(`Bearer ${token}`) + // use bearer token for IAM authentication + return Promise.resolve(iamToken) } } + + // ignore the API key value, in case of an IAM-based namespace + apikey = undefined + + // + // in case of CF-based namespaces, the user can opt-in for using bearer token authentication instead of using the default basic authentication + } else if (namespaceType === NS_TYPE_CF) { + if (bearer && !basic) { + // switch from basic auth to bearer token + authHandler = { + getAuthHeader: () => { + return Promise.resolve(`Bearer ${token}`) + } + } + } else if (apikey) { + // use basic auth + authHandler = { + getAuthHeader: () => { + const apiKeyBase64 = Buffer.from(apikey).toString('base64') + return Promise.resolve(`Basic ${apiKeyBase64}`) + } + } + } + } + + const namespaceDisplayName = namespace || '_' + + console.log(`deploying to ${namespaceType}-based namespace '${namespaceDisplayName}' ...`) + + if (!authHandler) { + throw new Error( + `Failed to determine the authentication strategy for the ${namespaceType}-based namespace '${namespaceDisplayName}'` + ) } - const wsk = openwhisk(Object.assign({ apihost, apiversion, api_key: apikey, auth_handler: authHandler, namespace, ignore_certs: ignorecerts }, options)) + const wsk = openwhisk( + Object.assign({ apihost, apiversion, auth_handler: authHandler, namespace, ignore_certs: ignorecerts }, options) + ) wsk.compositions = new Compositions(wsk) return wsk } @@ -90,9 +140,17 @@ class Compositions { return Object.assign({}, action, httpOptions) } - const actions = (composition.actions || []).concat(conductor.generate(composition, debug, kind, timeout, memory, logs)).map(addHttpOptions) - return actions.reduce((promise, action) => promise.then(() => overwrite && this.actions.delete(action).catch(() => { })) - .then(() => this.actions.create(action)), Promise.resolve()) + const actions = (composition.actions || []) + .concat(conductor.generate(composition, debug, kind, timeout, memory, logs)) + .map(addHttpOptions) + return actions + .reduce( + (promise, action) => + promise + .then(() => overwrite && this.actions.delete(action).catch(() => {})) + .then(() => this.actions.create(action)), + Promise.resolve() + ) .then(() => actions) } } diff --git a/ibmcloud-utils.js b/ibmcloud-utils.js new file mode 100644 index 0000000..adec6f2 --- /dev/null +++ b/ibmcloud-utils.js @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +'use strict' + +const fs = require('fs') +const os = require('os') +const path = require('path') + +const getCloudFunctionsConfig = () => { + try { + // read the ibm cloud functions cli config file + const ibmCloudFunctionsPropsPath = + process.env.IC_FN_CONFIG_FILE || path.join(os.homedir(), '.bluemix/plugins/cloud-functions/config.json') + const ibmCloudFunctionsConfig = JSON.parse(fs.readFileSync(ibmCloudFunctionsPropsPath, { encoding: 'utf8' })) + + return ibmCloudFunctionsConfig + } catch (error) { + console.error('Could not open ibmcloud functions plugin config') + throw error + } +} + +const getNamespaceType = () => { + return getCloudFunctionsConfig().WskCliNamespaceMode +} + +const getNamespaceId = () => { + return getCloudFunctionsConfig().WskCliNamespaceId +} + +/** + * return a Apache OpenWhisk Client SDK for JavaScript compliant authentication header token, + * which can be used within a custom authentication handler + * see https://github.com/apache/openwhisk-client-js#using-3rd-party-authentication-handler + * for further details + */ +const getIamAuthHeader = () => { + // for authentication, we'll use the user IAM access token + let iamToken + try { + // read the IAM Access token from the ibm cloud config file + const ibmCloudPropsPath = process.env.IC_CONFIG_FILE || path.join(os.homedir(), '.bluemix/config.json') + const ibmCloudConfig = JSON.parse(fs.readFileSync(ibmCloudPropsPath, { encoding: 'utf8' })) + + iamToken = ibmCloudConfig.IAMToken + } catch (error) { + console.error('Could not open ibmcloud config') + throw error + } + + // return an object that provides a getAuthHeader function to comply with the authentication handler interface + // required by OpenWhisk Client SDK for JavaScript + return iamToken +} + +module.exports = { + getIamAuthHeader, + getNamespaceType, + getNamespaceId +} diff --git a/test/cf-plugin-config.json b/test/cf-plugin-config.json new file mode 100644 index 0000000..8047c6e --- /dev/null +++ b/test/cf-plugin-config.json @@ -0,0 +1,3 @@ +{ + "WskCliNamespaceMode": "CF" +} \ No newline at end of file From fcbf554d24f5347ce34a7a0a13cc15fa25a8f0f1 Mon Sep 17 00:00:00 2001 From: Nikolai Baudis Date: Mon, 15 Mar 2021 11:05:03 +0100 Subject: [PATCH 90/94] Add retry sample (#71) --- samples/retry.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 samples/retry.js diff --git a/samples/retry.js b/samples/retry.js new file mode 100644 index 0000000..77f46ba --- /dev/null +++ b/samples/retry.js @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +const composer = require('openwhisk-composer') + +function generateEvenNumber (args) { + const number = Math.floor(Math.random() * 10) + console.log(`generated number ${number}`) + + if (number % 2 !== 0) { + throw new Error(`error: number is not even`) + } + + return { value: number } +} + +function useDefaultNumber (args) { + console.log(`handling error, using default value`) + return { value: 42 } +} + +module.exports = composer.try( + composer.retry(2, composer.action('generateEvenNumber', { action: generateEvenNumber })), + composer.action('useDefaultNumber', { action: useDefaultNumber })) From 48cc891b894375858d553f67ec34796775c1423a Mon Sep 17 00:00:00 2001 From: Nikolai Baudis Date: Thu, 18 Mar 2021 11:58:42 +0100 Subject: [PATCH 91/94] Add IAM token expiration check (#72) * Add IAM token expiration check * Fix linter issues * Use ibmcloud config path from env; mock test configs instead * Compare timestamp with UTC time in tests * Mock env config path and default locations --- .travis.yml | 1 + client.js | 10 ++++++ ibmcloud-utils.js | 20 ++++++++++-- package.json | 1 + test/ibmcloud-utils.js | 69 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 test/ibmcloud-utils.js diff --git a/.travis.yml b/.travis.yml index 6b32f6c..9f0e9bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,7 @@ env: - __OW_IGNORE_CERTS=true - REDIS=redis://172.17.0.1:6379 - IC_FN_CONFIG_FILE=./test/cf-plugin-config.json + - IC_CONFIG_FILE=./test/cf-config.json before_install: - ./travis/scancode.sh before_script: diff --git a/client.js b/client.js index ad81eb8..27757c2 100644 --- a/client.js +++ b/client.js @@ -76,6 +76,16 @@ module.exports = function (options, basic, bearer) { // // check for IAM-based namespaces, first if (namespaceType === NS_TYPE_IAM) { + const tokenTimestamp = ibmcloudUtils.getIamTokenTimestamp() + + if (ibmcloudUtils.iamTokenExpired(tokenTimestamp)) { + console.log( + 'Error: Your IAM token seems to be expired. Plase perform an `ibmcloud login` ' + + 'to make sure your token is up to date.' + ) + throw new Error('IAM token expired') + } + // for authentication, we'll use the user IAM access token const iamToken = ibmcloudUtils.getIamAuthHeader() diff --git a/ibmcloud-utils.js b/ibmcloud-utils.js index adec6f2..5c70e4a 100644 --- a/ibmcloud-utils.js +++ b/ibmcloud-utils.js @@ -67,8 +67,24 @@ const getIamAuthHeader = () => { return iamToken } +const getIamTokenTimestamp = () => { + const timestamp = getCloudFunctionsConfig().IamTimeTokenRefreshed + return new Date(timestamp) +} + +const iamTokenExpired = (timeRefreshed, timeReference) => { + if (typeof (timeReference) === 'undefined') { + timeReference = new Date() + } + + // time difference in hours exceeds 1 hour + return (timeReference - timeRefreshed) / 1000 / 3600 > 1 +} + module.exports = { + iamTokenExpired, getIamAuthHeader, - getNamespaceType, - getNamespaceId + getIamTokenTimestamp, + getNamespaceId, + getNamespaceType } diff --git a/package.json b/package.json index a91850d..7bb189a 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ }, "devDependencies": { "mocha": "^5.2.0", + "mock-fs": "^4.13.0", "pre-commit": "^1.2.2", "standard": "^12.0.1" }, diff --git a/test/ibmcloud-utils.js b/test/ibmcloud-utils.js new file mode 100644 index 0000000..34f99a6 --- /dev/null +++ b/test/ibmcloud-utils.js @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* eslint-env mocha */ + +'use strict' + +const assert = require('assert') +const mock = require('mock-fs') +const path = require('path') +const os = require('os') + +const ibmcloudUtils = require('../ibmcloud-utils') +const client = require('../client') + +describe('ibmcloud-utils', function () { + describe('ibmcloud-utils.token-expiration', function () { + const ibmCloudFunctionsPropsPath = + process.env.IC_FN_CONFIG_FILE || path.join(os.homedir(), '.bluemix/plugins/cloud-functions/config.json') + const ibmCloudPropsPath = process.env.IC_CONFIG_FILE || path.join(os.homedir(), '.bluemix/config.json') + + it('read timestamp', function () { + mock({ + [ibmCloudFunctionsPropsPath]: '{ "IamTimeTokenRefreshed": "2021-03-15T13:24:14+01:00" }' + }) + const timestamp = ibmcloudUtils.getIamTokenTimestamp() + assert.strictEqual(timestamp.getTime(), Date.UTC(2021, 2, 15, 12, 24, 14)) + }) + + it('token not expired', function () { + const timeRefreshed = new Date(2021, 2, 13, 13, 24, 14) + const timeReference = new Date(2021, 2, 13, 13, 30, 0) + const tokenExpired = ibmcloudUtils.iamTokenExpired(timeRefreshed, timeReference) + assert.strictEqual(tokenExpired, false) + }) + + it('token expired', function () { + const timeRefreshed = new Date(2021, 2, 13, 13, 24, 14) + const timeReference = new Date(2021, 2, 13, 14, 25, 0) + const tokenExpired = ibmcloudUtils.iamTokenExpired(timeRefreshed, timeReference) + assert.strictEqual(tokenExpired, true) + }) + + it('client fails when token expired', function () { + mock({ + [ibmCloudFunctionsPropsPath]: '{ "IamTimeTokenRefreshed": "2021-03-14T12:00:00+01:00", ' + + '"WskCliNamespaceId": "some-namespace-id", ' + + '"WskCliNamespaceMode": "IAM" }', + [ibmCloudPropsPath]: '{ "IAMToken": "some-token" }' + }) + + assert.throws(() => client(), /IAM token expired/) + }) + }) +}) From 3cde51029dbfe9cad11a918b2441d13c49d18a8c Mon Sep 17 00:00:00 2001 From: Nikolai Baudis Date: Fri, 19 Mar 2021 22:12:27 +0100 Subject: [PATCH 92/94] Adapt project setup to ibm-functions org (#73) * Update package info; update package name in docs and samples * Add npm deploy config --- .travis.yml | 8 ++++++++ README.md | 23 +++++++++++------------ docs/COMBINATORS.md | 2 +- package.json | 9 +++++---- samples/demo.js | 2 +- samples/retry.js | 2 +- 6 files changed, 27 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f0e9bd..c415305 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,3 +30,11 @@ before_install: - ./travis/scancode.sh before_script: - ./travis/setup.sh +deploy: + provider: npm + email: reggeenr@de.ibm.com + api_key: + secure: lyftFmbsZ0S/kcAjf5nVR1W+a1IrtsSghQ7o9w6A7COTKNwBh1QNnF+yh8OL72Sc4/PgRiV4Z6Jg9ZFCt3bWd3tsRcXqTXXspFC/lHsj//0s6M+a0c9pFr/uhND0hWXrIkVr0VLXNPp/3LMORS7fzjKktx/yksivBcdGHj4SX4sz3wHI3uq6gfb9OQXWqcs7jBOgMClKFeqOLaDAFJzRf9DZFsV9z5Eq2MwCALaoXZBbbmNcq795fioHKnMLzMVlN16aWsuDyFxGn/LLMdlmgaDLiF0KITtLM1V9XNrEETurLD41TcNChlsBcsHA15Seg9bsiKU7PX7+s+kb55eB3Gg9wJYhXfND5OFh+DL3GT7tLPetXda8sHaCkoEKOEdy30HEqPYZLy7X2fYQj7Ety4sqhe6SRkPFYhuS6+r179B/0Xu+KF17y1VG7CWHwTEKotZOLF4TLOudJ9O7+rUI0xOlNXj7tAURjXY6OJ1DMAefpRcwM5xaC8/3OIimK7Ab3BZn4or1PwpzK5qQDnaI/350IAK9wDkLyyT1OFywq7xNyfgKhv5gIgjoYEBAdwNTjjMcrGaTyFxLSoo3SluXXMYy9H3FXfBwNJfbF8mfHf3K/U1IdjlJ4TxlEPoUvPSv1a5M2oswZwKeRM6Mqmal+P0tAJzOY2rsJxTtpwkeMpk= + on: + tags: true + repo: ibm-functions/composer diff --git a/README.md b/README.md index 35113bd..97ee616 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,9 @@ # --> -# Apache OpenWhisk Composer +# @ibm-functions/composer -[![Travis](https://travis-ci.com/apache/openwhisk-composer.svg?branch=master)](https://travis-ci.com/apache/openwhisk-composer) +[![Travis](https://travis-ci.org/ibm-functions/composer.svg?branch=master)](https://travis-ci.org/ibm-functions/composer) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) @@ -47,7 +47,7 @@ This repository includes: Composer is distributed as Node.js package. To install this package, use the Node Package Manager: ``` -npm install -g openwhisk-composer +npm install -g @ibm-functions/composer ``` We recommend installing the package globally (with `-g` option) if you intend to use the `compose` and `deploy` commands to compile and deploy compositions. @@ -57,7 +57,7 @@ use the `compose` and `deploy` commands to compile and deploy compositions. A composition is typically defined by means of a JavaScript expression as illustrated in [samples/demo.js](samples/demo.js): ```javascript -const composer = require('openwhisk-composer') +const composer = require('@ibm-functions/composer') module.exports = composer.if( composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }), @@ -98,9 +98,9 @@ existing definitions. ## Running a composition The `demo` composition may be invoked like any action, for instance using the -OpenWhisk CLI: +[IBM Cloud CLI](https://cloud.ibm.com/docs/cli): ``` -wsk action invoke demo -p password passw0rd +ibmcloud fn action invoke demo -p password passw0rd ``` ``` ok: invoked /_/demo with id 09ca3c7f8b68489c8a3c7f8b68b89cdc @@ -108,7 +108,7 @@ ok: invoked /_/demo with id 09ca3c7f8b68489c8a3c7f8b68b89cdc The result of this invocation is the result of the last action in the composition, in this case the `failure` action since the password in incorrect: ``` -wsk activation result 09ca3c7f8b68489c8a3c7f8b68b89cdc +ibmcloud fn activation result 09ca3c7f8b68489c8a3c7f8b68b89cdc ``` ```json { @@ -119,7 +119,7 @@ wsk activation result 09ca3c7f8b68489c8a3c7f8b68b89cdc This invocation creates a trace, i.e., a series of activation records: ``` -wsk activation list +ibmcloud fn activation list ```
 Datetime            Activation ID                    Kind     Start Duration   Status  Entity
@@ -211,9 +211,8 @@ combinators or the `async` combinator.
 # Installation from Source
 
 To install composer from a source release, download the composer source code
-from the [Apache OpenWhisk
-Downloads](https://openwhisk.apache.org/downloads.html) page, rename the release
-tarball to `openwhisk-composer.tgz` and install it with command:
+from [our GitHub repo](https://github.com/ibm-functions/composer/releases),
+rename the release tarball to `composer.tgz` and install it with command:
 ```shell
-npm install -g openwhisk-composer.tgz
+npm install -g composer.tgz
 ```
diff --git a/docs/COMBINATORS.md b/docs/COMBINATORS.md
index 93ca4af..76017f5 100644
--- a/docs/COMBINATORS.md
+++ b/docs/COMBINATORS.md
@@ -544,7 +544,7 @@ belongs to the same package as the composition, without having to specify the
 package name beforehand.
 
 ```javascript
-const composer = require('openwhisk-composer')
+const composer = require('@ibm-functions/composer')
 
 function invoke (actionShortName) {
   return composer.let(
diff --git a/package.json b/package.json
index 7bb189a..06273c5 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,9 @@
 {
   "license": "Apache-2.0",
-  "name": "openwhisk-composer",
+  "name": "@ibm-functions/composer",
   "version": "0.12.0",
   "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.",
-  "homepage": "https://github.com/apache/openwhisk-composer",
+  "homepage": "https://github.com/ibm-functions/composer",
   "main": "composer.js",
   "scripts": {
     "test": "standard && mocha"
@@ -17,13 +17,14 @@
     "client.js",
     "composer.js",
     "conductor.js",
-    "fqn.js",
     "docs/*.md",
+    "fqn.js",
+    "ibmcloud-utils.js",
     "samples/"
   ],
   "repository": {
     "type": "git",
-    "url": "https://github.com/apache/openwhisk-composer.git"
+    "url": "https://github.com/ibm-functions/composer.git"
   },
   "keywords": [
     "functions",
diff --git a/samples/demo.js b/samples/demo.js
index 9454bbc..12c632f 100644
--- a/samples/demo.js
+++ b/samples/demo.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-const composer = require('openwhisk-composer')
+const composer = require('@ibm-functions/composer')
 
 module.exports = composer.if(
   composer.action('authenticate', { action: function ({ password }) { return { value: password === 'abc123' } } }),
diff --git a/samples/retry.js b/samples/retry.js
index 77f46ba..f0f7e14 100644
--- a/samples/retry.js
+++ b/samples/retry.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-const composer = require('openwhisk-composer')
+const composer = require('@ibm-functions/composer')
 
 function generateEvenNumber (args) {
   const number = Math.floor(Math.random() * 10)

From 41b1865a215a36b5e7f14744b7aaf1d5e8c7838b Mon Sep 17 00:00:00 2001
From: Nikolai Baudis 
Date: Tue, 23 Mar 2021 14:28:15 +0100
Subject: [PATCH 93/94] Bump Ansible to 2.8.19 (#74)

---
 travis/setup.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/travis/setup.sh b/travis/setup.sh
index ac48a00..4e247f4 100755
--- a/travis/setup.sh
+++ b/travis/setup.sh
@@ -35,7 +35,7 @@ cd $ROOTDIR
 git clone --depth=1 https://github.com/apache/openwhisk.git openwhisk
 
 # Install Ansible
-pip install --user ansible==2.5.2
+pip install --user ansible==2.8.19
 
 # Configure runtimes
 cp $SCRIPTDIR/runtimes.json $WHISKDIR/ansible/files

From 6b4c68a66423ce6fb416f53804124689b94b0fc7 Mon Sep 17 00:00:00 2001
From: Enrico Regge 
Date: Wed, 24 Mar 2021 11:39:54 +0100
Subject: [PATCH 94/94] 1.0.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 06273c5..d9e7110 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "license": "Apache-2.0",
   "name": "@ibm-functions/composer",
-  "version": "0.12.0",
+  "version": "1.0.0",
   "description": "Composer is a new programming model for composing cloud functions built on Apache OpenWhisk.",
   "homepage": "https://github.com/ibm-functions/composer",
   "main": "composer.js",




pFad - Phonifier reborn



Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy