## 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;
    };