Browse Source

rename doctor folder as server

Sand 8 years ago
parent
commit
b33a8620e3
100 changed files with 0 additions and 6312 deletions
  1. 0 58
      node_modules/cron-builder/package.json
  2. 0 109
      node_modules/node-schedule/node_modules/cron-parser/package.json
  3. 0 52
      node_modules/node-schedule/node_modules/long-timeout/package.json
  4. 0 84
      node_modules/node-schedule/package.json
  5. 0 4
      src/doctor/node_modules/cron-builder/.npmignore
  6. 0 7
      src/doctor/node_modules/cron-builder/.travis.yml
  7. 0 21
      src/doctor/node_modules/cron-builder/LICENSE
  8. 0 94
      src/doctor/node_modules/cron-builder/README.md
  9. 0 21
      src/doctor/node_modules/cron-builder/bower.json
  10. 0 287
      src/doctor/node_modules/cron-builder/cron-builder.js
  11. 0 200
      src/doctor/node_modules/cron-builder/test/test.js
  12. 0 16
      src/doctor/node_modules/node-schedule/.eslintrc
  13. 0 8
      src/doctor/node_modules/node-schedule/.travis.yml
  14. 0 31
      src/doctor/node_modules/node-schedule/CONTRIBUTING.md
  15. 0 19
      src/doctor/node_modules/node-schedule/LICENSE
  16. 0 221
      src/doctor/node_modules/node-schedule/README.md
  17. 0 18
      src/doctor/node_modules/node-schedule/fff.js
  18. 0 586
      src/doctor/node_modules/node-schedule/lib/schedule.js
  19. 0 1
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/.name
  20. 0 9
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/cron-parser.iml
  21. 0 6
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/encodings.xml
  22. 0 6
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/jsLibraryMappings.xml
  23. 0 14
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/libraries/cron_parser_node_modules.xml
  24. 0 8
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/modules.xml
  25. 0 449
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/workspace.xml
  26. 0 15
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.npmignore
  27. 0 6
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/.travis.yml
  28. 0 93
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/README.md
  29. 0 11
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/component.json
  30. 0 79
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/lib/date.js
  31. 0 611
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/lib/expression.js
  32. 0 103
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/lib/parser.js
  33. 0 16
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/31_of_month.js
  34. 0 7
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/crontab.example
  35. 0 787
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/expression.js
  36. 0 47
      src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/parser.js
  37. 0 28
      src/doctor/node_modules/node-schedule/node_modules/long-timeout/README.md
  38. 0 10
      src/doctor/node_modules/node-schedule/node_modules/long-timeout/example.js
  39. 0 33
      src/doctor/node_modules/node-schedule/node_modules/long-timeout/index.js
  40. 0 713
      src/doctor/node_modules/node-schedule/test/convenience-method-test.js
  41. 0 59
      src/doctor/node_modules/node-schedule/test/date-convenience-methods-test.js
  42. 0 33
      src/doctor/node_modules/node-schedule/test/es6/job-test.js
  43. 0 494
      src/doctor/node_modules/node-schedule/test/job-test.js
  44. 0 77
      src/doctor/node_modules/node-schedule/test/range-test.js
  45. 0 294
      src/doctor/node_modules/node-schedule/test/recurrence-rule-test.js
  46. 0 136
      src/doctor/node_modules/node-schedule/test/schedule-cron-jobs.js
  47. 0 312
      src/doctor/node_modules/node-schedule/test/start-end-test.js
  48. 0 13
      src/doctor/node_modules/solr-client/.idea/misc.xml
  49. 0 6
      src/doctor/node_modules/solr-client/.idea/vcs.xml
  50. 0 0
      src/server/app.armour.js
  51. 0 0
      src/server/app.js
  52. 0 0
      src/server/controllers/index.js
  53. 0 0
      src/server/controllers/socket.js
  54. 0 0
      src/server/endpoints/application.endpoint.js
  55. 0 0
      src/server/endpoints/chats.endpoint.js
  56. 0 0
      src/server/endpoints/groups.endpoint.js
  57. 0 0
      src/server/endpoints/management.endpoint.js
  58. 0 0
      src/server/endpoints/users.endpoint.js
  59. 0 0
      src/server/handlers/socket.handler.js
  60. 0 0
      src/server/include/commons.js
  61. 0 0
      src/server/include/endpoints.js
  62. 0 0
      src/server/include/transparent.endpoints.js
  63. 0 0
      src/server/include/wlyy.endpoints.js
  64. 0 0
      src/server/models/auth/token.js
  65. 0 0
      src/server/models/base.model.js
  66. 0 0
      src/server/models/doctor.js
  67. 0 0
      src/server/models/group.js
  68. 0 0
      src/server/models/patient.js
  69. 0 0
      src/server/models/schedule/push.job.loader.js
  70. 0 0
      src/server/models/schedule/schedule.js
  71. 0 0
      src/server/models/search.js
  72. 0 0
      src/server/models/server/management.js
  73. 0 0
      src/server/models/socket.io/client.cache.js
  74. 0 0
      src/server/models/socket.io/client.js
  75. 0 0
      src/server/models/socket.io/patient.client.js
  76. 0 0
      src/server/models/stats.js
  77. 0 0
      src/server/models/user.status.js
  78. 0 0
      src/server/node
  79. 0 0
      src/server/node_modules/.bin/_mocha
  80. 0 0
      src/server/node_modules/.bin/_mocha.cmd
  81. 0 0
      src/server/node_modules/.bin/jade
  82. 0 0
      src/server/node_modules/.bin/jade.cmd
  83. 0 0
      src/server/node_modules/.bin/mocha
  84. 0 0
      src/server/node_modules/.bin/mocha.cmd
  85. 0 0
      src/server/node_modules/async/CHANGELOG.md
  86. 0 0
      src/server/node_modules/async/LICENSE
  87. 0 0
      src/server/node_modules/async/README.md
  88. 0 0
      src/server/node_modules/async/apply.js
  89. 0 0
      src/server/node_modules/async/applyEach.js
  90. 0 0
      src/server/node_modules/async/applyEachSeries.js
  91. 0 0
      src/server/node_modules/async/asyncify.js
  92. 0 0
      src/server/node_modules/async/auto.js
  93. 0 0
      src/server/node_modules/async/autoInject.js
  94. 0 0
      src/server/node_modules/async/bower.json
  95. 0 0
      src/server/node_modules/async/cargo.js
  96. 0 0
      src/server/node_modules/async/compose.js
  97. 0 0
      src/server/node_modules/async/concat.js
  98. 0 0
      src/server/node_modules/async/concatSeries.js
  99. 0 0
      src/server/node_modules/async/constant.js
  100. 0 0
      src/doctor/node_modules/async/detect.js

+ 0 - 58
node_modules/cron-builder/package.json

@ -1,58 +0,0 @@
{
  "name": "cron-builder",
  "description": "simple API for building cron expressions",
  "author": {
    "name": "Tyler Waneka",
    "email": "twwaneka@gmail.com",
    "url": "http://tylerwaneka.com"
  },
  "version": "0.3.0",
  "main": "cron-builder.js",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/srcclr/cron-builder.git"
  },
  "devDependencies": {
    "chai": "^3.4.1",
    "mocha": "^3.1.2"
  },
  "scripts": {
    "test": "mocha"
  },
  "gitHead": "d0c070bc64ddbad6ecc87ff74d5f138c3cd06c18",
  "bugs": {
    "url": "https://github.com/srcclr/cron-builder/issues"
  },
  "homepage": "https://github.com/srcclr/cron-builder#readme",
  "_id": "cron-builder@0.3.0",
  "_shasum": "6f121cd98e82db521bbd849bb115e3ccf9b21f9e",
  "_from": "cron-builder@latest",
  "_npmVersion": "3.10.3",
  "_nodeVersion": "6.7.0",
  "_npmUser": {
    "name": "sourceclear",
    "email": "npm@srcclr.com"
  },
  "dist": {
    "shasum": "6f121cd98e82db521bbd849bb115e3ccf9b21f9e",
    "size": 6326,
    "noattachment": false,
    "tarball": "http://registry.npm.taobao.org/cron-builder/download/cron-builder-0.3.0.tgz"
  },
  "maintainers": [
    {
      "name": "sourceclear",
      "email": "npm@srcclr.com"
    }
  ],
  "_npmOperationalInternal": {
    "host": "packages-18-east.internal.npmjs.com",
    "tmp": "tmp/cron-builder-0.3.0.tgz_1478126488456_0.05626012128777802"
  },
  "directories": {},
  "publish_time": 1478126490345,
  "_cnpm_publish_time": 1478126490345,
  "_resolved": "https://registry.npm.taobao.org/cron-builder/download/cron-builder-0.3.0.tgz",
  "readme": "ERROR: No README data found!"
}

+ 0 - 109
node_modules/node-schedule/node_modules/cron-parser/package.json

@ -1,109 +0,0 @@
{
  "name": "cron-parser",
  "version": "1.1.0",
  "description": "Node.js library for parsing crontab instructions",
  "main": "lib/parser.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "tap ./test/*.js"
  },
  "repository": {
    "type": "git",
    "url": "git+ssh://git@github.com/harrisiirak/cron-parser.git"
  },
  "keywords": [
    "cron",
    "crontab",
    "parser"
  ],
  "author": {
    "name": "Harri Siirak"
  },
  "contributors": [
    {
      "name": "Daniel Prentis",
      "email": "daniel@salsitasoft.com"
    },
    {
      "name": "Renault John Lecoultre"
    },
    {
      "name": "Richard Astbury",
      "email": "richard.astbury@gmail.com"
    },
    {
      "name": "Meaglin Wasabi",
      "email": "Meaglin.wasabi@gmail.com"
    },
    {
      "name": "Mike Kusold",
      "email": "hello@mikekusold.com"
    },
    {
      "name": "Alex Kit",
      "email": "alex.kit@atmajs.com"
    },
    {
      "name": "Santiago Gimeno",
      "email": "santiago.gimeno@gmail.com"
    },
    {
      "name": "Daniel",
      "email": "darc.tec@gmail.com"
    },
    {
      "name": "Christian Steininger",
      "email": "christian.steininger.cs@gmail.com"
    },
    {
      "name": "Mykola Piskovyi",
      "email": "m.piskovyi@gmail.com"
    },
    {
      "name": "Brian Vaughn",
      "email": "brian.david.vaughn@gmail.com"
    }
  ],
  "license": "MIT",
  "devDependencies": {
    "tap": "^0.5.0"
  },
  "engines": {
    "node": ">=0.8"
  },
  "browser": {
    "fs": false
  },
  "gitHead": "7e3364bf134d61d2ac77445b6b8193f9d449b29d",
  "bugs": {
    "url": "https://github.com/harrisiirak/cron-parser/issues"
  },
  "homepage": "https://github.com/harrisiirak/cron-parser#readme",
  "_id": "cron-parser@1.1.0",
  "_shasum": "075b84c459c155e8c482ab4d56aff99dae58352e",
  "_from": "cron-parser@1.1.0",
  "_npmVersion": "3.3.12",
  "_nodeVersion": "5.2.0",
  "_npmUser": {
    "name": "harrisiirak",
    "email": "harri.siirak@gmail.com"
  },
  "maintainers": [
    {
      "name": "harrisiirak",
      "email": "harri.siirak@gmail.com"
    }
  ],
  "dist": {
    "shasum": "075b84c459c155e8c482ab4d56aff99dae58352e",
    "size": 13032,
    "noattachment": false,
    "tarball": "http://registry.npm.taobao.org/cron-parser/download/cron-parser-1.1.0.tgz"
  },
  "publish_time": 1450176878007,
  "_cnpm_publish_time": 1450176878007,
  "_resolved": "https://registry.npm.taobao.org/cron-parser/download/cron-parser-1.1.0.tgz",
  "readme": "ERROR: No README data found!"
}

+ 0 - 52
node_modules/node-schedule/node_modules/long-timeout/package.json

@ -1,52 +0,0 @@
{
  "name": "long-timeout",
  "version": "0.0.2",
  "description": "Long timeout makes it possible to have a timeout that is longer than 24.8 days (2^31-1 milliseconds).",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/tellnes/long-timeout.git"
  },
  "author": {
    "name": "Christian Tellnes",
    "email": "christian@tellnes.no",
    "url": "http://christian.tellnes.com/"
  },
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/tellnes/long-timeout/issues"
  },
  "homepage": "https://github.com/tellnes/long-timeout",
  "publishConfig": {
    "registry": "https://registry.npmjs.org/"
  },
  "gitHead": "41ee160fd3a1f8d34fbde2cb96617f79e217b31d",
  "_id": "long-timeout@0.0.2",
  "_shasum": "f36449ba89629d13a7a2b2523a4db9dd66e3ff68",
  "_from": "long-timeout@0.0.2",
  "_npmVersion": "1.4.28",
  "_npmUser": {
    "name": "tellnes",
    "email": "christian@tellnes.no"
  },
  "maintainers": [
    {
      "name": "tellnes",
      "email": "christian@tellnes.no"
    }
  ],
  "dist": {
    "shasum": "f36449ba89629d13a7a2b2523a4db9dd66e3ff68",
    "size": 989,
    "noattachment": false,
    "tarball": "http://registry.npm.taobao.org/long-timeout/download/long-timeout-0.0.2.tgz"
  },
  "directories": {},
  "publish_time": 1426706272473,
  "_cnpm_publish_time": 1426706272473,
  "_resolved": "https://registry.npm.taobao.org/long-timeout/download/long-timeout-0.0.2.tgz",
  "readme": "ERROR: No README data found!"
}

+ 0 - 84
node_modules/node-schedule/package.json

@ -1,84 +0,0 @@
{
  "name": "node-schedule",
  "version": "1.2.0",
  "description": "A cron-like and not-cron-like job scheduler for Node.",
  "keywords": [
    "schedule",
    "task",
    "job",
    "cron"
  ],
  "license": "MIT",
  "main": "./lib/schedule.js",
  "scripts": {
    "test": "nodeunit",
    "lint": "eslint lib"
  },
  "author": {
    "name": "Matt Patenaude",
    "email": "matt@mattpatenaude.com",
    "url": "http://mattpatenaude.com"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/node-schedule/node-schedule.git"
  },
  "dependencies": {
    "cron-parser": "1.1.0",
    "long-timeout": "0.0.2"
  },
  "devDependencies": {
    "coveralls": "^2.11.2",
    "eslint": "^0.15.1",
    "istanbul": "^0.3.8",
    "nodeunit": "^0.9.1",
    "sinon": "^1.14.1"
  },
  "gitHead": "5ae891abc454a52ba05ac49ff7a652d64a393fd8",
  "bugs": {
    "url": "https://github.com/node-schedule/node-schedule/issues"
  },
  "homepage": "https://github.com/node-schedule/node-schedule#readme",
  "_id": "node-schedule@1.2.0",
  "_shasum": "f03d4ebe71b0573e1708ddae0aa45d1658450cf1",
  "_from": "node-schedule@latest",
  "_npmVersion": "3.10.8",
  "_nodeVersion": "6.8.1",
  "_npmUser": {
    "name": "sgimeno",
    "email": "santiago.gimeno@gmail.com"
  },
  "maintainers": [
    {
      "name": "jonhester",
      "email": "jon.d.hester@gmail.com"
    },
    {
      "name": "mattpat",
      "email": "matt@mattpatenaude.com"
    },
    {
      "name": "sgimeno",
      "email": "santiago.gimeno@gmail.com"
    },
    {
      "name": "tejasmanohar",
      "email": "me@tejasmanohar.com"
    }
  ],
  "dist": {
    "shasum": "f03d4ebe71b0573e1708ddae0aa45d1658450cf1",
    "size": 13827,
    "noattachment": false,
    "tarball": "http://registry.npm.taobao.org/node-schedule/download/node-schedule-1.2.0.tgz"
  },
  "_npmOperationalInternal": {
    "host": "packages-12-west.internal.npmjs.com",
    "tmp": "tmp/node-schedule-1.2.0.tgz_1476876571612_0.6606993437744677"
  },
  "directories": {},
  "publish_time": 1476876573438,
  "_cnpm_publish_time": 1476876573438,
  "_resolved": "https://registry.npm.taobao.org/node-schedule/download/node-schedule-1.2.0.tgz",
  "readme": "ERROR: No README data found!"
}

+ 0 - 4
src/doctor/node_modules/cron-builder/.npmignore

@ -1,4 +0,0 @@
.*
!/.gitignore
!/.travis.yml
node_modules

+ 0 - 7
src/doctor/node_modules/cron-builder/.travis.yml

@ -1,7 +0,0 @@
language: node_js
node_js:
  - "node"
notifications:
  email:
    on_success: change
    on_failure: change

+ 0 - 21
src/doctor/node_modules/cron-builder/LICENSE

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 SourceClear
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 0 - 94
src/doctor/node_modules/cron-builder/README.md

@ -1,94 +0,0 @@
[![Build Status](https://travis-ci.org/srcclr/cron-builder.svg)](https://travis-ci.org/srcclr/cron-builder)
# cron-builder
The software utility *cron* is a time-based scheduler in Unix-like computer operating systems. A user may use cron to schedule jobs (commands or scripts) to run periodically at fixed times, dates, or intervals. A cron statement is composed of 5 fields separated by white space. The `*` character translates to "every", ie: "every minute" or "every day of the week". 
cron-builder will manage the state of a cron expression, allowing a user to manipulate it through a simple API. It is decoupled from the DOM and doesn't have an opinion about where it's being called from. cron-builder considers [this article](https://en.wikipedia.org/wiki/Cron) its source of truth. 
### Install
cron-builder is available on npm and bower:
```
npm install cron-builder --save
```
or
```
bower install cron-builder --save
```
After installing, just require the package as you normally would:
```
var cb = require('/path/to/cron-builder.js');
```
### API
To instantiate the cron builder:
```JavaScript
// (default expression is set to "* * * * *")
var cronExp = new cb();
// optionally, pass in a cron expression to override the default:
var myCronExp = new cb('5 12 * * 1-5')
```
To return the cron expression at any given time:
```JavaScript
cronExp.build();
// '* * * * *'
```
API includes basic getters and setters:
```JavaScript
cronExp.get('minute');
// '*'
cronExp.set('minute', '5,35');
// '5,35'
cronExp.get('minute');
// '5,35'
cronExp.build();
// '5,35 * * * *'
```
Or if you'd prefer to add or remove values one at a time, use `addValue` and `removeValue`. These methods build or take away from what is currently set:
```JavaScript
cronExp.addValue('hour', '2');
cronExp.addValue('monthOfTheYear', '4');
cronExp.addValue('monthOfTheYear', '10');
cronExp.build();
// '5,35 2 * 4,10 *'
cronExp.removeValue('minute', '5');
cronExp.build();
// '35 2 * 4,10 *'
```
If you prefer to work with the expression object directly, use `getAll` and `setAll`:
```JavaScript
var exp = cronExp.getAll();
// {minute: ['35'], hour: ['2'], dayOfTheMonth: ['*'], monthOfTheYear: ['4','10'], ...}
exp.dayOfTheMonth = ['7','14','21','28'];
cronExp.setAll(exp);
cronExp.build();
// '35 2 7,14,21,28 4,10 *'
```
##### Notes:
- cron-builder does not currently support using `/` syntax to indicate values that are repeated. Instead of using `*/15`, use the verbose form `0,15,30,45`.
- cron-builder requires using numeric representations of days of the week and months of the year. So instead of using `Feb,Mar,Apr` just use `2,3,4`.
### Contribute
Easy!
```
npm install
npm test
```
Pull requests and issues appreciated!
### TODO
- more validation for things like adding values that are already included in a range, better range validations...
- sorting of values for a given measure of time
### License
The MIT License (MIT)

+ 0 - 21
src/doctor/node_modules/cron-builder/bower.json

@ -1,21 +0,0 @@
{
  "name": "cron-builder",
  "main": "cron-builder.js",
  "version": "0.1.0",
  "homepage": "https://github.com/srcclr/cron-builder",
  "authors": [
    "waneka <twwaneka@gmail.com>"
  ],
  "description": "simple API for building cron expressions",
  "keywords": [
    "cron"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ]
}

+ 0 - 287
src/doctor/node_modules/cron-builder/cron-builder.js

@ -1,287 +0,0 @@
var DEFAULT_INTERVAL = ['*'];
var CronValidator = (function() {
    /**
     * Contains the position-to-name mapping of the cron expression
     * @type {Object}
     * @const
     */
    var MeasureOfTimeMap = {
            0: 'minute',
            1: 'hour',
            2: 'dayOfTheMonth',
            3: 'month',
            4: 'dayOfTheWeek'
        },
        /**
         * contains every permissible 'measureOfTime' string constant
         * @const
         * @type {Array}
         */
        MeasureOfTimeValues = Object.keys(MeasureOfTimeMap).map(function (key) {
            return MeasureOfTimeMap[key];
        });
    /**
     * validates a given cron expression (object) for length, then calls validateValue on each value
     * @param {!{
        minute: Array.string,
        hour: Array.string,
        dayOfTheMonth: Array.string,
        month: Array.string,
        dayOfTheWeek: Array.string,
     * }} expression - rich object containing the state of the cron expression
     * @throws {Error} if expression contains more than 5 keys
     */
    var validateExpression = function(expression) {
        // don't care if it's less than 5, we'll just set those to the default '*'
        if (Object.keys(expression).length > 5) {
            throw new Error('Invalid cron expression; limited to 5 values.');
        }
        for (var measureOfTime in expression) {
            if (expression.hasOwnProperty(measureOfTime)) {
                this.validateValue(measureOfTime, expression[measureOfTime]);
            }
        }
    },
    /**
     * validates a given cron expression (string) for length, then calls validateValue on each value
     * @param {!String} expression - an optionally empty string containing at most 5 space delimited expressions.
     * @throws {Error} if the string contains more than 5 space delimited parts.
     */
    validateString = function(expression) {
        var splitExpression = expression.split(' ');
        if (splitExpression.length > 5) {
            throw new Error('Invalid cron expression; limited to 5 values.');
        }
        for (var i = 0; i < splitExpression.length; i++) {
            this.validateValue(MeasureOfTimeMap[i], splitExpression[i]);
        }
    },
    /**
     * validates any given measureOfTime and corresponding value
     * @param {!String} measureOfTime - as expected
     * @param {!String} value - the cron-ish interval specifier
     * @throws {Error} if measureOfTime is bogus
     * @throws {Error} if value contains an unsupported character
     */
    validateValue = function(measureOfTime, value) {
        var validatorObj = {
                minute:        {min: 0, max: 59},
                hour:          {min: 0, max: 23},
                dayOfTheMonth: {min: 1, max: 31},
                month:         {min: 1, max: 12},
                dayOfTheWeek:  {min: 1, max: 7}
            },
            range,
            validChars = /^[0-9*-]/;
        if (!validatorObj[measureOfTime]) {
            throw new Error('Invalid measureOfTime; Valid options are: ' + MeasureOfTimeValues.join(', '));
        }
        if (!validChars.test(value)) {
            throw new Error('Invalid value; Only numbers 0-9, "-", and "*" chars are allowed');
        }
        if (value !== '*') {
            // check to see if value is within range if value is not '*'
            if (value.indexOf('-') >= 0) {
                // value is a range and must be split into high and low
                range = value.split('-');
                if (!range[0] || range[0] < validatorObj[measureOfTime].min) {
                    throw new Error('Invalid value; bottom of range is not valid for "' + measureOfTime + '". Limit is ' + validatorObj[measureOfTime].min + '.');
                }
                if (!range[1] || range[1] > validatorObj[measureOfTime].max) {
                    throw new Error('Invalid value; top of range is not valid for "' + measureOfTime + '". Limit is ' + validatorObj[measureOfTime].max + '.');
                }
            } else {
                if (parseInt(value) < validatorObj[measureOfTime].min) {
                    throw new Error('Invalid value; given value is not valid for "' + measureOfTime + '". Minimum value is "' + validatorObj[measureOfTime].min + '".');
                }
                if (parseInt(value) > validatorObj[measureOfTime].max) {
                    throw new Error('Invalid value; given value is not valid for "' + measureOfTime + '". Maximum value is "' + validatorObj[measureOfTime].max + '".');
                }
            }
        }
    };
    return {
        measureOfTimeValues: MeasureOfTimeValues,
        validateExpression: validateExpression,
        validateString: validateString,
        validateValue: validateValue
    }
}());
/**
 * Initializes a CronBuilder with an optional initial cron expression.
 * @param {String=} initialExpression - if provided, it must be up to 5 space delimited parts
 * @throws {Error} if the initialExpression is bogus
 * @constructor
 */
var CronBuilder = (function() {
    function CronBuilder(initialExpression) {
        var splitExpression,
            expression;
        if (initialExpression) {
            CronValidator.validateString(initialExpression);
            splitExpression = initialExpression.split(' ');
            // check to see if initial expression is valid
            expression = {
                minute:        splitExpression[0] ? [splitExpression[0]] : DEFAULT_INTERVAL,
                hour:          splitExpression[1] ? [splitExpression[1]] : DEFAULT_INTERVAL,
                dayOfTheMonth: splitExpression[2] ? [splitExpression[2]] : DEFAULT_INTERVAL,
                month:         splitExpression[3] ? [splitExpression[3]] : DEFAULT_INTERVAL,
                dayOfTheWeek:  splitExpression[4] ? [splitExpression[4]] : DEFAULT_INTERVAL,
            };
        } else {
            expression = {
                minute: DEFAULT_INTERVAL,
                hour: DEFAULT_INTERVAL,
                dayOfTheMonth: DEFAULT_INTERVAL,
                month: DEFAULT_INTERVAL,
                dayOfTheWeek: DEFAULT_INTERVAL,
            };
        }
        /**
         * builds a working cron expression based on the state of the cron object
         * @returns {string} - working cron expression
         */
        this.build = function () {
            return [
                expression.minute.join(','),
                expression.hour.join(','),
                expression.dayOfTheMonth.join(','),
                expression.month.join(','),
                expression.dayOfTheWeek.join(','),
            ].join(' ');
        };
        /**
         * adds a value to what exists currently (builds)
         * @param {!String} measureOfTime
         * @param {!Number} value
         * @throws {Error} if measureOfTime or value fail validation
         */
        this.addValue = function (measureOfTime, value) {
            CronValidator.validateValue(measureOfTime, value);
            if (expression[measureOfTime].length === 1 && expression[measureOfTime][0] === '*') {
                expression[measureOfTime] = [value];
            } else {
                if (expression[measureOfTime].indexOf(value) < 0) {
                    expression[measureOfTime].push(value);
                }
            }
        };
        /**
         * removes a single explicit value (subtracts)
         * @param {!String} measureOfTime - as you might guess
         * @param {!String} value - the offensive value
         * @throws {Error} if measureOfTime is bogus.
         */
        this.removeValue = function (measureOfTime, value) {
            if (!expression[measureOfTime]) {
                throw new Error('Invalid measureOfTime: Valid options are: ' + CronValidator.measureOfTimeValues.join(', '));
            }
            if (expression[measureOfTime].length === 1 && expression[measureOfTime][0] === '*') {
                return 'The value for "' + measureOfTime + '" is already at the default value of "*" - this is a no-op.';
            }
            expression[measureOfTime] = expression[measureOfTime].filter(function (timeValue) {
               return value !== timeValue;
            });
            if (!expression[measureOfTime].length) {
                expression[measureOfTime] = DEFAULT_INTERVAL;
            }
        };
        /**
         * returns the current state of a given measureOfTime
         * @param {!String} measureOfTime one of "minute", "hour", etc
         * @returns {!String} comma separated blah blah
         * @throws {Error} if the measureOfTime is not one of the permitted values.
         */
        this.get = function (measureOfTime) {
            if (!expression[measureOfTime]) {
                throw new Error('Invalid measureOfTime: Valid options are: ' + CronValidator.measureOfTimeValues.join(', '));
            }
            return expression[measureOfTime].join(',');
        };
        /**
         * sets the state of a given measureOfTime
         * @param {!String} measureOfTime - yup
         * @param {!Array.<String>} value - the 5 tuple array of values to set
         * @returns {!String} the comma separated version of the value that you passed in
         * @throws {Error} if your "value" is not an Array&lt;String&gt;
         * @throws {Error} when any item in your value isn't a legal cron-ish descriptor
         */
        this.set = function (measureOfTime, value) {
            if (!Array.isArray(value)) {
                throw new Error('Invalid value; Value must be in the form of an Array.');
            }
            for(var i = 0; i < value.length; i++) {
                CronValidator.validateValue(measureOfTime, value[i]);
            }
            expression[measureOfTime] = value;
            return expression[measureOfTime].join(',');
        };
        /**
         * Returns a rich object that describes the current state of the cron expression.
         * @returns {!{
            minute: Array.string,
            hour: Array.string,
            dayOfTheMonth: Array.string,
            month: Array.string,
            dayOfTheWeek: Array.string,
         * }}
         */
        this.getAll = function () {
            return expression;
        };
        /**
         * sets the state for the entire cron expression
         * @param {!{
            minute: Array.string,
            hour: Array.string,
            dayOfTheMonth: Array.string,
            month: Array.string,
            dayOfTheWeek: Array.string,
         * }} expToSet - the entirety of the cron expression.
         * @throws {Error} as usual
         */
        this.setAll = function (expToSet) {
            CronValidator.validateExpression(expToSet);
            expression = expToSet;
        };
    }
    return CronBuilder;
}());
module.exports = CronBuilder;

+ 0 - 200
src/doctor/node_modules/cron-builder/test/test.js

@ -1,200 +0,0 @@
var chai = require('chai'),
    expect = chai.expect,
    cb = require('../cron-builder.js');
describe('cron-builder', function () {
    var cron;
    it('defaults to "* * * * *" when initialized without arguments', function () {
        cron = new cb();
        expect(cron.get('minute')).to.equal('*');
        expect(cron.get('hour')).to.equal('*');
        expect(cron.get('dayOfTheMonth')).to.equal('*');
        expect(cron.get('month')).to.equal('*');
        expect(cron.get('dayOfTheWeek')).to.equal('*');
    });
    it('protects against the user accessing the expression directly', function () {
        cron = new cb();
        expect(cron.minute).to.not.eql(['*']);
        expect(cron.hour).to.be.undefined;
    });
    it('protects against the user manipulating the expression directly', function () {
        cron = new cb();
        cron.minute = ['5'];
        expect(cron.get('minute')).to.not.equal('5');
        expect(cron.get('minute')).to.equal('*');
    });
    it('returns a working cron expression when calling .build()', function () {
        expect(cron.build()).to.equal('* * * * *');
    });
    it('sets a single value', function () {
        cron = new cb();
        expect(cron.set('hour', ['5'])).to.equal('5');
        expect(cron.build()).to.equal('* 5 * * *');
    });
    it('sets multiple values at once', function () {
        cron = new cb();
        expect(cron.set('minute', ['0', '10', '20', '30', '40', '50'])).to.equal('0,10,20,30,40,50');
        expect(cron.build()).to.equal('0,10,20,30,40,50 * * * *');
    });
    it('sets a range', function () {
        cron = new cb();
        expect(cron.set('dayOfTheWeek', ['5-7'])).to.equal('5-7');
        expect(cron.build()).to.equal('* * * * 5-7');
    });
    it('multiple sets build the cron string accurately', function () {
        cron = new cb();
        cron.set('minute', ['10', '30', '50']);
        cron.set('hour', ['6', '18']);
        cron.set('dayOfTheMonth', ['1', '15']);
        cron.set('dayOfTheWeek', ['1-5']);
        expect(cron.build()).to.equal('10,30,50 6,18 1,15 * 1-5');
    });
    it('validates against setting an incorrect measureOfTime', function () {
        cron = new cb();
        expect(function () { cron.set(['5'], 'minutes') }).to.throw(Error);
    });
    it('validates against setting a value that is not an Array', function () {
        cron = new cb();
        expect(function () { cron.set('10', 'hour') }).to.throw(Error);
    });
    it('validates against setting a value that is not a number or range of numbers', function () {
        cron = new cb();
        expect(function () { cron.set(['!'], 'hour') }).to.throw(Error);
    });
    describe('validates against setting values outside the valid range', function () {
        it('validates against values too low', function () {
            cron = new cb();
            expect(function () { cron.set(['0'], 'dayOfTheWeek') }).to.throw(Error);
        });
        it('validates against values too high', function () {
            cron = new cb();
            expect(function () { cron.set(['100'], 'hour') }).to.throw(Error);
        });
        it('validates against setting a range that is out of bounds', function () {
            cron = new cb();
            expect(function () { cron.set(['20-60'], 'minute') }).to.throw(Error);
            expect(function () { cron.set(['12', '22-26', '15'], 'hour') }).to.throw(Error);
        });
    });
    it('gets a single value', function () {
        cron = new cb();
        cron.set('minute', ['30']);
        expect(cron.get('minute')).to.equal('30');
    });
    it('validates against getting with an invalid measureOfTime', function () {
        cron = new cb();
        expect(function () { cron.get('hours'); }).to.throw(Error);
    });
    it('returns the entire expression object when getAll is called', function () {
        cron = new cb();
        var getAllResponse = cron.getAll();
        expect(getAllResponse).to.be.an('object');
        expect(getAllResponse).to.have.property('minute').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('hour').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('dayOfTheMonth').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('month').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('dayOfTheWeek').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
    });
    it('sets the entire object when setAll is called', function () {
        cron = new cb();
        var getAllResponse = cron.getAll();
        getAllResponse.hour = ['13'];
        getAllResponse.month = ['1-6'];
        getAllResponse.dayOfTheWeek = ['1,3,5,7'];
        cron.setAll(getAllResponse);
        expect(cron.build()).to.equal('* 13 * 1-6 1,3,5,7');
    });
    it('validates setting all with too many keys in the expression object', function () {
        cron = new cb();
        var getAllResponse = cron.getAll();
        getAllResponse.tooManyMeasuresOfTime = ['13'];
        expect(function () { cron.setAll(getAllResponse) }).to.throw(Error);
    });
    it('validates setting with an incorrect value with setAll', function () {
        cron = new cb();
        var getAllResponse = cron.getAll();
        getAllResponse.hour = ['28'];
        expect(function () { cron.setAll(getAllResponse) }).to.throw(Error);
    });
    it('adds a value to a measureOfTime that is set to "*"', function () {
        cron = new cb();
        cron.addValue('minute', '5');
        expect(cron.get('minute')).to.equal('5');
        expect(cron.build()).to.equal('5 * * * *');
    });
    it('adds a value to a measure of time that has been set to a number', function () {
        cron = new cb();
        cron.addValue('hour', '5');
        cron.addValue('hour', '10');
        expect(cron.get('hour')).to.equal('5,10');
    });
    it('validates duplicate values', function () {
        cron = new cb();
        cron.addValue('dayOfTheMonth', '5');
        cron.addValue('dayOfTheMonth', '15');
        cron.addValue('dayOfTheMonth', '5');
        expect(cron.get('dayOfTheMonth')).to.equal('5,15');
    });
    it('validates an invalid value when adding', function () {
        cron = new cb();
        expect(function () { cron.addValue('62', 'minute') }).to.throw(Error);
    });
    it('removes a value that exists with other values', function () {
        cron = new cb();
        cron.set('dayOfTheWeek', ['2', '4']);
        cron.removeValue('dayOfTheWeek', '4');
        expect(cron.get('dayOfTheWeek')).to.equal('2');
    });
    it('resets the value to the default "*" when removing the only value', function () {
        cron = new cb();
        cron.set('minute', ['7']);
        expect(cron.get('minute')).to.equal('7');
        cron.removeValue('minute', '7');
        expect(cron.get('minute')).to.equal('*');
    });
    it('validates an invalid measure of time when removing a value', function () {
        cron = new cb();
        expect(function () { cron.removeValue('ninute') }).to.throw(Error);
    });
    it('accepts a cron expression when instantiating', function () {
        cron = new cb('30 0-6 * * 1-5');
        expect(cron.build()).to.equal('30 0-6 * * 1-5');
    });
    it('validates bad values when instantiating with an explicit expression', function () {
        expect(function () { cron = new cb('30 0-6 * * 1-10') }).to.throw(Error);
    });
    it('validates an expression that is too long when instantiating with an explicit expression', function () {
        expect(function () { cron = new cb('30 0-6 * * 1-5 * *') }).to.throw(Error);
    });
});

+ 0 - 16
src/doctor/node_modules/node-schedule/.eslintrc

@ -1,16 +0,0 @@
{
  "env": {
    "node": true
  },
  "rules": {
    "eqeqeq": [2, "smart"],
    "indent": [2, 2],
    "no-constant-condition": false,
    "no-redeclare": 1,
    "no-underscore-dangle": false,
    "no-use-before-define": [true,"nofunc"],
    "quotes": [2, "single"],
    "space-before-blocks": 2,
    "strict": 2
  }
}

+ 0 - 8
src/doctor/node_modules/node-schedule/.travis.yml

@ -1,8 +0,0 @@
language: node_js
node_js:
  - "0.12"
  - "0.10"
  - "4"
  - "5"
before_script: npm run lint
script: ./node_modules/.bin/istanbul cover ./node_modules/.bin/nodeunit test && cat ./coverage/lcov.info | ./node_modules/.bin/coveralls && rm -rf ./coverage

+ 0 - 31
src/doctor/node_modules/node-schedule/CONTRIBUTING.md

@ -1,31 +0,0 @@
## Rules
1. **No `--force` pushes** or modifying the git history in any way
2. Follow existing code style
3. Pull requests with tests are much more likely to be accepted
4. Follow the guidelines below
## Bugfix or Feature?
This project uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). Simply put, you need to decide if your contribution will be a bug fix that could be released as a patch, or a feature that will end up being a minor or major release.
### Found a bug that can be fixed without affecting the API?
1. **Fork** this repo
2. Create a new branch from `master` to work in
3. **Add tests** if needed
4. Make sure your code **lints** by running `npm run lint`
5. Make sure your code **passes tests** by running `npm test`
6. Submit a **pull request** against the `master` branch
### New feature or anything that would result in a change to the API?
1. **Fork** this repo
2. Create a new branch from `develop` to work in
3. **Add tests** to as needed
4. Make sure your code **lints** by running `npm run lint`
5. Make sure your code **passes tests** by running `npm test`
6. Submit a **pull request** against the `develop` branch
## Releases
Declaring formal releases remains the prerogative of the project maintainer.

+ 0 - 19
src/doctor/node_modules/node-schedule/LICENSE

@ -1,19 +0,0 @@
Copyright (C) 2015 Matt Patenaude.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

+ 0 - 221
src/doctor/node_modules/node-schedule/README.md

@ -1,221 +0,0 @@
# Node Schedule
[![NPM version](http://img.shields.io/npm/v/node-schedule.svg)](https://www.npmjs.com/package/node-schedule)
[![Downloads](https://img.shields.io/npm/dm/node-schedule.svg)](https://www.npmjs.com/package/node-schedule)
[![Build Status](https://travis-ci.org/node-schedule/node-schedule.svg?branch=master)](https://travis-ci.org/node-schedule/node-schedule)
[![Join the chat at https://gitter.im/node-schedule/node-schedule](https://img.shields.io/badge/gitter-chat-green.svg)](https://gitter.im/node-schedule/node-schedule?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![NPM](https://nodei.co/npm/node-schedule.png?downloads=true)](https://nodei.co/npm/node-schedule/)
>__Announcement:__ Node Schedule is looking for add additional collaborators
with commit access. If you are actively involved in open source,
ping [Tejas Manohar] via [email](mailto:me@tejas.io) to express interest.
Those who already contribute to the project are preferred.
Node Schedule is a flexible cron-like and not-cron-like job scheduler for Node.js.
It allows you to schedule jobs (arbitrary functions) for execution at
specific dates, with optional recurrence rules. It only uses a single timer
at any given time (rather than reevaluating upcoming jobs every second/minute).
## Usage
### Installation
You can install using [npm](https://www.npmjs.com/package/node-schedule).
```
npm install node-schedule
```
### Overview
Node Schedule is for time-based scheduling, not interval-based scheduling.
While you can easily bend it to your will, if you only want to do something like
"run this function every 5 minutes", you'll find `setInterval` much easier to use,
and far more appropriate. But if you want to, say, "run this function at the :20
and :50 of every hour on the third Tuesday of every month," you'll find that
Node Schedule suits your needs better. Additionally, Node Schedule has Windows
support unlike true cron since the node runtime is now fully supported.
Note that Node Schedule is designed for in-process scheduling, i.e. scheduled jobs
will only fire as long as your script is running, and the schedule will disappear
when execution completes. If you need to schedule jobs that will persist even when
your script *isn't* running, consider using actual [cron].
### Jobs and Scheduling
Every scheduled job in Node Schedule is represented by a `Job` object. You can
create jobs manually, then execute the `schedule()` method to apply a schedule,
or use the convenience function `scheduleJob()` as demonstrated below.
`Job` objects are `EventEmitter`'s, and emit a `run` event after each execution.
They also emit a `scheduled` event each time they're scheduled to run, and a
`canceled` event when an invocation is canceled before it's executed (both events
receive a JavaScript date object as a parameter). Note that jobs are scheduled the
first time immediately, so if you create a job using the `scheduleJob()`
convenience method, you'll miss the first `scheduled` event. Also note that
`canceled` is the single-L American spelling.
### Cron-style Scheduling
The cron format consists of:
```
*    *    *    *    *    *
┬    ┬    ┬    ┬    ┬    ┬
│    │    │    │    │    |
│    │    │    │    │    └ day of week (0 - 7) (0 or 7 is Sun)
│    │    │    │    └───── month (1 - 12)
│    │    │    └────────── day of month (1 - 31)
│    │    └─────────────── hour (0 - 23)
│    └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)
```
Examples with the cron format:
```js
var schedule = require('node-schedule');
var j = schedule.scheduleJob('42 * * * *', function(){
  console.log('The answer to life, the universe, and everything!');
});
```
And:
```js
var j = schedule.scheduleJob('0 17 ? * 0,4-6', function(){
  console.log('Today is recognized by Rebecca Black!');
});
```
Execute a cron job every 5 Minutes = */5 * * * *
#### Unsupported Cron Features
Currently, `W` (nearest weekday), `L` (last day of month/week), and `#` (nth weekday
of the month) are not supported. Most other features supported by popular cron
implementations should work just fine.
[cron-parser] is used to parse crontab instructions.
### Date-based Scheduling
Say you very specifically want a function to execute at 5:30am on December 21, 2012.
Remember - in JavaScript - 0 - January, 11 - December.
```js
var schedule = require('node-schedule');
var date = new Date(2012, 11, 21, 5, 30, 0);
var j = schedule.scheduleJob(date, function(){
  console.log('The world is going to end today.');
});
```
You can invalidate the job with the `cancel()` method:
```js
j.cancel();
```
To use current data in the future you can use binding:
```js
var schedule = require('node-schedule');
var date = new Date(2012, 11, 21, 5, 30, 0);
var x = 'Tada!';
var j = schedule.scheduleJob(date, function(y){
  console.log(y);
}.bind(null,x));
x = 'Changing Data';
```
This will log 'Tada!' when the scheduled Job runs, rather than 'Changing Data',
which x changes to immediately after scheduling.
### Recurrence Rule Scheduling
You can build recurrence rules to specify when a job should recur. For instance,
consider this rule, which executes the function every hour at 42 minutes after the hour:
```js
var schedule = require('node-schedule');
var rule = new schedule.RecurrenceRule();
rule.minute = 42;
var j = schedule.scheduleJob(rule, function(){
  console.log('The answer to life, the universe, and everything!');
});
```
You can also use arrays to specify a list of acceptable values, and the `Range`
object to specify a range of start and end values, with an optional step parameter.
For instance, this will print a message on Thursday, Friday, Saturday, and Sunday at 5pm:
```js
var rule = new schedule.RecurrenceRule();
rule.dayOfWeek = [0, new schedule.Range(4, 6)];
rule.hour = 17;
rule.minute = 0;
var j = schedule.scheduleJob(rule, function(){
  console.log('Today is recognized by Rebecca Black!');
});
```
> **Note**: It's worth noting that the default value of a component of a recurrence rule is
`null` (except for seconds, which is 0 for familiarity with cron). *If we did not
explicitly set `minute` to 0 above, the message would have instead been logged at
5:00pm, 5:01pm, 5:02pm, ..., 5:59pm.* Probably not what you want.
#### Object Literal Syntax
To make things a little easier, an object literal syntax is also supported, like
in this example which will log a message every Sunday at 2:30pm:
```js
var j = schedule.scheduleJob({hour: 14, minute: 30, dayOfWeek: 0}, function(){
  console.log('Time for tea!');
});
```
#### Set StartTime and EndTime
It will run after 5 seconds and stop after 10 seconds in this example.
The ruledat supports the above.
```js
let startTime = new Date(Date.now() + 5000);
let endTime = new Date(now.getTime() + 5000);
var j = schedule.scheduleJob({ start: startTime, end: endTime, rule: '*/1 * * * * *' }, function(){
  console.log('Time for tea!');
});
```
## Contributing
This module was originally developed by [Matt Patenaude], and is now maintained by
[Tejas Manohar] and [other wonderful contributors].
We'd love to get your contributions. Individuals making significant and valuable
contributions are given commit-access to the project to contribute as they see fit.
Before jumping in, check out our [Contributing] page guide!
## Copyright and license
Copyright 2015 Matt Patenaude.
Licensed under the **[MIT License] [license]**.
[cron]: http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5
[Contributing]: https://github.com/node-schedule/node-schedule/blob/master/CONTRIBUTING.md
[Matt Patenaude]: https://github.com/mattpat
[Tejas Manohar]: http://tejas.io
[license]: https://github.com/node-schedule/node-schedule/blob/master/LICENSE
[Tejas Manohar]: https://github.com/tejasmanohar
[other wonderful contributors]: https://github.com/node-schedule/node-schedule/graphs/contributors
[cron-parser]: https://github.com/harrisiirak/cron-parser

+ 0 - 18
src/doctor/node_modules/node-schedule/fff.js

@ -1,18 +0,0 @@
var schedule = require('./');
// Create new cron for each iteration (creating 1-10 mins)
//for (var x = 1; x<10; x++){
//      var rule = new schedule.RecurrenceRule();
//      rule.minute = new schedule.Range(0, 59, x);
//      schedule.scheduleJob(rule, function() {
//     // Can I access the RULE which is being executed NOW somehow?!
//        console.log(this);
//     });
//}
var job = schedule.scheduleJob('* * * * * *', function() {
  console.log(this.spec);
});
job.spec = '* * * * * *';

+ 0 - 586
src/doctor/node_modules/node-schedule/lib/schedule.js

@ -1,586 +0,0 @@
'use strict';
/*
  node-schedule
  A cron-like and not-cron-like job scheduler for Node.
*/
var events = require('events'),
  util = require('util'),
  cronParser = require('cron-parser'),
  CronDate = require('cron-parser/lib/date'),
  lt = require('long-timeout');
/* Job object */
var anonJobCounter = 0;
function isValidDate(date) {
  // Taken from http://stackoverflow.com/a/12372720/1562178
  // If getTime() returns NaN it'll return false anyway
  return date.getTime() === date.getTime();
}
function Job(name, job, callback) {
  // setup a private pendingInvocations variable
  var pendingInvocations = [];
  //setup a private number of invocations variable
  var triggeredJobs = 0;
  // Set scope vars
  var jobName = name && typeof name === 'string' ? name : '<Anonymous Job ' + (++anonJobCounter) + '>';
  this.job = name && typeof name === 'function' ? name : job;
  // Make sure callback is actually a callback
  if (this.job === name) {
    // Name wasn't provided and maybe a callback is there
    this.callback = typeof job === 'function' ? job : false;
  } else {
    // Name was provided, and maybe a callback is there
    this.callback = typeof callback === 'function' ? callback : false;
  }
  // Check for generator
  if (typeof this.job === 'function' &&
      this.job.prototype &&
      this.job.prototype.next) {
    this.job = function() {
      return this.next().value;
    }.bind(this.job.call(this));
  }
  // define properties
  Object.defineProperty(this, 'name', {
    value: jobName,
    writable: false,
    enumerable: true
  });
  // method that require private access
  this.trackInvocation = function(invocation) {
    // add to our invocation list
    pendingInvocations.push(invocation);
    // and sort
    pendingInvocations.sort(sorter);
    return true;
  };
  this.stopTrackingInvocation = function(invocation) {
    var invIdx = pendingInvocations.indexOf(invocation);
    if (invIdx > -1) {
      pendingInvocations.splice(invIdx, 1);
      return true;
    }
    return false;
  };
  this.triggeredJobs = function() {
    return triggeredJobs;
  };
  this.setTriggeredJobs = function(triggeredJob) {
    triggeredJobs = triggeredJob;
  };
  this.cancel = function(reschedule) {
    reschedule = (typeof reschedule == 'boolean') ? reschedule : false;
    var inv, newInv;
    var newInvs = [];
    for (var j = 0; j < pendingInvocations.length; j++) {
      inv = pendingInvocations[j];
      cancelInvocation(inv);
      if (reschedule && inv.recurrenceRule.recurs) {
        newInv = scheduleNextRecurrence(inv.recurrenceRule, this, inv.fireDate, inv.endDate);
        if (newInv !== null) {
          newInvs.push(newInv);
        }
      }
    }
    pendingInvocations = [];
    for (var k = 0; k < newInvs.length; k++) {
      this.trackInvocation(newInvs[k]);
    }
    // remove from scheduledJobs if reschedule === false
    if (!reschedule) {
      if (this.name) {
        delete scheduledJobs[this.name];
      }
    }
    return true;
  };
  this.cancelNext = function(reschedule) {
    reschedule = (typeof reschedule == 'boolean') ? reschedule : true;
    if (!pendingInvocations.length) {
      return false;
    }
    var newInv;
    var nextInv = pendingInvocations.shift();
    cancelInvocation(nextInv);
    if (reschedule && nextInv.recurrenceRule.recurs) {
      newInv = scheduleNextRecurrence(nextInv.recurrenceRule, this, nextInv.fireDate, nextInv.endDate);
      if (newInv !== null) {
        this.trackInvocation(newInv);
      }
    }
    return true;
  };
  this.reschedule = function(spec) {
    var inv;
    var cInvs = pendingInvocations.slice();
    for (var j = 0; j < cInvs.length; j++) {
      inv = cInvs[j];
      cancelInvocation(inv);
    }
    pendingInvocations = [];
    if (this.schedule(spec)) {
      this.setTriggeredJobs(0);
      return true;
    } else {
      pendingInvocations = cInvs;
      return false;
    }
  };
  this.nextInvocation = function() {
    if (!pendingInvocations.length) {
      return null;
    }
    return pendingInvocations[0].fireDate;
  };
  this.pendingInvocations = function() {
    return pendingInvocations;
  };
}
util.inherits(Job, events.EventEmitter);
Job.prototype.invoke = function() {
  if (typeof this.job == 'function') {
    this.setTriggeredJobs(this.triggeredJobs() + 1);
    this.job();
  } else {
    this.job.execute();
  }
};
Job.prototype.runOnDate = function(date) {
  return this.schedule(date);
};
Job.prototype.schedule = function(spec) {
  var self = this;
  var success = false;
  var inv;
  var start;
  var end;
  if (typeof spec === 'object' && spec.rule) {
    start = spec.start || null;
    end = spec.end || null;
    spec = spec.rule;
    if (start != null) {
      if (!(start instanceof Date)) {
        start = new Date(start);
      }
      if (!isValidDate(start) || start.getTime() < Date.now()) {
        start = null;
      }
    }
    if (end != null && !(end instanceof Date) && !isValidDate(end = new Date(end))) {
      end = null;
    }
  }
  try {
    var res = cronParser.parseExpression(spec, { currentDate: start });
    inv = scheduleNextRecurrence(res, self, start, end);
    if (inv !== null) {
      success = self.trackInvocation(inv);
    }
  } catch (err) {
    var type = typeof spec;
    if ((type === 'string') || (type === 'number')) {
      spec = new Date(spec);
    }
    if ((spec instanceof Date) && (isValidDate(spec))) {
      if (spec.getTime() >= Date.now()) {
        inv = new Invocation(self, spec);
        scheduleInvocation(inv);
        success = self.trackInvocation(inv);
      }
    } else if (type === 'object') {
      if (!(spec instanceof RecurrenceRule)) {
        var r = new RecurrenceRule();
        if ('year' in spec) {
          r.year = spec.year;
        }
        if ('month' in spec) {
          r.month = spec.month;
        }
        if ('date' in spec) {
          r.date = spec.date;
        }
        if ('dayOfWeek' in spec) {
          r.dayOfWeek = spec.dayOfWeek;
        }
        if ('hour' in spec) {
          r.hour = spec.hour;
        }
        if ('minute' in spec) {
          r.minute = spec.minute;
        }
        if ('second' in spec) {
          r.second = spec.second;
        }
        spec = r;
      }
      inv = scheduleNextRecurrence(spec, self, start, end);
      if (inv !== null) {
        success = self.trackInvocation(inv);
      }
    }
  }
  scheduledJobs[this.name] = this;
  return success;
};
/* API
  invoke()
  runOnDate(date)
  schedule(date || recurrenceRule || cronstring)
  cancel(reschedule = false)
  cancelNext(reschedule = true)
   Property constraints
  name: readonly
  job: readwrite
*/
/* DoesntRecur rule */
var DoesntRecur = new RecurrenceRule();
DoesntRecur.recurs = false;
/* Invocation object */
function Invocation(job, fireDate, recurrenceRule, endDate) {
  this.job = job;
  this.fireDate = fireDate;
  this.endDate = endDate;
  this.recurrenceRule = recurrenceRule || DoesntRecur;
  this.timerID = null;
}
function sorter(a, b) {
  return (a.fireDate.getTime() - b.fireDate.getTime());
}
/* Range object */
function Range(start, end, step) {
  this.start = start || 0;
  this.end = end || 60;
  this.step = step || 1;
}
Range.prototype.contains = function(val) {
  if (this.step === null || this.step === 1) {
    return (val >= this.start && val <= this.end);
  } else {
    for (var i = this.start; i < this.end; i += this.step) {
      if (i === val) {
        return true;
      }
    }
    return false;
  }
};
/* RecurrenceRule object */
/*
  Interpreting each property:
  null - any value is valid
  number - fixed value
  Range - value must fall in range
  array - value must validate against any item in list
  NOTE: Cron months are 1-based, but RecurrenceRule months are 0-based.
*/
function RecurrenceRule(year, month, date, dayOfWeek, hour, minute, second) {
  this.recurs = true;
  this.year = (year == null) ? null : year;
  this.month = (month == null) ? null : month;
  this.date = (date == null) ? null : date;
  this.dayOfWeek = (dayOfWeek == null) ? null : dayOfWeek;
  this.hour = (hour == null) ? null : hour;
  this.minute = (minute == null) ? null : minute;
  this.second = (second == null) ? 0 : second;
}
RecurrenceRule.prototype.nextInvocationDate = function(base) {
  base = (base instanceof Date) ? base : (new Date());
  if (!this.recurs) {
    return null;
  }
  var now = new Date();
  var fullYear = now.getFullYear();
  if ((this.year !== null) &&
      (typeof this.year == 'number') &&
      (this.year < fullYear)) {
    return null;
  }
  var next = new CronDate(base.getTime());
  next.addSecond();
  while (true) {
    if (this.year !== null) {
      fullYear = next.getFullYear();
      if ((typeof this.year == 'number') && (this.year < fullYear)) {
        next = null;
        break;
      }
      if (!recurMatch(fullYear, this.year)) {
        next.addYear();
        next.setMonth(0);
        next.setDate(1);
        next.setHours(0);
        next.setMinutes(0);
        next.setSeconds(0);
        continue;
      }
    }
    if (this.month != null && !recurMatch(next.getMonth(), this.month)) {
      next.addMonth();
      continue;
    }
    if (this.date != null && !recurMatch(next.getDate(), this.date)) {
      next.addDay();
      continue;
    }
    if (this.dayOfWeek != null && !recurMatch(next.getDay(), this.dayOfWeek)) {
      next.addDay();
      continue;
    }
    if (this.hour != null && !recurMatch(next.getHours(), this.hour)) {
      next.addHour();
      continue;
    }
    if (this.minute != null && !recurMatch(next.getMinutes(), this.minute)) {
      next.addMinute();
      continue;
    }
    if (this.second != null && !recurMatch(next.getSeconds(), this.second)) {
      next.addSecond();
      continue;
    }
    break;
  }
  return next;
};
function recurMatch(val, matcher) {
  if (matcher == null) {
    return true;
  }
  if (typeof matcher === 'number' || typeof matcher === 'string') {
    return (val === matcher);
  } else if (matcher instanceof Range) {
    return matcher.contains(val);
  } else if (Array.isArray(matcher) || (matcher instanceof Array)) {
    for (var i = 0; i < matcher.length; i++) {
      if (recurMatch(val, matcher[i])) {
        return true;
      }
    }
  }
  return false;
}
/* Date-based scheduler */
function runOnDate(date, job) {
  var now = (new Date()).getTime();
  var then = date.getTime();
  if (then < now) {
    setImmediate(job);
    return null;
  }
  return lt.setTimeout(job, (then - now));
}
var invocations = [];
var currentInvocation = null;
function scheduleInvocation(invocation) {
  invocations.push(invocation);
  invocations.sort(sorter);
  prepareNextInvocation();
  invocation.job.emit('scheduled', invocation.fireDate);
}
function prepareNextInvocation() {
  if (invocations.length > 0 && currentInvocation !== invocations[0]) {
    if (currentInvocation !== null) {
      lt.clearTimeout(currentInvocation.timerID);
      currentInvocation.timerID = null;
      currentInvocation = null;
    }
    currentInvocation = invocations[0];
    var job = currentInvocation.job;
    var cinv = currentInvocation;
    currentInvocation.timerID = runOnDate(currentInvocation.fireDate, function() {
      currentInvocationFinished();
      if (job.callback) {
        job.callback();
      }
      if (cinv.recurrenceRule.recurs || cinv.recurrenceRule._endDate === null) {
        var inv = scheduleNextRecurrence(cinv.recurrenceRule, cinv.job, cinv.fireDate, cinv.endDate);
        if (inv !== null) {
          inv.job.trackInvocation(inv);
        }
      }
      job.stopTrackingInvocation(cinv);
      job.invoke();
      job.emit('run');
    });
  }
}
function currentInvocationFinished() {
  invocations.shift();
  currentInvocation = null;
  prepareNextInvocation();
}
function cancelInvocation(invocation) {
  var idx = invocations.indexOf(invocation);
  if (idx > -1) {
    invocations.splice(idx, 1);
    if (invocation.timerID !== null) {
      lt.clearTimeout(invocation.timerID);
    }
    if (currentInvocation === invocation) {
      currentInvocation = null;
    }
    invocation.job.emit('canceled', invocation.fireDate);
    prepareNextInvocation();
  }
}
/* Recurrence scheduler */
function scheduleNextRecurrence(rule, job, prevDate, endDate) {
  prevDate = (prevDate instanceof Date) ? prevDate : (new Date());
  var date = (rule instanceof RecurrenceRule) ? rule.nextInvocationDate(prevDate) : rule.next();
  if (date === null) {
    return null;
  }
  if ((endDate instanceof Date) && date.getTime() > endDate.getTime()) {
    return null;
  }
  var inv = new Invocation(job, date, rule, endDate);
  scheduleInvocation(inv);
  return inv;
}
/* Convenience methods */
var scheduledJobs = {};
function scheduleJob() {
  if (arguments.length < 2) {
    return null;
  }
  var name = (arguments.length >= 3 && typeof arguments[0] === 'string') ? arguments[0] : null;
  var spec = name ? arguments[1] : arguments[0];
  var method = name ? arguments[2] : arguments[1];
  var callback = name ? arguments[3] : arguments[2];
  var job = new Job(name, method, callback);
  if (job.schedule(spec)) {
    return job;
  }
  return null;
}
function rescheduleJob(job, spec) {
  if (job instanceof Job) {
    if (job.reschedule(spec)) {
      return job;
    }
  } else if (typeof job == 'string' || job instanceof String) {
    if (job in scheduledJobs && scheduledJobs.hasOwnProperty(job)) {
      if (scheduledJobs[job].reschedule(spec)) {
        return scheduledJobs[job];
      }
    }
  }
  return null;
}
function cancelJob(job) {
  var success = false;
  if (job instanceof Job) {
    success = job.cancel();
  } else if (typeof job == 'string' || job instanceof String) {
    if (job in scheduledJobs && scheduledJobs.hasOwnProperty(job)) {
      success = scheduledJobs[job].cancel();
    }
  }
  return success;
}
/* Public API */
module.exports.Job = Job;
module.exports.Range = Range;
module.exports.RecurrenceRule = RecurrenceRule;
module.exports.Invocation = Invocation;
module.exports.scheduleJob = scheduleJob;
module.exports.rescheduleJob = rescheduleJob;
module.exports.scheduledJobs = scheduledJobs;
module.exports.cancelJob = cancelJob;

+ 0 - 1
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/.name

@ -1 +0,0 @@
cron-parser

+ 0 - 9
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/cron-parser.iml

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
  <component name="NewModuleRootManager">
    <content url="file://$MODULE_DIR$" />
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="library" name="cron-parser node_modules" level="project" />
  </component>
</module>

+ 0 - 6
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/encodings.xml

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Encoding">
    <file url="PROJECT" charset="UTF-8" />
  </component>
</project>

+ 0 - 6
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/jsLibraryMappings.xml

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="JavaScriptLibraryMappings">
    <file url="file://$PROJECT_DIR$" libraries="{cron-parser node_modules}" />
  </component>
</project>

+ 0 - 14
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/libraries/cron_parser_node_modules.xml

@ -1,14 +0,0 @@
<component name="libraryTable">
  <library name="cron-parser node_modules" type="javaScript">
    <properties>
      <option name="frameworkName" value="node_modules" />
      <sourceFilesUrls>
        <item url="file://$PROJECT_DIR$/node_modules" />
      </sourceFilesUrls>
    </properties>
    <CLASSES>
      <root url="file://$PROJECT_DIR$/node_modules" />
    </CLASSES>
    <SOURCES />
  </library>
</component>

+ 0 - 8
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/modules.xml

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/.idea/cron-parser.iml" filepath="$PROJECT_DIR$/.idea/cron-parser.iml" />
    </modules>
  </component>
</project>

+ 0 - 449
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.idea/workspace.xml

@ -1,449 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ChangeListManager">
    <list default="true" id="3b49e1a9-cdb2-4d4f-9d28-ba3b9a2392c0" name="Default" comment="">
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/component.json" afterPath="$PROJECT_DIR$/component.json" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/lib/expression.js" afterPath="$PROJECT_DIR$/lib/expression.js" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/package.json" afterPath="$PROJECT_DIR$/package.json" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/expression.js" afterPath="$PROJECT_DIR$/test/expression.js" />
    </list>
    <ignored path="cron-parser.iws" />
    <ignored path=".idea/workspace.xml" />
    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
    <option name="TRACKING_ENABLED" value="true" />
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    <option name="LAST_RESOLUTION" value="IGNORE" />
  </component>
  <component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
  <component name="CreatePatchCommitExecutor">
    <option name="PATCH_PATH" value="" />
  </component>
  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
  <component name="FavoritesManager">
    <favorites_list name="cron-parser" />
  </component>
  <component name="FileEditorManager">
    <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
      <file leaf-file-name="expression.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/lib/expression.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-25.555555">
              <caret line="393" column="30" selection-start-line="393" selection-start-column="30" selection-end-line="393" selection-end-column="30" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="package.json" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/package.json">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-0.625">
              <caret line="1" column="24" selection-start-line="1" selection-start-column="24" selection-end-line="1" selection-end-column="24" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="component.json" pinned="false" current-in-tab="true">
        <entry file="file://$PROJECT_DIR$/component.json">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.059840426">
              <caret line="3" column="68" selection-start-line="3" selection-start-column="68" selection-end-line="3" selection-end-column="68" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="expression.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/expression.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-9.444445">
              <caret line="470" column="40" selection-start-line="470" selection-start-column="40" selection-end-line="470" selection-end-column="40" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="test.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-14.444445">
              <caret line="26" column="1" selection-start-line="26" selection-start-column="1" selection-end-line="26" selection-end-column="1" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
    </leaf>
  </component>
  <component name="Git.Settings">
    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
  </component>
  <component name="IdeDocumentHistory">
    <option name="CHANGED_PATHS">
      <list>
        <option value="$PROJECT_DIR$/lib/date.js" />
        <option value="$PROJECT_DIR$/README.md" />
        <option value="$PROJECT_DIR$/test.js" />
        <option value="$PROJECT_DIR$/test/expression.js" />
        <option value="$PROJECT_DIR$/lib/expression.js" />
        <option value="$PROJECT_DIR$/package.json" />
        <option value="$PROJECT_DIR$/component.json" />
      </list>
    </option>
  </component>
  <component name="JsBuildToolGruntFileManager" detection-done="true" />
  <component name="JsBuildToolPackageJson" detection-done="true">
    <package-json value="$PROJECT_DIR$/package.json" />
  </component>
  <component name="JsGulpfileManager">
    <detection-done>true</detection-done>
  </component>
  <component name="ProjectFrameBounds">
    <option name="y" value="23" />
    <option name="width" value="1440" />
    <option name="height" value="873" />
  </component>
  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="0" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
  <component name="ProjectView">
    <navigator currentView="ProjectPane" proportions="" version="1">
      <flattenPackages />
      <showMembers />
      <showModules />
      <showLibraryContents />
      <hideEmptyPackages />
      <abbreviatePackageNames />
      <autoscrollToSource />
      <autoscrollFromSource />
      <sortByType />
      <manualOrder />
      <foldersAlwaysOnTop value="true" />
    </navigator>
    <panes>
      <pane id="Scratches" />
      <pane id="Scope" />
      <pane id="ProjectPane">
        <subPane>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="cron-parser" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="cron-parser" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="cron-parser" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="cron-parser" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="cron-parser" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="test" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="cron-parser" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="cron-parser" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="lib" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
        </subPane>
      </pane>
    </panes>
  </component>
  <component name="PropertiesComponent">
    <property name="WebServerToolWindowFactoryState" value="false" />
    <property name="HbShouldOpenHtmlAsHb" value="" />
    <property name="javascript.nodejs.core.library.configured.version" value="4.2.1" />
    <property name="last_opened_file_path" value="$PROJECT_DIR$" />
  </component>
  <component name="RunManager">
    <configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" working-dir="">
      <method />
    </configuration>
  </component>
  <component name="ShelveChangesManager" show_recycled="false" />
  <component name="SvnConfiguration">
    <configuration />
  </component>
  <component name="TaskManager">
    <task active="true" id="Default" summary="Default task">
      <changelist id="3b49e1a9-cdb2-4d4f-9d28-ba3b9a2392c0" name="Default" comment="" />
      <created>1442076131230</created>
      <option name="number" value="Default" />
      <updated>1442076131230</updated>
    </task>
    <servers />
  </component>
  <component name="ToolWindowManager">
    <frame x="0" y="23" width="1440" height="873" extended-state="0" />
    <editor active="true" />
    <layout>
      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
      <window_info id="npm" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    </layout>
  </component>
  <component name="Vcs.Log.UiProperties">
    <option name="RECENTLY_FILTERED_USER_GROUPS">
      <collection />
    </option>
    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
      <collection />
    </option>
  </component>
  <component name="VcsContentAnnotationSettings">
    <option name="myLimit" value="2678400000" />
  </component>
  <component name="XDebuggerManager">
    <breakpoint-manager />
    <watches-manager />
  </component>
  <component name="editorHistoryManager">
    <entry file="file://$PROJECT_DIR$/lib/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="375" column="25" selection-start-line="375" selection-start-column="25" selection-end-line="375" selection-end-column="25" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/date.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/README.md">
      <provider editor-type-id="MarkdownPreviewEditor">
        <state />
      </provider>
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="92" column="20" selection-start-line="92" selection-start-column="20" selection-end-line="92" selection-end-column="20" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="375" column="25" selection-start-line="375" selection-start-column="25" selection-end-line="375" selection-end-column="25" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="375" column="25" selection-start-line="375" selection-start-column="25" selection-end-line="375" selection-end-column="25" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/date.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/README.md">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="92" column="20" selection-start-line="92" selection-start-column="20" selection-end-line="92" selection-end-column="20" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="375" column="25" selection-start-line="375" selection-start-column="25" selection-end-line="375" selection-end-column="25" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/date.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="78" column="26" selection-start-line="78" selection-start-column="26" selection-end-line="78" selection-end-column="26" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/README.md">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="92" column="20" selection-start-line="92" selection-start-column="20" selection-end-line="92" selection-end-column="20" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="375" column="25" selection-start-line="375" selection-start-column="25" selection-end-line="375" selection-end-column="25" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/date.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="78" column="26" selection-start-line="78" selection-start-column="26" selection-end-line="78" selection-end-column="26" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/README.md">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="92" column="20" selection-start-line="92" selection-start-column="20" selection-end-line="92" selection-end-column="20" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="375" column="25" selection-start-line="375" selection-start-column="25" selection-end-line="375" selection-end-column="25" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/date.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="78" column="26" selection-start-line="78" selection-start-column="26" selection-end-line="78" selection-end-column="26" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/README.md">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/README.md">
      <provider editor-type-id="MarkdownPreviewEditor">
        <state />
      </provider>
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="92" column="20" selection-start-line="92" selection-start-column="20" selection-end-line="92" selection-end-column="20" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/date.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.8840206">
          <caret line="78" column="26" selection-start-line="78" selection-start-column="26" selection-end-line="78" selection-end-column="26" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/parser.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-1.1069587">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-14.444445">
          <caret line="26" column="1" selection-start-line="26" selection-start-column="1" selection-end-line="26" selection-end-column="1" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-9.444445">
          <caret line="470" column="40" selection-start-line="470" selection-start-column="40" selection-end-line="470" selection-end-column="40" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/lib/expression.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-25.555555">
          <caret line="393" column="30" selection-start-line="393" selection-start-column="30" selection-end-line="393" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-0.625">
          <caret line="1" column="24" selection-start-line="1" selection-start-column="24" selection-end-line="1" selection-end-column="24" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/component.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.059840426">
          <caret line="3" column="68" selection-start-line="3" selection-start-column="68" selection-end-line="3" selection-end-column="68" />
          <folding />
        </state>
      </provider>
    </entry>
  </component>
</project>

+ 0 - 15
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.npmignore

@ -1,15 +0,0 @@
node_modules/
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
npm-debug.log

+ 0 - 6
src/doctor/node_modules/node-schedule/node_modules/cron-parser/.travis.yml

@ -1,6 +0,0 @@
language: node_js
node_js: 
  - "0.12"
  - "0.11"
  - "0.10"
  - "iojs"

+ 0 - 93
src/doctor/node_modules/node-schedule/node_modules/cron-parser/README.md

@ -1,93 +0,0 @@
cron-parser
================
[![Build Status](https://travis-ci.org/harrisiirak/cron-parser.png?branch=master)](https://travis-ci.org/harrisiirak/cron-parser)
[![NPM version](https://badge.fury.io/js/cron-parser.png)](http://badge.fury.io/js/cron-parser)
Node.js library for parsing crontab instructions
Setup
========
```bash
npm install cron-parser
```
Supported format
========
```
*    *    *    *    *    *
┬    ┬    ┬    ┬    ┬    ┬
│    │    │    │    │    |
│    │    │    │    │    └ day of week (0 - 7) (0 or 7 is Sun)
│    │    │    │    └───── month (1 - 12)
│    │    │    └────────── day of month (1 - 31)
│    │    └─────────────── hour (0 - 23)
│    └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, optional)
```
Supports mixed use of ranges and range increments (L, W and # characters are not supported currently). See tests for examples.
Usage
========
Simple expression.
```javascript
var parser = require('cron-parser');
try {
  var interval = parser.parseExpression('*/2 * * * *');
  console.log('Date: ', interval.next().toString()); // Sat Dec 29 2012 00:42:00 GMT+0200 (EET)
  console.log('Date: ', interval.next().toString()); // Sat Dec 29 2012 00:44:00 GMT+0200 (EET)
  console.log('Date: ', interval.next().toUTC().toString()); // Sat Dec 28 2012 22:46:00 GMT+0200 (EET)
} catch (err) {
  console.log('Error: ' + err.message);
}
```
Iteration with limited timespan. Also returns ES6 compatible iterator (when iterator flag is set to true).
```javascript
var parser = require('cron-parser');
var options = {
  currentDate: new Date('Wed, 26 Dec 2012 12:38:53 UTC'),
  endDate: new Date('Wed, 26 Dec 2012 14:40:00 UTC'),
  iterator: true
};
try {
  var interval = parser.parseExpression('*/22 * * * *', options);
  while (true) {
    try {
      var obj = interval.next();
      console.log('value:', obj.value.toString(), 'done:', obj.done);
    } catch (e) {
      break;
    }
  }
  // value: Wed Dec 26 2012 14:44:00 GMT+0200 (EET) done: false
  // value: Wed Dec 26 2012 15:00:00 GMT+0200 (EET) done: false
  // value: Wed Dec 26 2012 15:22:00 GMT+0200 (EET) done: false
  // value: Wed Dec 26 2012 15:44:00 GMT+0200 (EET) done: false
  // value: Wed Dec 26 2012 16:00:00 GMT+0200 (EET) done: false
  // value: Wed Dec 26 2012 16:22:00 GMT+0200 (EET) done: true
} catch (err) {
  console.log('Error: ' + err.message);
}
```
Options
========
* *currentDate* - Start date of the iteration
* *endDate* - End date of the iteration
* *iterator* - Return ES6 compatible iterator object 
* *utc* - Enable UTC

+ 0 - 11
src/doctor/node_modules/node-schedule/node_modules/cron-parser/component.json

@ -1,11 +0,0 @@
{
  "name": "cron-parser",
  "repo": "harrisiirak/cron-parser",
  "description": "Node.js library for parsing crontab instructions",
  "version": "1.1.0",
  "keywords": ["cron", "crontab", "parser"],
  "dependencies": {},
  "development": {},
  "main": "lib/parser.js",
  "scripts": [ "lib/parser.js", "lib/expression.js", "lib/date.js" ]
}

+ 0 - 79
src/doctor/node_modules/node-schedule/node_modules/cron-parser/lib/date.js

@ -1,79 +0,0 @@
'use strict';
/**
 * Date class extension methods
 */
var extensions = {
  addYear: function addYear() {
    this.setFullYear(this.getFullYear() + 1);
  },
  addMonth: function addMonth() {
    this.setDate(1);
    this.setHours(0);
    this.setMinutes(0);
    this.setSeconds(0);
    this.setMonth(this.getMonth() + 1);
  },
  addDay: function addDay() {
    var day = this.getDate();
    this.setDate(day + 1);
    this.setHours(0);
    this.setMinutes(0);
    this.setSeconds(0);
    if (this.getDate() === day) {
      this.setDate(day + 2);
    }
  },
  addHour: function addHour() {
    var hours = this.getHours();
    this.setHours(hours + 1);
    if (this.getHours() === hours) {
      this.setHours(hours + 2);
    }
    this.setMinutes(0);
    this.setSeconds(0);
  },
  addMinute: function addMinute() {
    this.setMinutes(this.getMinutes() + 1);
    this.setSeconds(0);
  },
  addSecond: function addSecond() {
    this.setSeconds(this.getSeconds() + 1);
  },
  toUTC: function toUTC() {
    var to = new CronDate(this);
    var ms = to.getTime() + (to.getTimezoneOffset() * 60000);
    to.setTime(ms);
    return to;
  }
};
/**
 * Extends Javascript Date class by adding
 * utility methods for basic date incrementation
 */
function CronDate (timestamp) {
  var date = timestamp ? new Date(timestamp) : new Date();
  // Attach extensions
  var methods = Object.keys(extensions);
  for (var i = 0, c = methods.length; i < c; i++) {
    var method = methods[i];
    date[method] = extensions[method].bind(date);
  }
  return date;
}
module.exports = CronDate;

+ 0 - 611
src/doctor/node_modules/node-schedule/node_modules/cron-parser/lib/expression.js

@ -1,611 +0,0 @@
'use strict';
// Load Date class extensions
var CronDate = require('./date');
/**
 * Construct a new expression parser
 *
 * Options:
 *   currentDate: iterator start date
 *   endDate: iterator end date
 *
 * @constructor
 * @private
 * @param {Object} fields  Expression fields parsed values
 * @param {Object} options Parser options
 */
function CronExpression (fields, options) {
  this._options = options;
  this._currentDate = new CronDate(options.currentDate);
  this._endDate = options.endDate ? new CronDate(options.endDate) : null;
  this._fields = {};
  this._isIterator = options.iterator || false;
  this._hasIterated = false;
  this._utc = options.utc || false;
  // Map fields
  for (var i = 0, c = CronExpression.map.length; i < c; i++) {
    var key = CronExpression.map[i];
    this._fields[key] = fields[i];
  }
}
/**
 * Field mappings
 * @type {Array}
 */
CronExpression.map = [ 'second', 'minute', 'hour', 'dayOfMonth', 'month', 'dayOfWeek' ];
/**
 * Prefined intervals
 * @type {Object}
 */
CronExpression.predefined = {
  '@yearly': '0 0 1 1 *',
  '@monthly': '0 0 1 * *',
  '@weekly': '0 0 * * 0',
  '@daily': '0 0 * * *',
  '@hourly': '0 * * * *'
};
/**
 * Fields constraints
 * @type {Array}
 */
CronExpression.constraints = [
  [ 0, 59 ], // Second
  [ 0, 59 ], // Minute
  [ 0, 23 ], // Hour
  [ 1, 31 ], // Day of month
  [ 1, 12 ], // Month
  [ 0, 7 ] // Day of week
];
/**
 * Days in month
 * @type {number[]}
 */
CronExpression.daysInMonth = [
  31,
  28,
  31,
  30,
  31,
  30,
  31,
  31,
  30,
  31,
  30,
  31
];
/**
 * Field aliases
 * @type {Object}
 */
CronExpression.aliases = {
  month: {
    jan: 1,
    feb: 2,
    mar: 3,
    apr: 4,
    may: 5,
    jun: 6,
    jul: 7,
    aug: 8,
    sep: 9,
    oct: 10,
    nov: 11,
    dec: 12
  },
  dayOfWeek: {
    sun: 0,
    mon: 1,
    tue: 2,
    wed: 3,
    thu: 4,
    fri: 5,
    sat: 6
  }
};
/**
 * Field defaults
 * @type {Array}
 */
CronExpression.parseDefaults = [ '0', '*', '*', '*', '*', '*' ];
/**
 * Parse input interval
 *
 * @param {String} field Field symbolic name
 * @param {String} value Field value
 * @param {Array} constraints Range upper and lower constraints
 * @return {Array} Sequence of sorted values
 * @private
 */
CronExpression._parseField = function _parseField (field, value, constraints) {
  // Replace aliases
  switch (field) {
    case 'month':
    case 'dayOfWeek':
      var aliases = CronExpression.aliases[field];
      value = value.replace(/[a-z]{1,3}/gi, function(match) {
        match = match.toLowerCase();
        if (typeof aliases[match] !== undefined) {
          return aliases[match];
        } else {
          throw new Error('Cannot resolve alias "' + match + '"')
        }
      });
      break;
  }
  // Check for valid characters.
  if (!(/^[\d|/|*|\-|,]+$/.test(value))) {
    throw new Error('Invalid characters, got value: ' + value)
  }
  // Replace '*'
  if (value.indexOf('*') !== -1) {
    value = value.replace(/\*/g, constraints.join('-'));
  }
  //
  // Inline parsing functions
  //
  // Parser path:
  //  - parseSequence
  //    - parseRepeat
  //      - parseRange
  /**
   * Parse sequence
   *
   * @param {String} val
   * @return {Array}
   * @private
   */
  function parseSequence (val) {
    var stack = [];
    function handleResult (result) {
      var max = stack.length > 0 ? Math.max.apply(Math, stack) : -1;
      if (result instanceof Array) { // Make sequence linear
        for (var i = 0, c = result.length; i < c; i++) {
          var value = result[i];
          // Check constraints
          if (value < constraints[0] || value > constraints[1]) {
            throw new Error(
                'Constraint error, got value ' + value + ' expected range ' +
                constraints[0] + '-' + constraints[1]
            );
          }
          if (value > max) {
            stack.push(value);
          }
          max = Math.max.apply(Math, stack);
        }
      } else { // Scalar value
        result = +result;
        // Check constraints
        if (result < constraints[0] || result > constraints[1]) {
          throw new Error(
            'Constraint error, got value ' + result + ' expected range ' +
            constraints[0] + '-' + constraints[1]
          );
        }
        if (field == 'dayOfWeek') {
          result = result % 7;
        }
        if (result > max) {
          stack.push(result);
        }
      }
    }
    var atoms = val.split(',');
    if (atoms.length > 1) {
      for (var i = 0, c = atoms.length; i < c; i++) {
        handleResult(parseRepeat(atoms[i]));
      }
    } else {
      handleResult(parseRepeat(val));
    }
    return stack;
  }
  /**
   * Parse repetition interval
   *
   * @param {String} val
   * @return {Array}
   */
  function parseRepeat (val) {
    var repeatInterval = 1;
    var atoms = val.split('/');
    if (atoms.length > 1) {
      return parseRange(atoms[0], atoms[atoms.length - 1]);
    }
    return parseRange(val, repeatInterval);
  }
  /**
   * Parse range
   *
   * @param {String} val
   * @param {Number} repeatInterval Repetition interval
   * @return {Array}
   * @private
   */
  function parseRange (val, repeatInterval) {
    var stack = [];
    var atoms = val.split('-');
    if (atoms.length > 1 ) {
      // Invalid range, return value
      if (atoms.length < 2 || !atoms[0].length) {
        return +val;
      }
      // Validate range
      var min = +atoms[0];
      var max = +atoms[1];
      if (Number.isNaN(min) || Number.isNaN(max) ||
          min < constraints[0] || max > constraints[1]) {
        throw new Error(
          'Constraint error, got range ' +
          min + '-' + max +
          ' expected range ' +
          constraints[0] + '-' + constraints[1]
        );
      } else if (min >= max) {
        throw new Error('Invalid range: ' + val);
      }
      // Create range
      var repeatIndex = +repeatInterval;
      if (Number.isNaN(repeatIndex) || repeatIndex <= 0) {
        throw new Error('Constraint error, cannot repeat at every ' + repeatIndex + ' time.');
      }
      for (var index = min, count = max; index <= count; index++) {
        if (repeatIndex > 0 && (repeatIndex % repeatInterval) === 0) {
          repeatIndex = 1;
          stack.push(index);
        } else {
          repeatIndex++;
        }
      }
      return stack;
    }
    return +val;
  }
  return parseSequence(value);
};
/**
 * Find next matching schedule date
 *
 * @return {CronDate}
 * @private
 */
CronExpression.prototype._findSchedule = function _findSchedule () {
  /**
   * Match field value
   *
   * @param {String} value
   * @param {Array} sequence
   * @return {Boolean}
   * @private
   */
  function matchSchedule (value, sequence) {
    for (var i = 0, c = sequence.length; i < c; i++) {
      if (sequence[i] >= value) {
        return sequence[i] === value;
      }
    }
    return sequence[0] === value;
  }
  /**
   * Detect if input range fully matches constraint bounds
   * @param {Array} range Input range
   * @param {Array} constraints Input constraints
   * @returns {Boolean}
   * @private
   */
  function isWildcardRange (range, constraints) {
    if (range instanceof Array && !range.length) {
      return false;
    }
    if (constraints.length !== 2) {
      return false;
    }
    return range.length === (constraints[1] - (constraints[0] < 1 ? - 1 : 0));
  }
  
  var method = function(name) {
    return !this._utc ? name : ('getUTC' + name.slice(3));
  }.bind(this);
  var currentDate = new CronDate(this._currentDate);
  var endDate = this._endDate;
  // TODO: Improve this part
  // Always increment second value when second part is present
  if (this._fields.second.length > 1 && !this._hasIterated) {
    currentDate.addSecond();
  }
  // Find matching schedule
  while (true) {
    // Validate timespan
    if (endDate && (endDate.getTime() - currentDate.getTime()) < 0) {
      throw new Error('Out of the timespan range');
    }
    // Day of month and week matching:
    //
    // "The day of a command's execution can be specified by two fields --
    // day of month, and day of week.  If  both	 fields	 are  restricted  (ie,
    // aren't  *),  the command will be run when either field matches the cur-
    // rent time.  For example, "30 4 1,15 * 5" would cause a command to be
    // run at 4:30 am on the  1st and 15th of each month, plus every Friday."
    //
    // http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5
    //
    var dayOfMonthMatch = matchSchedule(currentDate[method('getDate')](), this._fields.dayOfMonth);
    var dayOfWeekMatch = matchSchedule(currentDate[method('getDay')](), this._fields.dayOfWeek);
    var isDayOfMonthWildcardMatch = isWildcardRange(this._fields.dayOfMonth, CronExpression.constraints[3]);
    var isMonthWildcardMatch = isWildcardRange(this._fields.month, CronExpression.constraints[4]);
    var isDayOfWeekWildcardMatch = isWildcardRange(this._fields.dayOfWeek, CronExpression.constraints[5]);
    // Validate days in month if explicit value is given
    if (!isMonthWildcardMatch) {
      var currentYear = currentDate[method('getFullYear')]();
      var currentMonth = currentDate[method('getMonth')]() + 1;
      var previousMonth = currentMonth === 1 ? 11 : currentMonth - 1;
      var daysInPreviousMonth = CronExpression.daysInMonth[previousMonth - 1];
      var daysOfMontRangeMax = this._fields.dayOfMonth[this._fields.dayOfMonth.length - 1];
      var _daysInPreviousMonth = daysInPreviousMonth;
      var _daysOfMontRangeMax = daysOfMontRangeMax;
      // Handle leap year
      var isLeap = !((currentYear % 4) || (!(currentYear % 100) && (currentYear % 400)));
      if (isLeap) {
        _daysInPreviousMonth = 29;
        _daysOfMontRangeMax = 29;
      }
      if (this._fields.month[0] === previousMonth && _daysInPreviousMonth < _daysOfMontRangeMax) {
        throw new Error('Invalid explicit day of month definition');
      }
    }
    // Add day if select day not match with month (according to calendar)
    if (!dayOfMonthMatch || !dayOfWeekMatch) {
      currentDate.addDay();
      continue;
    }
    // Add day if not day of month is set (and no match) and day of week is wildcard
    if (!isDayOfMonthWildcardMatch && isDayOfWeekWildcardMatch && !dayOfMonthMatch) {
      currentDate.addDay();
      continue;
    }
    // Add day if not day of week is set (and no match) and day of month is wildcard
    if (isDayOfMonthWildcardMatch && !isDayOfWeekWildcardMatch && !dayOfWeekMatch) {
      currentDate.addDay();
      continue;
    }
    // Add day if day of mont and week are non-wildcard values and both doesn't match
    if (!(isDayOfMonthWildcardMatch && isDayOfWeekWildcardMatch) &&
        !dayOfMonthMatch && !dayOfWeekMatch) {
      currentDate.addDay();
      continue;
    }
    // Match month
    if (!matchSchedule(currentDate[method('getMonth')]() + 1, this._fields.month)) {
      currentDate.addMonth();
      continue;
    }
    // Match hour
    if (!matchSchedule(currentDate[method('getHours')](), this._fields.hour)) {
      currentDate.addHour();
      continue;
    }
    // Match minute
    if (!matchSchedule(currentDate[method('getMinutes')](), this._fields.minute)) {
      currentDate.addMinute();
      continue;
    }
    // Match second
    if (!matchSchedule(currentDate[method('getSeconds')](), this._fields.second)) {
      currentDate.addSecond();
      continue;
    }
    break;
  }
  // When internal date is not mutated, append one second as a padding
  var nextDate = new CronDate(currentDate);
  if (this._currentDate !== currentDate) {
    nextDate.addSecond();
  }
  this._currentDate = nextDate;
  this._hasIterated = true;
  return currentDate;
};
/**
 * Find next suitable date
 *
 * @public
 * @return {CronDate|Object}
 */
CronExpression.prototype.next = function next () {
  var schedule = this._findSchedule();
  // Try to return ES6 compatible iterator
  if (this._isIterator) {
    return {
      value: schedule,
      done: !this.hasNext()
    };
  }
  return schedule;
};
/**
 * Check if next suitable date exists
 *
 * @public
 * @return {Boolean}
 */
CronExpression.prototype.hasNext = function() {
  var current = this._currentDate;
  try {
    this.next();
    return true;
  } catch (err) {
    return false;
  } finally {
    this._currentDate = current;
  }
};
/**
 * Iterate over expression iterator
 *
 * @public
 * @param {Number} steps Numbers of steps to iterate
 * @param {Function} callback Optional callback
 * @return {Array} Array of the iterated results
 */
CronExpression.prototype.iterate = function iterate (steps, callback) {
  var dates = [];
  for (var i = 0, c = steps; i < c; i++) {
    try {
      var item = this.next();
      dates.push(item);
      // Fire the callback
      if (callback) {
        callback(item, i);
      }
    } catch (err) {
      break;
    }
  }
  return dates;
};
/**
 * Reset expression iterator state
 *
 * @public
 */
CronExpression.prototype.reset = function reset () {
  this._currentDate = new CronDate(this._options.currentDate);
};
/**
 * Parse input expression (async)
 *
 * @public
 * @param {String} expression Input expression
 * @param {Object} [options] Parsing options
 * @param {Function} [callback]
 */
CronExpression.parse = function parse (expression, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }
  function parse (expression, options) {
    if (!options) {
      options = {};
    }
    if (!options.currentDate) {
      options.currentDate = new CronDate();
    }
    // Is input expression predefined?
    if (CronExpression.predefined[expression]) {
      expression = CronExpression.predefined[expression];
    }
    // Split fields
    var fields = [];
    var atoms = expression.split(' ');
    // Resolve fields
    var start = (CronExpression.map.length - atoms.length);
    for (var i = 0, c = CronExpression.map.length; i < c; ++i) {
      var field = CronExpression.map[i]; // Field name
      var value = atoms[atoms.length > c ? i : i - start]; // Field value
      if (i < start || !value) {
        fields.push(CronExpression._parseField(
          field,
          CronExpression.parseDefaults[i],
          CronExpression.constraints[i])
        );
      } else { // Use default value
        fields.push(CronExpression._parseField(
          field,
          value,
          CronExpression.constraints[i])
        );
      }
    }
    return new CronExpression(fields, options);
  }
  return parse(expression, options);
};
module.exports = CronExpression;

+ 0 - 103
src/doctor/node_modules/node-schedule/node_modules/cron-parser/lib/parser.js

@ -1,103 +0,0 @@
'use strict';
var CronExpression = require('./expression');
function CronParser() {}
/**
 * Parse crontab entry
 *
 * @private
 * @param {String} entry Crontab file entry/line
 */
CronParser._parseEntry = function _parseEntry (entry) {
  var atoms = entry.split(' ');
  if (atoms.length === 6) {
    return {
      interval: CronExpression.parse(entry)
    };
  } else if (atoms.length > 6) {
    return {
      interval: CronExpression.parse(entry),
      command: atoms.slice(6, atoms.length)
    };
  } else {
    throw new Error('Invalid entry: ' + entry);
  }
};
/**
 * Wrapper for CronExpression.parser method
 *
 * @public
 * @param {String} expression Input expression
 * @param {Object} [options] Parsing options
 * @return {Object}
 */
CronParser.parseExpression = function parseExpression (expression, options, callback) {
  return CronExpression.parse(expression, options, callback);
};
/**
 * Parse content string
 *
 * @public
 * @param {String} data Crontab content
 * @return {Object}
 */
CronParser.parseString = function parseString (data) {
  var self = this;
  var blocks = data.split('\n');
  var response = {
    variables: {},
    expressions: [],
    errors: {}
  };
  for (var i = 0, c = blocks.length; i < c; i++) {
    var block = blocks[i];
    var matches = null;
    var entry = block.replace(/^\s+|\s+$/g, ''); // Remove surrounding spaces
    if (entry.length > 0) {
      if (entry.match(/^#/)) { // Comment
        continue;
      } else if ((matches = entry.match(/^(.*)=(.*)$/))) { // Variable
        response.variables[matches[1]] = matches[2];
      } else { // Expression?
        var result = null;
        try {
          result = self._parseEntry('0 ' + entry);
          response.expressions.push(result.interval);
        } catch (err) {
          response.errors[entry] = err;
        }
      }
    }
  }
  return response;
};
/**
 * Parse crontab file
 *
 * @public
 * @param {String} filePath Path to file
 * @param {Function} callback
 */
CronParser.parseFile = function parseFile (filePath, callback) {
  require('fs').readFile(filePath, function(err, data) {
    if (err) {
      callback(err);
      return;
    }
    return callback(null, CronParser.parseString(data.toString()));
  });
};
module.exports = CronParser;

+ 0 - 16
src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/31_of_month.js

@ -1,16 +0,0 @@
var util = require('util');
var test = require('tap').test;
var expression = require('../lib/expression');
test('expression 31 of month', function(t) {
  try {
    var interval = expression.parse('0 0 31 * *');
    var i;
    for (i = 0; i < 100; ++i) {
      interval.next();
    }
    t.end();
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
});

+ 0 - 7
src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/crontab.example

@ -1,7 +0,0 @@
# Comment line (ignore)
ENV1="test1"
ENV2="test2"
*/10 * * * * /path/to/exe
*/10 * * * * /path/to/exe
0 09-18 * * 1-5 /path/to/exe

+ 0 - 787
src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/expression.js

@ -1,787 +0,0 @@
var util = require('util');
var test = require('tap').test;
var CronExpression = require('../lib/expression');
var CronDate = require('../lib/date');
test('empty expression test', function(t) {
  try {
    var interval = CronExpression.parse('');
    t.ok(interval, 'Interval parsed');
    var date = new CronDate();
    date.addMinute();
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getMinutes(), date.getMinutes(), 'Schedule matches');
    t.end();
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
});
test('default expression test', function(t) {
  try {
    var interval = CronExpression.parse('* * * * *');
    t.ok(interval, 'Interval parsed');
    var date = new CronDate();
    date.addMinute();
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getMinutes(), date.getMinutes(), 'Schedule matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('second value out of the range', function(t) {
  try {
    CronExpression.parse('61 * * * * *');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, got value 61 expected range 0-59');
  }
  t.end();
});
test('second value out of the range', function(t) {
  try {
    CronExpression.parse('-1 * * * * *');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, got value -1 expected range 0-59');
  }
  t.end();
});
test('minute value out of the range', function(t) {
  try {
    CronExpression.parse('* 32,72 * * * *');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, got value 72 expected range 0-59');
  }
  t.end();
});
test('hour value out of the range', function(t) {
  try {
    CronExpression.parse('* * 12-36 * * *');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, got range 12-36 expected range 0-23');
  }
  t.end();
});
test('day of the month value out of the range', function(t) {
  try {
    CronExpression.parse('* * * 10-15,40 * *');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, got value 40 expected range 1-31');
  }
  t.end();
});
test('month value out of the range', function(t) {
  try {
    CronExpression.parse('* * * * */10,12-13 *');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, got range 12-13 expected range 1-12');
  }
  t.end();
});
test('day of the week value out of the range', function(t) {
  try {
    CronExpression.parse('* * * * * 9');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, got value 9 expected range 0-7');
  }
  t.end();
});
test('incremental minutes expression test', function(t) {
  try {
    var interval = CronExpression.parse('*/3 * * * *');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getMinutes() % 3, 0, 'Schedule matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('fixed expression test', function(t) {
  try {
    var interval = CronExpression.parse('10 2 12 8 0');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    t.equal(next.getHours(), 2, 'Hour matches');
    t.equal(next.getMinutes(), 10, 'Minute matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('invalid characters test - symbol', function(t) {
  try {
    CronExpression.parse('10 ! 12 8 0');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Invalid characters, got value: !');
  }
  t.end();
});
test('invalid characters test - letter', function(t) {
  try {
    CronExpression.parse('10 x 12 8 0');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Invalid characters, got value: x');
  }
  t.end();
});
test('invalid characters test - parentheses', function(t) {
  try {
    CronExpression.parse('10 ) 12 8 0');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Invalid characters, got value: )');
  }
  t.end();
});
test('interval with invalid characters test', function(t) {
  try {
    CronExpression.parse('10 */A 12 8 0');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Invalid characters, got value: */A');
  }
  t.end();
});
test('range with invalid characters test', function(t) {
  try {
    CronExpression.parse('10 0-z 12 8 0');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Invalid characters, got value: 0-z');
  }
  t.end();
});
test('group with invalid characters test', function(t) {
  try {
    CronExpression.parse('10 0,1,z 12 8 0');
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Invalid characters, got value: 0,1,z');
  }
  t.end();
});
test('range test with iterator', function(t) {
  try {
    var interval = CronExpression.parse('10-30 2 12 8 0');
    t.ok(interval, 'Interval parsed');
    var intervals = interval.iterate(20);
    t.ok(intervals, 'Found intervals');
    for (var i = 0, c = intervals.length; i < c; i++) {
      var next = intervals[i];
      t.ok(next, 'Found next scheduled interval');
      t.equal(next.getDay(), 0, 'Day matches');
      t.equal(next.getMonth(), 7, 'Month matches');
      t.equal(next.getDate(), 12, 'Day of month matches');
      t.equal(next.getHours(), 2, 'Hour matches');
      t.equal(next.getMinutes(), 10 + i, 'Minute matches');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('incremental range test with iterator', function(t) {
  try {
    var interval = CronExpression.parse('10-30/2 2 12 8 0');
    t.ok(interval, 'Interval parsed');
    var intervals = interval.iterate(10);
    t.ok(intervals, 'Found intervals');
    for (var i = 0, c = intervals.length; i < c; i++) {
      var next = intervals[i];
      t.ok(next, 'Found next scheduled interval');
      t.equal(next.getDay(), 0, 'Day matches');
      t.equal(next.getMonth(), 7, 'Month matches');
      t.equal(next.getDate(), 12, 'Day of month matches');
      t.equal(next.getHours(), 2, 'Hour matches');
      t.equal(next.getMinutes(), 10 + (i * 2), 'Minute matches');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('predefined expression', function(t) {
  try {
    var interval = CronExpression.parse('@yearly');
    t.ok(interval, 'Interval parsed');
    var date = new CronDate();
    date.addYear();
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getFullYear(), date.getFullYear(), 'Year matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('expression limited with start and end date', function(t) {
  try {
    var options = {
      currentDate: new CronDate('Wed, 26 Dec 2012 14:38:53'),
      endDate: new CronDate('Wed, 26 Dec 2012 16:40:00')
    };
    var interval = CronExpression.parse('*/20 * * * *', options);
    t.ok(interval, 'Interval parsed');
    var dates = interval.iterate(10);
    t.equal(dates.length, 7, 'Dates count matches');
    interval.reset(); // Reset
    var next = interval.next();
    t.equal(next.getHours(), 14, 'Hour matches');
    t.equal(next.getMinutes(), 40, 'Minute matches');
    next = interval.next();
    t.equal(next.getHours(), 15, 'Hour matches');
    t.equal(next.getMinutes(), 0, 'Minute matches');
    next = interval.next();
    t.equal(next.getHours(), 15, 'Hour matches');
    t.equal(next.getMinutes(), 20, 'Minute matches');
    next = interval.next();
    t.equal(next.getHours(), 15, 'Hour matches');
    t.equal(next.getMinutes(), 40, 'Minute matches');
    next = interval.next();
    t.equal(next.getHours(), 16, 'Hour matches');
    t.equal(next.getMinutes(), 0, 'Minute matches');
    next = interval.next();
    t.equal(next.getHours(), 16, 'Hour matches');
    t.equal(next.getMinutes(), 20, 'Minute matches');
    next = interval.next();
    t.equal(next.getHours(), 16, 'Hour matches');
    t.equal(next.getMinutes(), 40, 'Minute matches');
    try {
      interval.next();
      t.ok(false, 'Should fail');
    } catch (e) {
      t.ok(true, 'Failed as expected');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('parse expression as UTC', function(t) {
  try {
    var options = {
      utc: true
    };
    var interval = CronExpression.parse('0 0 10 * * *', options);
    var date = interval.next();
    t.equal(date.getUTCHours(), 10, 'Correct UTC hour value');
    interval = CronExpression.parse('0 */5 * * * *', options);
    var date = interval.next(), now = new Date();
    now.setMinutes(now.getMinutes() + 5 - (now.getMinutes() % 5));
    t.equal(date.getHours(), now.getHours(), 'Correct local time for 5 minute interval');
  } catch (err) {
    t.ifError(err, 'UTC parse error');
  }
  t.end();
});
test('expression using days of week strings', function(t) {
  try {
    var interval = CronExpression.parse('15 10 * * MON-TUE');
    t.ok(interval, 'Interval parsed');
    var intervals = interval.iterate(8);
    t.ok(intervals, 'Found intervals');
    for (var i = 0, c = intervals.length; i < c; i++) {
      var next = intervals[i];
      var day = next.getDay();
      t.ok(next, 'Found next scheduled interval');
      t.ok(day == 1 || day == 2, 'Day matches')
      t.equal(next.getHours(), 10, 'Hour matches');
      t.equal(next.getMinutes(), 15, 'Minute matches');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('expression using mixed days of week strings', function(t) {
  try {
    var options = {
      currentDate: new CronDate('Wed, 26 Dec 2012 14:38:53')
    };
    var interval = CronExpression.parse('15 10 * jAn-FeB mOn-tUE', options);
    t.ok(interval, 'Interval parsed');
    var intervals = interval.iterate(8);
    t.ok(intervals, 'Found intervals');
    for (var i = 0, c = intervals.length; i < c; i++) {
      var next = intervals[i];
      var day = next.getDay();
      var month = next.getMonth();
      t.ok(next, 'Found next scheduled interval');
      t.ok(month == 0 || month == 2, 'Month Matches');
      t.ok(day == 1 || day == 2, 'Day matches');
      t.equal(next.getHours(), 10, 'Hour matches');
      t.equal(next.getMinutes(), 15, 'Minute matches');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('expression using non-standard second field (wildcard)', function(t) {
  try {
    var options = {
      currentDate: new CronDate('Wed, 26 Dec 2012 14:38:00'),
      endDate: new CronDate('Wed, 26 Dec 2012 15:40:00')
    };
    var interval = CronExpression.parse('* * * * * *', options);
    t.ok(interval, 'Interval parsed');
    var intervals = interval.iterate(10);
    t.ok(intervals, 'Found intervals');
    for (var i = 0, c = intervals.length; i < c; i++) {
      var next = intervals[i];
      t.ok(next, 'Found next scheduled interval');
      t.equal(next.getSeconds(), i + 1, 'Second matches');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('expression using non-standard second field (step)', function(t) {
  try {
    var options = {
      currentDate: new CronDate('Wed, 26 Dec 2012 14:38:00'),
      endDate: new CronDate('Wed, 26 Dec 2012 15:40:00')
    };
    var interval = CronExpression.parse('*/20 * * * * *', options);
    t.ok(interval, 'Interval parsed');
    var intervals = interval.iterate(3);
    t.ok(intervals, 'Found intervals');
    t.equal(intervals[0].getSeconds(), 20, 'Second matches');
    t.equal(intervals[1].getSeconds(), 40, 'Second matches');
    t.equal(intervals[2].getSeconds(), 0, 'Second matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('expression using non-standard second field (range)', function(t) {
  try {
    var options = {
      currentDate: new CronDate('Wed, 26 Dec 2012 14:38:00'),
      endDate: new CronDate('Wed, 26 Dec 2012 15:40:00')
    };
    var interval = CronExpression.parse('20-40/10 * * * * *', options);
    t.ok(interval, 'Interval parsed');
    var intervals = interval.iterate(3);
    t.ok(intervals, 'Found intervals');
    for (var i = 0, c = intervals.length; i < c; i++) {
      var next = intervals[i];
      t.ok(next, 'Found next scheduled interval');
      t.equal(next.getSeconds(), 20 + (i * 10), 'Second matches');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('day of month and week are both set', function(t) {
  try {
    var interval = CronExpression.parse('10 2 12 8 0');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('Summertime bug test', function(t) {
  try {
    var month = new CronDate().getMonth() + 1;
    var interval = CronExpression.parse('0 0 0 1 '+month+' *');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    // Before fix the bug it was getting a timeout error if you are
    // in a timezone that changes the DST to ST in the hour 00:00h.
    t.ok(next, 'Found next scheduled interval');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('day of month and week are both set and dow is 7', function(t) {
  try {
    var interval = CronExpression.parse('10 2 12 8 7');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 0, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('day of month and week are both set and dow is 6,0', function(t) {
  try {
    var interval = CronExpression.parse('10 2 12 8 6,0');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    // next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('day of month and week are both set and dow is 6-7', function(t) {
  try {
    var interval = CronExpression.parse('10 2 12 8 6-7');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
    // next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getDay(), 6, 'Day matches');
    t.equal(next.getMonth(), 7, 'Month matches');
    t.equal(next.getDate(), 12, 'Day of month matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('day and date in week should matches', function(t){
  try {
    var interval = CronExpression.parse('0 1 1 1 * 1');
    t.ok(interval, 'Interval parsed');
    var next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getHours(), 1, 'Hours matches');
    t.equal(next.getDay(), 1, 'Day matches');
    t.equal(next.getDate(), 1, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getHours(), 1, 'Hours matches');
    t.equal(next.getDay(), 1, 'Day matches');
    t.equal(next.getDate(), 1, 'Day of month matches');
    next = interval.next();
    t.ok(next, 'Found next scheduled interval');
    t.equal(next.getHours(), 1, 'Hours matches');
    t.equal(next.getDay(), 1, 'Day matches');
    t.equal(next.getDate(), 1, 'Day of month matches');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('day of month value can\'t be larger than days in month maximum value if it\'s defined explicitly', function(t) {
  try {
    var interval = CronExpression.parse('0 4 30 2 *');
    t.ok(interval, 'Interval parsed');
    try {
      interval.next();
      t.ok(false, 'Should fail');
    } catch (e) {
      t.ok(true, 'Failed as expected');
    }
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('valid ES6 iterator should be returned if iterator options is set to true', function(t) {
  try {
    var options = {
      currentDate: new CronDate('Wed, 26 Dec 2012 14:38:53'),
      endDate: new CronDate('Wed, 26 Dec 2012 15:40:00'),
      iterator: true
    };
    var val = null;
    var interval = CronExpression.parse('*/25 * * * *', options);
    t.ok(interval, 'Interval parsed');
    val = interval.next();
    t.ok(val, 'Next iteration resolved');
    t.ok(val.value, 'Iterator value is set');
    t.notOk(val.done, 'Iterator is not finished');
    val = interval.next();
    t.ok(val, 'Next iteration resolved');
    t.ok(val.value, 'Iterator value is set');
    t.notOk(val.done, 'Iterator is not finished');
    val = interval.next();
    t.ok(val, 'Next iteration resolved');
    t.ok(val.value, 'Iterator value is set');
    t.ok(val.done, 'Iterator is finished');
  } catch (err) {
    t.ifError(err, 'Interval parse error');
  }
  t.end();
});
test('Must not parse an expression which has repeat 0 times', function(t) {
  try {
    var expression = CronExpression.parse('0 */0 * * *');
    var val = expression.next();
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, cannot repeat at every 0 time.');
  }
  t.end();
});
test('Must not parse an expression which has repeat negative number times', function(t) {
  try {
    var expression = CronExpression.parse('0 */-5 * * *');
    var val = expression.next();
  } catch (err) {
    t.ok(err, 'Error expected');
    t.equal(err.message, 'Constraint error, cannot repeat at every -5 time.');
  }
  t.end();
});

+ 0 - 47
src/doctor/node_modules/node-schedule/node_modules/cron-parser/test/parser.js

@ -1,47 +0,0 @@
var util = require('util');
var test = require('tap').test;
var CronParser = require('../lib/parser');
// Globals
test('load crontab file', function(t) {
  CronParser.parseFile('./crontab.example', function(err, result) {
    t.ifError(err, 'File read error');
    t.ok(result, 'Crontab parsed parsed');
    t.equal(Object.keys(result.variables).length, 2, 'variables length matches');
    t.equal(Object.keys(result.errors).length, 0, 'errors length matches');
    t.equal(result.expressions.length, 3, 'expressions length matches');
    // Parse expressions
    var next = null;
    t.equal(result.expressions[0].hasNext(), true);
    next = result.expressions[0].next();
    t.ok(next, 'first date');
    next = result.expressions[1].next();
    t.ok(next, 'second date');
    next = result.expressions[2].next();
    t.ok(next, 'third date');
    t.end();
  });
});
test('no next date', function(t) {
  var options = {
    currentDate: new Date(2014, 0, 1),
    endDate: new Date(2014, 0, 1)
  };
  try {
    var interval = CronParser.parseExpression('* * 2 * *', options);
    t.equal(interval.hasNext(), false);
  } catch (err) {
    t.ifError(err, 'Parse read error');
  }
  t.end();
});

+ 0 - 28
src/doctor/node_modules/node-schedule/node_modules/long-timeout/README.md

@ -1,28 +0,0 @@
# Long timeouts
Long timeout makes it possible to have a timeout that is longer than 24.8 days (2^31-1 milliseconds).
## Usage
```js
var lt = require('long-timeout')
var timeout = lt.setTimeout(function() {
  console.log('in 30 days')
}, 1000 * 60 * 60 * 24 * 30)
// Clear it
lt.clearTimeout(timeout)
```
## Install
    npm install long-timeout
## Licence
MIT

+ 0 - 10
src/doctor/node_modules/node-schedule/node_modules/long-timeout/example.js

@ -1,10 +0,0 @@
var lt = require('./')
lt.setTimeout(function() {
  console.log('in a long time')
}, Number.MAX_VALUE)
lt.setTimeout(function() {
  console.log('2 seconds')
}, 2000)

+ 0 - 33
src/doctor/node_modules/node-schedule/node_modules/long-timeout/index.js

@ -1,33 +0,0 @@
var TIMEOUT_MAX = 2147483647; // 2^31-1
exports.setTimeout = function(listener, after) {
  return new Timeout(listener, after)
}
exports.clearTimeout = function(timer) {
  if (timer) timer.close()
}
exports.Timeout = Timeout
function Timeout(listener, after) {
  this.listener = listener
  this.after = after
  this.start()
}
Timeout.prototype.start = function() {
  if (this.after <= TIMEOUT_MAX) {
    this.timeout = setTimeout(this.listener, this.after)
  } else {
    var self = this
    this.timeout = setTimeout(function() {
      self.after -= TIMEOUT_MAX
      self.start()
    }, TIMEOUT_MAX)
  }
}
Timeout.prototype.close = function() {
  clearTimeout(this.timeout)
}

+ 0 - 713
src/doctor/node_modules/node-schedule/test/convenience-method-test.js

@ -1,713 +0,0 @@
'use strict';
var sinon = require('sinon');
var main = require('../package.json').main;
var schedule = require('../' + main);
var clock;
module.exports = {
  setUp: function(cb) {
    clock = sinon.useFakeTimers();
    cb();
  },
  ".scheduleJob": {
    "Returns Job instance": function(test) {
      var job = schedule.scheduleJob(new Date(Date.now() + 1000), function() {});
      test.ok(job instanceof schedule.Job);
      job.cancel();
      test.done();
    }
  },
  ".scheduleJob(Date, fn)": {
    "Runs job once at some date": function(test) {
      test.expect(1);
      schedule.scheduleJob(new Date(Date.now() + 3000), function() {
        test.ok(true);
      });
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job doesn't emit initial 'scheduled' event": function(test) {
        var job = schedule.scheduleJob(new Date(Date.now() + 1000), function() {});
        job.on('scheduled', function() {
          test.ok(false);
        });
        setTimeout(function() {
          test.done();
        }, 1250);
        clock.tick(1250);
      },
      "Won't run job if scheduled in the past": function(test) {
        test.expect(1);
        var job = schedule.scheduleJob(new Date(Date.now() - 3000), function() {
          test.ok(false);
        });
        test.equal(job, null);
        setTimeout(function() {
          test.done();
        }, 1000);
        clock.tick(1000);
      }
  },
  ".scheduleJob(RecurrenceRule, fn)": {
    "Runs job at interval based on recur rule, repeating indefinitely": function(test) {
      test.expect(3);
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job doesn't emit initial 'scheduled' event": function(test) {
        /*
         * If this was Job#schedule it'd fire 4 times.
         */
        test.expect(3);
        var rule = new schedule.RecurrenceRule();
        rule.second = null; // fire every second
        var job = new schedule.scheduleJob(rule, function() {});
        job.on('scheduled', function(runOnDate) {
          test.ok(true);
        });
        setTimeout(function() {
          job.cancel();
          test.done();
        }, 3250);
        clock.tick(3250);
      },
      "Doesn't invoke job if recur rule schedules it in the past": function(test) {
        test.expect(1);
        var rule = new schedule.RecurrenceRule();
        rule.year = 1960;
        var job = schedule.scheduleJob(rule, function() {
          test.ok(false);
        });
        
        test.equal(job, null);
        setTimeout(function() {
          test.done();
        }, 1000);
        clock.tick(1000);
      }
  },
  ".scheduleJob({...}, fn)": {
    "Runs job at interval based on object, repeating indefinitely": function(test) {
      test.expect(3);
      var job = new schedule.scheduleJob({
        second: null // Fire every second
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job doesn't emit initial 'scheduled' event": function(test) {
        /*
         * With Job#schedule this would be 3:
         *  scheduled at time 0
         *  scheduled at time 1000
         *  scheduled at time 2000
         */
        test.expect(2);
        var job = schedule.scheduleJob({
          second: null // fire every second
        }, function() {});
        job.on('scheduled', function() {
          test.ok(true);
        });
        setTimeout(function() {
          job.cancel();
          test.done();
        }, 2250);
        clock.tick(2250);
      },
      "Doesn't invoke job if object schedules it in the past": function(test) {
        test.expect(1);
      
        var job = schedule.scheduleJob({
          year: 1960
        }, function() {
          test.ok(false);
        });
        
        test.equal(job, null);
        setTimeout(function() {
          test.done();
        }, 1000);
        clock.tick(1000);
      }
  },
  ".scheduleJob({...}, {...}, fn)": {
    "Callback called for each job if callback is provided": function(test) {
      test.expect(3);
      var job = new schedule.scheduleJob({
        second: null // Fire every second
      }, function() {}, function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  ".rescheduleJob(job, {...})": {
    "Reschedule jobs from object based to object based": function(test) {
      test.expect(3);
      var job = new schedule.scheduleJob({
        second: null
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job, {
          minute: null
        });
      }, 3250);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 5000);
      clock.tick(5000);
    },
    "Reschedule jobs from every minutes to every second": function(test) {
      test.expect(3);
      var timeout = 60 * 1000;
      var job = new schedule.scheduleJob({
        minute: null
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job, {
          second: null
        });
      }, timeout);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout + 2250);
      clock.tick(timeout + 2250);
    }
  },
  ".rescheduleJob(job, Date)": {
    "Reschedule jobs from Date to Date": function(test) {
      test.expect(1);
      var job = new schedule.scheduleJob(new Date(Date.now() + 3000), function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job, new Date(Date.now() + 5000));
      }, 1000);
      setTimeout(function() {
        test.done();
      }, 6150);
      clock.tick(6150);
    },
    "Reschedule jobs that has been executed": function(test) {
      test.expect(2);
      var job = new schedule.scheduleJob(new Date(Date.now() + 1000), function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job, new Date(Date.now() + 2000));
      }, 2000);
      setTimeout(function() {
        test.done();
      }, 5150);
      clock.tick(5150);
    }
  },
  ".rescheduleJob(job, RecurrenceRule)": {
    "Reschedule jobs from RecurrenceRule to RecurrenceRule": function(test) {
      test.expect(3);
      var timeout = 60 * 1000;
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      var newRule = new schedule.RecurrenceRule();
      newRule.minute = null;
      setTimeout(function() {
        schedule.rescheduleJob(job, newRule);
      }, 2250);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout + 2250);
      clock.tick(timeout + 2250);
    },
    "Reschedule jobs from RecurrenceRule to Date": function(test) {
      test.expect(3);
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job, new Date(Date.now() + 2000));
      }, 2150);
      setTimeout(function() {
        test.done();
      }, 4250);
      clock.tick(4250);
    },
    "Reschedule jobs from RecurrenceRule to {...}": function(test) {
      test.expect(3);
      var timeout = 60 * 1000;
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job, {
          minute: null
        });
      }, 2150);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout + 2150);
      clock.tick(timeout + 2150);
    },
    "Reschedule jobs that is not available": function(test) {
      test.expect(4);
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(null, new Date(Date.now() + 2000));
      }, 2150);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 4250);
      clock.tick(4250);
    }
  },
  '.rescheduleJob("job name", {...})': {
    "Reschedule jobs from object based to object based": function(test) {
      test.expect(3);
      var job = new schedule.scheduleJob({
        second: null
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job.name, {
          minute: null
        });
      }, 3250);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 5000);
      clock.tick(5000);
    },
    "Reschedule jobs from every minutes to every second": function(test) {
      test.expect(3);
      var timeout = 60 * 1000;
      var job = new schedule.scheduleJob({
        minute: null
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job.name, {
          second: null
        });
      }, timeout);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout + 2250);
      clock.tick(timeout + 2250);
    }
  },
  '.rescheduleJob("job name", Date)': {
    "Reschedule jobs from Date to Date": function(test) {
      test.expect(1);
      var job = new schedule.scheduleJob(new Date(Date.now() + 3000), function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job.name, new Date(Date.now() + 5000));
      }, 1000);
      setTimeout(function() {
        test.done();
      }, 6150);
      clock.tick(6150);
    },
    "Reschedule jobs that has been executed": function(test) {
      test.expect(2);
      var job = new schedule.scheduleJob(new Date(Date.now() + 1000), function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job.name, new Date(Date.now() + 2000));
      }, 2000);
      setTimeout(function() {
        test.done();
      }, 5150);
      clock.tick(5150);
    }
  },
  '.rescheduleJob("job name", RecurrenceRule)': {
    "Reschedule jobs from RecurrenceRule to RecurrenceRule": function(test) {
      test.expect(3);
      var timeout = 60 * 1000;
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      var newRule = new schedule.RecurrenceRule();
      newRule.minute = null;
      setTimeout(function() {
        schedule.rescheduleJob(job.name, newRule);
      }, 2250);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout + 2250);
      clock.tick(timeout + 2250);
    },
    "Reschedule jobs from RecurrenceRule to Date": function(test) {
      test.expect(3);
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job.name, new Date(Date.now() + 2000));
      }, 2150);
      setTimeout(function() {
        test.done();
      }, 4250);
      clock.tick(4250);
    },
    "Reschedule jobs from RecurrenceRule to {...}": function(test) {
      test.expect(3);
      var timeout = 60 * 1000;
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob(job.name, {
          minute: null
        });
      }, 2150);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout + 2150);
      clock.tick(timeout + 2150);
    },
    "Reschedule jobs that is not available": function(test) {
      test.expect(4);
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      var job = schedule.scheduleJob(rule, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.rescheduleJob("Blah", new Date(Date.now() + 2000));
      }, 2150);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 4250);
      clock.tick(4250);
    }
  },
  ".cancelJob(Job)": {
    "Prevents all future invocations of Job passed in": function(test) {
      test.expect(2);
      var job = schedule.scheduleJob({
        second: null
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.cancelJob(job);
      }, 2250);
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Can cancel Jobs scheduled with Job#schedule": function(test) {
      test.expect(2);
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      job.schedule({
        second: null
      });
      setTimeout(function() {
        schedule.cancelJob(job);
      }, 2250);
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job emits 'canceled' event": function(test) {
      test.expect(1);
      var job = schedule.scheduleJob({
        second: null
      }, function() {});
      job.on('canceled', function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.cancelJob(job);
        test.done();
      }, 1250);
      clock.tick(1250);
    }
  },
  '.cancelJob("job name")': {
    "Prevents all future invocations of Job identified by name": function(test) {
      test.expect(2);
      var job = schedule.scheduleJob({
        second: null
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.cancelJob(job.name);
      }, 2250);
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    /*
    "Can cancel Jobs scheduled with Job#schedule": function(test) {
      test.expect(2);
      var job = new schedule.Job(function() {
      test.ok(true);
      });
      job.schedule({
      second: null
      });
      setTimeout(function() {
      schedule.cancelJob(job.name);
      }, 2250);
      setTimeout(function() {
      test.done();
      }, 3250);
    },*/
    "Job emits 'canceled' event": function(test) {
      test.expect(1);
      var job = schedule.scheduleJob({
        second: null
      }, function() {});
      job.on('canceled', function() {
        test.ok(true);
      });
      setTimeout(function() {
        schedule.cancelJob(job.name);
        test.done();
      }, 1250);
      clock.tick(1250);
    },
    "Does nothing if no job found by that name": function(test) {
      test.expect(3);
      var job = schedule.scheduleJob({
        second: null
      }, function() {
        test.ok(true);
      });
      setTimeout(function() {
        // This cancel should not affect anything
        schedule.cancelJob('blah');
      }, 2250);
      setTimeout(function() {
        job.cancel(); // prevent tests from hanging
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  '.pendingInvocations()': {
    "Retrieves pendingInvocations of the job": function(test) {
      var job = schedule.scheduleJob(new Date(Date.now() + 1000), function() {});
      test.ok(job instanceof schedule.Job);
      test.ok(job.pendingInvocations()[0].job);
      job.cancel();
      test.done();
    }
  },
  tearDown: function(cb) {
    clock.restore();
    cb();
  }
};

+ 0 - 59
src/doctor/node_modules/node-schedule/test/date-convenience-methods-test.js

@ -1,59 +0,0 @@
'use strict';
var sinon = require('sinon');
var main = require('../package.json').main;
var schedule = require('../' + main);
var clock;
module.exports = {
  setUp: function(cb) {
    clock = sinon.useFakeTimers();
    cb();
  },
  "Date string": {
    "Should accept a valid date string": function(test) {
      test.expect(1);
      schedule.scheduleJob(new Date(Date.now() + 1000).toString(), function() {
        test.ok(true);
      });
      setTimeout(function() {
        test.done();
      }, 1250);
      clock.tick(1250);
    },
    "Should not accept invalid string as valid date": function(test) {
      test.expect(1);
      var job = schedule.scheduleJob("hello!!", function() {
      });
      test.equal(job, null);
      test.done();
    }
  },
  "UTC": {
     "Should accept a valid UTC date in milliseconds": function(test) {
      test.expect(1);
      schedule.scheduleJob(new Date(Date.now() + 1000).getTime(), function() {
        test.ok(true);
      });
      setTimeout(function() {
        test.done();
      }, 1250);
      clock.tick(1250);
    }
  },
  tearDown: function(cb) {
    clock.restore();
    cb();
  }
};

+ 0 - 33
src/doctor/node_modules/node-schedule/test/es6/job-test.js

@ -1,33 +0,0 @@
'use strict';
module.exports = function(schedule) {
  return {
    jobInGenerator: function(test) {
      test.expect(1);
      var job = new schedule.Job(function*() {
        test.ok(true);
      });
      job.runOnDate(new Date(Date.now() + 3000));
      setTimeout(function() {
        test.done();
      }, 3250);
    },
    jobContextInGenerator: function(test) {
      test.expect(1);
      var job = new schedule.Job('name of job', function*() {
        test.ok(this.name === 'name of job');
      });
      job.runOnDate(new Date(Date.now() + 3000));
      setTimeout(function() {
        test.done();
      }, 3250);
    }
  }
}

+ 0 - 494
src/doctor/node_modules/node-schedule/test/job-test.js

@ -1,494 +0,0 @@
'use strict';
var sinon = require('sinon');
var main = require('../package.json').main;
var schedule = require('../' + main);
var es6;
try {
  eval('(function* () {})()');
  es6 = require('./es6/job-test')(schedule);
} catch (e) {}
var clock;
module.exports = {
  setUp: function(cb) {
    clock = sinon.useFakeTimers();
    cb();
  },
  "Job constructor": {
    "Accepts Job name and function to run": function(test) {
      var job = new schedule.Job('the job', function() {});
      test.equal(job.name, 'the job');
      test.done();
    },
    "Job name is optional and will be auto-generated": function(test) {
      var job = new schedule.Job();
      test.ok(job.name);
      test.done();
    },
    "Uses unique names across auto-generated Job names": function(test) {
      var job1 = new schedule.Job();
      var job2 = new schedule.Job();
      test.notEqual(job1.name, job2.name);
      test.done();
    }
  },
  "#schedule(Date)": {
    "Runs job once at some date": function(test) {
      test.expect(1);
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      job.schedule(new Date(Date.now() + 3000));
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Cancel next job before it runs": function(test) {
      test.expect(1);
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      job.schedule(new Date(Date.now() + 1500));
      job.schedule(new Date(Date.now() + 3000));
      job.cancelNext();
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Run job on specified date": function(test) {
      test.expect(1);
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      job.runOnDate(new Date(Date.now() + 3000));
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Run job in generator": function(test) {
      if (!es6) {
        test.expect(0);
        test.done();
        return;
      }
      es6.jobInGenerator(test);
      clock.tick(3250);
    },
    "Context is passed into generator correctly": function(test) {
      if (!es6) {
        test.expect(0);
        test.done();
        return;
      }
      es6.jobContextInGenerator(test);
      clock.tick(3250);
    },
    "Won't run job if scheduled in the past": function(test) {
      test.expect(0);
      var job = new schedule.Job(function() {
        test.ok(false);
      });
      job.schedule(new Date(Date.now() - 3000));
      setTimeout(function() {
        test.done();
      }, 1000);
      clock.tick(1000);
    },
    "Jobs still run after scheduling a Job in the past": function(test) {
      test.expect(1);
      var pastJob = new schedule.Job(function() {
      // Should not run, blow up if it does
        test.ok(false);
      });
      pastJob.schedule(new Date(Date.now() - 3000));
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      job.schedule(new Date(Date.now() + 3000));
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job emits 'scheduled' event with 'run at' Date": function(test) {
      test.expect(1);
      var date = new Date(Date.now() + 3000);
      var job = new schedule.Job(function() {
        test.done();
      });
      job.on('scheduled', function(runAtDate) {
        test.equal(runAtDate, date);
      });
      job.schedule(date);
      clock.tick(3250);
    }
  },
  "#schedule(Date, fn)": {
    "Runs job once at some date, calls callback when done": function(test) {
      test.expect(1);
      var job = new schedule.Job(function() {}, function() {
        test.ok(true);
      });
      job.schedule(new Date(Date.now() + 3000));
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  "#schedule(RecurrenceRule)": {
    "Runs job at interval based on recur rule, repeating indefinitely": function(test) {
      test.expect(3);
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // fire every second
      job.schedule(rule);
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job emits 'scheduled' event for every next invocation": function(test) {
        // Job will run 3 times but be scheduled 4 times, 4th run never happens
        // due to cancel.
        test.expect(4);
        var job = new schedule.Job(function() {});
        job.on('scheduled', function(runOnDate) {
          test.ok(true);
        });
        var rule = new schedule.RecurrenceRule();
        rule.second = null; // fire every second
        job.schedule(rule);
        setTimeout(function() {
          job.cancel();
          test.done();
        }, 3250);
        clock.tick(3250);
      },
      "Doesn't invoke job if recur rule schedules it in the past": function(test) {
        test.expect(0);
        var job = new schedule.Job(function() {
          test.ok(false);
        });
        var rule = new schedule.RecurrenceRule();
        rule.year = 2000;
        job.schedule(rule);
        setTimeout(function() {
          job.cancel();
          test.done();
        }, 1000);
        clock.tick(1000);
      }
  },
  "#schedule({...})": {
    "Runs job at interval based on object, repeating indefinitely": function(test) {
      test.expect(3);
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      job.schedule({
        second: null // fire every second
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job emits 'scheduled' event for every next invocation": function(test) {
        // Job will run 3 times but be scheduled 4 times, 4th run never happens
        // due to cancel.
        test.expect(4);
        var job = new schedule.Job(function() {});
        job.on('scheduled', function(runOnDate) {
          test.ok(true);
        });
        job.schedule({
          second: null // Fire every second
        });
        setTimeout(function() {
          job.cancel();
          test.done();
        }, 3250);
        clock.tick(3250);
      },
      "Doesn't invoke job if object schedules it in the past": function(test) {
        test.expect(0);
        var job = new schedule.Job(function() {
          test.ok(false);
        });
        job.schedule({
          year: 2000
        });
        setTimeout(function() {
          job.cancel();
          test.done();
        }, 1000);
        clock.tick(1000);
      }
  },
  "#schedule('jobName', {...})": {
    "Runs job with a custom name input": function(test) {
      test.expect(3);
      var job = new schedule.Job('jobName', function() {
        test.equal(job.name, 'jobName');
      });
      job.schedule({
        second: null // fire every second
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  "#schedule({...}, {...})": {
    "Runs job and run callback when job is done if callback is provided": function(test) {
      test.expect(3);
      var job = new schedule.Job(function() {}, function() {
        test.ok(true);
      });
      job.schedule({
        second: null // fire every second
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Runs job with a custom name input and run callback when job is done": function(test) {
      test.expect(3);
      var job = new schedule.Job('MyJob', function() {}, function() {
        test.equal(job.name, 'MyJob');
      });
      job.schedule({
        second: null // fire every second
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  "#cancel": {
    "Prevents all future invocations": function(test) {
      test.expect(1);
      var job = new schedule.Job(function() {
        test.ok(true);
      });
      job.schedule({
        second: null // fire every second
      });
      setTimeout(function() {
        job.cancel();
      }, 1250);
      setTimeout(function() {
        test.done();
      }, 2250);
      clock.tick(2250);
    },
    "Job emits 'canceled' event": function(test) {
      test.expect(1);
      var job = new schedule.Job(function() {});
      job.on('canceled', function() {
        test.ok(true);
      });
      job.schedule({
        second: null // fire every second
      });
      setTimeout(function() {
        job.cancel();
      }, 1250);
      setTimeout(function() {
        test.done();
      }, 2250);
      clock.tick(2250);
    },
    "Job is added to scheduledJobs when created and removed when cancelled": function(test) {
      test.expect(4);
      var job1 = new schedule.Job('cancelJob', function() {});
      job1.schedule({
        second: null // fire every second
      });
      var job2 = schedule.scheduleJob('second',
                                      { second: null },
                                      function() {},
                                      function() {});
      test.strictEqual(schedule.scheduledJobs.cancelJob, job1);
      test.strictEqual(schedule.scheduledJobs.second, job2);
      setTimeout(function() {
        job1.cancel();
        job2.cancel();
        test.strictEqual(schedule.scheduledJobs.cancelJob, undefined);
        test.strictEqual(schedule.scheduledJobs.second, undefined);
        test.done();
      }, 1250);
      clock.tick(1250);
    }
  },
  "#reschedule": {
    "When rescheduled counter will be reset to zero": function(test) {
      var job = new schedule.scheduleJob({
        second: null
      }, function() {});
      setTimeout(function() {
        test.equal(job.triggeredJobs(), 3);
        schedule.rescheduleJob(job, {
          minute: null
        });
      }, 3250);
      setTimeout(function() {
        job.cancel();
        test.equal(job.triggeredJobs(), 0);
        test.done();
      }, 5000);
      clock.tick(5000);
    }
  },
  "When invoked": {
    "Job emits 'run' event": function(test) {
      test.expect(1);
      var job = new schedule.Job(function() {});
      job.on('run', function() {
        test.ok(true);
      });
      job.schedule(new Date(Date.now() + 3000));
      setTimeout(function() {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    "Job counter increase properly": function(test) {
      var job = new schedule.Job(function() {});
      job.schedule({
        second: null // fire every second
      });
      setTimeout(function() {
        job.cancel();
        test.equal(job.triggeredJobs(), 2);
        test.done();
      }, 2250);
      clock.tick(2250);
    }
  },
  tearDown: function(cb) {
    clock.restore();
    cb();
  }
};

+ 0 - 77
src/doctor/node_modules/node-schedule/test/range-test.js

@ -1,77 +0,0 @@
'use strict';
var main = require('../package.json').main;
var schedule = require('../' + main);
module.exports = {
  "step defaults to 1": function(test) {
    var range = new schedule.Range(2, 6);
    test.equals(1, range.step);
    test.done();
  },
  "when step is 1": {
    "setUp": function(done) {
      this.range = new schedule.Range(2, 6, 1);
      done();
    },
    "includes start value": function(test) {
      test.ok(this.range.contains(2));
      test.done();
    },
    "includes end value": function(test) {
      test.ok(this.range.contains(6));
      test.done();
    },
    "includes value between start and end": function(test) {
      test.ok(this.range.contains(3));
      test.done();
    },
    "excludes values outside of start and end": function(test) {
      test.ok(!this.range.contains(1));
      test.ok(!this.range.contains(7));
      test.done();
    }
  },
  "when step > 1": {
    "setUp": function(done) {
      this.range = new schedule.Range(2, 6, 2);
      done();
    },
    "includes start value": function(test) {
      test.ok(this.range.contains(2));
      test.done();
    },
    "excludes end value": function(test) {
      test.ok(!this.range.contains(6));
      test.done();
    },
    "includes value between start and end that is evenly divisible by step": function(test) {
      test.ok(this.range.contains(4));
      test.done();
    },
    "excludes value between start and end that is not evenly divisible by step": function(test) {
      test.ok(!this.range.contains(5));
      test.done();
    },
    "excludes values outside of start and end": function(test) {
      test.ok(!this.range.contains(1));
      test.ok(!this.range.contains(7));
      test.done();
    }
  }
};

+ 0 - 294
src/doctor/node_modules/node-schedule/test/recurrence-rule-test.js

@ -1,294 +0,0 @@
'use strict';
var main = require('../package.json').main;
var schedule = require('../' + main);
var sinon = require('sinon');
var clock;
// 12:30:15 pm Thursday 29 April 2010 in the timezone this code is being run in
var base = new Date(2010, 3, 29, 12, 30, 15, 0);
var baseMs = base.getTime();
module.exports = {
  "setUp": function(cb) {
    clock = sinon.useFakeTimers(baseMs);
    cb();
  },
  "tearDown": function(cb) {
    clock.restore();
    cb();
  },
  "#nextInvocationDate(Date)": {
    "next second": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.second = null;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 12, 30, 16, 0), next);
      test.done();
    },
    "next 25th second": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.second = 25;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 12, 30, 25, 0), next);
      test.done();
    },
    "next 5th second (minutes incremented)": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.second = 5;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 12, 31, 5, 0), next);
      test.done();
    },
    "next 40th minute": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.minute = 40;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 12, 40, 0, 0), next);
      test.done();
    },
    "next 1st minute (hours incremented)": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.minute = 1;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 13, 1, 0, 0), next);
      test.done();
    },
    "next 23rd hour": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.hour = 23;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 23, 0, 0, 0), next);
      test.done();
    },
    "next 3rd hour (days incremented)": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.hour = 3;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 30, 3, 0, 0, 0), next);
      test.done();
    },
    "next Friday": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.dayOfWeek = 5;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 30, 0, 0, 0, 0), next);
      test.done();
    },
    "next Monday (months incremented)": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.dayOfWeek = 1;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 4, 3, 0, 0, 0, 0), next);
      test.done();
    },
    "next 30th date": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.date = 30;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 30, 0, 0, 0, 0), next);
      test.done();
    },
    "next 5th date (months incremented)": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.date = 5;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 4, 5, 0, 0, 0, 0), next);
      test.done();
    },
    "next October": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.month = 9;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 9, 1, 0, 0, 0, 0), next);
      test.done();
    },
    "next February (years incremented)": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.month = 1;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2011, 1, 1, 0, 0, 0, 0), next);
      test.done();
    },
    "in the year 2040": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.year = 2040;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2040, 0, 1, 0, 0, 0, 0), next);
      test.done();
    },
    "using past year": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.year = 2000;
      var next = rule.nextInvocationDate(base);
      test.equal(null, next);
      test.done();
    },
    "using mixed time components": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.second = 50;
      rule.minute = 5;
      rule.hour = 10;
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 30, 10, 5, 50, 0), next);
      test.done();
    },
    /*
    "using date and dayOfWeek together": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.dayOfWeek = 4; // This is Thursday April 1st
      rule.date = 10;   // This is Saturday April 10th
      var next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 1, 0, 0, 0, 0), next);
      test.done();
    }*/
    "returns null when no invocations left": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.year = 2000;
      var next = rule.nextInvocationDate(base);
      test.strictEqual(null, next);
      test.done();
    },
    "specify span of components using Range": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.minute = new schedule.Range(4, 6);
      var next;
      next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 13, 4, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 13, 5, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 13, 6, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 14, 4, 0, 0), next);
      test.done();
    },
    "specify intervals within span of components using Range with step": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.minute = new schedule.Range(4, 8, 2);
      var next;
      next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 13, 4, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 13, 6, 0, 0), next);
      /* Should Range stay inclusive on both ends when step > 1
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 13, 8, 0, 0), next);
      */
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 14, 4, 0, 0), next);
      test.done();
    },
    "specify span and explicit components using Array of Ranges and Numbers": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.minute = [2, new schedule.Range(4, 6)];
      var next;
      next = rule.nextInvocationDate(base);
      test.deepEqual(new Date(2010, 3, 29, 13, 2, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 13, 4, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 13, 5, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 13, 6, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2010, 3, 29, 14, 2, 0, 0), next);
      test.done();
    },
    "From 31th May schedule the 1st of every June": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.second = 0;
      rule.minute = 0;
      rule.hour = 0;
      rule.date = 1;
      rule.month = 5;
      var next;
      var base1 = new Date(2010, 4, 31, 12, 30, 15, 0);
      next = rule.nextInvocationDate(base1);
      test.deepEqual(new Date(2010, 5, 1, 0, 0, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.deepEqual(new Date(2011, 5, 1, 0, 0, 0, 0), next);
      test.done();
    },
    "With the year set should not loop indefinetely": function(test) {
      var rule = new schedule.RecurrenceRule();
      rule.second = 0;
      rule.minute = 0;
      rule.hour = 0;
      rule.date = 1;
      rule.month = 5;
      rule.year = 2010;
      var next;
      var base1 = new Date(2010, 4, 31, 12, 30, 15, 0);
      next = rule.nextInvocationDate(base1);
      test.deepEqual(new Date(2010, 5, 1, 0, 0, 0, 0), next);
      next = rule.nextInvocationDate(next);
      test.equal(next, null);
      test.done();
    }
  }
};

+ 0 - 136
src/doctor/node_modules/node-schedule/test/schedule-cron-jobs.js

@ -1,136 +0,0 @@
'use strict';
var sinon = require('sinon');
var main = require('../package.json').main;
var schedule = require('../' + main);
var clock;
module.exports = {
  ".scheduleJob(cron_expr, fn)": {
    setUp: function(cb) {
      var now = Date.now();
      clock = sinon.useFakeTimers();
      clock.tick(now);
      cb();
    },
    "Runs job every second": function(test) {
      test.expect(3);
      var timeout = 3 * 1000 + 150;
      var job = schedule.scheduleJob('* * * * * *', function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout);
      clock.tick(timeout);
    },
    "Runs job every minute": function(test) {
      test.expect(3);
      var timeout = 3 * 60 * 1000;
      var job = schedule.scheduleJob('0 * * * * *', function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout);
      clock.tick(timeout);
    },
    "Runs job every hour": function(test) {
      test.expect(3);
      var timeout = 3 * 60 * 60 * 1000;
      var job = schedule.scheduleJob('0 0 * * * *', function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout);
      clock.tick(timeout);
    },
    "Runs job every day": function(test) {
      test.expect(3);
      var timeout = 3 * 24 * 60 * 60 * 1000;
      var job = schedule.scheduleJob('0 0 0 * * *', function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout);
      clock.tick(timeout);
    },
    "Runs job every week": function(test) {
      test.expect(3);
      var timeout = 3 * 7 * 24 * 60 * 60 * 1000;
      var job = schedule.scheduleJob('0 0 0 * * 1', function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout);
      clock.tick(timeout);
    },
    "Runs job every month": function(test) {
      test.expect(48);
      var timeout = 4 * 365.25 * 24 * 60 * 60 * 1000;
      var job = schedule.scheduleJob('0 0 0 1 * *', function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout);
      clock.tick(timeout);
    },
    "Runs job every year": function(test) {
      test.expect(4);
      var timeout = 4 * 365.25 * 24 * 60 * 60 * 1000;
      var job = schedule.scheduleJob('0 0 0 1 1 *', function() {
        test.ok(true);
      });
      setTimeout(function() {
        job.cancel();
        test.done();
      }, timeout);
      clock.tick(timeout);
    },
    tearDown: function(cb) {
      clock.restore();
      cb();
    }
  }
};

+ 0 - 312
src/doctor/node_modules/node-schedule/test/start-end-test.js

@ -1,312 +0,0 @@
'use strict';
var sinon = require('sinon');
var main = require('../package.json').main;
var schedule = require('../' + main);
var clock;
module.exports = {
  setUp: function (cb) {
    clock = sinon.useFakeTimers();
    cb();
  },
  'RecurrenceRule': {
    'no endTime , startTime less than now': function (test) {
      test.expect(3);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // every second
      job.schedule({
        start: new Date(Date.now() - 2000),
        rule: rule
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no endTime , startTime greater than now': function (test) {
      test.expect(1);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // every second
      job.schedule({
        start: new Date(Date.now() + 2000),
        rule: rule
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no startTime , endTime less than now': function (test) {
      test.expect(0);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // every second
      job.schedule({
        end: new Date(Date.now() - 2000),
        rule: rule
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no startTime , endTime greater than now': function (test) {
      test.expect(2);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // every second
      job.schedule({
        end: new Date(Date.now() + 2000),
        rule: rule
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'has startTime and endTime': function (test) {
      test.expect(1);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      var rule = new schedule.RecurrenceRule();
      rule.second = null; // every second
      job.schedule({
        start: new Date(Date.now() + 1000),
        end: new Date(Date.now() + 2000),
        rule: rule
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  'Object Literal': {
    'no endTime , startTime less than now': function (test) {
      test.expect(3);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        start: new Date(Date.now() - 2000),
        rule: { second: null }
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no endTime , startTime greater than now': function (test) {
      test.expect(1);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        start: new Date(Date.now() + 2000),
        rule: { second: null }
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no startTime , endTime less than now': function (test) {
      test.expect(0);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        end: new Date(Date.now() - 2000),
        rule: { second: null }
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no startTime , endTime greater than now': function (test) {
      test.expect(2);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        end: new Date(Date.now() + 2000),
        rule: { second: null }
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'has startTime and endTime': function (test) {
      test.expect(1);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        start: new Date(Date.now() + 1000),
        end: new Date(Date.now() + 2000),
        rule: { second: null }
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  'cron-style': {
    'no endTime , startTime less than now': function (test) {
      test.expect(3);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        start: new Date(Date.now() - 2000),
        rule: '*/1 * * * * *'
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no endTime , startTime greater than now': function (test) {
      test.expect(1);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        start: new Date(Date.now() + 2000),
        rule: '*/1 * * * * *'
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no startTime , endTime less than now': function (test) {
      test.expect(0);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        end: new Date(Date.now() - 2000),
        rule: '*/1 * * * * *'
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'no startTime , endTime greater than now': function (test) {
      test.expect(2);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        end: new Date(Date.now() + 2000),
        rule: '*/1 * * * * *'
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    },
    'has startTime and endTime': function (test) {
      test.expect(1);
      var job = new schedule.Job(function () {
        test.ok(true);
      });
      job.schedule({
        start: new Date(Date.now() + 1000),
        end: new Date(Date.now() + 2000),
        rule: '*/1 * * * * *'
      });
      setTimeout(function () {
        test.done();
      }, 3250);
      clock.tick(3250);
    }
  },
  tearDown: function (cb) {
    clock.restore();
    cb();
  }
};

+ 0 - 13
src/doctor/node_modules/solr-client/.idea/misc.xml

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="0" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
</project>

+ 0 - 6
src/doctor/node_modules/solr-client/.idea/vcs.xml

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
  </component>
</project>

src/doctor/app.armour.js → src/server/app.armour.js


src/doctor/app.js → src/server/app.js


src/doctor/controllers/index.js → src/server/controllers/index.js


src/doctor/controllers/socket.js → src/server/controllers/socket.js


src/doctor/endpoints/application.endpoint.js → src/server/endpoints/application.endpoint.js


src/doctor/endpoints/chats.endpoint.js → src/server/endpoints/chats.endpoint.js


src/doctor/endpoints/groups.endpoint.js → src/server/endpoints/groups.endpoint.js


src/doctor/endpoints/management.endpoint.js → src/server/endpoints/management.endpoint.js


src/doctor/endpoints/users.endpoint.js → src/server/endpoints/users.endpoint.js


src/doctor/handlers/socket.handler.js → src/server/handlers/socket.handler.js


src/doctor/include/commons.js → src/server/include/commons.js


src/doctor/include/endpoints.js → src/server/include/endpoints.js


src/doctor/include/transparent.endpoints.js → src/server/include/transparent.endpoints.js


src/doctor/include/wlyy.endpoints.js → src/server/include/wlyy.endpoints.js


src/doctor/models/auth/token.js → src/server/models/auth/token.js


src/doctor/models/base.model.js → src/server/models/base.model.js


src/doctor/models/doctor.js → src/server/models/doctor.js


src/doctor/models/group.js → src/server/models/group.js


src/doctor/models/patient.js → src/server/models/patient.js


src/doctor/models/schedule/push.job.loader.js → src/server/models/schedule/push.job.loader.js


src/doctor/models/schedule/schedule.js → src/server/models/schedule/schedule.js


src/doctor/models/search.js → src/server/models/search.js


src/doctor/models/server/management.js → src/server/models/server/management.js


src/doctor/models/socket.io/client.cache.js → src/server/models/socket.io/client.cache.js


src/doctor/models/socket.io/client.js → src/server/models/socket.io/client.js


src/doctor/models/socket.io/patient.client.js → src/server/models/socket.io/patient.client.js


src/doctor/models/stats.js → src/server/models/stats.js


src/doctor/models/user.status.js → src/server/models/user.status.js


src/doctor/node → src/server/node


src/doctor/node_modules/.bin/_mocha → src/server/node_modules/.bin/_mocha


src/doctor/node_modules/.bin/_mocha.cmd → src/server/node_modules/.bin/_mocha.cmd


src/doctor/node_modules/.bin/jade → src/server/node_modules/.bin/jade


src/doctor/node_modules/.bin/jade.cmd → src/server/node_modules/.bin/jade.cmd


src/doctor/node_modules/.bin/mocha → src/server/node_modules/.bin/mocha


src/doctor/node_modules/.bin/mocha.cmd → src/server/node_modules/.bin/mocha.cmd


src/doctor/node_modules/async/CHANGELOG.md → src/server/node_modules/async/CHANGELOG.md


src/doctor/node_modules/async/LICENSE → src/server/node_modules/async/LICENSE


src/doctor/node_modules/async/README.md → src/server/node_modules/async/README.md


src/doctor/node_modules/async/apply.js → src/server/node_modules/async/apply.js


src/doctor/node_modules/async/applyEach.js → src/server/node_modules/async/applyEach.js


src/doctor/node_modules/async/applyEachSeries.js → src/server/node_modules/async/applyEachSeries.js


src/doctor/node_modules/async/asyncify.js → src/server/node_modules/async/asyncify.js


src/doctor/node_modules/async/auto.js → src/server/node_modules/async/auto.js


src/doctor/node_modules/async/autoInject.js → src/server/node_modules/async/autoInject.js


src/doctor/node_modules/async/bower.json → src/server/node_modules/async/bower.json


src/doctor/node_modules/async/cargo.js → src/server/node_modules/async/cargo.js


src/doctor/node_modules/async/compose.js → src/server/node_modules/async/compose.js


src/doctor/node_modules/async/concat.js → src/server/node_modules/async/concat.js


src/doctor/node_modules/async/concatSeries.js → src/server/node_modules/async/concatSeries.js


src/doctor/node_modules/async/constant.js → src/server/node_modules/async/constant.js


+ 0 - 0
src/doctor/node_modules/async/detect.js


Some files were not shown because too many files changed in this diff