{"_id":"noflo-automaton","_rev":"28-22c5034044653b71cf165016522f33bf","name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","dist-tags":{"latest":"0.1.6"},"versions":{"0.0.0":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.0.0","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","underscore":"~1.5.1"},"devDependencies":{"grunt":"~0.4.1","grunt-contrib-coffee":"~0.6.6","grunt-coffeelint":"~0.0.6","grunt-cafe-mocha":"~0.1.2","chai":"~1.5.0","mocha":"~1.9.0","grunt-mocha-phantomjs":"~0.2.2","grunt-component-build":"~0.2.7","grunt-contrib-uglify":"~0.2.0","grunt-contrib-watch":"~0.3.1","component-json":"~0.1.4","grunt-combine":"~0.8.3","grunt-component":"~0.1.2"},"keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"readme":"# noflo-automaton\n[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton)\n\nAutomate navigation on the web. This component library is built for NoFlo using\nCasper.js.\n\nGiven a URL and a rule object (structure described below), noflo-automaton\nwould go through the rule object and try to reach the end, at which point the\nautomaton would forward the accumulated output to its OUT port with the status\nnumber of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status number being the rule number in the provided rule\nobject.\n\n## The Rule Object\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object containing an array of rules. It works\nvirtually the same way as an assembly language does.\n\n### Rule Object API\n\nFor each **rule**, the automaton expects:\n\n* **selector**: The CSS3 selector to operate on\n* **actions**: An array of actions to perform (see below)\n* **conditions**: An array of conditions to test for success before moving on\n  (see below)\n* **name**: *optional* An identifier so other rules can refer to this rule\n* **on-success**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **on-failure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n* **test-timeout**: *optional* Number of milliseconds to timeout before\n  applying 'conditions'. Default to 0 miliseconds (i.e. immediately calling\n  `setTimeout()` with `0` milliseconds)\n* **retry-timeout**: *optional* Number of milliseconds to timeout before\n  retrying upon failure. Default to `0` milliseconds\n* **retry-count**: *optional* How many times to retry before giving up? Default\n  to no retry (i.e. quit the program with a failure status number)\n\nFor each **action** in the actions array:\n\n* **action**: One of [mouse and form\n  events](http://www.w3schools.com/jsref/dom_obj_event.asp) without the 'on'\n  prefix. It also accepts 'value' which would change the value of an input and\n  trigger the 'change' event.\n* **selector**: *optional* The element to perform the action on. Default to the\n  element specified by the rule selector.\n\nFor each **condition** in the conditions array:\n\n* **condition**: The value to match on the element. This is a RegExp string.\n  For instance, when `class=\"page row item\"` and `property` is `class`, the\n  condition is not going to match with `^row$`. However, it would match with\n  `row`.\n* **name**: *optional* An identifier for other conditions to refer to this\n* **property**: *optional* The attribute name (e.g. 'class') to test.  Default\n  to the content of the HTML element\n* **selector**: *optional* The selector to test the condition on. Default to\n  the element specified by the rule selector.\n* **on-success**: *optional* The next condition by its name to test on success.\n  If it's `false`, stop testing and assume success. If it's `true`, move on to\n  the next condition. Default to `true`\n* **on-failure**: *optional* The next condition by its name to test on failure.\n  If it's `false`, stop testing and assume failure. If it's `true`, move on to\n  the next condition. Default to `false`\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      {\n        \"selector\": \"body #page .row\",\n        \"actions\": [\n          { \"action\": \"click\" },\n          { \"action\": \"click\", \"selector\": \"body #page .row .item\" }\n        ],\n        \"conditions\": [\n          { \"condition\": \"Item\" },\n          { \"condition\": \"You\", \"selector\": \"body #page .row .item#you\" }\n        ]\n      }\n    ]\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply). Along with the expectation that after each test and rule,\nthere is a timeout to allow DOM events to fire, the flow must be completely\nstateless.\n\nTherefore, each component in the automaton, including the graph\n`automaton/automaton` itself, expects the same inbound object, which follows\nthe protocol of:\n\n* **page**: The DOM element of the page against which all selectors are\n  executed.\n* **rules**: This is the rule obejct.\n* **status**: *internal* This is the current rule's offset in the rule object.\n  This is used internally as a counter to refer to the the current rule to be\n  applied as well as forwarded to OUT upon completion.\n* **counts**: *internal* This is a hash of counters used by some components in\n  order to track when to quit upon repeated failures.\n\nOn OUT port from the graph `automaton/automaton` it outputs an object following\nthis protocol:\n\n* **status**: `true` if it's successful. `false` if the provided page or rule\n  object is not valid. The position of the rule in the rule object otherwise.\n* **error**: *optional* An error object or a string indicating the error\n  message if any\n* **page**: The DOM element passed to the graph in the beginning\n* **rules**: The rule object passed to the graph in the beginning\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.0.0","dist":{"shasum":"f8e66332e1824d3fbe89698e6862061390d4a0ce","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.0.0.tgz","integrity":"sha512-LwgtBAnT1zvQios2QZ/0fuGcWC1JWCSaf8UGOCGBkdddy9K7Vs7B8dMmRWu2hqMTd0zNmigLelCrzUBkdoL7Dg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGwCVspYHJ8bcgfdjzh9XXc8Zy0LdrxM8s9TGCS0doOwAiAFZYccGuS9fhk30BssRZV4TQlaUeJhlaKfhF8hkqTTIA=="}]},"_from":".","_npmVersion":"1.3.5","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.0.1":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.0.1","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","underscore":"~1.5.1","spooky":"~0.2.3","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"~0.0.6","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.0"},"keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"TestActions":"components/TestActions.coffee","TestEffects":"components/TestEffects.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Run":"components/Run.coffee","Click":"components/Click.coffee","Extract":"components/Extract.coffee","Fill":"components/Fill.coffee","Value":"components/Value.coffee","Missing":"components/Missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web\n[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nThis component library is built for [NoFlo](http://noflojs.org/) using\n[Casper.js](http://casperjs.org/) via\n[SpookyJS](https://github.com/WaterfallEngineering/SpookyJS) as driver.\n\nGiven a URL and a rule object (structure described below), noflo-automaton\nwould go through the rule object and try to reach the end, at which point the\nautomaton would forward the accumulated output to its OUT port with the status\nnumber of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status number being the rule number in the provided rule\nobject.\n\nNote that the output of this library is asynchronous.\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n## API\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **url**: The URL to start the navigation with\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A dictionary of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before URL and rules ports disconnect given that it\nis optional.\n\nNote that jQuery (v2.0.3) is always injected unless it is already included on\nthe page. Manual injection may result in conflict.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  *browser*. For instance, `[output] {\"a\":\"b\"}` would be saved while\n  `{\"a\":\"b\"}` would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n## The Rule Object\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object containing an array of rules. It works\nvirtually the same way as an assembly language does.\n\n### Rule Object API\n\n#### NOTE: The follow API has not been completely implemented. See issues #2 - #5.\n\nFor each **rule**, the automaton expects:\n\n* **selector**: The CSS3 selector to operate on\n* **actions**: An array of actions to perform (see below)\n* **conditions**: An array of conditions to test for success before moving on\n  (see below)\n* **name**: *optional* An identifier so other rules can refer to this rule\n* **on-success**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **on-failure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n* **test-timeout**: *optional* Number of milliseconds to timeout before\n  applying 'conditions'. Default to 0 miliseconds (i.e. immediately calling\n  `setTimeout()` with `0` milliseconds)\n* **retry-timeout**: *optional* Number of milliseconds to timeout before\n  retrying upon failure. Default to `0` milliseconds\n* **retry-count**: *optional* How many times to retry before giving up? Default\n  to no retry (i.e. quit the program with a failure status number)\n\nFor each **action** in the actions array:\n\n* **action**: One of [mouse and form\n  events](http://www.w3schools.com/jsref/dom_obj_event.asp) without the 'on'\n  prefix. It also accepts:\n  * *value* which changes the value of an input and trigger the `change`\n    event.\n  * *form* which fills a form with the provided dictionary of form element name\n    and its desired value\n* **selector**: *optional* The element to perform the action on. Default to the\n  element specified by the rule selector.\n\nFor each **condition** in the conditions array:\n\n* **condition**: The value to match on the element. This is a RegExp string.\n  For instance, when `class=\"page row item\"` and `property` is `class`, the\n  condition is not going to match with `^row$`. However, it would match with\n  `row`.\n* **name**: *optional* An identifier for other conditions to refer to this\n* **property**: *optional* The attribute name (e.g. 'class') to test.  Default\n  to the content of the HTML element\n* **selector**: *optional* The selector to test the condition on. Default to\n  the element specified by the rule selector.\n* **on-success**: *optional* The next condition by its name to test on success.\n  If it's `false`, stop testing and assume success. If it's `true`, move on to\n  the next condition. Default to `true`\n* **on-failure**: *optional* The next condition by its name to test on failure.\n  If it's `false`, stop testing and assume failure. If it's `true`, move on to\n  the next condition. Default to `false`\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      {\n        \"selector\": \"body #page .row\",\n        \"actions\": [\n          { \"action\": \"click\" },\n          { \"action\": \"click\", \"selector\": \"body #page .row .item\" }\n        ],\n        \"conditions\": [\n          { \"condition\": \"Item\" },\n          { \"condition\": \"You\", \"selector\": \"body #page .row .item#you\" }\n        ]\n      }\n    ]\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply). Along with the expectation that after each test and rule,\nthere is a timeout to allow DOM events to fire, the flow must be completely\nstateless.\n\nTherefore, each component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule obejct.\n* **offset**: This is the current rule's offset in the rule object.  This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a hash of counters used by some components in order to\n  track when to quit upon repeated failures.\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto the page. An action runner is simply a\ncomponent of this repository that accepts a context object of the following\nprotocol:\n\n* **spooky**: The SpookyJS object on which it applies the action\n* **action**: The action extracted from the context object for the runner to\n  apply\n\nThe runner checks rather it should act on it by examining `action.action`,\nwhich is a string denoting the name of the action. If it is qualified to handle\nit, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/TestActions`\ncomponent or other runners. This cascading structure allows certain runners to\nalways take precedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object as action runners\napply the actions.\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.0.1","dist":{"shasum":"2edc9fcb2d3b1967b0ec4b13a6de1a5bd0e68e02","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.0.1.tgz","integrity":"sha512-6NNO1peel90kPD+/d2vLkhfjpagba0JUdhVJ+TmvnRawuyJ8d7YC37Cfl4bFItIDt2ExTassPHytsgtWa85m2Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCZ6GQkZ4bOe+lQA2GExHfdaVVrXtrvTmm+jqHqvIMhcAIgN/bglv6eOFd6xWHqF6BXlUPxv/zbAw3cXASfEC6VPdA="}]},"_from":".","_npmVersion":"1.3.5","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.0.2":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.0.2","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","underscore":"~1.5.1","spooky":"~0.2.3","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"~0.0.6","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.0"},"keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"TestActions":"components/TestActions.coffee","TestEffects":"components/TestEffects.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Run":"components/Run.coffee","Click":"components/Click.coffee","Extract":"components/Extract.coffee","Fill":"components/Fill.coffee","Value":"components/Value.coffee","Missing":"components/Missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web\n[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nThis component library is built for [NoFlo](http://noflojs.org/) using\n[Casper.js](http://casperjs.org/) via\n[SpookyJS](https://github.com/WaterfallEngineering/SpookyJS) as driver.\n\nGiven a URL and a rule object (structure described below), noflo-automaton\nwould go through the rule object and try to reach the end, at which point the\nautomaton would forward the accumulated output to its OUT port with the status\nnumber of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status number being the rule number in the provided rule\nobject.\n\nNote that the output of this library is asynchronous.\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n## API\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **url**: The URL to start the navigation with\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A dictionary of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before URL and rules ports disconnect given that it\nis optional.\n\nNote that jQuery (v2.0.3) is always injected unless it is already included on\nthe page. Manual injection may result in conflict.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  *browser*. For instance, `[output] {\"a\":\"b\"}` would be saved while\n  `{\"a\":\"b\"}` would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n## The Rule Object\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object containing an array of rules. It works\nvirtually the same way as an assembly language does.\n\n### Rule Object API\n\n#### NOTE: The follow API has not been completely implemented. See issues #2 - #5.\n\nFor each **rule**, the automaton expects:\n\n* **selector**: The CSS3 selector to operate on\n* **actions**: An array of actions to perform (see below)\n* **conditions**: An array of conditions to test for success before moving on\n  (see below)\n* **name**: *optional* An identifier so other rules can refer to this rule\n* **on-success**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **on-failure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n* **test-timeout**: *optional* Number of milliseconds to timeout before\n  applying 'conditions'. Default to 0 miliseconds (i.e. immediately calling\n  `setTimeout()` with `0` milliseconds)\n* **retry-timeout**: *optional* Number of milliseconds to timeout before\n  retrying upon failure. Default to `0` milliseconds\n* **retry-count**: *optional* How many times to retry before giving up? Default\n  to no retry (i.e. quit the program with a failure status number)\n\nFor each **action** in the actions array:\n\n* **action**: One of [mouse and form\n  events](http://www.w3schools.com/jsref/dom_obj_event.asp) without the 'on'\n  prefix. It also accepts:\n  * *value* which changes the value of an input and trigger the `change`\n    event.\n  * *form* which fills a form with the provided dictionary of form element name\n    and its desired value\n* **selector**: *optional* The element to perform the action on. Default to the\n  element specified by the rule selector.\n\nFor each **condition** in the conditions array:\n\n* **condition**: The value to match on the element. This is a RegExp string.\n  For instance, when `class=\"page row item\"` and `property` is `class`, the\n  condition is not going to match with `^row$`. However, it would match with\n  `row`.\n* **name**: *optional* An identifier for other conditions to refer to this\n* **property**: *optional* The attribute name (e.g. 'class') to test.  Default\n  to the content of the HTML element\n* **selector**: *optional* The selector to test the condition on. Default to\n  the element specified by the rule selector.\n* **on-success**: *optional* The next condition by its name to test on success.\n  If it's `false`, stop testing and assume success. If it's `true`, move on to\n  the next condition. Default to `true`\n* **on-failure**: *optional* The next condition by its name to test on failure.\n  If it's `false`, stop testing and assume failure. If it's `true`, move on to\n  the next condition. Default to `false`\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      {\n        \"selector\": \"body #page .row\",\n        \"actions\": [\n          { \"action\": \"click\" },\n          { \"action\": \"click\", \"selector\": \"body #page .row .item\" }\n        ],\n        \"conditions\": [\n          { \"condition\": \"Item\" },\n          { \"condition\": \"You\", \"selector\": \"body #page .row .item#you\" }\n        ]\n      }\n    ]\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply). Along with the expectation that after each test and rule,\nthere is a timeout to allow DOM events to fire, the flow must be completely\nstateless.\n\nTherefore, each component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule obejct.\n* **offset**: This is the current rule's offset in the rule object.  This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a hash of counters used by some components in order to\n  track when to quit upon repeated failures.\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto the page. An action runner is simply a\ncomponent of this repository that accepts a context object of the following\nprotocol:\n\n* **spooky**: The SpookyJS object on which it applies the action\n* **action**: The action extracted from the context object for the runner to\n  apply\n\nThe runner checks rather it should act on it by examining `action.action`,\nwhich is a string denoting the name of the action. If it is qualified to handle\nit, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/TestActions`\ncomponent or other runners. This cascading structure allows certain runners to\nalways take precedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object as action runners\napply the actions.\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.0.2","dist":{"shasum":"5ba92488a350c63c374147d45e9faad358f2ed5f","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.0.2.tgz","integrity":"sha512-O9z86ZOGoJWD19od/A2a476Me7F7QLuHu5ELO3gxcdGoXEGUpUa5AZMw41diNAD1Bzt2IyHp7BRzZAf28U8xIQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBtSekQ6JcmAj+2dRm8qSZClNxS9HEoR95yuXw2nxlFIAiArhyhhVt3Kwng1zlF3ifxWD9eJgVTA4AlhcVJMbm4T3Q=="}]},"_from":".","_npmVersion":"1.3.5","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.0.3":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.0.3","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","underscore":"~1.5.1","spooky":"~0.2.3","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"~0.0.6","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.0"},"keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"TestActions":"components/TestActions.coffee","TestEffects":"components/TestEffects.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Run":"components/Run.coffee","Click":"components/Click.coffee","Wait":"components/Wait.coffee","Extract":"components/Extract.coffee","Fill":"components/Fill.coffee","Capture":"components/Capture.coffee","Value":"components/Value.coffee","Output":"components/Output.coffee","Missing":"components/Missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web\n[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nThis component library is built for [NoFlo](http://noflojs.org/) using\n[Casper.js](http://casperjs.org/) via\n[SpookyJS](https://github.com/WaterfallEngineering/SpookyJS) as driver.\n\nGiven a URL and a rule object (structure described below), noflo-automaton\nwould go through the rule object and try to reach the end, at which point the\nautomaton would forward the accumulated output to its OUT port with the status\nnumber of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status number being the rule number in the provided rule\nobject.\n\nNote that the output of this library is asynchronous.\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n## API\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **url**: The URL to start the navigation with\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A dictionary of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before URL and rules ports disconnect given that it\nis optional.\n\nNote that jQuery (v2.0.3) is always injected unless it is already included on\nthe page. Manual injection may result in conflict.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  *browser*. For instance, `[output] {\"a\":\"b\"}` would be saved while\n  `{\"a\":\"b\"}` would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n## The Rule Object\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object containing an array of rules. It works\nvirtually the same way as an assembly language does.\n\n### Rule Object API\n\n#### NOTE: The follow API has not been completely implemented. See issues #2 - #5.\n\nFor each **rule**, the automaton expects:\n\n* **selector**: The CSS3 selector to operate on\n* **actions**: An array of actions to perform (see below)\n* **conditions**: An array of conditions to test for success before moving on\n  (see below)\n* **name**: *optional* An identifier so other rules can refer to this rule\n* **on-success**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **on-failure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n* **test-timeout**: *optional* Number of milliseconds to timeout before\n  applying 'conditions'. Default to 0 miliseconds (i.e. immediately calling\n  `setTimeout()` with `0` milliseconds)\n* **retry-timeout**: *optional* Number of milliseconds to timeout before\n  retrying upon failure. Default to `0` milliseconds\n* **retry-count**: *optional* How many times to retry before giving up? Default\n  to no retry (i.e. quit the program with a failure status number)\n\nFor each **action** in the actions array:\n\n* **action**: One of [mouse and form\n  events](http://www.w3schools.com/jsref/dom_obj_event.asp) without the 'on'\n  prefix. It also accepts:\n  * *value* which changes the value of an input and trigger the `change`\n    event.\n  * *form* which fills a form with the provided dictionary of form element name\n    and its desired value\n* **selector**: *optional* The element to perform the action on. Default to the\n  element specified by the rule selector.\n\nFor each **condition** in the conditions array:\n\n* **condition**: The value to match on the element. This is a RegExp string.\n  For instance, when `class=\"page row item\"` and `property` is `class`, the\n  condition is not going to match with `^row$`. However, it would match with\n  `row`.\n* **name**: *optional* An identifier for other conditions to refer to this\n* **property**: *optional* The attribute name (e.g. 'class') to test.  Default\n  to the content of the HTML element\n* **selector**: *optional* The selector to test the condition on. Default to\n  the element specified by the rule selector.\n* **on-success**: *optional* The next condition by its name to test on success.\n  If it's `false`, stop testing and assume success. If it's `true`, move on to\n  the next condition. Default to `true`\n* **on-failure**: *optional* The next condition by its name to test on failure.\n  If it's `false`, stop testing and assume failure. If it's `true`, move on to\n  the next condition. Default to `false`\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      {\n        \"selector\": \"body #page .row\",\n        \"actions\": [\n          { \"action\": \"click\" },\n          { \"action\": \"click\", \"selector\": \"body #page .row .item\" }\n        ],\n        \"conditions\": [\n          { \"condition\": \"Item\" },\n          { \"condition\": \"You\", \"selector\": \"body #page .row .item#you\" }\n        ]\n      }\n    ]\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply). Along with the expectation that after each test and rule,\nthere is a timeout to allow DOM events to fire, the flow must be completely\nstateless.\n\nTherefore, each component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule obejct.\n* **offset**: This is the current rule's offset in the rule object.  This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a hash of counters used by some components in order to\n  track when to quit upon repeated failures.\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto the page. An action runner is simply a\ncomponent of this repository that accepts a context object of the following\nprotocol:\n\n* **spooky**: The SpookyJS object on which it applies the action\n* **action**: The action extracted from the context object for the runner to\n  apply\n\nThe runner checks rather it should act on it by examining `action.action`,\nwhich is a string denoting the name of the action. If it is qualified to handle\nit, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/TestActions`\ncomponent or other runners. This cascading structure allows certain runners to\nalways take precedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object as action runners\napply the actions.\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.0.3","dist":{"shasum":"a3080a7eec5391e9d6d0d317d5dd9829de29c4ae","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.0.3.tgz","integrity":"sha512-QNaUQ6rsyKMRq0ANV1CH0Cz0yVo+O56BoD7jXUD5VGtbh7gQwM3Co0nVLoNMuH/JrlA6zIL0EmD4jdJMVHDCgQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIB6+VqBXz0QyjrBxQPKbuO07tw9UYqRJRYAsHzWUfKulAiEA3HwNC0qJCWAeiH1TB9N2hlbH5VkDY8OV+0MB+bmMNCM="}]},"_from":".","_npmVersion":"1.3.5","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.0.4":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.0.4","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","underscore":"~1.5.1","spooky":"~0.2.3","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"~0.0.6","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.0"},"keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"TestActions":"components/TestActions.coffee","TestEffects":"components/TestEffects.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Run":"components/Run.coffee","Click":"components/Click.coffee","Wait":"components/Wait.coffee","Extract":"components/Extract.coffee","Fill":"components/Fill.coffee","Capture":"components/Capture.coffee","Value":"components/Value.coffee","Output":"components/Output.coffee","Missing":"components/Missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web\n[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nThis component library is built for [NoFlo](http://noflojs.org/) using\n[Casper.js](http://casperjs.org/) via\n[SpookyJS](https://github.com/WaterfallEngineering/SpookyJS) as driver.\n\nGiven a URL and a rule object (structure described below), noflo-automaton\nwould go through the rule object and try to reach the end, at which point the\nautomaton would forward the accumulated output to its OUT port with the status\nnumber of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status number being the rule number in the provided rule\nobject.\n\nNote that the output of this library is asynchronous.\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n## API\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **url**: The URL to start the navigation with\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A dictionary of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before URL and rules ports disconnect given that it\nis optional.\n\nNote that jQuery (v2.0.3) is always injected unless it is already included on\nthe page. Manual injection may result in conflict.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  *browser*. For instance, `[output] {\"a\":\"b\"}` would be saved while\n  `{\"a\":\"b\"}` would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n## The Rule Object\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object containing an array of rules. It works\nvirtually the same way as an assembly language does.\n\n### Rule Object API\n\n#### NOTE: The follow API has not been completely implemented. See issues #2 - #5.\n\nFor each **rule**, the automaton expects:\n\n* **selector**: The CSS3 selector to operate on\n* **actions**: An array of actions to perform (see below)\n* **conditions**: An array of conditions to test for success before moving on\n  (see below)\n* **name**: *optional* An identifier so other rules can refer to this rule\n* **on-success**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **on-failure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n* **test-timeout**: *optional* Number of milliseconds to timeout before\n  applying 'conditions'. Default to 0 miliseconds (i.e. immediately calling\n  `setTimeout()` with `0` milliseconds)\n* **retry-timeout**: *optional* Number of milliseconds to timeout before\n  retrying upon failure. Default to `0` milliseconds\n* **retry-count**: *optional* How many times to retry before giving up? Default\n  to no retry (i.e. quit the program with a failure status number)\n\nFor each **action** in the actions array:\n\n* **action**: One of [mouse and form\n  events](http://www.w3schools.com/jsref/dom_obj_event.asp) without the 'on'\n  prefix. It also accepts:\n  * *value* which changes the value of an input and trigger the `change`\n    event.\n  * *form* which fills a form with the provided dictionary of form element name\n    and its desired value\n* **selector**: *optional* The element to perform the action on. Default to the\n  element specified by the rule selector.\n\nFor each **condition** in the conditions array:\n\n* **condition**: The value to match on the element. This is a RegExp string.\n  For instance, when `class=\"page row item\"` and `property` is `class`, the\n  condition is not going to match with `^row$`. However, it would match with\n  `row`.\n* **name**: *optional* An identifier for other conditions to refer to this\n* **property**: *optional* The attribute name (e.g. 'class') to test.  Default\n  to the content of the HTML element\n* **selector**: *optional* The selector to test the condition on. Default to\n  the element specified by the rule selector.\n* **on-success**: *optional* The next condition by its name to test on success.\n  If it's `false`, stop testing and assume success. If it's `true`, move on to\n  the next condition. Default to `true`\n* **on-failure**: *optional* The next condition by its name to test on failure.\n  If it's `false`, stop testing and assume failure. If it's `true`, move on to\n  the next condition. Default to `false`\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      {\n        \"selector\": \"body #page .row\",\n        \"actions\": [\n          { \"action\": \"click\" },\n          { \"action\": \"click\", \"selector\": \"body #page .row .item\" }\n        ],\n        \"conditions\": [\n          { \"condition\": \"Item\" },\n          { \"condition\": \"You\", \"selector\": \"body #page .row .item#you\" }\n        ]\n      }\n    ]\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply). Along with the expectation that after each test and rule,\nthere is a timeout to allow DOM events to fire, the flow must be completely\nstateless.\n\nTherefore, each component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule obejct.\n* **offset**: This is the current rule's offset in the rule object.  This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a hash of counters used by some components in order to\n  track when to quit upon repeated failures.\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto the page. An action runner is simply a\ncomponent of this repository that accepts a context object of the following\nprotocol:\n\n* **spooky**: The SpookyJS object on which it applies the action\n* **action**: The action extracted from the context object for the runner to\n  apply\n\nThe runner checks rather it should act on it by examining `action.action`,\nwhich is a string denoting the name of the action. If it is qualified to handle\nit, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/TestActions`\ncomponent or other runners. This cascading structure allows certain runners to\nalways take precedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object as action runners\napply the actions.\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.0.4","dist":{"shasum":"a0f0619eb92696f51e91f5a318b43047d1fa765d","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.0.4.tgz","integrity":"sha512-p1X3c6GFkR3c/9lTCTJ0kAsidnjubouqkDZ//bNhW7twukOJXSJp5Pk49olk8rowODsHLjb3GwJLIBmMIvxvNg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGWiFvOFuX2HffaabqajHcWeZrB6kj6UcuhA2AQFpzcmAiAfZb1ew2O1VzffilaFD3itP2QN+kaZTm7uiY2bvROalw=="}]},"_from":".","_npmVersion":"1.3.5","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.0.5":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.0.5","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","spooky":"~0.2.3","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3","q":"~0.9.7","lodash":"~2.3.0"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"~0.0.6","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.0"},"main":"lib/main.coffee","keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"Rule":"components/Rule.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Start":"components/Start.coffee","Click":"components/runners/Click.coffee","Wait":"components/runners/Wait.coffee","WaitFor":"components/runners/WaitFor.coffee","Extract":"components/runners/Extract.coffee","Fill":"components/runners/Fill.coffee","Capture":"components/runners/Capture.coffee","Open":"components/runners/Open.coffee","Value":"components/runners/Value.coffee","Output":"components/runners/Output.coffee","Missing":"components/runners/Missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web <br/>[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nGiven a URL and a rule set (structure described below), noflo-automaton would\ngo through the rule set and try to reach the end, at which point the automaton\nwould forward the accumulated output to its OUT port with the status of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status being the rule number in the provided rule set.\n\n\n## Why not just CasperJS?\n\nAutomaton is a nice abstraction over CasperJS. It provides a consistent\nJSON-based API so you could program with this:\n\n    [\n      { \"action\": \"start\", \"url\": \"http://casperjs.org/\" },\n      { \"action\": \"title\" },\n      { \"action\": \"open\", \"url\": \"http://phantomjs.org\" }\n      { \"action\": \"title\" }\n    ]\n\nRather than this:\n\n    var casper = require('casper').create();\n\n    casper.start('http://casperjs.org/', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.thenOpen('http://phantomjs.org', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.run();\n\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n\n## Usage\n\nThere are two user modes: CommonJS and NoFlo. CommonJS mode exposes a regular class\nfor you to run a JavaScript object-based (i.e. parsed JSON) rule set. In NoFlo\n  mode, it is a graph in NoFlo that you could connect to your network.\n\nYour JSON rule set \n\n### CommonJS Mode\n\nIn CommonJS mode, you simply create a new automaton and call `run`. Assuming the\nJSON file described under the section \"Why not just CasperJS\" above is\navailable at `rules.json`:\n\n    var Automaton = require('noflo-automaton');\n    var rules = require('./rules.json');\n\n    automaton = new Automaton\n\nA promise is returned.\n\n    promise = automaton.run(json);\n\n    promise.then(function(status, output) {\n      if (status === true) {\n        console.log('SUCCESS!');\n      } else {\n        console.log('STOPPED AT ' + status);\n      }\n\n      console.log('OUTPUT:');\n      console.log(output);\n\n    }, function(error) {\n      console.log('FAILED TO SET UP');\n      console.log(error);\n    });\n\n### NoFlo Mode\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A map of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before the **RULES** ports disconnect given that it\nis optional.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  browser. For instance, `[output] {\"a\":\"b\"}` would be saved while `{\"a\":\"b\"}`\n  would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n\n## The Rule Set\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object (i.e. JSON-like) containing an array\nof rules. It works virtually the same way as an assembly language does.\n\n### Rule Set API\n\n#### NOTE: The follow API has not been completely implemented. See issues #9\n\nFor each **rule**, the automaton expects:\n\n* **action**: see the `components/runners` directory for available actions\n* **selector**: *optional* The element to perform the action on. Some actions\n  do not require an element selector, like `open`\n* **_name**: *optional* An identifier so other rules can refer to this rule\n* **_onSuccess**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **_onFailure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      { \"action\": \"click\", \"selector\": \"body #page .row\" },\n      { \"action\": \"click\", \"selector\": \"body #page .row .item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row\", \"value\": \"Item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row .item#you\", \"value\": \"You\" }\n    ]\n\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply).\n\nEach component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule set\n* **offset**: This is the current rule's offset in the rule set. This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a map of counters used by components in order to\n  track progress. This is the only state the components are allowed to keep\n\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto a page. An action runner is simply a\ncomponent of this repository that accepts a context object.\n\nThe runner checks rather it should act on it by examining `rule.action`, which\nis the name of the action as displayed in the rule set. If it is qualified to\nhandle it, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/Iterate` component or\nother runners. This cascading structure allows certain runners to always take\nprecedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object.\n\n\n## Technologies\n\nAutomaton can't be an automaton without:\n\n* [NoFlo](http://noflojs.org/)\n* [PhantomJS](http://phantomjs.org/)\n* [CasperJS](http://casperjs.org/)\n* [SpookyJS](https://github.com/WaterfallEngineering/SpookyJS)\n\nI know,\n\n .-.\n(o o) boo!\n| O \\\n \\   \\\n  `~~~'\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.0.5","dist":{"shasum":"443ed4ea8460486debb3008230bfda81a0c872bb","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.0.5.tgz","integrity":"sha512-psyFSYZdkVDEmSAEgPlzd8kuIsx5NldbY43gWHsmOf4p4ggwH6hJFey7BOuAjqLoQTAeyV7jt5CYChPBrOniXQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD6YiXGoDzGkJFde2Yey1ppUpVw3dcb5Tmi2ZiIRh8b4AIgPtzYvFxJQ/8NymT4dIFtfuD8GTG1vAID6gfvlV7kPDk="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.1.0":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.1.0","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","spooky":"~0.2.3","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3","q":"~0.9.7","lodash":"~2.3.0"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"~0.0.6","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.0"},"main":"lib/main.coffee","keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"Rule":"components/Rule.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Start":"components/Start.coffee","Click":"components/runners/Click.coffee","Wait":"components/runners/Wait.coffee","WaitFor":"components/runners/WaitFor.coffee","Extract":"components/runners/Extract.coffee","Fill":"components/runners/Fill.coffee","Capture":"components/runners/Capture.coffee","Open":"components/runners/Open.coffee","Value":"components/runners/Value.coffee","Output":"components/runners/Output.coffee","Missing":"components/runners/Missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web <br/>[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nGiven a URL and a rule set (structure described below), noflo-automaton would\ngo through the rule set and try to reach the end, at which point the automaton\nwould forward the accumulated output to its OUT port with the status of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status being the rule number in the provided rule set.\n\n\n## Why not just CasperJS?\n\nAutomaton is a nice abstraction over CasperJS. It provides a consistent\nJSON-based API so you could program with this:\n\n    [\n      { \"action\": \"start\", \"url\": \"http://casperjs.org/\" },\n      { \"action\": \"title\" },\n      { \"action\": \"open\", \"url\": \"http://phantomjs.org\" }\n      { \"action\": \"title\" }\n    ]\n\nRather than this:\n\n    var casper = require('casper').create();\n\n    casper.start('http://casperjs.org/', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.thenOpen('http://phantomjs.org', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.run();\n\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n\n## Usage\n\nThere are two user modes: CommonJS and NoFlo. CommonJS mode exposes a regular class\nfor you to run a JavaScript object-based (i.e. parsed JSON) rule set. In NoFlo\n  mode, it is a graph in NoFlo that you could connect to your network.\n\nYour JSON rule set \n\n### CommonJS Mode\n\nIn CommonJS mode, you simply create a new automaton and call `run`. Assuming the\nJSON file described under the section \"Why not just CasperJS\" above is\navailable at `rules.json`:\n\n    var Automaton = require('noflo-automaton');\n    var rules = require('./rules.json');\n\n    automaton = new Automaton\n\nA promise is returned.\n\n    promise = automaton.run(json);\n\n    promise.then(function(status, output) {\n      if (status === true) {\n        console.log('SUCCESS!');\n      } else {\n        console.log('STOPPED AT ' + status);\n      }\n\n      console.log('OUTPUT:');\n      console.log(output);\n\n    }, function(error) {\n      console.log('FAILED TO SET UP');\n      console.log(error);\n    });\n\n### NoFlo Mode\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A map of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before the **RULES** ports disconnect given that it\nis optional.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  browser. For instance, `[output] {\"a\":\"b\"}` would be saved while `{\"a\":\"b\"}`\n  would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n\n## The Rule Set\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object (i.e. JSON-like) containing an array\nof rules. It works virtually the same way as an assembly language does.\n\n### Rule Set API\n\n#### NOTE: The follow API has not been completely implemented. See issues #9\n\nFor each **rule**, the automaton expects:\n\n* **action**: see the `components/runners` directory for available actions\n* **selector**: *optional* The element to perform the action on. Some actions\n  do not require an element selector, like `open`\n* **_name**: *optional* An identifier so other rules can refer to this rule\n* **_onSuccess**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **_onFailure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      { \"action\": \"click\", \"selector\": \"body #page .row\" },\n      { \"action\": \"click\", \"selector\": \"body #page .row .item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row\", \"value\": \"Item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row .item#you\", \"value\": \"You\" }\n    ]\n\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply).\n\nEach component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule set\n* **offset**: This is the current rule's offset in the rule set. This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a map of counters used by components in order to\n  track progress. This is the only state the components are allowed to keep\n\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto a page. An action runner is simply a\ncomponent of this repository that accepts a context object.\n\nThe runner checks rather it should act on it by examining `rule.action`, which\nis the name of the action as displayed in the rule set. If it is qualified to\nhandle it, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/Iterate` component or\nother runners. This cascading structure allows certain runners to always take\nprecedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object.\n\n\n## Technologies\n\nAutomaton can't be an automaton without:\n\n* [NoFlo](http://noflojs.org/)\n* [PhantomJS](http://phantomjs.org/)\n* [CasperJS](http://casperjs.org/)\n* [SpookyJS](https://github.com/WaterfallEngineering/SpookyJS)\n\nI know,\n\n .-.\n(o o) boo!\n| O \\\n \\   \\\n  `~~~'\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.1.0","dist":{"shasum":"10a8cf30796a6aafcfc634e96f3eb8e2130764e5","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.1.0.tgz","integrity":"sha512-NNs1z1RyMtVjQr7eavRK7McfEj+Jp4LX/5cPmAvq1bSPDAlWlGhngytNAUXDCZgW7swrxt4u3R7SAaoR3nDHBg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFW4a88lybKU3ClUqWWtIYttCglXuM0By4P01yklU9nwAiBD26afuGNc387Bh7YekbdigtL1z+FrPD5gvt4SvGz58Q=="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.1.1":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.1.1","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","spooky":"~0.2.3","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3","q":"~0.9.7","lodash":"~2.3.0"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"~0.0.6","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.0"},"main":"lib/main.coffee","keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"Rule":"components/Rule.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Start":"components/Start.coffee","Click":"components/runners/Click.coffee","Wait":"components/runners/Wait.coffee","WaitFor":"components/runners/WaitFor.coffee","Extract":"components/runners/Extract.coffee","Fill":"components/runners/Fill.coffee","Capture":"components/runners/Capture.coffee","Open":"components/runners/Open.coffee","Value":"components/runners/Value.coffee","Output":"components/runners/Output.coffee","Missing":"components/runners/Missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web <br/>[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nGiven a URL and a rule set (structure described below), noflo-automaton would\ngo through the rule set and try to reach the end, at which point the automaton\nwould forward the accumulated output to its OUT port with the status of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status being the rule number in the provided rule set.\n\n\n## Why not just CasperJS?\n\nAutomaton is a nice abstraction over CasperJS. It provides a consistent\nJSON-based API so you could program with this:\n\n    [\n      { \"action\": \"start\", \"url\": \"http://casperjs.org/\" },\n      { \"action\": \"title\" },\n      { \"action\": \"open\", \"url\": \"http://phantomjs.org\" }\n      { \"action\": \"title\" }\n    ]\n\nRather than this:\n\n    var casper = require('casper').create();\n\n    casper.start('http://casperjs.org/', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.thenOpen('http://phantomjs.org', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.run();\n\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n\n## Usage\n\nThere are two user modes: CommonJS and NoFlo. CommonJS mode exposes a regular class\nfor you to run a JavaScript object-based (i.e. parsed JSON) rule set. In NoFlo\n  mode, it is a graph in NoFlo that you could connect to your network.\n\nYour JSON rule set \n\n### CommonJS Mode\n\nIn CommonJS mode, you simply create a new automaton and call `run`. Assuming the\nJSON file described under the section \"Why not just CasperJS\" above is\navailable at `rules.json`:\n\n    var Automaton = require('noflo-automaton');\n    var rules = require('./rules.json');\n\n    automaton = new Automaton\n\nA promise is returned.\n\n    promise = automaton.run(json);\n\n    promise.then(function(status, output) {\n      if (status === true) {\n        console.log('SUCCESS!');\n      } else {\n        console.log('STOPPED AT ' + status);\n      }\n\n      console.log('OUTPUT:');\n      console.log(output);\n\n    }, function(error) {\n      console.log('FAILED TO SET UP');\n      console.log(error);\n    });\n\n### NoFlo Mode\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A map of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before the **RULES** ports disconnect given that it\nis optional.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  browser. For instance, `[output] {\"a\":\"b\"}` would be saved while `{\"a\":\"b\"}`\n  would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n\n## The Rule Set\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object (i.e. JSON-like) containing an array\nof rules. It works virtually the same way as an assembly language does.\n\n### Rule Set API\n\n#### NOTE: The follow API has not been completely implemented. See issues #9\n\nFor each **rule**, the automaton expects:\n\n* **action**: see the `components/runners` directory for available actions\n* **selector**: *optional* The element to perform the action on. Some actions\n  do not require an element selector, like `open`\n* **_name**: *optional* An identifier so other rules can refer to this rule\n* **_onSuccess**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **_onFailure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      { \"action\": \"click\", \"selector\": \"body #page .row\" },\n      { \"action\": \"click\", \"selector\": \"body #page .row .item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row\", \"value\": \"Item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row .item#you\", \"value\": \"You\" }\n    ]\n\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply).\n\nEach component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule set\n* **offset**: This is the current rule's offset in the rule set. This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a map of counters used by components in order to\n  track progress. This is the only state the components are allowed to keep\n\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto a page. An action runner is simply a\ncomponent of this repository that accepts a context object.\n\nThe runner checks rather it should act on it by examining `rule.action`, which\nis the name of the action as displayed in the rule set. If it is qualified to\nhandle it, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/Iterate` component or\nother runners. This cascading structure allows certain runners to always take\nprecedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object.\n\n\n## Technologies\n\nAutomaton can't be an automaton without:\n\n* [NoFlo](http://noflojs.org/)\n* [PhantomJS](http://phantomjs.org/)\n* [CasperJS](http://casperjs.org/)\n* [SpookyJS](https://github.com/WaterfallEngineering/SpookyJS)\n\nI know,\n\n .-.\n(o o) boo!\n| O \\\n \\   \\\n  `~~~'\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.1.1","dist":{"shasum":"59e5d32fd1daf9613f68c19c3d7a7bf864be5562","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.1.1.tgz","integrity":"sha512-LBMW7uWRPEQy7cbiUbtpcShp5igO1WwwDChvZFvlZc0W+LiR3vQoEzz1Oj15aX1SvFN4Q80kgyZBzuwUW5FmPw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDv+B/4sFiy31wvupTuoOnIalHI0NrcnXa3Zh+rlJBn1QIhAO9tIfSgFQBsFcUAIumhYM5p3W2CVW0FlHUw2JpB3a+E"}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.1.3":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.1.3","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","spooky":"~0.2.4","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3","q":"~0.9.7","lodash":"~2.3.0"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"0.0.7","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.2","grunt-bump":"0.0.11","grunt-conventional-changelog":"~1.0.0"},"main":"lib/main.coffee","keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"Rule":"components/Rule.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Start":"components/Start.coffee","Click":"components/runners/click.coffee","Wait":"components/runners/wait.coffee","WaitFor":"components/runners/waitFor.coffee","Extract":"components/runners/extract.coffee","Fill":"components/runners/fill.coffee","Capture":"components/runners/capture.coffee","Open":"components/runners/open.coffee","Value":"components/runners/value.coffee","Select":"components/runners/select.coffee","Bypass":"components/runners/bypass.coffee","Output":"components/runners/output.coffee","Missing":"components/runners/missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web <br/>[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nGiven a URL and a rule set (structure described below), noflo-automaton would\ngo through the rule set and try to reach the end, at which point the automaton\nwould forward the accumulated output to its OUT port with the status of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status being the rule number in the provided rule set.\n\n\n## Why not just CasperJS?\n\nAutomaton is a nice abstraction over CasperJS. It provides a consistent\nJSON-based API so you could program with this:\n\n    [\n      { \"action\": \"start\", \"url\": \"http://casperjs.org/\" },\n      { \"action\": \"title\" },\n      { \"action\": \"open\", \"url\": \"http://phantomjs.org\" }\n      { \"action\": \"title\" }\n    ]\n\nRather than this:\n\n    var casper = require('casper').create();\n\n    casper.start('http://casperjs.org/', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.thenOpen('http://phantomjs.org', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.run();\n\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n\n## Usage\n\nThere are two user modes: CommonJS and NoFlo. CommonJS mode exposes a regular class\nfor you to run a JavaScript object-based (i.e. parsed JSON) rule set. In NoFlo\n  mode, it is a graph in NoFlo that you could connect to your network.\n\nYour JSON rule set \n\n### CommonJS Mode\n\nIn CommonJS mode, you simply create a new automaton and call `run`. Assuming the\nJSON file described under the section \"Why not just CasperJS\" above is\navailable at `rules.json`:\n\n    var Automaton = require('noflo-automaton');\n    var rules = require('./rules.json');\n\n    automaton = new Automaton\n\nA promise is returned.\n\n    promise = automaton.run(json);\n\n    promise.then(function(status, output) {\n      if (status === true) {\n        console.log('SUCCESS!');\n      } else {\n        console.log('STOPPED AT ' + status);\n      }\n\n      console.log('OUTPUT:');\n      console.log(output);\n\n    }, function(error) {\n      console.log('FAILED TO SET UP');\n      console.log(error);\n    });\n\n### NoFlo Mode\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A map of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before the **RULES** ports disconnect given that it\nis optional.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  browser. For instance, `[output] {\"a\":\"b\"}` would be saved while `{\"a\":\"b\"}`\n  would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n\n## The Rule Set\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object (i.e. JSON-like) containing an array\nof rules. It works virtually the same way as an assembly language does.\n\n### Rule Set API\n\n#### NOTE: The follow API has not been completely implemented. See issues #9\n\nFor each **rule**, the automaton expects:\n\n* **action**: see the `components/runners` directory for available actions\n* **selector**: *optional* The element to perform the action on. Some actions\n  do not require an element selector, like `open`\n* **_name**: *optional* An identifier so other rules can refer to this rule\n* **_onSuccess**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **_onFailure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      { \"action\": \"click\", \"selector\": \"body #page .row\" },\n      { \"action\": \"click\", \"selector\": \"body #page .row .item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row\", \"value\": \"Item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row .item#you\", \"value\": \"You\" }\n    ]\n\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply).\n\nEach component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule set\n* **offset**: This is the current rule's offset in the rule set. This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a map of counters used by components in order to\n  track progress. This is the only state the components are allowed to keep\n\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto a page. An action runner is simply a\ncomponent of this repository that accepts a context object.\n\nThe runner checks rather it should act on it by examining `rule.action`, which\nis the name of the action as displayed in the rule set. If it is qualified to\nhandle it, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/Iterate` component or\nother runners. This cascading structure allows certain runners to always take\nprecedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object.\n\n\n## Technologies\n\nAutomaton can't be an automaton without:\n\n* [NoFlo](http://noflojs.org/)\n* [PhantomJS](http://phantomjs.org/)\n* [CasperJS](http://casperjs.org/)\n* [SpookyJS](https://github.com/WaterfallEngineering/SpookyJS)\n\nI know,\n\n .-.\n(o o) boo!\n| O \\\n \\   \\\n  `~~~'\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.1.3","dist":{"shasum":"caa0790b783f3b2d01d9429e8a6fa1d3ea0601a7","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.1.3.tgz","integrity":"sha512-A+39maKo0oqp2C/RDL0owG9KwbiCFLCghMH6JLFM+LIgWtr4tQsnJI4WBv8cHK6b5Kn8PkOCuutSd5LeTi6Etg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFCHHbutkE2pHu0n1G0wqp6hO32EUvz0nTvrQgBUZdl4AiEApjv4dp57b1YMCLu8N++1AehXl2H0PEiljVdofwScQmg="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.1.4":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.1.4","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","spooky":"~0.2.4","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3","q":"~0.9.7","lodash":"~2.3.0"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"0.0.7","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.2","grunt-bump":"0.0.11","grunt-conventional-changelog":"~1.0.0"},"main":"lib/main.coffee","keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"Rule":"components/Rule.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Start":"components/Start.coffee","Click":"components/runners/click.coffee","Wait":"components/runners/wait.coffee","WaitFor":"components/runners/waitFor.coffee","WaitForText":"components/runners/waitForText.coffee","JqueryValue":"components/runners/JqueryValue.coffee","Extract":"components/runners/extract.coffee","Fill":"components/runners/fill.coffee","Capture":"components/runners/capture.coffee","Open":"components/runners/open.coffee","Value":"components/runners/value.coffee","Select":"components/runners/select.coffee","Bypass":"components/runners/bypass.coffee","Output":"components/runners/output.coffee","Missing":"components/runners/missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web <br/>[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nGiven a URL and a rule set (structure described below), noflo-automaton would\ngo through the rule set and try to reach the end, at which point the automaton\nwould forward the accumulated output to its OUT port with the status of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status being the rule number in the provided rule set.\n\n\n## Why not just CasperJS?\n\nAutomaton is a nice abstraction over CasperJS. It provides a consistent\nJSON-based API so you could program with this:\n\n    [\n      { \"action\": \"start\", \"url\": \"http://casperjs.org/\" },\n      { \"action\": \"title\" },\n      { \"action\": \"open\", \"url\": \"http://phantomjs.org\" }\n      { \"action\": \"title\" }\n    ]\n\nRather than this:\n\n    var casper = require('casper').create();\n\n    casper.start('http://casperjs.org/', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.thenOpen('http://phantomjs.org', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.run();\n\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n\n## Usage\n\nThere are two user modes: CommonJS and NoFlo. CommonJS mode exposes a regular class\nfor you to run a JavaScript object-based (i.e. parsed JSON) rule set. In NoFlo\n  mode, it is a graph in NoFlo that you could connect to your network.\n\nYour JSON rule set \n\n### CommonJS Mode\n\nIn CommonJS mode, you simply create a new automaton and call `run`. Assuming the\nJSON file described under the section \"Why not just CasperJS\" above is\navailable at `rules.json`:\n\n    var Automaton = require('noflo-automaton');\n    var rules = require('./rules.json');\n\n    automaton = new Automaton\n\nA promise is returned.\n\n    promise = automaton.run(json);\n\n    promise.then(function(status, output) {\n      if (status === true) {\n        console.log('SUCCESS!');\n      } else {\n        console.log('STOPPED AT ' + status);\n      }\n\n      console.log('OUTPUT:');\n      console.log(output);\n\n    }, function(error) {\n      console.log('FAILED TO SET UP');\n      console.log(error);\n    });\n\n### NoFlo Mode\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A map of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before the **RULES** ports disconnect given that it\nis optional.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  browser. For instance, `[output] {\"a\":\"b\"}` would be saved while `{\"a\":\"b\"}`\n  would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n\n## The Rule Set\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object (i.e. JSON-like) containing an array\nof rules. It works virtually the same way as an assembly language does.\n\n### Rule Set API\n\n#### NOTE: The follow API has not been completely implemented. See issues #9\n\nFor each **rule**, the automaton expects:\n\n* **action**: see the `components/runners` directory for available actions\n* **selector**: *optional* The element to perform the action on. Some actions\n  do not require an element selector, like `open`\n* **_name**: *optional* An identifier so other rules can refer to this rule\n* **_onSuccess**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **_onFailure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      { \"action\": \"click\", \"selector\": \"body #page .row\" },\n      { \"action\": \"click\", \"selector\": \"body #page .row .item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row\", \"value\": \"Item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row .item#you\", \"value\": \"You\" }\n    ]\n\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply).\n\nEach component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule set\n* **offset**: This is the current rule's offset in the rule set. This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a map of counters used by components in order to\n  track progress. This is the only state the components are allowed to keep\n\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto a page. An action runner is simply a\ncomponent of this repository that accepts a context object.\n\nThe runner checks rather it should act on it by examining `rule.action`, which\nis the name of the action as displayed in the rule set. If it is qualified to\nhandle it, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/Iterate` component or\nother runners. This cascading structure allows certain runners to always take\nprecedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object.\n\n\n## Technologies\n\nAutomaton can't be an automaton without:\n\n* [NoFlo](http://noflojs.org/)\n* [PhantomJS](http://phantomjs.org/)\n* [CasperJS](http://casperjs.org/)\n* [SpookyJS](https://github.com/WaterfallEngineering/SpookyJS)\n\nI know,\n\n .-.\n(o o) boo!\n| O \\\n \\   \\\n  `~~~'\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.1.4","dist":{"shasum":"5ff2d185fd907505b125390fe84713ba09aff645","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.1.4.tgz","integrity":"sha512-MbcPHpKoEGvcsXC7IQhTTtnpwGjWnNy8LZvyBOYBbHwe4AVCbpo+JiYFLS9PXsTe6VV8yEl6cRv0g2zyVSVH4Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHXXpysoguMz7hvqojg1axFD0zlCqzYvX3VkrYpkENYXAiBqYG5ulA8oyx5Gwn1YNtcKMtcnqROXOUVGrII/KJKVpQ=="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.1.5":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.1.5","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","spooky":"~0.2.4","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3","q":"~0.9.7","lodash":"~2.3.0"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"0.0.7","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.2","grunt-bump":"0.0.11","grunt-conventional-changelog":"~1.0.0"},"main":"lib/main.coffee","keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"Rule":"components/Rule.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Start":"components/Start.coffee","Click":"components/runners/click.coffee","Wait":"components/runners/wait.coffee","WaitFor":"components/runners/waitFor.coffee","WaitForText":"components/runners/waitForText.coffee","JqueryValue":"components/runners/JqueryValue.coffee","Extract":"components/runners/extract.coffee","Fill":"components/runners/fill.coffee","Capture":"components/runners/capture.coffee","Open":"components/runners/open.coffee","Value":"components/runners/value.coffee","Select":"components/runners/select.coffee","Bypass":"components/runners/bypass.coffee","Output":"components/runners/output.coffee","Missing":"components/runners/missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web <br/>[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nGiven a URL and a rule set (structure described below), noflo-automaton would\ngo through the rule set and try to reach the end, at which point the automaton\nwould forward the accumulated output to its OUT port with the status of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status being the rule number in the provided rule set.\n\n\n## Why not just CasperJS?\n\nAutomaton is a nice abstraction over CasperJS. It provides a consistent\nJSON-based API so you could program with this:\n\n    [\n      { \"action\": \"start\", \"url\": \"http://casperjs.org/\" },\n      { \"action\": \"title\" },\n      { \"action\": \"open\", \"url\": \"http://phantomjs.org\" }\n      { \"action\": \"title\" }\n    ]\n\nRather than this:\n\n    var casper = require('casper').create();\n\n    casper.start('http://casperjs.org/', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.thenOpen('http://phantomjs.org', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.run();\n\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n\n## Usage\n\nThere are two user modes: CommonJS and NoFlo. CommonJS mode exposes a regular class\nfor you to run a JavaScript object-based (i.e. parsed JSON) rule set. In NoFlo\n  mode, it is a graph in NoFlo that you could connect to your network.\n\nYour JSON rule set \n\n### CommonJS Mode\n\nIn CommonJS mode, you simply create a new automaton and call `run`. Assuming the\nJSON file described under the section \"Why not just CasperJS\" above is\navailable at `rules.json`:\n\n    var Automaton = require('noflo-automaton');\n    var rules = require('./rules.json');\n\n    automaton = new Automaton\n\nA promise is returned.\n\n    promise = automaton.run(json);\n\n    promise.then(function(status, output) {\n      if (status === true) {\n        console.log('SUCCESS!');\n      } else {\n        console.log('STOPPED AT ' + status);\n      }\n\n      console.log('OUTPUT:');\n      console.log(output);\n\n    }, function(error) {\n      console.log('FAILED TO SET UP');\n      console.log(error);\n    });\n\n### NoFlo Mode\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A map of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before the **RULES** ports disconnect given that it\nis optional.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  browser. For instance, `[output] {\"a\":\"b\"}` would be saved while `{\"a\":\"b\"}`\n  would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n\n## The Rule Set\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object (i.e. JSON-like) containing an array\nof rules. It works virtually the same way as an assembly language does.\n\n### Rule Set API\n\n#### NOTE: The follow API has not been completely implemented. See issues #9\n\nFor each **rule**, the automaton expects:\n\n* **action**: see the `components/runners` directory for available actions\n* **selector**: *optional* The element to perform the action on. Some actions\n  do not require an element selector, like `open`\n* **_name**: *optional* An identifier so other rules can refer to this rule\n* **_onSuccess**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **_onFailure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      { \"action\": \"click\", \"selector\": \"body #page .row\" },\n      { \"action\": \"click\", \"selector\": \"body #page .row .item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row\", \"value\": \"Item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row .item#you\", \"value\": \"You\" }\n    ]\n\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply).\n\nEach component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule set\n* **offset**: This is the current rule's offset in the rule set. This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a map of counters used by components in order to\n  track progress. This is the only state the components are allowed to keep\n\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto a page. An action runner is simply a\ncomponent of this repository that accepts a context object.\n\nThe runner checks rather it should act on it by examining `rule.action`, which\nis the name of the action as displayed in the rule set. If it is qualified to\nhandle it, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/Iterate` component or\nother runners. This cascading structure allows certain runners to always take\nprecedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object.\n\n\n## Technologies\n\nAutomaton can't be an automaton without:\n\n* [NoFlo](http://noflojs.org/)\n* [PhantomJS](http://phantomjs.org/)\n* [CasperJS](http://casperjs.org/)\n* [SpookyJS](https://github.com/WaterfallEngineering/SpookyJS)\n\nI know,\n\n .-.\n(o o) boo!\n| O \\\n \\   \\\n  `~~~'\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.1.5","dist":{"shasum":"578c31820c641e5de64095ceb0968bee54378dc5","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.1.5.tgz","integrity":"sha512-HD3M0wEclcoA6FIB0nPZxJ+9oh2kCt1Hii2lw2IDDzu9Gh9WcpiWerbHt4g1bGPwyoE+jXhTEQOJq73EeAU72Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICTvfrSe4mqK2o06RejBzEX9UaVRgwZHzQDbQoTdaJyZAiBK0A+lXDYmJeZiEmVie8rTyNp4cDC9ZlQZG7mZB9pMvA=="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]},"0.1.6":{"name":"noflo-automaton","description":"Automate navigation on the web based on Casper.js","version":"0.1.6","author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"licenses":[{"type":"MIT","url":"https://github.com/kenhkan/noflo-automaton/blob/master/LICENSE.md"}],"dependencies":{"noflo":"~0.4.0","spooky":"~0.2.4","uuid":"~1.4.1","noflo-core":"~0.1.1","noflo-strings":"~0.1.1","underscore.string":"~2.3.3","q":"~0.9.7","lodash":"~2.3.0"},"devDependencies":{"grunt":"~0.4.1","grunt-coffeelint":"0.0.7","grunt-contrib-watch":"~0.3.1","grunt-contrib-nodeunit":"~0.2.2","grunt-bump":"0.0.11","grunt-conventional-changelog":"~1.0.0"},"main":"lib/main.coffee","keywords":["scraping","webpage","casperjs","phantomjs","navigation","automation"],"noflo":{"components":{"Rule":"components/Rule.coffee","Iterate":"components/Iterate.coffee","Setup":"components/Setup.coffee","Start":"components/Start.coffee","Click":"components/runners/click.coffee","Wait":"components/runners/wait.coffee","WaitFor":"components/runners/waitFor.coffee","WaitForText":"components/runners/waitForText.coffee","JqueryValue":"components/runners/jqueryValue.coffee","Extract":"components/runners/extract.coffee","Fill":"components/runners/fill.coffee","Capture":"components/runners/capture.coffee","Open":"components/runners/open.coffee","Value":"components/runners/value.coffee","Select":"components/runners/select.coffee","Bypass":"components/runners/bypass.coffee","Output":"components/runners/output.coffee","Missing":"components/runners/missing.coffee"},"graphs":{"Automaton":"graphs/Automaton.fbp"}},"scripts":{"test":"grunt test"},"readme":"# Automate navigation on the web <br/>[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton) [![Dependency Status](https://gemnasium.com/kenhkan/noflo-automaton.png)](https://gemnasium.com/kenhkan/noflo-automaton) [![NPM version](https://badge.fury.io/js/noflo-automaton.png)](http://badge.fury.io/js/noflo-automaton) [![Stories in Ready](https://badge.waffle.io/kenhkan/noflo-automaton.png)](http://waffle.io/kenhkan/noflo-automaton)\n\nGiven a URL and a rule set (structure described below), noflo-automaton would\ngo through the rule set and try to reach the end, at which point the automaton\nwould forward the accumulated output to its OUT port with the status of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status being the rule number in the provided rule set.\n\n\n## Why not just CasperJS?\n\nAutomaton is a nice abstraction over CasperJS. It provides a consistent\nJSON-based API so you could program with this:\n\n    [\n      { \"action\": \"start\", \"url\": \"http://casperjs.org/\" },\n      { \"action\": \"title\" },\n      { \"action\": \"open\", \"url\": \"http://phantomjs.org\" }\n      { \"action\": \"title\" }\n    ]\n\nRather than this:\n\n    var casper = require('casper').create();\n\n    casper.start('http://casperjs.org/', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.thenOpen('http://phantomjs.org', function() {\n        this.echo(this.getTitle());\n    });\n\n    casper.run();\n\n\n## Installation\n\nCasper.js and by extension, Phantom.js, are required. In other words, this\nlibrary runs only on a server and not the browser. Check out [Casper.js\ndocumentation](http://docs.casperjs.org/en/latest/installation.html) for\ninstallation instructions.\n\nOnce you have these installed, it's just a simple `npm install --save\nnoflo-automaton`!\n\n\n## Usage\n\nThere are two user modes: CommonJS and NoFlo. CommonJS mode exposes a regular class\nfor you to run a JavaScript object-based (i.e. parsed JSON) rule set. In NoFlo\n  mode, it is a graph in NoFlo that you could connect to your network.\n\nYour JSON rule set \n\n### CommonJS Mode\n\nIn CommonJS mode, you simply create a new automaton and call `run`. Assuming the\nJSON file described under the section \"Why not just CasperJS\" above is\navailable at `rules.json`:\n\n    var Automaton = require('noflo-automaton');\n    var rules = require('./rules.json');\n\n    automaton = new Automaton\n\nA promise is returned.\n\n    promise = automaton.run(json);\n\n    promise.then(function(status, output) {\n      if (status === true) {\n        console.log('SUCCESS!');\n      } else {\n        console.log('STOPPED AT ' + status);\n      }\n\n      console.log('OUTPUT:');\n      console.log(output);\n\n    }, function(error) {\n      console.log('FAILED TO SET UP');\n      console.log(error);\n    });\n\n### NoFlo Mode\n\nTo use noflo-automaton, you only need to interface with the\n`automaton/automaton` graph, which expects:\n\n* Inport **rules**: This is the rule obejct (see below)\n* Inport **options**: *optional* A map of options to be passed to\n  [Casper.js](http://docs.casperjs.org/en/latest/modules/casper.html). If\n  `verbose` set to true, all log from Casper.js will be printed to\n  `console.log`.\n\nOptions must be passed in before the **RULES** ports disconnect given that it\nis optional.\n\nThe graph outputs to the OUT port, with the **status** wrapping as group.\n**status** is `null` if successful or the offset of the last executed rule if\nfailed.\n\n* Outport **out**: The accumulated output from executing all the steps. This is\n  a stack of all `console.log` output prefixd with `[output] ` from the remote\n  browser. For instance, `[output] {\"a\":\"b\"}` would be saved while `{\"a\":\"b\"}`\n  would not.\n* Outport **error**: An error packet if the rule or the options object is not\n  valid\n\n\n## The Rule Set\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object (i.e. JSON-like) containing an array\nof rules. It works virtually the same way as an assembly language does.\n\n### Rule Set API\n\n#### NOTE: The follow API has not been completely implemented. See issues #9\n\nFor each **rule**, the automaton expects:\n\n* **action**: see the `components/runners` directory for available actions\n* **selector**: *optional* The element to perform the action on. Some actions\n  do not require an element selector, like `open`\n* **_name**: *optional* An identifier so other rules can refer to this rule\n* **_onSuccess**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **_onFailure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      { \"action\": \"click\", \"selector\": \"body #page .row\" },\n      { \"action\": \"click\", \"selector\": \"body #page .row .item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row\", \"value\": \"Item\" },\n      { \"action\": \"test\", \"selector\": \"body #page .row .item#you\", \"value\": \"You\" }\n    ]\n\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply).\n\nEach component in the automaton internal loop expects the same\ninbound object, which follows the protocol of:\n\n* **spooky**: This is the SppokyJS object to iterate on. It is created on\n  demand.\n* **rules**: This is the rule set\n* **offset**: This is the current rule's offset in the rule set. This is\n  used internally as a counter to refer to the the current rule to be applied\n  as well as forwarded to OUT upon completion.\n* **counts**: This is a map of counters used by components in order to\n  track progress. This is the only state the components are allowed to keep\n\n\n## Action Runners\n\nAt the heart of automaton is the action runners. These are the actual\ncomponents applying the rules onto a page. An action runner is simply a\ncomponent of this repository that accepts a context object.\n\nThe runner checks rather it should act on it by examining `rule.action`, which\nis the name of the action as displayed in the rule set. If it is qualified to\nhandle it, it should act on it and not forward the context object.\n\nOn the other hand, if it does not know how to handle it, it should forward the\ncontext object as-is to its OUT port. The runner should also check if the OUT\nport is attached before sending.\n\nRunners should attach themselves to either the `automaton/Iterate` component or\nother runners. This cascading structure allows certain runners to always take\nprecedence over others.\n\nNote that action runners do not need to be attached back to the system as the\nSpookyJS object is passed by reference in the context object.\n\n\n## Technologies\n\nAutomaton can't be an automaton without:\n\n* [NoFlo](http://noflojs.org/)\n* [PhantomJS](http://phantomjs.org/)\n* [CasperJS](http://casperjs.org/)\n* [SpookyJS](https://github.com/WaterfallEngineering/SpookyJS)\n\nI know,\n\n .-.\n(o o) boo!\n| O \\\n \\   \\\n  `~~~'\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/kenhkan/noflo-automaton/issues"},"_id":"noflo-automaton@0.1.6","dist":{"shasum":"13eb5364b20b90c53fc204c7046826cddc1a4775","tarball":"https://registry.npmjs.org/noflo-automaton/-/noflo-automaton-0.1.6.tgz","integrity":"sha512-7pd7SeuGLtzaCxoqiFiR8ZvVM5Lg45KpYLmvqnG9C7V393+iW7CNxq3rqodvNO4kpw6BPbKlZFpzloEaotEtGQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICBogghtFDzxVE7+jPayE1kFaPfgd31+cRZMBYTMmk4eAiEAlw/IvexgXTJc7Gr9qyja02yoEiM01yc9GY4peMv9EEo="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"kenhkan","email":"kenhkan@gmail.com"},"maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}]}},"readme":"# noflo-automaton\n[![Build Status](https://secure.travis-ci.org/kenhkan/noflo-automaton.png?branch=master)](http://travis-ci.org/kenhkan/noflo-automaton)\n\nAutomate navigation on the web. This component library is built for NoFlo using\nCasper.js.\n\nGiven a URL and a rule object (structure described below), noflo-automaton\nwould go through the rule object and try to reach the end, at which point the\nautomaton would forward the accumulated output to its OUT port with the status\nnumber of 'true'.\n\nIf at any point it fails, the automaton would still forward the accumulated\noutput but with the status number being the rule number in the provided rule\nobject.\n\n## The Rule Object\n\nTo automate web navigation simply requires a list of rules to tell automaton\nwhat to look for, what to do if it is found, and which rule to execute next.\nThe object is a simple JavaScript object containing an array of rules. It works\nvirtually the same way as an assembly language does.\n\n### Rule Object API\n\nFor each **rule**, the automaton expects:\n\n* **selector**: The CSS3 selector to operate on\n* **actions**: An array of actions to perform (see below)\n* **conditions**: An array of conditions to test for success before moving on\n  (see below)\n* **name**: *optional* An identifier so other rules can refer to this rule\n* **on-success**: *optional* The next rule to execute upon success. It refers\n  to the rule by its name. Automaton scans forward for the name and does not go\n  back in history. In other words, automaton will execute the first instance of\n  the rules matching the name. If it's `false`, quit the program successfully.\n  If it's `true`, the immediately next rule is executed. Default to `true`\n* **on-failure**: *optional* The next rule to execute upon failure. The same\n  properties of determining the next rule to execute as for `on-success` apply.\n* **test-timeout**: *optional* Number of milliseconds to timeout before\n  applying 'conditions'. Default to 0 miliseconds (i.e. immediately calling\n  `setTimeout()` with `0` milliseconds)\n* **retry-timeout**: *optional* Number of milliseconds to timeout before\n  retrying upon failure. Default to `0` milliseconds\n* **retry-count**: *optional* How many times to retry before giving up? Default\n  to no retry (i.e. quit the program with a failure status number)\n\nFor each **action** in the actions array:\n\n* **action**: One of [mouse and form\n  events](http://www.w3schools.com/jsref/dom_obj_event.asp) without the 'on'\n  prefix. It also accepts 'value' which would change the value of an input and\n  trigger the 'change' event.\n* **selector**: *optional* The element to perform the action on. Default to the\n  element specified by the rule selector.\n\nFor each **condition** in the conditions array:\n\n* **condition**: The value to match on the element. This is a RegExp string.\n  For instance, when `class=\"page row item\"` and `property` is `class`, the\n  condition is not going to match with `^row$`. However, it would match with\n  `row`.\n* **name**: *optional* An identifier for other conditions to refer to this\n* **property**: *optional* The attribute name (e.g. 'class') to test.  Default\n  to the content of the HTML element\n* **selector**: *optional* The selector to test the condition on. Default to\n  the element specified by the rule selector.\n* **on-success**: *optional* The next condition by its name to test on success.\n  If it's `false`, stop testing and assume success. If it's `true`, move on to\n  the next condition. Default to `true`\n* **on-failure**: *optional* The next condition by its name to test on failure.\n  If it's `false`, stop testing and assume failure. If it's `true`, move on to\n  the next condition. Default to `false`\n\n### Examples\n\nClick on all the row items and test that all item has the content 'Item' except\nthe one marked with 'you' as ID.\n\n    [\n      {\n        \"selector\": \"body #page .row\",\n        \"actions\": [\n          { \"action\": \"click\" },\n          { \"action\": \"click\", \"selector\": \"body #page .row .item\" }\n        ],\n        \"conditions\": [\n          { \"condition\": \"Item\" },\n          { \"condition\": \"You\", \"selector\": \"body #page .row .item#you\" }\n        ]\n      }\n    ]\n\n## Data Structure\n\nThe automaton is essentially a looper that ends when there is a failure in\nsatisfying the provided conditions or when it completes successfully (i.e. no\nmore rules to apply). Along with the expectation that after each test and rule,\nthere is a timeout to allow DOM events to fire, the flow must be completely\nstateless.\n\nTherefore, each component in the automaton, including the graph\n`automaton/automaton` itself, expects the same inbound object, which follows\nthe protocol of:\n\n* **page**: The DOM element of the page against which all selectors are\n  executed.\n* **rules**: This is the rule obejct.\n* **status**: *internal* This is the current rule's offset in the rule object.\n  This is used internally as a counter to refer to the the current rule to be\n  applied as well as forwarded to OUT upon completion.\n* **counts**: *internal* This is a hash of counters used by some components in\n  order to track when to quit upon repeated failures.\n\nOn OUT port from the graph `automaton/automaton` it outputs an object following\nthis protocol:\n\n* **status**: `true` if it's successful. `false` if the provided page or rule\n  object is not valid. The position of the rule in the rule object otherwise.\n* **error**: *optional* An error object or a string indicating the error\n  message if any\n* **page**: The DOM element passed to the graph in the beginning\n* **rules**: The rule object passed to the graph in the beginning\n","maintainers":[{"name":"kenhkan","email":"kenhkan@gmail.com"}],"time":{"modified":"2022-06-22T04:19:36.586Z","created":"2013-08-13T04:04:44.377Z","0.0.0":"2013-08-13T04:04:46.096Z","0.0.1":"2013-08-19T08:56:48.058Z","0.0.2":"2013-08-24T05:35:21.159Z","0.0.3":"2013-08-25T09:38:32.793Z","0.0.4":"2013-08-25T18:02:09.264Z","0.0.5":"2013-11-20T11:35:07.963Z","0.1.0":"2013-11-20T11:39:34.217Z","0.1.1":"2013-11-20T13:38:31.971Z","0.1.3":"2013-11-25T04:50:30.629Z","0.1.4":"2013-11-25T09:03:16.218Z","0.1.5":"2013-11-25T11:29:27.905Z","0.1.6":"2013-11-25T14:09:41.108Z"},"author":{"name":"Kenneth Kan","email":"kenhkan@gmail.com"},"repository":{"type":"git","url":"https://github.com/kenhkan/noflo-automaton.git"},"users":{"sandwind":true}}