{"_id":"thedude","_rev":"12-295678513349b9851831f730bacbf775","time":{"0.0.2":"2015-10-08T15:40:26.947Z","0.0.3":"2015-10-08T15:40:26.947Z","0.0.4":"2015-10-08T15:40:26.947Z","created":"2018-08-02T09:45:22.213Z","0.1.0":"2018-08-02T09:45:22.314Z","modified":"2022-05-21T17:44:28.034Z","0.1.1":"2018-08-03T14:04:27.623Z","0.1.2":"2018-08-06T12:27:14.312Z"},"name":"thedude","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"thedude","version":"0.1.0","description":"Call and synchronize functions in the future","main":"dude.js","scripts":{"lint":"eslint .","test":"tap test.js"},"repository":{"type":"git","url":"git+https://github.com/frankban/dude.git"},"keywords":["calls","commit","future","later"],"author":{"name":"Francesco Banconi"},"license":"SEE LICENSE IN LICENSE.txt","bugs":{"url":"https://github.com/frankban/thedude/issues"},"homepage":"https://github.com/frankban/thedude#readme","devDependencies":{"eslint":"^4.19.1","tap":"^12.0.1"},"dependencies":{},"gitHead":"747a3f3d6aa2c8cf7c5c2eb3cec32f1b606fc4da","_id":"thedude@0.1.0","_npmVersion":"6.2.0","_nodeVersion":"8.11.3","_npmUser":{"name":"frankban","email":"frankban@gmail.com"},"dist":{"integrity":"sha512-5P//i87hsCToB52+pvaYrLxBBXzfKHVyK40ZO88RQbX9yWbZFEYe4Pwf8YYwvMgkFBymaljTVxlZbbjtErkKjw==","shasum":"737170f204658523ab341b80ec453607a6e522c6","tarball":"https://registry.npmjs.org/thedude/-/thedude-0.1.0.tgz","fileCount":20,"unpackedSize":39575,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbYtKyCRA9TVsSAnZWagAA2bMP/2lgl8ndSx+gtPZAk6di\nDICEhah32kRxiuWNWaEFEpdgx4Us6h3pg+91o2nolp2kFE9Os3FSP5f6a1+T\n5B/yzHiwDGuZktypegU+e/eWqKDyFlJ8pJ1BtUy+llB1CqNJthEVC1r9GUVJ\nXaDBbP4BNUtiBpSrbrz35Bld1cGUyaJP1U0R+hS6jbKLatEo+qPmj1IDPXXr\n5jbK1DHtBireaVE09oakDbMlm+mSoaL+uHunr5XtJ5qvxBQeV6FmoMV8PakM\nXqZ7LiL59vkhMHMJRcljS2RQYGe0e8X8zb0PrTSkOZMQBTkGvmPdubwqFVKC\nwqowfcBH+rHdzKvVtwprz/VLxd5goTFMlVgZ7DW8vUlhu96htyDdX4cVyQ3a\nhstMHw5oZS2JbzM9oEXS90JezxYysBjNeN28mzOF+NH1CCQiL5NG6oiHL9w7\nEUiAe77GwA8GPFOdZDLN2Lfydbx8I2iLkvT0Q8XRFFFkWG0nXW7iFZfROyaj\ned1dbJ/ZOo+d7Iauck7CJThV6gx1+GL2Ad69rNT8Bnn0MemIl/siU2bHREGk\neOjOvLsNXlvAznRKVo56+HfjzSMCA8iYJ/ya59Hw3D5Tl7kb0xfPyFq/Sp9G\nQU4pbPf34ZmG1T5uLY5TrnyNs9Tslfa+cCq8itBnKKtI9HwW87xwWdEZ/x4k\nR679\r\n=qxay\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE/65QfSdll0Eo5NpAgGHeoWqQ+JkKdPZxhqAHnPOsMhAiBZ0EVmAbraruvJlaX//YStKYEVF3rMuiMlR0ZHbCGLiw=="}]},"maintainers":[{"name":"frankban","email":"frankban@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/thedude_0.1.0_1533203122214_0.46329293878796163"},"_hasShrinkwrap":false},"0.1.1":{"name":"thedude","version":"0.1.1","description":"Call and synchronize functions in the future","main":"dude.js","scripts":{"lint":"eslint .","test":"tap test.js"},"repository":{"type":"git","url":"git+https://github.com/frankban/dude.git"},"keywords":["calls","commit","future","later"],"author":{"name":"Francesco Banconi"},"license":"SEE LICENSE IN LICENSE.txt","bugs":{"url":"https://github.com/frankban/thedude/issues"},"homepage":"https://github.com/frankban/thedude#readme","devDependencies":{"eslint":"^4.19.1","tap":"^12.0.1"},"dependencies":{},"gitHead":"b3d4b22807400a15d0d312b43e1c3fc8e2d3f387","_id":"thedude@0.1.1","_npmVersion":"6.2.0","_nodeVersion":"8.11.3","_npmUser":{"name":"frankban","email":"frankban@gmail.com"},"dist":{"integrity":"sha512-hOWizXwIkmcehDQSVSc0E1ydiUFj6UHiozcS4OjNJvnReaKauldOHSfcSiK1aIbKRIG5x8wRPcMIjGMhM60rCQ==","shasum":"09b1cedaf03a9f202ec8f0ede011e5e35d932d6f","tarball":"https://registry.npmjs.org/thedude/-/thedude-0.1.1.tgz","fileCount":20,"unpackedSize":51878,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbZGDsCRA9TVsSAnZWagAAOcEQAI0JgPIn+kwGVZhX6oGp\n+jPAvhNhXHVqArQ9T/xzvV6d3Y/GQI5mMkvVLNKj5DBJYYIivouc5Xpn9/ft\n7Dmr2t4mU5iwdUYfkry8bkQA6wAuOLJvqzceu6ptzuIJoaZGiZ2oM/GbYlHq\nY9B1h9U5ukmYGoS5FylvijpVrWSjw45+4BGhzDB4qDLDq9XgOmnmmaLB+1Xi\n93wNCAzR6T8pbhgZ2PdRhthQ7z50xffHI0rtFe4svwbGq54y034PmMYX+PZ5\nwvAmiJOJ76hCGGsc6/za/c/MPstfmloYZpVd6G5VDg27pEJmyYcQgWR2XBHX\n4iTjPXgl4nWC7E0t3IBO7ADLKlMh/eama2hv60k9nOeQYCG/HScEODnehiuR\nBCfMUuq5x+UZG/E97eqhNeOqY0upRGu8sBaQn8kUJjLk7QyBs55tmjkLr5Cu\n+RyHTV/1N8x1q3qu5AyD3EkZFBceky6mwVpkAKrfkParIY18nFaSUDqYcpjt\nd6Ae8kKO1V3ih2qNQMpjOHYZ4gb3hqHaNNJXwT5typINcVJzToSRsuTJEmSw\nuV4wDZkfg5/2q3PuxNIquL4g+Vjcii/9zo/GO/1dKjSEzZv7QXXMD73sryNW\nAWJRQRBNW8S0ou09wIVXsUC415N/chnQfpi1LIdknN6+sCVTW1vCExi9QsOS\nUwg9\r\n=9l9L\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCQUoVOaPz39LvD9i3wmcm8LmDzuiPS+bdLB8xGhW6xWgIhAPydW+cClyj4xjm5OaFmh68dU/CmxtFTNADeW2Pa2Iw1"}]},"maintainers":[{"name":"frankban","email":"frankban@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/thedude_0.1.1_1533305067505_0.22408968713548472"},"_hasShrinkwrap":false},"0.1.2":{"name":"thedude","version":"0.1.2","description":"Call and synchronize functions in the future","main":"dude.js","scripts":{"lint":"eslint .","test":"tap test.js"},"repository":{"type":"git","url":"git+https://github.com/frankban/dude.git"},"keywords":["calls","commit","future","later"],"author":{"name":"Francesco Banconi"},"license":"SEE LICENSE IN LICENSE.txt","bugs":{"url":"https://github.com/frankban/thedude/issues"},"homepage":"https://github.com/frankban/thedude#readme","devDependencies":{"eslint":"^4.19.1","tap":"^12.0.1"},"dependencies":{},"gitHead":"d637a52f285c55e1b0ad3d2e63265ab567463702","_id":"thedude@0.1.2","_npmVersion":"6.2.0","_nodeVersion":"8.11.3","_npmUser":{"name":"frankban","email":"frankban@gmail.com"},"dist":{"integrity":"sha512-nVTz8f+XhvhYf5X2aKshj9n4PDESS6cf+6Y+wVKYH6Z/TESdWNzTqY2RMrcnqtOI/oP0Ws2OL6wHPfR26qmawQ==","shasum":"ca4f16eed3de2a13d1b838c4c04f50e820344f65","tarball":"https://registry.npmjs.org/thedude/-/thedude-0.1.2.tgz","fileCount":20,"unpackedSize":51888,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbaD6iCRA9TVsSAnZWagAAN+EP/1XuawAZmbz/y1d0JLs0\nc1m7QC36QGDF7OQjPGgVnj4PUZjs5uJaeM/mrooUogsixTmAChiJ8jiQmn+C\nf6bnfSm5ZdbdqpRzc5J95TZogQevo+vyoMpOrPh4L7ZXxJgR4U6qzE84MF03\n9Mb+9rMvpbPjGjA8dqZeXQQrgm6OXXHcsAkRUHlyE1k/7n22mgUz7rlkFAXv\nE3Jc0HVLEYKIwSSIXMQyACj12bZxLJwjetmNvg6YqvINk2fdj44aMuFaRLGK\ncTNn/wray8e0FqdMERSZOX12mZZdp/dHBEYBf+IS/SyonJ9DuhSRWYwTLAhm\nbu4psGApQnuiml+xEyxlOR0hfV1ZIa6ql2eV3Nb6662aCZRTlqZL6ld+/dVs\nYen8Sw7tu8+Ug6p/Upwoay5G8bVpnN99mksZVZ+fqJ5JtXg+Q2S6puRLrXAr\nqE2nAzaT7Stu4+BMQNvh+lXsPCrYgbe0EEbBmquSensJlwMo05Un7KC8oLmd\nh67YHRxncUHX7mg/Zu5Kvq5pjW/nNBGPKzYTp2gOgRs+BMxcElH7iOuXJ1Bs\nifN5H1xHjRWxn7bEPTxYr54vYHB1HetS4oHQmzsD3kATHkgsGAd9Dgege8M6\nl/SeNsrIEE5WrS7HAmvU9khKMB85tEH+Vj4N2rUvNcQhneG+PmtupN1qEX3W\nfg1H\r\n=v4kT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICjNsZ9of/A+nDgvXTme445O2YTFS3tAhSS6ePb8mxoUAiB9asy5aDScPyddDcEpRzKAbPe4zQUoWikHl5RJ1Sowkg=="}]},"maintainers":[{"name":"frankban","email":"frankban@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/thedude_0.1.2_1533558434265_0.9500239115793958"},"_hasShrinkwrap":false}},"maintainers":[{"name":"frankban","email":"frankban@gmail.com"}],"description":"Call and synchronize functions in the future","homepage":"https://github.com/frankban/thedude#readme","keywords":["calls","commit","future","later"],"repository":{"type":"git","url":"git+https://github.com/frankban/dude.git"},"author":{"name":"Francesco Banconi"},"bugs":{"url":"https://github.com/frankban/thedude/issues"},"license":"SEE LICENSE IN LICENSE.txt","readme":"[![Build Status](https://travis-ci.org/frankban/dude.svg?branch=master)](https://travis-ci.org/frankban/thedude)\n\n# thedude\n\nCall functions in the future and synchronize their execution.\n\n## Getting started\n\nthedude, in its simpler form, allows for defining tasks to be executed later:\n```javascript\nconst dude = require('thedude');\n\nfunction sum(a, b) {\n    console.log(`${a} + ${b}`);\n    return a + b;\n};\nconst task = dude.task(sum, 42, 47);\n```\nThe code above creates a task that will sum, when executed, 42 and 47.\nInitially, the task is not running:\n```javascript\n> task.info();\n{ id: 0, status: 'procrastinating', notes: {} }\n```\nTo actually run the task, call its *run* method, which also accepts a callback\ncalled with the result.\n```javascript\n> task.run((err, result) => {\n    console.log('err:', err);\n    console.log('result:', result);\n});\n42 + 47\nerr: null\nresult: 89\n```\nThe status reflects that the task has been run:\n```javascript\n> task.info();\n{ id: 0, status: 'done', notes: {} }\n```\nTasks can be in the following statuses:\n*dude.PROCRASTINATING* -> *dude.RUNNING* -> *dude.DONE* or *dude.CANCELED*.\n\n### Lazy functions\n\nAnother way for creating tasks is through lazy functions. A regular function\ncan be easily turned into a lazy one by using the *dude.lazy()* decorator:\n```javascript\nconst lazySum = dude.lazy(sum);\n```\nWhen calling *lazySum* the original decorated *sum* is not actually executed.\nInstead, a task is returned that can be executed later, as already seen:\n```javascript\nconst task = lazySum(2, 5);\n> task.run(console.log);\nrunning sum\nnull 7\n```\nSo, for now, we can define lazy functions as functions returning a task. The\ndefinition will be slightly extended later, when describing asynchronous tasks.\n\n### Task lists\n\nWhen running multiple tasks together it is common to group them in a list:\n```javascript\nfunction sum(a, b) {\n    console.log(`${a} + ${b}`);\n    return a + b;\n};\nfunction mul(a, b) {\n    console.log(`${a} * ${b}`);\n    return a * b;\n};\n\nconst list = dude.list();\nsum = list.lazy(sum);\nmul = list.lazy(mul);\n\nsum(2, 3);\nmul(3, 4);\nmul(10, 100);\n```\nIn the example above, a list is created (with *dude.list()*) and then used to\nturn a couple of functions into lazy functions, with *list.lazy()*, which is\nequivalent to *dude.lazy*, except that it automatically add all tasks resulting\nby calling the decorated function to the list. Finally three tasks are created.\nIt is now possible to run all tasks together by calling *list.run()*:\n```javascript\n> list.run();\n2 + 3\n3 * 4\n10 * 100\n```\nTwo callbacks can be provided to *list.run()*, the first called every time a\ntask completes, the second called when all tasks are done.\n```javascript\n> list.run((err, result, task) => {\n    console.log('err:', err);\n    console.log('result:', result);\n    console.log('info:', task.info());\n});\n2 + 3\nerr: null\nresult: 5\ninfo: { id: 0, status: 'done', notes: {} }\n3 * 4\nerr: null\nresult: 12\ninfo: { id: 1, status: 'done', notes: {} }\n10 * 100\nerr: null\nresult: 1000\ninfo: { id: 2, status: 'done', notes: {} }\nundefined\n```\nSee the API reference below for a description of the arguments passed to\ncallbacks.\n\n### Lazy objects\n\nThe *lazy* decorator is also able to decorate objects. The resulting object's\nmethods are lazy, for instance:\n```javascript\nclass Calc {\n    sum(a, b) {\n        console.log(`${a} + ${b}`);\n        return a + b;\n    }\n    mul(a, b) {\n        console.log(`${a} * ${b}`);\n        return a * b;\n    }\n}\nlet calc = new Calc();\n\nconst list = dude.list();\ncalc = list.lazy(calc);\n\ncalc.sum(2, 3);\ncalc.mul(3, 4);\ncalc.mul(10, 100);\n```\nThe three calls at the end of this example do not actually execute the\ncorresponding operations but register the tasks on the list, as seen before.\nTo sum it up: lazy objects are objects whose methods are lazy.\n\n### Annotating tasks\n\nWhen working with many tasks, the task identifier included in *task.info()*\ncould not be enough to identify the underlying operation that will be done when\nthe task is run. Tasks can be annotated to add metadata info with the *note*\nmethod, for instance:\n```javascript\ncalc.sum(2, 3).note({name: 'sum', args: [2, 3]});\ncalc.mul(3, 4).note({name: 'mul', args: [3, 4]});\ncalc.mul(10, 100).note({name: 'sum', args: [10, 100]});\n> list.asArray().map(task => task.info().notes);\n[ { name: 'sum', args: [ 2, 3 ] },\n  { name: 'mul', args: [ 3, 4 ] },\n  { name: 'sum', args: [ 10, 100 ] } ]\n```\nWhat to store in notes is up to the caller. For instance, notes could be used\nto automatically generate a summary of what is going to happen when a task list\nis run.\n\n### Canceling tasks\n\nTasks can be canceled with the *task.cancel()* method, which returns whether\nthe operation succeeded. A task is successfully canceled when its status is\n*dude.PROCRASTINATING*. From the example above:\n```javascript\ncalc.sum(2, 3);\nconst t1 = calc.mul(3, 4);\nconst t2 = calc.mul(10, 100);\n> t1.cancel();\ntrue\n> t2.cancel();\ntrue\n>\n> list.run();\n2 + 3\n```\nOnly the sum task is actually run.\n\n## Synchronizing tasks\n\nthedude supports running and synchronizing asynchronous functions, so that\nmultiple tasks can be created to be run later even when one task depends on the\nexecution of another. Futures are used for declaring that a task cannot be run\ninstantly because it requires a value that is not yet known, but possibly will\nin the future.\n\n### Futures\n\nA future is similar to a promise, but it is much simpler, specific to thedude,\nand more oriented to future values rather than future callback execution\n(theners). The concept behind futures is very simple: they can be instantiated,\ncallback can be attached to be executed when a future is set a value, and a\nsingle value can be set once, as in the example below:\n```javascript\nconst f = dude.future();\nf.addCallback(value => console.log('first callback:', value));\nf.addCallback(value => console.log('second callback:', value));\n> f.set(42);\nfirst callback: 42\nsecond callback: 42\n```\nAfter *future.set()* is called, the future is done. When attaching callbacks to\nfutures already done, those callbacks are immediately executed:\n```javascript\n> f.addCallback(console.log);\n42\n```\nWhen a future is done, setting a value again raises an exception.\n\n### Async tasks\n\nLazy functions accept futures as part of their arguments to signify that they\nrequire values that will be only available later, asynchronously. Assume the\nfollowing example:\n```javascript\nfunction getRandomNumber(callback) {\n    setTimeout(() => callback(4), 2000);\n}\n\nfunction sum(a, b) {\n    console.log('result:', a + b);\n}\n\nconst list = dude.list();\ngetRandomNumber = list.lazy(getRandomNumber);\nsum = list.lazy(sum);\n\n// Goal: we want to get a random number and then sum 10 to it.\ngetRandomNumber(num => {\n    console.log('got random number', num);\n});\n// Problem: how to pass the random number as first argument?\nsum('???', 10);\n```\nIn a normal code execution, sum would be called in the callback passed to\ngetRandomNumber, and that would not be an issue. If using thedude is instead\nrequired, because for instance the use case requires getRandomNumber to be\nregistered as a task before sum, then there is a problem of creating a task\ndepending on a value that is not currently known. Futures can be used as\nplaceholders for these values. The example above becomes:\n```javascript\nfunction getRandomNumber(callback) {\n    setTimeout(() => callback(4), 2000);\n}\n\nfunction sum(a, b) {\n    console.log('result:', a + b);\n}\n\nconst list = dude.list();\ngetRandomNumber = list.lazy(getRandomNumber);\nsum = list.lazy(sum);\n\nconst fNum = dude.future(); // Create a future.\ngetRandomNumber(num => {\n    console.log('got random number', num);\n    fNum.set(num); // Assign a value to the future.\n});\nsum(fNum, 10);\n```\nFutures can also be nested in lazy function arguments. In any case, when the\nfuture is set, its position in the arguments passed to the lazy function will\nbe assigned the result of the future. When all futures are done the task is\nfinally executed; until that, the task is procrastinating and can be canceled,\neven after *task.run()* has been called.\n\nIt is now time to extend a little bit the definition of lazy functions: they\nare functions returning a task and accepting futures as placeholders for values\nthat will be available only later.\n\n## API reference\n\n#### createTask(func, ...args) ⇒ `Object`\n\nCreate a task representing a call of the given function and arguments.\n\n- *@param {Function} func* The function executed when running the task.\n- *@param {Array} args* The arguments to use when executing the function. An\n  argument can have any type as usual. If an argument is provided as a\n  future, the the task will wait for the future to be done before executing\n  the function. If the last argument is a function, it is a assumed to be a\n  callback, and therefore the function is assumed to be asynchronous.\n- *@returns {Object}* An API object to interact with the task, with the\n  following methods:\n  - *run(callback)*: run the task and, if provided, call the callback when\n    the execution completes. When the task function last argument is a\n    callback, then the callback provided to \"run\" is called right after the\n    asynchronous function executes its own callback;\n  - *note(notes)*: add annotations to the task, for instance to make it\n    easier to identify specific tasks or to provide metadata. The given\n    notes is an object with key/value pairs representing notes.\n  - *info()*: return information about the task as an object with the\n    following fields:\n    - *id*: the task identifier;\n    - *notes*: the notes added using note() (see above);\n    - *status*: a string representing the task status, between:\n      - *dude.PROCRASTINATING*: the task function has not been started yet.\n        Note that a task could be procrastinating even if run has been\n        called, for instance, because it's waiting for all required futures\n        to be done;\n      - *dude.RUNNING*: the task is currently running;\n      - *dude.CANCELED*: the task has been canceled using cancel, and will\n        not be able to be run anymore;\n      - *dude.DONE*: the task completed, and cannot be run again.\n  - *cancel()*: try to cancel the execution of the task, and return whether\n    the process succeeded. Note that canceling a task only succeeds when\n    the task is still procrastinating.\n\n#### lazy(funcOrInstance) ⇒ `Function or Object`\n\nReturn a lazy function or instance from the given function or instance.\n\nLazy functions return a task and accept futures as placeholders for values\nthat will be available only later.\n\n- *@param {Function or Object} funcOrInstance* The original function or instance\n  to decorate so that it becomes lazy. Being lazy means that the function\n  itself (or all object methods, when an instance is provided) returns a task\n  rather than actually execute its body.\n- *@returns {Function}* The lazy function or instance.\n\n#### list(options) ⇒ `Object`\n\nCreate a task list, which groups tasks to be executed together.\n\n- *@param {Object} options* Not used yet.\n- *@returns {Object}* A task list with the following methods:\n  - *add(task)*: add a task to this list;\n  - *lazy(funcOrInstance)*: equivalent to global lazy. When the returned\n    function is executed, the corresponding task is automatically added to the\n    task list;\n  - *asArray()*: return all tasks in the list;\n  - *clear()*: remove all tasks from the list;\n  - *run(changesCallback, doneCallback)*: run all tasks in this list. The given\n    optional *changesCallback* is called every time a task in the list completes\n    its execution. It receives an error (or null), the task result (if any) and\n    the task itself. The *doneCallback* is called when all current tasks\n    complete. It receives a list of objects, one object for every task run, with\n    the \"task\", \"result\" and \"err\" keys.\n\n#### future() ⇒ `Object`\n\nCreate and return a future, which represents a value that will be available in\nthe future.\n\n- *@returns {Object}* A future with the *done* attribute (reporting whether the)\n  future is done, and the following methods:\n  - *set(value)*: set the result for this future. From this point on, the future\n    is \"done\" and the done property returns true. An error is raised if a value\n    is set on a future that is already done;\n  - *addCallback(callback)*: register a callback to be called when the future is\n    done, with its result. If the future is already done, the callback is called\n    immediately with the value. Callbacks are executed in the order they are\n    added.\n","readmeFilename":"README.md"}