diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..7cde01d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "airbnb-base" +} diff --git a/.gitignore b/.gitignore index 82372cb..ecafe7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ /node_modules/ -spec/*.js -spec/browser/*.js npm-debug.log .DS_Store .noflo.json diff --git a/.travis.yml b/.travis.yml index 9996b8c..1145be5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: node_js sudo: false node_js: -- '0.12' -- '4.2' -- '6.2' +- 'lts/*' script: npm test diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100755 index 51b47de..0000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = -> - # Project configuration - @initConfig - pkg: @file.readJSON 'package.json' - - # load all of the .coffee files inside of our /spec directory - mochaTest: - nodejs: - src: ['spec/*.coffee'] - options: - reporter: 'spec' - timeout: 20000 - require: 'coffee-script/register' - grep: process.env.TESTS - - # Coding standards - coffeelint: - all: - files: - src: ['components/*.coffee', 'spec/*.coffee'] - options: - max_line_length: - value: 80 - level: 'ignore' - - # Grunt plugins used for testing - @loadNpmTasks 'grunt-mocha-test' - @loadNpmTasks 'grunt-coffeelint' - - # Our local tasks - @registerTask 'test', ['coffeelint', 'mochaTest'] - @registerTask 'default', ['test'] diff --git a/README.md b/README.md index d1cb988..0ee1049 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,15 @@ -# Canadianness -## Example program using noflo +# Canadianness [![Build Status](https://travis-ci.org/noflo/canadianness.svg?branch=master)](https://travis-ci.org/noflo/canadianness) [![Greenkeeper badge](https://badges.greenkeeper.io/noflo/canadianness.svg)](https://greenkeeper.io/) + +Basic example of programming with [NoFlo](https://noflojs.org). + +## Prerequisites + +You need to have [Node.js](http://nodejs.org) 6.10 or newer installed. + +## Install + + npm install + +## Run tests + + npm test diff --git a/components/ArrayToStream.js b/components/ArrayToStream.js new file mode 100644 index 0000000..d5d60a6 --- /dev/null +++ b/components/ArrayToStream.js @@ -0,0 +1,47 @@ +const noflo = require('noflo'); + +exports.getComponent = () => { + const c = new noflo.Component({ + description: 'Convert input array to a NoFlo stream', + inPorts: { + in: { + datatype: 'array', + description: 'data we want to send', + required: true, + }, + }, + outPorts: { + out: { + datatype: 'string', + description: 'the data wrapped in brackets', + required: true, + }, + }, + }); + + c.process((input, output) => { + if (!input.hasData('in')) { return; } + + let datas = input.getData('in'); + if (!Array.isArray(datas)) { + datas = [datas]; + } + + output.send({ + out: new noflo.IP('openBracket'), + }); + + datas.forEach((data) => { + output.send({ + out: new noflo.IP('data', data), + }); + }); + + output.send({ + out: new noflo.IP('closeBracket'), + }); + output.done(); + }); + + return c; +}; diff --git a/components/DetermineEmotion.coffee b/components/DetermineEmotion.coffee deleted file mode 100755 index b7b45f9..0000000 --- a/components/DetermineEmotion.coffee +++ /dev/null @@ -1,75 +0,0 @@ -noflo = require 'noflo' - -# https://en.wikipedia.org/wiki/Mode_(statistics) -findMode = (array) -> - frequency = {} - maxFrequency = 0 - result = undefined - for v of array - frequency[array[v]] = (frequency[array[v]] or 0) + 1 - if frequency[array[v]] > maxFrequency - maxFrequency = frequency[array[v]] - result = array[v] - result - -# could also pass in full contents here and determine distance from each other -exports.getComponent = -> - c = new noflo.Component - description: 'Find all of the instances of `word` in `content` and send them out in a stream' - inPorts: - content: - datatype: 'string' - description: 'the content which we look for the word in' - required: true - outPorts: - emotion: - datatype: 'string' - description: 'the emotion based the content in ehs' - required: true - error: - datatype: 'object' - - # we are using brackets to group the stream, so we do not want to forward them - c.process (input, output) -> - return unless input.hasStream 'content' - - # we get the [full stream](noflojs.org/documentation/process-api/#full-stream) - contents = input.getStream 'content' - - # since it has `openBracket` and `closeBracket` we only want the dat - contents = contents.filter (ip) -> ip.type is 'data' - - # since it is an array of IP objects, - # they contain other properties, we only want the data - contents = contents.map (ip) -> ip.data - - # to hold the emotion matches - matches = [] - - # the emotions we will use - emotions = - joy: ['eh!'] - neutral: ['eh'] - amusement: ['eh?', 'Eh?', 'Eh??'] - fear: ['eH??', 'eh??'] - surprise: ['eh !?', 'EH!?'] - anticipation: ['eh?!'] - excitment: ['EH!', 'eH!'] - sadness: ['...eh', '...eh...', '..eh', 'eh..', '..eh..'] - anger: ['EH!?', 'EH?'] - - # go through our content and our emotions - # then add them to our `matches` - for content in contents - for emotion, data of emotions - if content in data - matches.push emotion - - # if we didn't get any emotions, it is default neutral - if matches.length is 0 - mode = 'neutral' - # if we did, we need to find the emotion that was the most common - else - mode = findMode matches - - output.sendDone emotion: mode diff --git a/components/DetermineEmotion.js b/components/DetermineEmotion.js new file mode 100644 index 0000000..8948ef4 --- /dev/null +++ b/components/DetermineEmotion.js @@ -0,0 +1,113 @@ +// ## Import libraries +const noflo = require('noflo'); + +// ## Useful functions +// +// Function to calculate most common value (the [mode](https://en.wikipedia.org/wiki/Mode_(statistics)) +function findMode(array) { + const frequency = {}; + let maxFrequency = 0; + let result; + array.forEach((v) => { + frequency[v] = (frequency[v] || 0) + 1; + if (frequency[v] > maxFrequency) { + maxFrequency = frequency[v]; + result = v; + } + }); + return result; +} + +// ## Component declaration +// +// Define the input and output ports, and describe their function +exports.getComponent = () => { + const c = new noflo.Component({ + description: 'Find all of the instances of `word` in `content` and send them out in a stream', + inPorts: { + content: { + datatype: 'string', + description: 'the content which we look for the word in', + required: true, + }, + }, + outPorts: { + emotion: { + datatype: 'string', + description: 'the emotion based the content in ehs', + required: true, + }, + error: { + datatype: 'object', + }, + }, + }); + + // Since we want to work with a full stream, we disable bracket forwarding + c.forwardBrackets = {}; + + // ## Processing function + // + c.process((input, output) => { + // ### Receiving input + // + // We expect a [stream](noflojs.org/documentation/process-api/#full-stream) + // Will also accept a single (non-bracketed) input packet, returned as a stream of length 1 + if (!input.hasStream('content')) { return; } + + // The output will be a single packet (not a stream), + // hence we drop the `openBracket` and `closeBracket` + // and extract the data payload from the IP objects + const contents = input.getStream('content').filter(ip => ip.type === 'data').map(ip => ip.data); + + // ### Component business logic + // + // First find which emotions are present, then calculate which one is most common. + // This could alternatively be split into two dedicate components. + + // to hold the emotions found + const matches = []; + + // the emotions we will use + const emotions = { + joy: ['eh!'], + neutral: ['eh'], + amusement: ['eh?', 'Eh?', 'Eh??'], + fear: ['eH??', 'eh??'], + surprise: ['eh !?', 'EH!?'], + anticipation: ['eh?!'], + excitment: ['EH!', 'eH!'], + sadness: ['...eh', '...eh...', '..eh', 'eh..', '..eh..'], + anger: ['EH!?', 'EH?'], + }; + + // go through our content and our emotions + // then add them to our `matches` + contents.forEach((content) => { + Object.keys(emotions).forEach((emotion) => { + const data = emotions[emotion]; + if (data.indexOf(content) !== -1) { + matches.push(emotion); + } + }); + }); + + // if we didn't get any emotions, it default to 'neutral' + let mode; + if (matches.length === 0) { + mode = 'neutral'; + // if we did, we need to find the emotion that was the most common + } else { + mode = findMode(matches); + } + + // ### Send output + // + // Also signals completion by using `sendDone()` + output.sendDone({ + emotion: mode, + }); + }); + + return c; +}; diff --git a/components/FindWords.coffee b/components/FindWords.coffee deleted file mode 100755 index baa3ace..0000000 --- a/components/FindWords.coffee +++ /dev/null @@ -1,78 +0,0 @@ -noflo = require 'noflo' - -# a helper to match all on a string -matchAll = (string, regexp) -> - matches = [] - string.replace regexp, -> - arr = [].slice.call arguments, 0 - extras = arr.splice -2 - arr.index = extras[0] - arr.input = extras[1] - matches.push arr - return - if matches.length then matches else [] - -# since regexing will give the `index` and the `input`, we only want the match -actualMatches = (matches) -> - # because we want to send out an empty array if there are no matches - return [[]] if matches.length is 0 - matches.map (match) -> match[0] - -exports.getComponent = -> - c = new noflo.Component - description: 'Find all of the instances of `word` in `content` and send them out in a stream' - inPorts: - word: - datatype: 'string' # could be array|string, which would be `all` - description: 'the word we are looking for instances of' - control: true - required: true - content: - datatype: 'string' - description: 'the content which we look for the word in' - required: true - surrounding: # could use a regex but this is a specific case - datatype: 'boolean' - description: 'whether to get surrounding characters, symbols before and after until space' - default: false # if nothing is sent to it, this is the default when `get`ting from it - control: true - outPorts: - matches: - datatype: 'string' - description: 'the resulting findings as a stream of data packets' - required: true - - # we are only using data, - # so we do not need any brackets sent to the inPorts, pass them along - # - # control ports do not have brackets, - # so we don't need to do anything special with them - c.forwardBrackets = - content: 'matches' - c.process (input, output) -> - # if it is not data, remove it from the buffer - return input.buffer.get().pop() if input.ip.type isnt 'data' - # make sure we have data in the required inPorts - return unless input.has 'word', 'content', (ip) -> ip.type is 'data' - - # since we are sending out multiple `data` IPs - # we want to wrap them in brackets - output.send matches: new noflo.IP 'openBracket', content - - # get the data from our in ports - word = input.getData 'word' - content = input.getData 'content' - - # do our word processing - r = /([.?!]*eh[.?!]*)/gi - matches = matchAll content, r - matches = actualMatches matches - - # for each of our matches, send them out - for match in matches - # if you just send content, it will automatically put it in a data ip - # so this is the same as `output.send matches: new noflo.IP 'data', match` - output.send matches: match - - # this is the same as doing `output.send` and then `output.done` - output.sendDone matches: new noflo.IP 'closeBracket', content diff --git a/components/FindWords.js b/components/FindWords.js new file mode 100644 index 0000000..58b7ca1 --- /dev/null +++ b/components/FindWords.js @@ -0,0 +1,110 @@ +// ## Import libraries +const noflo = require('noflo'); + +// ## Helper functions +// +// Not NoFlo or even component-logic-specific, so nice to keep them separate + +// Return all RegExp matches on a string +function matchAll(string, regexp) { + const matches = []; + string.replace(regexp, (...rest) => { + const arr = rest.slice(0); + const extras = arr.splice(-2); + [arr.index, arr.input] = extras; + matches.push(arr); + }); + if (matches.length) { + return matches; + } + return []; +} + +// Extract the actual data of the match result +function actualMatches(matches) { + // because we want to send out an empty array if there are no matches + if (matches.length === 0) { return [[]]; } + return matches.map(match => match[0]); +} + +// ## Component declaration +exports.getComponent = () => { + const c = new noflo.Component({ + description: 'Find all of the instances of `word` in `content` and send them out in a stream', + inPorts: { + content: { + datatype: 'string', + description: 'the content which we look for a word in', + required: true, + }, + word: { + datatype: 'string', // could be array|string, which would be `all` + description: 'the word we are looking for instances of', + control: true, + required: true, + }, + surrounding: { // could use a regex but this is a specific case + datatype: 'boolean', + description: 'whether to get surrounding characters, symbols before and after until space', + default: false, // if nothing is sent to it, this is the default when `get`ting from it + control: true, + }, + }, + outPorts: { + matches: { + datatype: 'string', + description: 'the resulting findings as a stream of data packets', + required: true, + }, + }, + }); + + // ## Processing function + // + // To preserve streams, forward brackets from the primary inport `content` to the output. + c.forwardBrackets = { + content: ['matches'], + }; + + c.process((input, output) => { + // ### Receiving input data + // + // We need both a `word`, and `content` to start processing + // Since `word` is a control port, the latest value is kept, no need to continiously send + if (!input.hasData('word', 'content')) { return; } + // const [word, content] = input.getData('word', 'content'); + const content = input.getData('content'); + + // ### Component business logic + // + // since we are sending out multiple `data` IPs + // we want to wrap them in brackets + // TODO: make exception safe + output.send({ + matches: new noflo.IP('openBracket', content), + }); + + // do our word processing + const r = /([.?!]*eh[.?!]*)/gi; + let matches = matchAll(content, r); + matches = actualMatches(matches); + + // ### Sending output + // + // for each of our matches, send them out + matches.forEach((match) => { + // if you just send content, it will automatically put it in a data ip + // so this is the same as `output.send matches: new noflo.IP 'data', match` + output.send({ + matches: match, + }); + }); + + // this is the same as doing `output.send` and then `output.done` + output.sendDone({ + matches: new noflo.IP('closeBracket', content), + }); + }); + + return c; +}; diff --git a/components/TestDetermineEmotion.coffee b/components/TestDetermineEmotion.coffee deleted file mode 100644 index 7ea68d6..0000000 --- a/components/TestDetermineEmotion.coffee +++ /dev/null @@ -1,34 +0,0 @@ -noflo = require 'noflo' - -exports.getComponent = -> - c = new noflo.Component - description: 'Test using fbp-spec' - inPorts: - in: - datatype: 'array' - description: 'data we want to send' - required: true - outPorts: - out: - datatype: 'string' - description: 'the data wrapped in brackets' - required: true - - c.process (input, output) -> - # if it is not data, remove it from the buffer - return input.buffer.get().pop() if input.ip.type isnt 'data' - return unless input.has 'in' - - # needs the extra closeBracket - # because of the extra connect in translation layer - output.send out: new noflo.IP 'openBracket' - - datas = input.getData 'in' - unless Array.isArray datas - datas = [datas] - for data in datas - output.send out: new noflo.IP 'data', data - - output.send out: new noflo.IP 'closeBracket' - output.send out: new noflo.IP 'closeBracket' - output.done() diff --git a/components/WordScore.coffee b/components/WordScore.coffee deleted file mode 100755 index 598757c..0000000 --- a/components/WordScore.coffee +++ /dev/null @@ -1,93 +0,0 @@ -noflo = require 'noflo' -natural = require 'natural' -tokenizer = new natural.WordTokenizer() - -exports.getComponent = -> - c = new noflo.Component - description: 'Find how the input words compare against the list of weighted words' - inPorts: - list: - datatype: 'array' - description: 'list of words we will use with the list of content' - control: true - required: true - content: - datatype: 'string' - description: 'the content which we will determine the score of' - required: true - outPorts: - score: - datatype: 'number' - description: 'the resulting number of comparing the content with the list' - required: true - - # we are only using data, so we do not need any brackets sent to the inPorts, pass them along - c.forwardBrackets = - list: 'out' - content: 'out' - - c.process (input, output) -> - # our precondition, make sure it has both before trying to get the data - return unless input.has 'list', 'content', (ip) -> ip.type is 'data' - - # get the data - # content = input.getData 'content' - # list = input.getData 'list' - # @TODO: temporary hack since getData does not behave as one expects, change when fixed - content = ((input.getStream('content').filter (ip) -> ip.type is 'data').map (ip) -> ip.data)[0] - list = input.getStream('list')[0].data - - # our base score we will send out - score = 0 - - # splits content into an array of words - contents = tokenizer.tokenize content - - # if the list has the word in it, return the score - # otherwise, 0 points - wordScore = (word) -> - if list[word]? - return list[word] - else - return 0 - - # go through each of the comparisons in the list - # if it is Canadian: 1, American: -1, British: .5, None: 0 - spellingScore = (word) -> - for comparison in list - if word not in comparison["American"] - if word in comparison["Canadian"] - return 1 - else if word in comparison["British"] - return 0.5 - else - return -1 - - return 0 - - # if it has this, it is a spelling list - if list[0]?["Canadian"]? - scoringFunction = spellingScore - # otherwise it is an object list of words with scores - else - scoringFunction = wordScore - - # use this to singularize and pluralize each word - nounInflector = new natural.NounInflector() - - # go through each item in contents - for data in contents - plural = nounInflector.pluralize data - singular = nounInflector.singularize data - - # if it is already plural or singular do not use it - if plural isnt data - score += scoringFunction plural - if singular isnt data - score += scoringFunction singular - - score += scoringFunction data - - # we could do `output.sendDone score` if we wanted - # since there is only one outport it will know which one we mean - output.sendDone score: score diff --git a/components/WordScore.js b/components/WordScore.js new file mode 100644 index 0000000..fd67fc9 --- /dev/null +++ b/components/WordScore.js @@ -0,0 +1,119 @@ +// ## Import libraries +const noflo = require('noflo'); +const natural = require('natural'); + +const tokenizer = new natural.WordTokenizer(); + +// ## Component declaration +exports.getComponent = () => { + const c = new noflo.Component({ + description: 'Find how the input words compare against the list of weighted words', + inPorts: { + list: { + datatype: 'array', + description: 'list of words we will use with the list of content', + control: true, + required: true, + }, + content: { + datatype: 'string', + description: 'the content which we will determine the score of', + required: true, + }, + }, + outPorts: { + score: { + datatype: 'number', + description: 'the resulting number of comparing the content with the list', + required: true, + }, + }, + }); + + // ## Processing function + // + // To preserve streams, forward brackets from the primary inport to the output. + c.forwardBrackets = {}; + + c.process((input, output) => { + // ### Receive input + let scoringFunction; + if (!input.hasStream('content')) { return; } + if (!input.hasData('list')) { return; } + let content = input.getStream('content').filter(ip => ip.type === 'data').map(ip => ip.data); + const list = input.getData('list'); + + // there can be multiple pieces of content + content = content.join('\n'); + + // ### Component business logic + // our base score we will send out + let score = 0; + + // splits content into an array of words + const tokens = tokenizer.tokenize(content); + + // if the list has the word in it, return the score + // otherwise, 0 points + const wordScore = (word) => { + if (list[word] != null) { + return list[word]; + } + return 0; + }; + + // go through each of the comparisons in the list + // if it is Canadian: 1, American: -1, British: .5, None: 0 + const spellingScore = (word) => { + let value = 0; + list.forEach((comparison) => { + if (comparison.American.indexOf(word) !== -1) { + value = -1; + return; + } + if (comparison.Canadian.indexOf(word) !== -1) { + value = 1; + return; + } + if (comparison.British.indexOf(word) !== -1) { + value = 0.5; + } + }); + return value; + }; + + // if it has this, it is a spelling list + if ((list[0] != null ? list[0].Canadian : undefined) != null) { + scoringFunction = spellingScore; + // otherwise it is an object list of words with scores + } else { + scoringFunction = wordScore; + } + + // use this to singularize and pluralize each word + const nounInflector = new natural.NounInflector(); + + // go through each item in contents + tokens.forEach((data) => { + const plural = nounInflector.pluralize(data); + const singular = nounInflector.singularize(data); + + // if it is already plural or singular do not use it + if (plural !== data) { + score += scoringFunction(plural); + } + if (singular !== data) { + score += scoringFunction(singular); + } + + score += scoringFunction(data); + }); + + // ### Send output + output.sendDone({ + score, + }); + }); + + return c; +}; diff --git a/index.coffee b/index.coffee deleted file mode 100755 index c6efec5..0000000 --- a/index.coffee +++ /dev/null @@ -1,83 +0,0 @@ -noflo = require 'noflo' -trace = require('noflo-runtime-base').trace - -unless noflo.isBrowser() - baseDir = __dirname -else - baseDir = '/canadianness' - -spellingData = [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] -listData = {"eh": 11, "eh!": 11} - -canadianness = (args, cb) -> - spellingData = args['spelling'] - wordsData = args['words'] - # debugging [optional] - debug = args['debug'] or false - contentData = args['content'] - - loader = new noflo.ComponentLoader baseDir - # project name / graph or component name - loader.load 'canadianness/Canadianness', (err, instance) -> - throw err if err - - if debug - # instantiate our Tracer - tracer = new trace.Tracer() - - instance.once 'ready', -> - if debug - tracer.attach instance.network - - instance.start() - - # outPorts - score = noflo.internalSocket.createSocket() - emotion = noflo.internalSocket.createSocket() - - # inPorts - spelling = noflo.internalSocket.createSocket() - words = noflo.internalSocket.createSocket() - content = noflo.internalSocket.createSocket() - - # attach them - instance.inPorts.content.attach content - instance.inPorts.spelling.attach spelling - instance.inPorts.words.attach words - instance.outPorts.score.attach score - instance.outPorts.emotion.attach emotion - - # scoped variables since we don't know which data comes in first - scoreData = null - emotionData = null - - # when we listen for data, we can call this - # to check if both have received data - # when they have, call the callback - # and then, if we are debugging, write the trace - # and log where we wrote it to - finished = -> - return unless scoreData? and emotionData? - cb emotionData, scoreData - - if debug - tracer.dumpFile null, (err, f) -> - throw err if err - console.log 'Wrote flowtrace to', f - - # listen for data - score.on 'data', (data) -> - scoreData = data - finished() - - emotion.on 'data', (data) -> - emotionData = data - finished() - - # send the data - words.send wordsData - spelling.send spellingData - content.send contentData - -canadianness {spelling: spellingData, words: listData, content: 'eh', debug: true}, (score, emotion) -> - console.log score, emotion diff --git a/index.js b/index.js new file mode 100644 index 0000000..3a56df6 --- /dev/null +++ b/index.js @@ -0,0 +1,33 @@ +const noflo = require('noflo'); +const defaultSpellingData = require('./spellingdata.json'); + +const defaultWords = { + eh: 11, + 'eh!': 11, +}; + +// Produce the JavaScript entry point +function canadianness(contentData, options, callback) { + // Normalize options + const spellingData = options.spelling || defaultSpellingData; + const wordsData = options.words || defaultWords; + + // Convert options and input to a set of NoFlo packets to be sent + const inputs = { + words: wordsData, + spelling: spellingData, + content: contentData, + }; + + // Produce a NoFlo.asCallback wrapped function to execute our graph + const componentName = 'canadianness/Canadianness'; + const wrapperFunction = noflo.asCallback(componentName, { + baseDir: __dirname, + }); + + // Run the graph with inputs and call callback + wrapperFunction(inputs, callback); +} + +// Expose function as public API +module.exports = canadianness; diff --git a/package.json b/package.json index fab15fd..ac3a6a9 100644 --- a/package.json +++ b/package.json @@ -7,35 +7,33 @@ "candian", "canadianness" ], - "main": "./index.coffee", "author": "aretecode ", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/aretecode/canadianness.git" + "url": "https://github.com/noflo/canadianness.git" }, "dependencies": { - "coffee-script": "^1.10.0", - "natural": "^0.4.0", - "noflo": "git+https://github.com/aretecode/noflo-built.git", - "noflo-core": "^0.1.3", - "noflo-math": "git+https://github.com/aretecode/noflo-math.git" + "natural": "^0.5.0", + "noflo": "^1.0.0", + "noflo-math": "^0.3.0" }, "devDependencies": { - "chai": "^3.5.0", - "coffeelint": "^1.13.0", - "fbp-spec": "^0.1.15", - "grunt": "^0.4.5", - "grunt-cli": "^1.2.0", - "grunt-coffeelint": "^0.0.13", - "grunt-mocha-test": "^0.12.2", - "mocha": "^2.5.3", - "noflo-nodejs": "^0.7.1", - "noflo-runtime-base": "^0.7.3", - "noflo-tester": "0.0.3" + "chai": "^4.1.2", + "eslint": "^4.11.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-import": "^2.8.0", + "fbp-spec": "^0.6.2", + "mocha": "^5.0.0", + "noflo-core": "^0.5.0", + "noflo-filesystem": "^2.0.0", + "noflo-nodejs": "^0.10.0", + "noflo-strings": "^0.4.0" }, "scripts": { - "start": "./node_modules/.bin/noflo-nodejs --trace --debug", - "test": "./node_modules/.bin/grunt test" + "postinstall": "noflo-cache-preheat", + "start": "noflo-nodejs --trace --debug", + "pretest": "eslint *.js components/*.js", + "test": "mocha -R spec -t 2000 --exit spec/*.js" } } diff --git a/spec/API.js b/spec/API.js new file mode 100644 index 0000000..7ccca22 --- /dev/null +++ b/spec/API.js @@ -0,0 +1,21 @@ +const canadianness = require('../index.js'); +const chai = require('chai'); + +describe('Javascript API', () => + + describe('calling with sad content', () => { + const content = 'life is hard and then you die, ...eh'; + it('should return emotion=sadness', done => + canadianness(content, {}, (err, result) => { + if (err) { + done(err); + return; + } + chai.expect(result).to.include.keys(['emotion', 'score']); + chai.expect(result.emotion).to.equal('sadness'); + chai.expect(result.score).to.be.above(5); + done(); + }) + ); + }) +); diff --git a/spec/Canadianness.coffee b/spec/Canadianness.coffee deleted file mode 100755 index ee2e80a..0000000 --- a/spec/Canadianness.coffee +++ /dev/null @@ -1,277 +0,0 @@ -noflo = require 'noflo' - -# if you want to run your tests on the browser builds using phantom -unless noflo.isBrowser() - chai = require 'chai' - path = require 'path' - baseDir = path.resolve __dirname, '../' -else - baseDir = 'canadianness' - -# how we test the components first, then the graph as a whole -# because then we do not have to -# figure out where along the graph the problem is -describe 'Canadianness graph', -> - spellingData = [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] - listData = {"eh": 11, "eh!": 11} - - c = null - content = null - spelling = null - words = null - emotion = null - score = null - - # we are using this because we are waiting for both port event listeners - # to receive data - emotionData = null - scoreData = null - doDone = (done) -> - # if both are set, it is done, so reset test state - if scoreData? and emotionData? - scoreData = null - emotionData = null - done() - - # we only need to load the graph once, so it is in the before - before (done) -> - @timeout 4000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/Canadianness', (err, instance) -> - return done err if err - - # but we need to access the instance elsewhere, - # so it is assigned to the scoped variable - c = instance - - # because it is a graph, we want to wait until it is ready - c.once 'ready', -> - c.start() - # for asyncish - setTimeout done, 1 - - # before each test we want to attach all of the outports - # (we also attach the inports here as well so the `before` is simpler) - # and we want to detach the outports after each, - # otherwise the event listeners in the test that ran before - # would get triggered again - beforeEach -> - content = noflo.internalSocket.createSocket() - spelling = noflo.internalSocket.createSocket() - words = noflo.internalSocket.createSocket() - c.inPorts.content.attach content - c.inPorts.spelling.attach spelling - c.inPorts.words.attach words - - emotion = noflo.internalSocket.createSocket() - score = noflo.internalSocket.createSocket() - c.outPorts.emotion.attach emotion - c.outPorts.score.attach score - afterEach -> - c.outPorts.emotion.detach emotion - c.outPorts.score.detach score - - describe 'content "A bunch of centers had a color cancelation."', -> - it 'should be neutral, and uncanadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql -3 - scoreData = data - doDone done - - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'neutral' - emotionData = data - doDone done - - spelling.send spellingData - words.send listData - content.send 'A bunch of centers had a color cancelation.' - - describe 'content eh', -> - it 'should be neutral, yet highly Canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql 11 - scoreData = data - doDone done - - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'neutral' - emotionData = data - doDone done - - spelling.send spellingData - words.send listData - content.send 'eh' - - describe 'content "eh!"', -> - it 'should be joyful, and canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql 11 - scoreData = data - doDone done - - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'joy' - emotionData = data - doDone done - - spelling.send spellingData - words.send listData - content.send 'eh!' - -describe 'WordScore component', -> - listData = [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] - - c = null - content = null - list = null - score = null - before (done) -> - @timeout 4000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/WordScore', (err, instance) -> - return done err if err - c = instance - content = noflo.internalSocket.createSocket() - list = noflo.internalSocket.createSocket() - c.inPorts.content.attach content - c.inPorts.list.attach list - done() - beforeEach -> - score = noflo.internalSocket.createSocket() - c.outPorts.score.attach score - afterEach -> - c.outPorts.score.detach score - - describe 'with content `ardour eh`', -> - it 'should be Canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql 1 - done() - - list.send listData - content.send 'ardour eh?' - - describe 'with content `ax`', -> - it 'should be not Canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql -1 - done() - - list.send listData - content.send 'ax' - -describe 'FindWords component', -> - c = null - word = null - surrounding = null - content = null - matches = null - before (done) -> - @timeout 4000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/FindWords', (err, instance) -> - return done err if err - c = instance - word = noflo.internalSocket.createSocket() - content = noflo.internalSocket.createSocket() - surrounding = noflo.internalSocket.createSocket() - c.inPorts.word.attach word - c.inPorts.content.attach content - c.inPorts.surrounding.attach surrounding - done() - beforeEach -> - matches = noflo.internalSocket.createSocket() - c.outPorts.matches.attach matches - afterEach -> - c.outPorts.matches.detach matches - - describe 'with content eh', -> - it 'should be find one `eh`', (done) -> - matches.on 'data', (data) -> - chai.expect(data).to.eql 'eh' - done() - - word.send 'eh' - surrounding.send false - content.send 'eh' - - describe 'with content that has no `eh`s', -> - it 'should send an empty array', (done) -> - matches.on 'data', (data) -> - chai.expect(data).to.eql [] - done() - word.send 'eh' - surrounding.send false - content.send 'A string without it is a sad string.' - - describe 'with content that has multiple `eh`s', -> - it 'should send an array of ehs', (done) -> - expect = ['Eh...', 'eh?', 'EH!'] - matches.on 'ip', (ip) -> - if ip.type is 'data' - chai.expect(ip.data).to.eql expect.shift() - if ip.type is 'closeBracket' - done() - - word.send 'eh' - surrounding.send true - content.send 'Eh... eh? EH!' - -describe 'DetermineEmotion component', -> - c = null - emotion = null - content = null - error = null - before (done) -> - @timeout 4000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/DetermineEmotion', (err, instance) -> - return done err if err - c = instance - content = noflo.internalSocket.createSocket() - c.inPorts.content.attach content - done() - beforeEach -> - emotion = noflo.internalSocket.createSocket() - error = noflo.internalSocket.createSocket() - c.outPorts.emotion.attach emotion - c.outPorts.error.attach error - afterEach -> - c.outPorts.emotion.detach emotion - c.outPorts.error.detach error - - describe 'with content eh', -> - it 'should be neutral', (done) -> - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'neutral' - done() - - # needs the extra closeBracket - # because of the extra connect in translation layer - content.send new noflo.IP 'openBracket' - content.send new noflo.IP 'data', 'eh' - content.send new noflo.IP 'closeBracket' - content.send new noflo.IP 'closeBracket' - - describe 'with content eh!', -> - it 'should be joyful', (done) -> - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'joy' - done() - - content.send new noflo.IP 'openBracket' - content.send new noflo.IP 'data', 'eh!' - content.send new noflo.IP 'closeBracket' - - describe 'with content [eh?, eh!?, Eh?]', -> - it 'should be amusement', (done) -> - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'amusement' - done() - - content.send new noflo.IP 'openBracket' - content.send new noflo.IP 'data', 'eh?' - content.send new noflo.IP 'data', 'eh!?' - content.send new noflo.IP 'data', 'Eh?' - content.send new noflo.IP 'closeBracket' diff --git a/spec/CanadiannessNofloTester.coffee b/spec/CanadiannessNofloTester.coffee deleted file mode 100644 index be838a6..0000000 --- a/spec/CanadiannessNofloTester.coffee +++ /dev/null @@ -1,42 +0,0 @@ -Tester = require 'noflo-tester' -chai = require 'chai' - -describe 'FindWords component', -> - t = new Tester 'canadianness/FindWords' - before (done) -> - t.start (err, instance) -> - return throw err if err - done() - - describe 'with content eh', -> - it 'should be find one `eh`', (done) -> - # will only listen once and trigger after disconnect - t.receive 'matches', (data) -> - chai.expect(data).to.eql 'eh' - done() - - t.ins.word.send 'eh' - t.ins.surrounding.send false - t.ins.content.send 'eh' - - describe 'with content that has no `eh`s', -> - it 'should send an empty array', (done) -> - t.receive 'matches', (data) -> - chai.expect(data).to.eql [] - done() - t.ins.word.send 'eh' - t.ins.surrounding.send false - t.ins.content.send 'A string without it is a sad string.' - - describe 'with content that has multiple `eh`s', -> - it 'should send an array of ehs', (done) -> - expect = ['Eh...', 'eh?', 'EH!'] - t.outs.matches.on 'ip', (ip) -> - if ip.type is 'data' - chai.expect(ip.data).to.eql expect.shift() - if ip.type is 'closeBracket' - done() - - t.ins.word.send 'eh' - t.ins.surrounding.send true - t.ins.content.send 'Eh... eh? EH!' diff --git a/spec/canadianness.yaml b/spec/canadianness.yaml index fe90c7b..2f95f3b 100644 --- a/spec/canadianness.yaml +++ b/spec/canadianness.yaml @@ -1,11 +1,25 @@ topic: "canadianness/Canadianness" -name: "Canadianness fbpspec" +name: "Canadianness graph" +fixture: + type: 'fbp' + data: | + # @runtime noflo-nodejs + INPORT=graph.WORDS:WORDS + INPORT=graph.CONTENT:CONTENT + OUTPORT=graph.EMOTION:EMOTION + OUTPORT=graph.SCORE:SCORE + OUTPORT=errors.OUT:ERROR + # read the available spelling + './spellingdata.json' -> read(filesystem/ReadFile) -> words(strings/ParseJson) + words -> SPELLING graph(canadianness/Canadianness) + # forward errors + read ERROR -> errors(core/Repeat) + words ERROR -> errors cases: - name: 'content `A bunch of centers had a color cancelation.`' assertion: 'should be neutral and -3' inputs: - spelling: [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] words: {"eh": 11, "eh!": 11} content: 'A bunch of centers had a color cancelation.' expect: @@ -17,7 +31,6 @@ cases: name: 'content `eh`' assertion: 'should be neutral, yet highly Canadian' inputs: - spelling: [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] words: {"eh": 11, "eh!": 11} content: 'eh' expect: @@ -29,7 +42,6 @@ cases: name: 'content `eh!`' assertion: 'should be joyful, and Canadian' inputs: - spelling: [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] words: {"eh": 11, "eh!": 11} content: 'eh!' expect: diff --git a/spec/determineemotion.yaml b/spec/determineemotion.yaml index 13fefaf..b588406 100644 --- a/spec/determineemotion.yaml +++ b/spec/determineemotion.yaml @@ -1,12 +1,13 @@ topic: "canadianness/DetermineEmotion" -name: "Determine Emotion fbpspec" +name: "DetermineEmotion component" +timeout: 10000 fixture: type: 'fbp' data: | # @runtime noflo-nodejs - INPORT=TestDetermineEmotion.IN:IN + INPORT=stream.IN:IN OUTPORT=DetermineEmotion.EMOTION:EMOTION - TestDetermineEmotion(canadianness/TestDetermineEmotion) OUT -> CONTENT DetermineEmotion(canadianness/DetermineEmotion) + stream(canadianness/ArrayToStream) OUT -> CONTENT DetermineEmotion(canadianness/DetermineEmotion) cases: - diff --git a/spec/fbpspec.coffee b/spec/fbpspec.coffee deleted file mode 100644 index 8c99d82..0000000 --- a/spec/fbpspec.coffee +++ /dev/null @@ -1,15 +0,0 @@ -fbpspec = require 'fbp-spec' - -nodeRuntime = - label: "NoFlo node.js" - description: "" - type: "noflo" - protocol: "websocket" - secret: 'notasecret' - address: "ws://localhost:3333" - id: "7807f4d8-63e0-4a89-a577-2770c14f8106" - command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --capture-output=true --debug=true' - -fbpspec.mocha.run nodeRuntime, './spec', - fixturetimeout: 50000 - starttimeout: 100000 diff --git a/spec/fbpspec.js b/spec/fbpspec.js new file mode 100644 index 0000000..71b3c9c --- /dev/null +++ b/spec/fbpspec.js @@ -0,0 +1,17 @@ +const fbpspec = require('fbp-spec'); + +const nodeRuntime = { + label: "NoFlo node.js", + description: "", + type: "noflo", + protocol: "websocket", + secret: 'notasecret', + address: "ws://localhost:3333", + id: "7807f4d8-63e0-4a89-a577-2770c14f8106", + command: './node_modules/.bin/noflo-nodejs --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --capture-output=true' +}; + +fbpspec.mocha.run(nodeRuntime, './spec', { + fixturetimeout: 10000, + starttimeout: 10000 +}); diff --git a/spec/findwords.yaml b/spec/findwords.yaml index aec97c5..77a132d 100644 --- a/spec/findwords.yaml +++ b/spec/findwords.yaml @@ -1,5 +1,4 @@ topic: "canadianness/FindWords" -name: "Find words fbpspec" cases: - name: 'content eh' diff --git a/spellingdata.json b/spellingdata.json new file mode 100644 index 0000000..08676f7 --- /dev/null +++ b/spellingdata.json @@ -0,0 +1 @@ +[{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}]