diff --git a/.gitignore b/.gitignore index 20ed58f0e..c81f45425 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,10 @@ docker/**/data docker/**/logs docker/**/.env docker/.gradle +docker/dev_*/** +docker/nginx/test-ehr* +docker/nginx/cert.pem +docker/nginx/key.pem **/node_modules/ **/build/ @@ -11,3 +15,10 @@ docker/.gradle **/resources/credits/dependencies.txt **/.gradle + +**/app.css +**/app.css.map +**/app.js +**/app.js.map + +WNPRC_EHR/resources/web/wnprc_ehr/gen/ \ No newline at end of file diff --git a/AnimalRequests/.babelrc b/AnimalRequests/.babelrc new file mode 100644 index 000000000..14f0dc314 --- /dev/null +++ b/AnimalRequests/.babelrc @@ -0,0 +1,10 @@ +{ + "env": { + "test": { + "presets":["@babel/preset-react","@babel/preset-typescript"], + "plugins": [ + "transform-es2015-modules-commonjs" + ] + } + } +} diff --git a/AnimalRequests/.gitignore b/AnimalRequests/.gitignore new file mode 100644 index 000000000..e272fbfe8 --- /dev/null +++ b/AnimalRequests/.gitignore @@ -0,0 +1,6 @@ +node_modules +app.css +app.css.map +app.js +app.js.map +*.swp diff --git a/AnimalRequests/README.md b/AnimalRequests/README.md new file mode 100644 index 000000000..aad51849b --- /dev/null +++ b/AnimalRequests/README.md @@ -0,0 +1,36 @@ +# Animal Requests + +This is a single page app that uses [React Final Form](https://github.com/final-form/react-final-form) along with [TypeScript](https://github.com/Microsoft/TypeScript) and LabKey's [JavaScript API](https://www.labkey.org/_webdav/Documentation/%40files/reference/javascript-api/index.html). The form allows a user to submit a request for animals. + +Below is an example of one of the dropdown select fields within the form, followed by a brief explanation of each of the [props](https://reactjs.org/docs/components-and-props.html). + +``` + + + + +``` + +`Field` is a component imported from react-final-form. + +The `className` prop in the `Field` component is the class of field element, using bootstrap grid. + +The `name` prop is the name of the column in the insert DB. + +The `component` prop describes to react-final-form what type of `Field` it is. + +The `validate` prop takes a function that takes the field value, all the values of the form and the meta data about the field and returns an error if the value is invalid, or undefined if the value is valid. + +`DropdownOptions` is a component that produces a list of select options given `name` and `rowkey` props. + +The `name` prop in the `DropdownOptions` component is the name of the variable that holds the data in the react state. + +The `rowkey` prop is the key of the data row returned by LabKey server. + +More information about how the entire form works can be found in the documentation linked above. Also, another nice resource provided by react-final-form is its extensive [interactive examples](https://github.com/final-form/react-final-form#examples). diff --git a/AnimalRequests/build.gradle b/AnimalRequests/build.gradle new file mode 100644 index 000000000..f962357d1 --- /dev/null +++ b/AnimalRequests/build.gradle @@ -0,0 +1,11 @@ +apply plugin: 'java' +apply plugin: 'org.labkey.module' +compileJava { + options.compilerArgs << "-Xlint:unchecked" + +} + +dependencies { +// BuildUtils.addLabKeyDependency(project: project, config: "compile", depProjectPath: ":server:modules:wnprc-modules:WNPRC_EHR", depProjectConfig: "apiCompile") + compile project(":server:modules:wnprc-modules:WNPRC_EHR") +} diff --git a/AnimalRequests/jest-config.js b/AnimalRequests/jest-config.js new file mode 100644 index 000000000..f01cf2f62 --- /dev/null +++ b/AnimalRequests/jest-config.js @@ -0,0 +1,21 @@ +module.exports = { + "roots": [ + "/src" + ], + "globals": { + "LABKEY": {} + }, + "transform": { + "^.+\\.tsx?$": "ts-jest", + ".+\\.(css|styl|less|sass|scss)$": "jest-transform-css" + }, + "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx", + "json", + "node" + ], +} \ No newline at end of file diff --git a/AnimalRequests/module.properties b/AnimalRequests/module.properties new file mode 100644 index 000000000..f2cacadd0 --- /dev/null +++ b/AnimalRequests/module.properties @@ -0,0 +1,8 @@ +ModuleClass: org.labkey.animalrequests.AnimalRequestsModule +ModuleDependencies: WNPRC_EHR +Label: Enter Animal Requests into EHR +Description: Simple module that utilizes React and Typescript to enter animal requests into WNPRC EHR +URL: https://github.com/WNPRC-EHR-Services/wnprc-modules/AnimalRequests +License: Apache 2.0 +SupportedDatabases: pgsql +LicenseURL: http://www.apache.org/licenses/LICENSE-2.0 diff --git a/AnimalRequests/package-lock.json b/AnimalRequests/package-lock.json new file mode 100644 index 000000000..cb76307ac --- /dev/null +++ b/AnimalRequests/package-lock.json @@ -0,0 +1,10680 @@ +{ + "name": "animalrequests", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0" + } + }, + "@babel/core": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.0.tgz", + "integrity": "sha512-Dzl7U0/T69DFOTwqz/FJdnOSWS57NpjNfCwMKHABr589Lg8uX1RrlBIJ7L5Dubt/xkLsx0xH5EBFzlBVes1ayA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0", + "@babel/generator": "7.4.0", + "@babel/helpers": "7.4.2", + "@babel/parser": "7.4.2", + "@babel/template": "7.4.0", + "@babel/traverse": "7.4.0", + "@babel/types": "7.4.0", + "convert-source-map": "1.6.0", + "debug": "4.1.1", + "json5": "2.1.0", + "resolve": "1.10.0", + "semver": "5.6.0", + "source-map": "0.5.7" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "2.1.1" + } + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "1.2.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz", + "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==", + "dev": true, + "requires": { + "@babel/types": "7.4.0", + "jsesc": "2.5.2", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + } + } + }, + "@babel/helper-builder-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz", + "integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==", + "dev": true, + "requires": { + "@babel/types": "7.4.0", + "esutils": "2.0.2" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "7.0.0", + "@babel/template": "7.4.0", + "@babel/types": "7.4.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "7.4.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz", + "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==", + "dev": true, + "requires": { + "@babel/types": "7.4.0" + } + }, + "@babel/helpers": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.2.tgz", + "integrity": "sha512-gQR1eQeroDzFBikhrCccm5Gs2xBjZ57DNjGbqTaHo911IpmSxflOQWMAHPw/TXk8L3isv7s9lYzUkexOeTQUYg==", + "dev": true, + "requires": { + "@babel/template": "7.4.0", + "@babel/traverse": "7.4.0", + "@babel/types": "7.4.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "esutils": "2.0.2", + "js-tokens": "4.0.0" + } + }, + "@babel/parser": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.2.tgz", + "integrity": "sha512-9fJTDipQFvlfSVdD/JBtkiY0br9BtfvW2R8wo6CX/Ej2eMuV0gWPk1M67Mt3eggQvBqYW1FCEk8BN7WvGm/g5g==", + "dev": true + }, + "@babel/plugin-syntax-jsx": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", + "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz", + "integrity": "sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz", + "integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz", + "integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==", + "dev": true, + "requires": { + "@babel/helper-builder-react-jsx": "7.3.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.2.0" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz", + "integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.2.0" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz", + "integrity": "sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.2.0" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.4.0.tgz", + "integrity": "sha512-U7/+zKnRZg04ggM/Bm+xmu2B/PrwyDQTT/V89FXWYWNMxBDwSx56u6jtk9SEbfLFbZaEI72L+5LPvQjeZgFCrQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-typescript": "7.3.3" + } + }, + "@babel/polyfill": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.4.0.tgz", + "integrity": "sha512-bVsjsrtsDflIHp5I6caaAa2V25Kzn50HKPL6g3X0P0ni1ks+58cPB8Mz6AOKVuRPgaVdq/OwEUc/1vKqX+Mo4A==", + "requires": { + "core-js": "2.6.5", + "regenerator-runtime": "0.13.2" + }, + "dependencies": { + "core-js": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", + "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" + }, + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" + } + } + }, + "@babel/preset-react": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", + "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-transform-react-display-name": "7.2.0", + "@babel/plugin-transform-react-jsx": "7.3.0", + "@babel/plugin-transform-react-jsx-self": "7.2.0", + "@babel/plugin-transform-react-jsx-source": "7.2.0" + } + }, + "@babel/preset-typescript": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz", + "integrity": "sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-transform-typescript": "7.4.0" + } + }, + "@babel/runtime": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", + "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==", + "requires": { + "regenerator-runtime": "0.12.1" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, + "@babel/template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz", + "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0", + "@babel/parser": "7.4.2", + "@babel/types": "7.4.0" + } + }, + "@babel/traverse": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.0.tgz", + "integrity": "sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0", + "@babel/generator": "7.4.0", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-split-export-declaration": "7.4.0", + "@babel/parser": "7.4.2", + "@babel/types": "7.4.0", + "debug": "4.1.1", + "globals": "11.11.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "2.1.1" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz", + "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==", + "dev": true, + "requires": { + "esutils": "2.0.2", + "to-fast-properties": "2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "0.3.2", + "minimist": "1.2.0" + } + }, + "@jest/console": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.3.0.tgz", + "integrity": "sha512-NaCty/OOei6rSDcbPdMiCbYCI0KGFGPgGO6B09lwWt5QTxnkuhKYET9El5u5z1GAcSxkQmSMtM63e24YabCWqA==", + "dev": true, + "requires": { + "@jest/source-map": "24.3.0", + "@types/node": "11.12.1", + "chalk": "2.4.2", + "slash": "2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "@jest/core": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.5.0.tgz", + "integrity": "sha512-RDZArRzAs51YS7dXG1pbXbWGxK53rvUu8mCDYsgqqqQ6uSOaTjcVyBl2Jce0exT2rSLk38ca7az7t2f3b0/oYQ==", + "dev": true, + "requires": { + "@jest/console": "24.3.0", + "@jest/reporters": "24.5.0", + "@jest/test-result": "24.5.0", + "@jest/transform": "24.5.0", + "@jest/types": "24.5.0", + "ansi-escapes": "3.2.0", + "chalk": "2.4.2", + "exit": "0.1.2", + "graceful-fs": "4.1.15", + "jest-changed-files": "24.5.0", + "jest-config": "24.5.0", + "jest-haste-map": "24.5.0", + "jest-message-util": "24.5.0", + "jest-regex-util": "24.3.0", + "jest-resolve-dependencies": "24.5.0", + "jest-runner": "24.5.0", + "jest-runtime": "24.5.0", + "jest-snapshot": "24.5.0", + "jest-util": "24.5.0", + "jest-validate": "24.5.0", + "jest-watcher": "24.5.0", + "micromatch": "3.1.10", + "p-each-series": "1.0.0", + "pirates": "4.0.1", + "realpath-native": "1.1.0", + "rimraf": "2.6.1", + "strip-ansi": "5.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "4.1.0" + } + } + } + }, + "@jest/environment": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.5.0.tgz", + "integrity": "sha512-tzUHR9SHjMXwM8QmfHb/EJNbF0fjbH4ieefJBvtwO8YErLTrecc1ROj0uo2VnIT6SlpEGZnvdCK6VgKYBo8LsA==", + "dev": true, + "requires": { + "@jest/fake-timers": "24.5.0", + "@jest/transform": "24.5.0", + "@jest/types": "24.5.0", + "@types/node": "11.12.1", + "jest-mock": "24.5.0" + } + }, + "@jest/fake-timers": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.5.0.tgz", + "integrity": "sha512-i59KVt3QBz9d+4Qr4QxsKgsIg+NjfuCjSOWj3RQhjF5JNy+eVJDhANQ4WzulzNCHd72srMAykwtRn5NYDGVraw==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "@types/node": "11.12.1", + "jest-message-util": "24.5.0", + "jest-mock": "24.5.0" + } + }, + "@jest/reporters": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.5.0.tgz", + "integrity": "sha512-vfpceiaKtGgnuC3ss5czWOihKOUSyjJA4M4udm6nH8xgqsuQYcyDCi4nMMcBKsHXWgz9/V5G7iisnZGfOh1w6Q==", + "dev": true, + "requires": { + "@jest/environment": "24.5.0", + "@jest/test-result": "24.5.0", + "@jest/transform": "24.5.0", + "@jest/types": "24.5.0", + "chalk": "2.4.2", + "exit": "0.1.2", + "glob": "7.1.3", + "istanbul-api": "2.1.1", + "istanbul-lib-coverage": "2.0.3", + "istanbul-lib-instrument": "3.1.0", + "istanbul-lib-source-maps": "3.0.2", + "jest-haste-map": "24.5.0", + "jest-resolve": "24.5.0", + "jest-runtime": "24.5.0", + "jest-util": "24.5.0", + "jest-worker": "24.4.0", + "node-notifier": "5.4.0", + "slash": "2.0.0", + "source-map": "0.6.1", + "string-length": "2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/source-map": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz", + "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==", + "dev": true, + "requires": { + "callsites": "3.0.0", + "graceful-fs": "4.1.15", + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.5.0.tgz", + "integrity": "sha512-u66j2vBfa8Bli1+o3rCaVnVYa9O8CAFZeqiqLVhnarXtreSXG33YQ6vNYBogT7+nYiFNOohTU21BKiHlgmxD5A==", + "dev": true, + "requires": { + "@jest/console": "24.3.0", + "@jest/types": "24.5.0", + "@types/istanbul-lib-coverage": "1.1.0" + } + }, + "@jest/transform": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.5.0.tgz", + "integrity": "sha512-XSsDz1gdR/QMmB8UCKlweAReQsZrD/DK7FuDlNo/pE8EcKMrfi2kqLRk8h8Gy/PDzgqJj64jNEzOce9pR8oj1w==", + "dev": true, + "requires": { + "@babel/core": "7.4.0", + "@jest/types": "24.5.0", + "babel-plugin-istanbul": "5.1.1", + "chalk": "2.4.2", + "convert-source-map": "1.6.0", + "fast-json-stable-stringify": "2.0.0", + "graceful-fs": "4.1.15", + "jest-haste-map": "24.5.0", + "jest-regex-util": "24.3.0", + "jest-util": "24.5.0", + "micromatch": "3.1.10", + "realpath-native": "1.1.0", + "slash": "2.0.0", + "source-map": "0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/types": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.5.0.tgz", + "integrity": "sha512-kN7RFzNMf2R8UDadPOl6ReyI+MT8xfqRuAnuVL+i4gwjv/zubdDK+EDeLHYwq1j0CSSR2W/MmgaRlMZJzXdmVA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "1.1.0", + "@types/yargs": "12.0.10" + } + }, + "@react-bootstrap/react-popper": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@react-bootstrap/react-popper/-/react-popper-1.2.1.tgz", + "integrity": "sha512-4l3q7LcZEhrSkI4d3Ie3g4CdrXqqTexXX4PFT45CB0z5z2JUbaxgRwKNq7r5j2bLdVpZm+uvUGqxJw8d9vgbJQ==", + "requires": { + "babel-runtime": "6.26.0", + "create-react-context": "0.2.2", + "popper.js": "1.14.7", + "prop-types": "15.7.2", + "typed-styles": "0.0.5", + "warning": "3.0.0" + }, + "dependencies": { + "typed-styles": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.5.tgz", + "integrity": "sha512-ht+rEe5UsdEBAa3gr64+QjUOqjOLJfWLvl5HZR5Ev9uo/OnD3p43wPeFSB1hNFc13GXQF/JU1Bn0YHLUqBRIlw==" + } + } + }, + "@restart/context": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", + "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==" + }, + "@restart/hooks": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.1.6.tgz", + "integrity": "sha512-eP1NykkdPlagH60YV+k2qGDCq3rkNtY6Sz0T2DVU1MQPa4pVRofIj+leFM2SLZLzy5nQFga4YnX7oM2d2LJRpA==" + }, + "@types/babel__core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.0.tgz", + "integrity": "sha512-wJTeJRt7BToFx3USrCDs2BhEi4ijBInTQjOIukj6a/5tEkwpFMVZ+1ppgmE+Q/FQyc5P/VWUbx7I9NELrKruHA==", + "dev": true, + "requires": { + "@babel/parser": "7.4.2", + "@babel/types": "7.4.0", + "@types/babel__generator": "7.0.2", + "@types/babel__template": "7.0.2", + "@types/babel__traverse": "7.0.6" + } + }, + "@types/babel__generator": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", + "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", + "dev": true, + "requires": { + "@babel/types": "7.4.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "7.4.2", + "@babel/types": "7.4.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.6.tgz", + "integrity": "sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==", + "dev": true, + "requires": { + "@babel/types": "7.4.0" + } + }, + "@types/history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.2.tgz", + "integrity": "sha512-ui3WwXmjTaY73fOQ3/m3nnajU/Orhi6cEu5rzX+BrAAJxa3eITXZ5ch9suPqtM03OWhAHhPSyBGCN4UKoxO20Q==" + }, + "@types/hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-O2OGyW9wlO2bbDmZRH17MecArQfsIa1g//ve2IJk6BnmwEglFz5kdhP1BlgeqjVNH5IHIhsc83DWFo8StCe8+Q==", + "requires": { + "@types/react": "15.6.0" + } + }, + "@types/istanbul-lib-coverage": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz", + "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==", + "dev": true + }, + "@types/jest": { + "version": "24.0.11", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.11.tgz", + "integrity": "sha512-2kLuPC5FDnWIDvaJBzsGTBQaBbnDweznicvK7UGYzlIJP4RJR2a4A/ByLUXEyEgag6jz8eHdlWExGDtH3EYUXQ==", + "dev": true, + "requires": { + "@types/jest-diff": "20.0.1" + } + }, + "@types/jest-diff": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", + "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", + "dev": true + }, + "@types/node": { + "version": "11.12.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.12.1.tgz", + "integrity": "sha512-sKDlqv6COJrR7ar0+GqqhrXQDzQlMcqMnF2iEU6m9hLo8kxozoAGUazwPyELHlRVmjsbvlnGXjnzyptSXVmceA==", + "dev": true + }, + "@types/react": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-15.6.0.tgz", + "integrity": "sha512-cj0xPUuKS+5K9UWeHMeRUc32i7qrDZNKTrW92crNphx8hMy1gVmuJVune7E7NXpFVPn6O7VazXuXeDiCvNXDhg==" + }, + "@types/react-bootstrap": { + "version": "0.32.17", + "resolved": "https://registry.npmjs.org/@types/react-bootstrap/-/react-bootstrap-0.32.17.tgz", + "integrity": "sha512-w/Agv91PQ2q5w4MK+plWshyvLMFePxdl+b2KtlFHBSbr6FgaguIGEAdhA3l0hyKDmEj3VMHGFiBqwhsQJ2Rltg==", + "requires": { + "@types/react": "15.6.0" + } + }, + "@types/react-dom": { + "version": "15.5.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-15.5.1.tgz", + "integrity": "sha512-4c+e/QPfvSa48YhgGOcQWoHishTo6BuJqka0Bh8qeLdnK1jS+1Nz8W/w1G17AIjtLxONYFUqmi8qyt+8p/yMFA==", + "requires": { + "@types/react": "15.6.0" + } + }, + "@types/react-redux": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.0.3.tgz", + "integrity": "sha512-6qsIHHNwF41viooUgR2lXHL81v3uyeJsugq9YCMYE4g2bDyG710G/I/w5nbn7AQ9XfuOLUwrWfm3edV7gDJ9AQ==", + "requires": { + "@types/hoist-non-react-statics": "3.3.0", + "@types/react": "15.6.0", + "redux": "4.0.1" + }, + "dependencies": { + "redux": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz", + "integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==", + "requires": { + "loose-envify": "1.4.0", + "symbol-observable": "1.2.0" + } + } + } + }, + "@types/react-router": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.0.14.tgz", + "integrity": "sha512-wbcqBGFv2KcBo0fIief2MJeE5e1Ph9Z35FzWPmadNMzd5dwpFGLVxyDQiLc30u3ehNrgG7JlQcFYLe5YJnToyA==", + "requires": { + "@types/history": "4.7.2", + "@types/react": "15.6.0" + } + }, + "@types/react-router-dom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-4.3.1.tgz", + "integrity": "sha512-GbztJAScOmQ/7RsQfO4cd55RuH1W4g6V1gDW3j4riLlt+8yxYLqqsiMzmyuXBLzdFmDtX/uU2Bpcm0cmudv44A==", + "requires": { + "@types/history": "4.7.2", + "@types/react": "15.6.0", + "@types/react-router": "4.0.14" + } + }, + "@types/redux-actions": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/redux-actions/-/redux-actions-1.2.7.tgz", + "integrity": "sha512-V/uwJjkC90gSj613aPF2kqJVFgdfgq1fxDjBSTuTSuMpc7kGRpyylKacWeMOlZlpGPhgrMsfjqrzvlGZI1RioQ==" + }, + "@types/redux-form": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/@types/redux-form/-/redux-form-6.6.2.tgz", + "integrity": "sha1-8zhARqs2CVeMwo2vbFAjHCWGCgY=", + "requires": { + "@types/react": "15.6.0", + "redux": "3.7.2" + } + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.10.tgz", + "integrity": "sha512-WsVzTPshvCSbHThUduGGxbmnwcpkgSctHGHTqzWyFg4lYAuV5qXlyFPOsP3OWqCINfmg/8VXP+zJaa4OxEsBQQ==", + "dev": true + }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", + "dev": true + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "2.1.22", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "acorn-globals": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", + "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", + "dev": true, + "requires": { + "acorn": "6.1.1", + "acorn-walk": "6.1.1" + }, + "dependencies": { + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "dev": true + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.3" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "3.1.10", + "normalize-path": "2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + } + } + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "2.0.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-findindex-polyfill": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/array-findindex-polyfill/-/array-findindex-polyfill-0.1.0.tgz", + "integrity": "sha1-w2JmW+x2RfItejw6rJeT9xw2Iu8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "dev": true + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", + "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000935", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-jest": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.5.0.tgz", + "integrity": "sha512-0fKCXyRwxFTJL0UXDJiT2xYxO9Lu2vBd9n+cC+eDjESzcVG3s2DRGAxbzJX21fceB1WYoBjAh8pQ83dKcl003g==", + "dev": true, + "requires": { + "@jest/transform": "24.5.0", + "@jest/types": "24.5.0", + "@types/babel__core": "7.1.0", + "babel-plugin-istanbul": "5.1.1", + "babel-preset-jest": "24.3.0", + "chalk": "2.4.2", + "slash": "2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "babel-loader": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", + "integrity": "sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==", + "dev": true, + "requires": { + "find-cache-dir": "2.1.0", + "loader-utils": "1.2.3", + "mkdirp": "0.5.1", + "util.promisify": "1.0.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "dev": true, + "requires": { + "find-up": "3.0.0", + "istanbul-lib-instrument": "3.1.0", + "test-exclude": "5.1.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "3.0.0", + "path-exists": "3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "2.1.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "2.2.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + } + } + }, + "babel-plugin-jest-hoist": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.3.0.tgz", + "integrity": "sha512-nWh4N1mVH55Tzhx2isvUN5ebM5CDUvIpXPZYMRazQughie/EqGnbR+czzoQlhUmJG9pPJmYDRhvocotb2THl1w==", + "dev": true, + "requires": { + "@types/babel__traverse": "7.0.6" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + }, + "dependencies": { + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.4.0", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + } + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "requires": { + "babel-runtime": "6.26.0", + "core-js": "2.6.4", + "regenerator-runtime": "0.10.5" + } + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0" + } + }, + "babel-preset-jest": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.3.0.tgz", + "integrity": "sha512-VGTV2QYBa/Kn3WCOKdfS31j9qomaXSgJqi65B6o05/1GsJyj9LVhSljM9ro4S+IBGj/ENhNBuH9bpqzztKAQSw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "7.2.0", + "babel-plugin-jest-hoist": "24.3.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.6.4", + "regenerator-runtime": "0.11.1" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "pascalcase": "0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "better-npm-run": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/better-npm-run/-/better-npm-run-0.0.15.tgz", + "integrity": "sha1-EADtFLT3fIU95aUUiAX35093HPA=", + "dev": true, + "requires": { + "commander": "2.19.0", + "dotenv": "2.0.0", + "object-assign": "4.1.1" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", + "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "1.6.16" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": "2.1.2" + } + } + } + }, + "bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + } + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "1.2.0", + "browserify-des": "1.0.2", + "evp_bytestokey": "1.0.3" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "randombytes": "2.0.6" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "elliptic": "6.4.1", + "inherits": "2.0.3", + "parse-asn1": "5.1.3" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "1.0.8" + } + }, + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000935", + "electron-to-chromium": "1.3.113" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.0.0" + } + }, + "bser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "dev": true, + "requires": { + "node-int64": "0.4.0" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "1.3.0", + "ieee754": "1.1.12", + "isarray": "1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" + } + }, + "callsites": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "caniuse-api": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", + "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000935", + "lodash.memoize": "4.1.2", + "lodash.uniq": "4.5.0" + } + }, + "caniuse-db": { + "version": "1.0.30000935", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000935.tgz", + "integrity": "sha512-HFqvW9MZZcWD02F3J2GV2ggQyIXiDr7DRPlOWSKVIihu8J1dtsYFqtMjmFqiYamfOmY4NHyn7xFaWAHBtFWgjQ==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "4.8.4" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "chokidar": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.0.tgz", + "integrity": "sha512-5t6G2SH8eO6lCvYOoUpaRnF5Qfd//gd7qJAkwRUw9qlGVkiQ13uwQngqbWWaurOsaAm9+kUGbITADxt6H0XFNQ==", + "dev": true, + "requires": { + "anymatch": "2.0.0", + "async-each": "1.0.1", + "braces": "2.3.2", + "fsevents": "1.2.7", + "glob-parent": "3.1.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "4.0.0", + "normalize-path": "3.0.0", + "path-is-absolute": "1.0.1", + "readdirp": "2.2.1", + "upath": "1.1.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.2" + } + }, + "clap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "dev": true, + "requires": { + "chalk": "1.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + } + } + }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "1.5.1" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "1.0.0", + "object-visit": "1.0.1" + } + }, + "color": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", + "dev": true, + "requires": { + "clone": "1.0.4", + "color-convert": "1.9.3", + "color-string": "0.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-string": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "colormin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", + "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", + "dev": true, + "requires": { + "color": "0.11.4", + "css-color-names": "0.0.4", + "has": "1.0.3" + } + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "compare-versions": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.4.0.tgz", + "integrity": "sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg==", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "connected-react-router": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.3.2.tgz", + "integrity": "sha512-YxrAfMExl/OBsi+ojA4ywZeC7cmQ52MnZ4bhzqLhhjuOiXcQogC4kW0kodouXAXrXDovb2l3yEhDfpH99/wYcw==", + "requires": { + "immutable": "3.8.2", + "seamless-immutable": "7.1.4" + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.4.tgz", + "integrity": "sha512-05qQ5hXShcqGkPZpXEFLIpxayZscVD2kuMBZewxiIPPEagukO4mqgPA9CWhUvFBJfy3ODdK2p9xyHh7FTU9/7A==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "vary": "1.1.2" + } + }, + "cosmiconfig": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.6.tgz", + "integrity": "sha512-6DWfizHriCrFWURP1/qyhsiFvYdlJzbCzmtFWh744+KyWsJo5+kPzUZZaMRSSItoYc0pxFX7gEO7ZC1/gN/7AQ==", + "dev": true, + "requires": { + "is-directory": "0.3.1", + "js-yaml": "3.13.0", + "parse-json": "4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "js-yaml": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.2", + "json-parse-better-errors": "1.0.2" + } + } + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "elliptic": "6.4.1" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "md5.js": "1.3.5", + "ripemd160": "2.0.2", + "sha.js": "2.4.11" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "inherits": "2.0.3", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" + } + }, + "create-react-class": { + "version": "15.6.3", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz", + "integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==", + "requires": { + "fbjs": "0.8.17", + "loose-envify": "1.4.0", + "object-assign": "4.1.1" + } + }, + "create-react-context": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz", + "integrity": "sha512-KkpaLARMhsTsgp0d2NA/R94F/eDLbhXERdIq3LvX2biCAXcDvHYoOqHfWCHf1+OLj+HKBotLG3KqaOOf+C1C+A==", + "requires": { + "fbjs": "0.8.17", + "gud": "1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.5", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "1.0.1", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.3", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "diffie-hellman": "5.0.3", + "inherits": "2.0.3", + "pbkdf2": "3.0.17", + "public-encrypt": "4.0.3", + "randombytes": "2.0.6", + "randomfill": "1.0.4" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-loader": { + "version": "0.28.7", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.7.tgz", + "integrity": "sha512-GxMpax8a/VgcfRrVy0gXD6yLd5ePYbXX/5zGgTVYp4wXtJklS8Z2VaUArJgc//f6/Dzil7BaJObdSv8eKKCPgg==", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "css-selector-tokenizer": "0.7.1", + "cssnano": "3.10.0", + "icss-utils": "2.1.0", + "loader-utils": "1.2.3", + "lodash.camelcase": "4.3.0", + "object-assign": "4.1.1", + "postcss": "5.2.18", + "postcss-modules-extract-imports": "1.2.1", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0", + "postcss-value-parser": "3.3.1", + "source-list-map": "2.0.1" + } + }, + "css-modules-loader-core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz", + "integrity": "sha1-WQhmgpShvs0mGuCkziGwtVHyHRY=", + "dev": true, + "requires": { + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.1", + "postcss-modules-extract-imports": "1.1.0", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.1.tgz", + "integrity": "sha1-AA29H47vIXqjaLmiEsX8QLKo8/I=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "postcss-modules-extract-imports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", + "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", + "dev": true, + "requires": { + "postcss": "6.0.1" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "0.1.0", + "fastparse": "1.1.2", + "regexpu-core": "1.0.0" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", + "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", + "dev": true, + "requires": { + "autoprefixer": "6.7.7", + "decamelize": "1.2.0", + "defined": "1.0.0", + "has": "1.0.3", + "object-assign": "4.1.1", + "postcss": "5.2.18", + "postcss-calc": "5.3.1", + "postcss-colormin": "2.2.2", + "postcss-convert-values": "2.6.1", + "postcss-discard-comments": "2.0.4", + "postcss-discard-duplicates": "2.1.0", + "postcss-discard-empty": "2.1.0", + "postcss-discard-overridden": "0.1.1", + "postcss-discard-unused": "2.2.3", + "postcss-filter-plugins": "2.0.3", + "postcss-merge-idents": "2.1.7", + "postcss-merge-longhand": "2.0.2", + "postcss-merge-rules": "2.1.2", + "postcss-minify-font-values": "1.0.5", + "postcss-minify-gradients": "1.0.5", + "postcss-minify-params": "1.2.2", + "postcss-minify-selectors": "2.1.1", + "postcss-normalize-charset": "1.1.1", + "postcss-normalize-url": "3.0.8", + "postcss-ordered-values": "2.2.3", + "postcss-reduce-idents": "2.4.0", + "postcss-reduce-initial": "1.0.1", + "postcss-reduce-transforms": "1.0.4", + "postcss-svgo": "2.1.6", + "postcss-unique-selectors": "2.0.2", + "postcss-value-parser": "3.3.1", + "postcss-zindex": "2.2.0" + } + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "1.2.3", + "source-map": "0.5.7" + } + }, + "cssom": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", + "dev": true + }, + "cssstyle": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz", + "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==", + "dev": true, + "requires": { + "cssom": "0.3.6" + } + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.47" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "2.0.0", + "whatwg-mimetype": "2.3.0", + "whatwg-url": "7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" + } + } + } + }, + "date-fns": { + "version": "2.0.0-alpha.27", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.0.0-alpha.27.tgz", + "integrity": "sha512-cqfVLS+346P/Mpj2RpDrBv0P4p2zZhWWvfY5fuWrXNR/K38HaAGEkeOwb47hIpQP9Jr/TIxjZ2/sNMQwdXuGMg==" + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "3.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "1.1.0" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "diff-sequences": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", + "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.6" + } + }, + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "7.3.1" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "4.0.2" + } + }, + "dotenv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-2.0.0.tgz", + "integrity": "sha1-vXWcNXqqcDZeAclrewvsCKbg2Uk=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "0.1.1", + "safer-buffer": "2.1.2" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.113", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz", + "integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==", + "dev": true + }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.7", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "1.4.0" + } + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "4.1.15", + "memory-fs": "0.4.1", + "object-assign": "4.1.1", + "tapable": "0.2.9" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "1.2.0", + "function-bind": "1.1.1", + "has": "1.0.3", + "is-callable": "1.1.4", + "is-regex": "1.0.4", + "object-keys": "1.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "1.1.4", + "is-date-object": "1.0.1", + "is-symbol": "1.0.2" + } + }, + "es5-ext": { + "version": "0.10.47", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.47.tgz", + "integrity": "sha512-/1TItLfj+TTfWoeRcDn/0FbGV6SNo4R+On2GGVucPU/j3BWnXE2Co8h8CTo4Tu34gFJtnmwS9xiScKs4EjZhdw==", + "dev": true, + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "next-tick": "1.0.0" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.47", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.47", + "es6-iterator": "2.0.3", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "dev": true + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.47", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.47" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.47", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "dev": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.47" + } + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "1.3.5", + "safe-buffer": "5.1.2" + } + }, + "exec-sh": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", + "dev": true + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "expect": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.5.0.tgz", + "integrity": "sha512-p2Gmc0CLxOgkyA93ySWmHFYHUPFIHG6XZ06l7WArWAsrqYVaVEkOU5NtT5i68KUyGKbkQgDCkiT65bWmdoL6Bw==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "ansi-styles": "3.2.1", + "jest-get-type": "24.3.0", + "jest-matcher-utils": "24.5.0", + "jest-message-util": "24.5.0", + "jest-regex-util": "24.3.0" + } + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dev": true, + "requires": { + "accepts": "1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.4", + "qs": "6.5.2", + "range-parser": "1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "1.4.0", + "type-is": "1.6.16", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + } + } + }, + "express-http-proxy": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/express-http-proxy/-/express-http-proxy-1.5.1.tgz", + "integrity": "sha512-k1RdysZWZ8wdPnsLa4iyrrYyUFih/sYKkn6WfkU/q5A8eUdh3l+oXhrRuQmEYEsZmiexVvpiOCkogl03jYfcbg==", + "dev": true, + "requires": { + "debug": "3.2.6", + "es6-promise": "4.2.6", + "raw-body": "2.3.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "extract-text-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.0.tgz", + "integrity": "sha1-kMqnkHvESfM1AF46x1MrQbAN5hI=", + "dev": true, + "requires": { + "async": "2.6.1", + "loader-utils": "1.2.3", + "schema-utils": "0.3.0", + "webpack-sources": "1.3.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "2.0.0" + } + }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.19" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + } + } + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "7.1.3", + "minimatch": "3.0.4" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "final-form": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/final-form/-/final-form-4.12.0.tgz", + "integrity": "sha512-z1fSzDNmIBlDjRMaluM3WgDbcwCFpPm7mvopplgXGMRS49MXR+1n//lteLwPURdGQNOZhWm3GwiEJanEHCItww==", + "requires": { + "@babel/runtime": "7.3.1" + } + }, + "final-form-arrays": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/final-form-arrays/-/final-form-arrays-1.1.2.tgz", + "integrity": "sha512-Pmq3MXI9zbSsY7WZ2eodWQAHpsw2/i5YkagzcCgqzRcSSHB8BD3yWi7YPSGTPXuG0ixcQe9VAYpQ+UEWcqf4zg==" + }, + "final-form-set-field-data": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/final-form-set-field-data/-/final-form-set-field-data-1.0.2.tgz", + "integrity": "sha512-gAnENimyQ5GW3OEGca5pbwm4lYshW2orzfBlPUYqzcm7ZxkQrVO8FqCAgEcCM+Rq9U1OU0q+D+UkqETvvDY6jw==" + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.4.0", + "unpipe": "1.0.0" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "1.0.1", + "make-dir": "2.1.0", + "pkg-dir": "3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "4.0.1", + "semver": "5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.7", + "mime-types": "2.1.22" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.12.1", + "node-pre-gyp": "0.10.3" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "2.3.5" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.3" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.1.2", + "yallist": "3.0.3" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "2.3.5" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.9", + "iconv-lite": "0.4.24", + "sax": "1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "1.0.3", + "mkdirp": "0.5.1", + "needle": "2.2.4", + "nopt": "4.0.1", + "npm-packlist": "1.2.0", + "npmlog": "4.1.2", + "rc": "1.2.8", + "rimraf": "2.6.3", + "semver": "5.6.0", + "tar": "4.4.8" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.1", + "osenv": "0.1.5" + } + }, + "npm-bundled": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "3.0.1", + "npm-bundled": "1.0.5" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.5", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.6.0", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "1.1.1", + "fs-minipass": "1.2.5", + "minipass": "2.3.5", + "minizlib": "1.2.1", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.2", + "yallist": "3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "generic-names": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-1.0.3.tgz", + "integrity": "sha1-LXhqEhruUIh2eWk56OO/+DbCCRc=", + "dev": true, + "requires": { + "loader-utils": "0.2.17" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "3.1.0", + "path-dirname": "1.0.2" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + } + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, + "handlebars": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz", + "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==", + "dev": true, + "requires": { + "neo-async": "2.6.0", + "optimist": "0.6.1", + "source-map": "0.6.1", + "uglify-js": "3.5.2" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "uglify-js": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.2.tgz", + "integrity": "sha512-imog1WIsi9Yb56yRt5TfYVxGmnWs3WSGU73ieSOlMVFwhJCA9W8fqFFMMj4kgDqiS/80LGdsYnWL7O9UcjEBlg==", + "dev": true, + "optional": true, + "requires": { + "commander": "2.19.0", + "source-map": "0.6.1" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "6.10.0", + "har-schema": "2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.2" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" + } + }, + "history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", + "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", + "requires": { + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "resolve-pathname": "2.2.0", + "value-equal": "0.4.0", + "warning": "3.0.0" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "1.1.7", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "16.8.1" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "1.0.5" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": "1.4.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.16.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": "2.1.2" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", + "dev": true, + "requires": { + "postcss": "6.0.23" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "5.5.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "dev": true + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "2.1.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "3.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "3.0.0", + "resolve-cwd": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "3.0.0", + "path-exists": "3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "2.1.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "2.2.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "1.4.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.13.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-generator-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.0.0.tgz", + "integrity": "sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g==", + "dev": true + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.3" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "dev": true, + "requires": { + "html-comment-regex": "1.1.2" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "1.7.3", + "whatwg-fetch": "3.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz", + "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==", + "dev": true, + "requires": { + "async": "2.6.1", + "compare-versions": "3.4.0", + "fileset": "2.0.3", + "istanbul-lib-coverage": "2.0.3", + "istanbul-lib-hook": "2.0.3", + "istanbul-lib-instrument": "3.1.0", + "istanbul-lib-report": "2.0.4", + "istanbul-lib-source-maps": "3.0.2", + "istanbul-reports": "2.1.1", + "js-yaml": "3.13.0", + "make-dir": "1.3.0", + "minimatch": "3.0.4", + "once": "1.4.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "js-yaml": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.1" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz", + "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==", + "dev": true, + "requires": { + "append-transform": "1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "7.4.0", + "@babel/parser": "7.4.2", + "@babel/template": "7.4.0", + "@babel/traverse": "7.4.0", + "@babel/types": "7.4.0", + "istanbul-lib-coverage": "2.0.3", + "semver": "5.6.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz", + "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "2.0.3", + "make-dir": "1.3.0", + "supports-color": "6.1.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz", + "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", + "dev": true, + "requires": { + "debug": "4.1.1", + "istanbul-lib-coverage": "2.0.3", + "make-dir": "1.3.0", + "rimraf": "2.6.3", + "source-map": "0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "7.1.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", + "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", + "dev": true, + "requires": { + "handlebars": "4.1.1" + } + }, + "jest": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.5.0.tgz", + "integrity": "sha512-lxL+Fq5/RH7inxxmfS2aZLCf8MsS+YCUBfeiNO6BWz/MmjhDGaIEA/2bzEf9q4Q0X+mtFHiinHFvQ0u+RvW/qQ==", + "dev": true, + "requires": { + "import-local": "2.0.0", + "jest-cli": "24.5.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.6.0", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "jest-cli": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.5.0.tgz", + "integrity": "sha512-P+Jp0SLO4KWN0cGlNtC7JV0dW1eSFR7eRpoOucP2UM0sqlzp/bVHeo71Omonvigrj9AvCKy7NtQANtqJ7FXz8g==", + "dev": true, + "requires": { + "@jest/core": "24.5.0", + "@jest/test-result": "24.5.0", + "@jest/types": "24.5.0", + "chalk": "2.4.2", + "exit": "0.1.2", + "import-local": "2.0.0", + "is-ci": "2.0.0", + "jest-config": "24.5.0", + "jest-util": "24.5.0", + "jest-validate": "24.5.0", + "prompts": "2.0.4", + "realpath-native": "1.1.0", + "yargs": "12.0.5" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "3.0.0", + "path-exists": "3.0.0" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "0.1.3", + "mimic-fn": "2.0.0", + "p-is-promise": "2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "1.0.0", + "lcid": "2.0.0", + "mem": "4.2.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "2.1.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "2.2.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "3.0.0", + "get-caller-file": "1.0.3", + "os-locale": "3.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "5.2.0", + "decamelize": "1.2.0" + } + } + } + }, + "jest-changed-files": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.5.0.tgz", + "integrity": "sha512-Ikl29dosYnTsH9pYa1Tv9POkILBhN/TLZ37xbzgNsZ1D2+2n+8oEZS2yP1BrHn/T4Rs4Ggwwbp/x8CKOS5YJOg==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "execa": "1.0.0", + "throat": "4.1.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.6.0", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "3.0.0" + } + } + } + }, + "jest-config": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.5.0.tgz", + "integrity": "sha512-t2UTh0Z2uZhGBNVseF8wA2DS2SuBiLOL6qpLq18+OZGfFUxTM7BzUVKyHFN/vuN+s/aslY1COW95j1Rw81huOQ==", + "dev": true, + "requires": { + "@babel/core": "7.4.0", + "@jest/types": "24.5.0", + "babel-jest": "24.5.0", + "chalk": "2.4.2", + "glob": "7.1.3", + "jest-environment-jsdom": "24.5.0", + "jest-environment-node": "24.5.0", + "jest-get-type": "24.3.0", + "jest-jasmine2": "24.5.0", + "jest-regex-util": "24.3.0", + "jest-resolve": "24.5.0", + "jest-util": "24.5.0", + "jest-validate": "24.5.0", + "micromatch": "3.1.10", + "pretty-format": "24.5.0", + "realpath-native": "1.1.0" + } + }, + "jest-diff": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.5.0.tgz", + "integrity": "sha512-mCILZd9r7zqL9Uh6yNoXjwGQx0/J43OD2vvWVKwOEOLZliQOsojXwqboubAQ+Tszrb6DHGmNU7m4whGeB9YOqw==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "diff-sequences": "24.3.0", + "jest-get-type": "24.3.0", + "pretty-format": "24.5.0" + } + }, + "jest-docblock": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz", + "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==", + "dev": true, + "requires": { + "detect-newline": "2.1.0" + } + }, + "jest-each": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.5.0.tgz", + "integrity": "sha512-6gy3Kh37PwIT5sNvNY2VchtIFOOBh8UCYnBlxXMb5sr5wpJUDPTUATX2Axq1Vfk+HWTMpsYPeVYp4TXx5uqUBw==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "chalk": "2.4.2", + "jest-get-type": "24.3.0", + "jest-util": "24.5.0", + "pretty-format": "24.5.0" + } + }, + "jest-environment-jsdom": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.5.0.tgz", + "integrity": "sha512-62Ih5HbdAWcsqBx2ktUnor/mABBo1U111AvZWcLKeWN/n/gc5ZvDBKe4Og44fQdHKiXClrNGC6G0mBo6wrPeGQ==", + "dev": true, + "requires": { + "@jest/environment": "24.5.0", + "@jest/fake-timers": "24.5.0", + "@jest/types": "24.5.0", + "jest-mock": "24.5.0", + "jest-util": "24.5.0", + "jsdom": "11.12.0" + } + }, + "jest-environment-node": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.5.0.tgz", + "integrity": "sha512-du6FuyWr/GbKLsmAbzNF9mpr2Iu2zWSaq/BNHzX+vgOcts9f2ayXBweS7RAhr+6bLp6qRpMB6utAMF5Ygktxnw==", + "dev": true, + "requires": { + "@jest/environment": "24.5.0", + "@jest/fake-timers": "24.5.0", + "@jest/types": "24.5.0", + "jest-mock": "24.5.0", + "jest-util": "24.5.0" + } + }, + "jest-get-type": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.3.0.tgz", + "integrity": "sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow==", + "dev": true + }, + "jest-haste-map": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.5.0.tgz", + "integrity": "sha512-mb4Yrcjw9vBgSvobDwH8QUovxApdimGcOkp+V1ucGGw4Uvr3VzZQBJhNm1UY3dXYm4XXyTW2G7IBEZ9pM2ggRQ==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "fb-watchman": "2.0.0", + "graceful-fs": "4.1.15", + "invariant": "2.2.4", + "jest-serializer": "24.4.0", + "jest-util": "24.5.0", + "jest-worker": "24.4.0", + "micromatch": "3.1.10", + "sane": "4.1.0" + } + }, + "jest-jasmine2": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.5.0.tgz", + "integrity": "sha512-sfVrxVcx1rNUbBeyIyhkqZ4q+seNKyAG6iM0S2TYBdQsXjoFDdqWFfsUxb6uXSsbimbXX/NMkJIwUZ1uT9+/Aw==", + "dev": true, + "requires": { + "@babel/traverse": "7.4.0", + "@jest/environment": "24.5.0", + "@jest/test-result": "24.5.0", + "@jest/types": "24.5.0", + "chalk": "2.4.2", + "co": "4.6.0", + "expect": "24.5.0", + "is-generator-fn": "2.0.0", + "jest-each": "24.5.0", + "jest-matcher-utils": "24.5.0", + "jest-message-util": "24.5.0", + "jest-runtime": "24.5.0", + "jest-snapshot": "24.5.0", + "jest-util": "24.5.0", + "pretty-format": "24.5.0", + "throat": "4.1.0" + } + }, + "jest-leak-detector": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.5.0.tgz", + "integrity": "sha512-LZKBjGovFRx3cRBkqmIg+BZnxbrLqhQl09IziMk3oeh1OV81Hg30RUIx885mq8qBv1PA0comB9bjKcuyNO1bCQ==", + "dev": true, + "requires": { + "pretty-format": "24.5.0" + } + }, + "jest-matcher-utils": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.5.0.tgz", + "integrity": "sha512-QM1nmLROjLj8GMGzg5VBra3I9hLpjMPtF1YqzQS3rvWn2ltGZLrGAO1KQ9zUCVi5aCvrkbS5Ndm2evIP9yZg1Q==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "jest-diff": "24.5.0", + "jest-get-type": "24.3.0", + "pretty-format": "24.5.0" + } + }, + "jest-message-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.5.0.tgz", + "integrity": "sha512-6ZYgdOojowCGiV0D8WdgctZEAe+EcFU+KrVds+0ZjvpZurUW2/oKJGltJ6FWY2joZwYXN5VL36GPV6pNVRqRnQ==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0", + "@jest/test-result": "24.5.0", + "@jest/types": "24.5.0", + "@types/stack-utils": "1.0.1", + "chalk": "2.4.2", + "micromatch": "3.1.10", + "slash": "2.0.0", + "stack-utils": "1.0.2" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "jest-mock": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.5.0.tgz", + "integrity": "sha512-ZnAtkWrKf48eERgAOiUxVoFavVBziO2pAi2MfZ1+bGXVkDfxWLxU0//oJBkgwbsv6OAmuLBz4XFFqvCFMqnGUw==", + "dev": true, + "requires": { + "@jest/types": "24.5.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "dev": true + }, + "jest-regex-util": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz", + "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==", + "dev": true + }, + "jest-resolve": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.5.0.tgz", + "integrity": "sha512-ZIfGqLX1Rg8xJpQqNjdoO8MuxHV1q/i2OO1hLXjgCWFWs5bsedS8UrOdgjUqqNae6DXA+pCyRmdcB7lQEEbXew==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "browser-resolve": "1.11.3", + "chalk": "2.4.2", + "jest-pnp-resolver": "1.2.1", + "realpath-native": "1.1.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.5.0.tgz", + "integrity": "sha512-dRVM1D+gWrFfrq2vlL5P9P/i8kB4BOYqYf3S7xczZ+A6PC3SgXYSErX/ScW/469pWMboM1uAhgLF+39nXlirCQ==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "jest-regex-util": "24.3.0", + "jest-snapshot": "24.5.0" + } + }, + "jest-runner": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.5.0.tgz", + "integrity": "sha512-oqsiS9TkIZV5dVkD+GmbNfWBRPIvxqmlTQ+AQUJUQ07n+4xTSDc40r+aKBynHw9/tLzafC00DIbJjB2cOZdvMA==", + "dev": true, + "requires": { + "@jest/console": "24.3.0", + "@jest/environment": "24.5.0", + "@jest/test-result": "24.5.0", + "@jest/types": "24.5.0", + "chalk": "2.4.2", + "exit": "0.1.2", + "graceful-fs": "4.1.15", + "jest-config": "24.5.0", + "jest-docblock": "24.3.0", + "jest-haste-map": "24.5.0", + "jest-jasmine2": "24.5.0", + "jest-leak-detector": "24.5.0", + "jest-message-util": "24.5.0", + "jest-resolve": "24.5.0", + "jest-runtime": "24.5.0", + "jest-util": "24.5.0", + "jest-worker": "24.4.0", + "source-map-support": "0.5.11", + "throat": "4.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", + "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==", + "dev": true, + "requires": { + "buffer-from": "1.1.1", + "source-map": "0.6.1" + } + } + } + }, + "jest-runtime": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.5.0.tgz", + "integrity": "sha512-GTFHzfLdwpaeoDPilNpBrorlPoNZuZrwKKzKJs09vWwHo+9TOsIIuszK8cWOuKC7ss07aN1922Ge8fsGdsqCuw==", + "dev": true, + "requires": { + "@jest/console": "24.3.0", + "@jest/environment": "24.5.0", + "@jest/source-map": "24.3.0", + "@jest/transform": "24.5.0", + "@jest/types": "24.5.0", + "@types/yargs": "12.0.10", + "chalk": "2.4.2", + "exit": "0.1.2", + "glob": "7.1.3", + "graceful-fs": "4.1.15", + "jest-config": "24.5.0", + "jest-haste-map": "24.5.0", + "jest-message-util": "24.5.0", + "jest-mock": "24.5.0", + "jest-regex-util": "24.3.0", + "jest-resolve": "24.5.0", + "jest-snapshot": "24.5.0", + "jest-util": "24.5.0", + "jest-validate": "24.5.0", + "realpath-native": "1.1.0", + "slash": "2.0.0", + "strip-bom": "3.0.0", + "yargs": "12.0.5" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.6.0", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "3.0.0", + "path-exists": "3.0.0" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "0.1.3", + "mimic-fn": "2.0.0", + "p-is-promise": "2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "1.0.0", + "lcid": "2.0.0", + "mem": "4.2.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "2.1.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "2.2.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "3.0.0", + "get-caller-file": "1.0.3", + "os-locale": "3.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "5.2.0", + "decamelize": "1.2.0" + } + } + } + }, + "jest-serializer": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz", + "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==", + "dev": true + }, + "jest-snapshot": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.5.0.tgz", + "integrity": "sha512-eBEeJb5ROk0NcpodmSKnCVgMOo+Qsu5z9EDl3tGffwPzK1yV37mjGWF2YeIz1NkntgTzP+fUL4s09a0+0dpVWA==", + "dev": true, + "requires": { + "@babel/types": "7.4.0", + "@jest/types": "24.5.0", + "chalk": "2.4.2", + "expect": "24.5.0", + "jest-diff": "24.5.0", + "jest-matcher-utils": "24.5.0", + "jest-message-util": "24.5.0", + "jest-resolve": "24.5.0", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "pretty-format": "24.5.0", + "semver": "5.6.0" + } + }, + "jest-transform-css": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-transform-css/-/jest-transform-css-2.0.0.tgz", + "integrity": "sha512-KV5pD27qUltAVj0mZEVvqd+Ahe+WNPOVWKA1BRpIhBJ5OeUUOM46ivAznJrC5B1JrVNbMzWjPxnKl6QTsAAT3Q==", + "dev": true, + "requires": { + "common-tags": "1.8.0", + "cosmiconfig": "5.0.6", + "cross-spawn": "6.0.5", + "postcss-load-config": "2.0.0", + "postcss-modules": "1.3.2", + "style-inject": "0.3.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.6.0", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + } + } + }, + "jest-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.5.0.tgz", + "integrity": "sha512-Xy8JsD0jvBz85K7VsTIQDuY44s+hYJyppAhcsHsOsGisVtdhar6fajf2UOf2mEVEgh15ZSdA0zkCuheN8cbr1Q==", + "dev": true, + "requires": { + "@jest/console": "24.3.0", + "@jest/fake-timers": "24.5.0", + "@jest/source-map": "24.3.0", + "@jest/test-result": "24.5.0", + "@jest/types": "24.5.0", + "@types/node": "11.12.1", + "callsites": "3.0.0", + "chalk": "2.4.2", + "graceful-fs": "4.1.15", + "is-ci": "2.0.0", + "mkdirp": "0.5.1", + "slash": "2.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "jest-validate": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.5.0.tgz", + "integrity": "sha512-gg0dYszxjgK2o11unSIJhkOFZqNRQbWOAB2/LOUdsd2LfD9oXiMeuee8XsT0iRy5EvSccBgB4h/9HRbIo3MHgQ==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "camelcase": "5.2.0", + "chalk": "2.4.2", + "jest-get-type": "24.3.0", + "leven": "2.1.0", + "pretty-format": "24.5.0" + }, + "dependencies": { + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.5.0.tgz", + "integrity": "sha512-/hCpgR6bg0nKvD3nv4KasdTxuhwfViVMHUATJlnGCD0r1QrmIssimPbmc5KfAQblAVxkD8xrzuij9vfPUk1/rA==", + "dev": true, + "requires": { + "@jest/test-result": "24.5.0", + "@jest/types": "24.5.0", + "@types/node": "11.12.1", + "@types/yargs": "12.0.10", + "ansi-escapes": "3.2.0", + "chalk": "2.4.2", + "jest-util": "24.5.0", + "string-length": "2.0.0" + } + }, + "jest-worker": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.4.0.tgz", + "integrity": "sha512-BH9X/klG9vxwoO99ZBUbZFfV8qO0XNZ5SIiCyYK2zOuJBl6YJVAeNIQjcoOVNu4HGEHeYEKsUWws8kSlSbZ9YQ==", + "dev": true, + "requires": { + "@types/node": "11.12.1", + "merge-stream": "1.0.1", + "supports-color": "6.1.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "js-base64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", + "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "2.7.3" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "2.0.0", + "acorn": "5.7.3", + "acorn-globals": "4.3.0", + "array-equal": "1.0.0", + "cssom": "0.3.6", + "cssstyle": "1.2.2", + "data-urls": "1.1.0", + "domexception": "1.0.1", + "escodegen": "1.11.1", + "html-encoding-sniffer": "1.0.2", + "left-pad": "1.3.0", + "nwsapi": "2.1.2", + "parse5": "4.0.0", + "pn": "1.1.0", + "request": "2.88.0", + "request-promise-native": "1.0.7", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.5.0", + "w3c-hr-time": "1.0.1", + "webidl-conversions": "4.0.2", + "whatwg-encoding": "1.0.5", + "whatwg-mimetype": "2.3.0", + "whatwg-url": "6.5.0", + "ws": "5.2.2", + "xml-name-validator": "3.0.0" + } + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "kleur": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.2.tgz", + "integrity": "sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q==", + "dev": true + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.15", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "5.2.2", + "emojis-list": "2.1.0", + "json5": "1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "1.2.0" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + } + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "4.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.4" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "1.0.1" + } + }, + "marked": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==" + }, + "math-expression-evaluator": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", + "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "0.1.7", + "readable-stream": "2.3.6" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "requires": { + "readable-stream": "2.3.6" + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", + "dev": true + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "dev": true, + "requires": { + "mime-db": "1.38.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", + "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "dev": true, + "requires": { + "assert": "1.4.1", + "browserify-zlib": "0.2.0", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "domain-browser": "1.2.0", + "events": "3.0.0", + "https-browserify": "1.0.0", + "os-browserify": "0.3.0", + "path-browserify": "0.0.0", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.6", + "stream-browserify": "2.0.2", + "stream-http": "2.8.3", + "string_decoder": "1.1.1", + "timers-browserify": "2.0.10", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.11.1", + "vm-browserify": "0.0.4" + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", + "dev": true, + "requires": { + "growly": "1.3.0", + "is-wsl": "1.1.0", + "semver": "5.6.0", + "shellwords": "0.1.1", + "which": "1.3.1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "2.7.1", + "resolve": "1.10.0", + "semver": "5.6.0", + "validate-npm-package-license": "3.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "prepend-http": "1.0.4", + "query-string": "4.3.4", + "sort-keys": "1.1.2" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwsapi": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.2.tgz", + "integrity": "sha512-TQOQNxqEdxVjwgwNZyvKDF0vALmzQKZJEZwE3fZWDb7Ns5Hw6l9PxJTGKOHZGsmf7R6grsOe8lWxI43Clz79zg==", + "dev": true, + "requires": { + "jsdom": "14.0.0" + }, + "dependencies": { + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + }, + "jsdom": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.0.0.tgz", + "integrity": "sha512-/VkyPmdtbwqpJSkwDx3YyJ3U1oawYNB/h5z8vTUZGAzjtu2OHTeFRfnJqyMHsJ5Cyes23trOmvUpM1GfHH1leA==", + "dev": true, + "requires": { + "abab": "2.0.0", + "acorn": "6.1.1", + "acorn-globals": "4.3.0", + "array-equal": "1.0.0", + "cssom": "0.3.6", + "cssstyle": "1.2.2", + "data-urls": "1.1.0", + "domexception": "1.0.1", + "escodegen": "1.11.1", + "html-encoding-sniffer": "1.0.2", + "nwsapi": "2.1.2", + "parse5": "5.1.0", + "pn": "1.1.0", + "request": "2.88.0", + "request-promise-native": "1.0.7", + "saxes": "3.1.9", + "symbol-tree": "3.2.2", + "tough-cookie": "2.5.0", + "w3c-hr-time": "1.0.1", + "w3c-xmlserializer": "1.1.2", + "webidl-conversions": "4.0.2", + "whatwg-encoding": "1.0.5", + "whatwg-mimetype": "2.3.0", + "whatwg-url": "7.0.0", + "ws": "6.2.1", + "xml-name-validator": "3.0.0" + } + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "dev": true + }, + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "1.0.0" + } + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + } + } + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "3.0.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "1.1.3", + "es-abstract": "1.13.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "3.0.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.10", + "wordwrap": "0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pako": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz", + "integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==", + "dev": true + }, + "parse-asn1": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.3.tgz", + "integrity": "sha512-VrPoetlz7B/FqjBLD2f5wBVZvsZVLnRUrxVLfRYhGXCODa/NWE4p3Wp+6+aV3ZPL3KM7/OZmxDIwwijD7yuucg==", + "dev": true, + "requires": { + "asn1.js": "4.10.1", + "browserify-aes": "1.2.0", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.17", + "safe-buffer": "5.1.2" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.2" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "1.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "3.0.0", + "path-exists": "3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "2.1.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "2.2.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + } + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "popper.js": { + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz", + "integrity": "sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ==" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "1.1.3", + "js-base64": "2.5.1", + "source-map": "0.5.7", + "supports-color": "3.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "postcss-calc": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-message-helpers": "2.0.0", + "reduce-css-calc": "1.3.0" + } + }, + "postcss-colormin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", + "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", + "dev": true, + "requires": { + "colormin": "1.1.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-convert-values": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", + "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-discard-comments": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-duplicates": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", + "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-empty": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-overridden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-unused": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "uniqs": "2.0.0" + } + }, + "postcss-filter-plugins": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz", + "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-load-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", + "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", + "dev": true, + "requires": { + "cosmiconfig": "4.0.0", + "import-cwd": "2.1.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", + "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", + "dev": true, + "requires": { + "is-directory": "0.3.1", + "js-yaml": "3.13.0", + "parse-json": "4.0.0", + "require-from-string": "2.0.2" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "js-yaml": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.2", + "json-parse-better-errors": "1.0.2" + } + } + } + }, + "postcss-merge-idents": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", + "dev": true, + "requires": { + "has": "1.0.3", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-merge-longhand": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", + "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-merge-rules": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", + "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-api": "1.6.1", + "postcss": "5.2.18", + "postcss-selector-parser": "2.2.3", + "vendors": "1.0.2" + } + }, + "postcss-message-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", + "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=", + "dev": true + }, + "postcss-minify-font-values": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-minify-gradients": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-minify-params": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", + "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1", + "uniqs": "2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", + "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "has": "1.0.3", + "postcss": "5.2.18", + "postcss-selector-parser": "2.2.3" + } + }, + "postcss-modules": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-1.3.2.tgz", + "integrity": "sha512-QujH5ZpPtr1fBWTKDa43Hx45gm7p19aEtHaAtkMCBZZiB/D5za2wXSMtAf94tDUZHF3F5KZcTXISUNqgEQRiDw==", + "dev": true, + "requires": { + "css-modules-loader-core": "1.1.0", + "generic-names": "1.0.3", + "lodash.camelcase": "4.3.0", + "postcss": "7.0.14", + "string-hash": "1.1.3" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "postcss": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", + "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", + "dev": true, + "requires": { + "postcss": "6.0.23" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "5.5.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "dev": true, + "requires": { + "css-selector-tokenizer": "0.7.1", + "postcss": "6.0.23" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "5.5.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "dev": true, + "requires": { + "css-selector-tokenizer": "0.7.1", + "postcss": "6.0.23" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "5.5.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "dev": true, + "requires": { + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.23" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "5.5.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "postcss-normalize-charset": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-normalize-url": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", + "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", + "dev": true, + "requires": { + "is-absolute-url": "2.1.0", + "normalize-url": "1.9.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-ordered-values": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", + "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-reduce-idents": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", + "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-reduce-initial": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", + "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-reduce-transforms": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", + "dev": true, + "requires": { + "has": "1.0.3", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1" + } + }, + "postcss-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", + "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", + "dev": true, + "requires": { + "flatten": "1.0.2", + "indexes-of": "1.0.1", + "uniq": "1.0.1" + } + }, + "postcss-svgo": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", + "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", + "dev": true, + "requires": { + "is-svg": "2.1.0", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.1", + "svgo": "0.7.2" + } + }, + "postcss-unique-selectors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.18", + "uniqs": "2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "postcss-zindex": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", + "dev": true, + "requires": { + "has": "1.0.3", + "postcss": "5.2.18", + "uniqs": "2.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "pretty-format": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.5.0.tgz", + "integrity": "sha512-/3RuSghukCf8Riu5Ncve0iI+BzVkbRU5EeUoArKARZobREycuH5O4waxvaNIloEXdb0qwgmEAed5vTpX1HNROQ==", + "dev": true, + "requires": { + "@jest/types": "24.5.0", + "ansi-regex": "4.1.0", + "ansi-styles": "3.2.1", + "react-is": "16.8.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "react-is": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", + "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", + "dev": true + } + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "2.0.6" + } + }, + "prompts": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.0.4.tgz", + "integrity": "sha512-HTzM3UWp/99A0gk51gAegwo1QRYA7xjcZufMNe33rCclFszUYAuHe1fIN/3ZmiHeGPkUsNaRyQm1hHOfM0PKxA==", + "dev": true, + "requires": { + "kleur": "3.0.2", + "sisteransi": "1.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "react-is": "16.8.1" + } + }, + "prop-types-extra": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.0.tgz", + "integrity": "sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==", + "requires": { + "react-is": "16.8.1", + "warning": "3.0.0" + } + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "dev": true, + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "parse-asn1": "5.1.3", + "randombytes": "2.0.6", + "safe-buffer": "5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "1.4.1", + "once": "1.4.0" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", + "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "2.0.6", + "safe-buffer": "5.1.2" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": "2.1.2" + } + } + } + }, + "react": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.1.tgz", + "integrity": "sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==", + "requires": { + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "prop-types": "15.7.2", + "scheduler": "0.13.1" + } + }, + "react-bootstrap": { + "version": "1.0.0-beta.6", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.0.0-beta.6.tgz", + "integrity": "sha512-4RwXBCm45dHar1mMq7Wz8X9dI3b84R+Un696S+amgjePcxb6DqqqcxYla1FR7FJ+IIODr12HTjxu4LRVtIEsSQ==", + "requires": { + "@babel/runtime": "7.4.3", + "@react-bootstrap/react-popper": "1.2.1", + "@restart/context": "2.1.4", + "@restart/hooks": "0.1.6", + "classnames": "2.2.6", + "dom-helpers": "3.4.0", + "invariant": "2.2.4", + "keycode": "2.2.0", + "popper.js": "1.14.7", + "prop-types": "15.7.2", + "prop-types-extra": "1.1.0", + "react-overlays": "1.2.0", + "react-transition-group": "2.8.0", + "uncontrollable": "6.1.0", + "warning": "4.0.3" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz", + "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==", + "requires": { + "regenerator-runtime": "0.13.2" + } + }, + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "1.4.0" + } + } + } + }, + "react-context-toolbox": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-context-toolbox/-/react-context-toolbox-2.0.2.tgz", + "integrity": "sha512-tY4j0imkYC3n5ZlYSgFkaw7fmlCp3IoQQ6DxpqeNHzcD0hf+6V+/HeJxviLUZ1Rv1Yn3N3xyO2EhkkZwHn0m1A==" + }, + "react-datepicker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.1.0.tgz", + "integrity": "sha512-zsPqierShVc0NN+JCyJO18jMFDTbGNSgmekQm+Zr5JYH/aZShsjOBGQmjNiQmIw7nJNQDRzh1oQUND3TY/9Swg==", + "requires": { + "classnames": "2.2.6", + "date-fns": "2.0.0-alpha.27", + "prop-types": "15.7.2", + "react-onclickoutside": "6.8.0", + "react-popper": "1.3.3" + } + }, + "react-dom": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.1.tgz", + "integrity": "sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==", + "requires": { + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "prop-types": "15.7.2", + "scheduler": "0.13.1" + } + }, + "react-final-form": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-4.1.0.tgz", + "integrity": "sha512-O8p1EPQ/PFWNcX3bYGsLzuo/KnGeNfGfFi2UAX8jXLXrGcGdTfZMnyo/DFHdEKA9aKso61d/PHekQ9sst0cOmw==", + "requires": { + "@babel/runtime": "7.4.3" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz", + "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==", + "requires": { + "regenerator-runtime": "0.13.2" + } + }, + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" + } + } + }, + "react-final-form-arrays": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/react-final-form-arrays/-/react-final-form-arrays-2.0.3.tgz", + "integrity": "sha512-iHGGAbOVsTlp/lhE6EUsqzhjPZSvcExLWE91Qx0remHOJvQ2wkxHe8HTA9KBlId8YJ1fkz6g417GTq/1IFnL9w==", + "requires": { + "@babel/runtime": "7.4.3", + "react-lifecycles-compat": "3.0.4" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz", + "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==", + "requires": { + "regenerator-runtime": "0.13.2" + } + }, + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" + } + } + }, + "react-final-form-listeners": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-final-form-listeners/-/react-final-form-listeners-1.0.2.tgz", + "integrity": "sha512-AaUUHcXRhD3esC80yUfYPI8FJ3TUiMu0f4hk18QL8NMCWjokg6NWS32WkRJsH3bLWDoiy7+uNVOAAyO/XoupyA==", + "requires": { + "@babel/runtime": "7.3.1" + } + }, + "react-is": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.1.tgz", + "integrity": "sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA==" + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-onclickoutside": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.8.0.tgz", + "integrity": "sha512-5Q4Rn7QLEoh7WIe66KFvYIpWJ49GeHoygP1/EtJyZjXKgrWH19Tf0Ty3lWyQzrEEDyLOwUvvmBFSE3dcDdvagA==" + }, + "react-overlays": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-1.2.0.tgz", + "integrity": "sha512-i/FCV8wR6aRaI+Kz/dpJhOdyx+ah2tN1RhT9InPrexyC4uzf3N4bNayFTGtUeQVacj57j1Mqh1CwV60/5153Iw==", + "requires": { + "classnames": "2.2.6", + "dom-helpers": "3.4.0", + "prop-types": "15.7.2", + "prop-types-extra": "1.1.0", + "react-context-toolbox": "2.0.2", + "react-popper": "1.3.3", + "uncontrollable": "6.1.0", + "warning": "4.0.3" + }, + "dependencies": { + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "1.4.0" + } + } + } + }, + "react-popper": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.3.tgz", + "integrity": "sha512-ynMZBPkXONPc5K4P5yFWgZx5JGAUIP3pGGLNs58cfAPgK67olx7fmLp+AdpZ0+GoQ+ieFDa/z4cdV6u7sioH6w==", + "requires": { + "@babel/runtime": "7.3.1", + "create-react-context": "0.2.2", + "popper.js": "1.14.7", + "prop-types": "15.7.2", + "typed-styles": "0.0.7", + "warning": "4.0.3" + }, + "dependencies": { + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "1.4.0" + } + } + } + }, + "react-redux": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-6.0.0.tgz", + "integrity": "sha512-EmbC3uLl60pw2VqSSkj6HpZ6jTk12RMrwXMBdYtM6niq0MdEaRq9KYCwpJflkOZj349BLGQm1MI/JO1W96kLWQ==", + "requires": { + "@babel/runtime": "7.3.1", + "hoist-non-react-statics": "3.3.0", + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "prop-types": "15.7.2", + "react-is": "16.8.1" + } + }, + "react-router": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.0.0.tgz", + "integrity": "sha512-6EQDakGdLG/it2x9EaCt9ZpEEPxnd0OCLBHQ1AcITAAx7nCnyvnzf76jKWG1s2/oJ7SSviUgfWHofdYljFexsA==", + "requires": { + "@babel/runtime": "7.3.1", + "create-react-context": "0.2.2", + "history": "4.9.0", + "hoist-non-react-statics": "3.3.0", + "loose-envify": "1.4.0", + "path-to-regexp": "1.7.0", + "prop-types": "15.7.2", + "react-is": "16.8.1", + "tiny-invariant": "1.0.3", + "tiny-warning": "1.0.2" + }, + "dependencies": { + "history": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/history/-/history-4.9.0.tgz", + "integrity": "sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==", + "requires": { + "@babel/runtime": "7.3.1", + "loose-envify": "1.4.0", + "resolve-pathname": "2.2.0", + "tiny-invariant": "1.0.3", + "tiny-warning": "1.0.2", + "value-equal": "0.4.0" + } + } + } + }, + "react-router-dom": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.0.0.tgz", + "integrity": "sha512-wSpja5g9kh5dIteZT3tUoggjnsa+TPFHSMrpHXMpFsaHhQkm/JNVGh2jiF9Dkh4+duj4MKCkwO6H08u6inZYgQ==", + "requires": { + "@babel/runtime": "7.3.1", + "history": "4.9.0", + "loose-envify": "1.4.0", + "prop-types": "15.7.2", + "react-router": "5.0.0", + "tiny-invariant": "1.0.3", + "tiny-warning": "1.0.2" + }, + "dependencies": { + "history": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/history/-/history-4.9.0.tgz", + "integrity": "sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==", + "requires": { + "@babel/runtime": "7.3.1", + "loose-envify": "1.4.0", + "resolve-pathname": "2.2.0", + "tiny-invariant": "1.0.3", + "tiny-warning": "1.0.2", + "value-equal": "0.4.0" + } + } + } + }, + "react-transition-group": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.8.0.tgz", + "integrity": "sha512-So23a1MPn8CGoW5WNU4l0tLiVkOFmeXSS1K4Roe+dxxqqHvI/2XBmj76jx+u96LHnQddWG7LX8QovPAainSmWQ==", + "requires": { + "dom-helpers": "3.4.0", + "loose-envify": "1.4.0", + "prop-types": "15.7.2", + "react-lifecycles-compat": "3.0.4" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.5.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "4.1.15", + "micromatch": "3.1.10", + "readable-stream": "2.3.6" + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "1.0.0" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "math-expression-evaluator": "1.2.17", + "reduce-function-call": "1.0.2" + } + }, + "reduce-function-call": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "dev": true, + "requires": { + "balanced-match": "0.4.2" + } + }, + "redux": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", + "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", + "requires": { + "loose-envify": "1.4.0", + "symbol-observable": "1.2.0" + } + }, + "redux-devtools-extension": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz", + "integrity": "sha1-4Pmo6N/KfBe+kscSSVijuU6ykR0=", + "dev": true + }, + "redux-form": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-8.1.0.tgz", + "integrity": "sha512-d2+0OaJpSq3kwkbPtFlG3W/HENWLxX8NqqTHSOnfgIrID/9faH/rxejLa1X3HChilCTm71zWe/g9zaLPCMCofQ==", + "requires": { + "@babel/runtime": "7.3.1", + "es6-error": "4.1.1", + "hoist-non-react-statics": "3.3.0", + "invariant": "2.2.4", + "is-promise": "2.1.0", + "prop-types": "15.7.2", + "react-is": "16.8.1", + "react-lifecycles-compat": "3.0.4" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "16.8.1" + } + } + } + }, + "redux-form-website-template": { + "version": "0.0.41", + "resolved": "https://registry.npmjs.org/redux-form-website-template/-/redux-form-website-template-0.0.41.tgz", + "integrity": "sha1-Zg/TgYrgFKXp86dnhG2GKP0BdIY=", + "requires": { + "babel-polyfill": "6.26.0", + "classnames": "2.2.6", + "marked": "0.3.19", + "react": "15.6.2", + "react-dom": "15.6.2", + "react-redux": "4.4.9", + "redux": "3.7.2", + "redux-form": "6.2.1" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + }, + "react": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/react/-/react-15.6.2.tgz", + "integrity": "sha1-26BDSrQ5z+gvEI8PURZjkIF5qnI=", + "requires": { + "create-react-class": "15.6.3", + "fbjs": "0.8.17", + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "prop-types": "15.7.2" + } + }, + "react-dom": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.2.tgz", + "integrity": "sha1-Qc+t9pO3V/rycIRDodH9WgK+9zA=", + "requires": { + "fbjs": "0.8.17", + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "prop-types": "15.7.2" + } + }, + "react-redux": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.9.tgz", + "integrity": "sha512-3XS7mjTOcvaP2H5OE/LxEgDHRuEyTZxBRlwvXHzNqYkZdYd7Ra98AimWoDSHP9OcLoydjA1ocgiZxxcqeXj0Sw==", + "requires": { + "create-react-class": "15.6.3", + "hoist-non-react-statics": "2.5.5", + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "prop-types": "15.7.2" + } + }, + "redux-form": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-6.2.1.tgz", + "integrity": "sha1-WZb5tkjisrwgEq2y3qA7mZfc8P8=", + "requires": { + "array-findindex-polyfill": "0.1.0", + "deep-equal": "1.0.1", + "es6-error": "4.1.1", + "hoist-non-react-statics": "1.2.0", + "invariant": "2.2.4", + "is-promise": "2.1.0", + "shallowequal": "0.2.2" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", + "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=" + } + } + } + } + }, + "redux-thunk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.2.0.tgz", + "integrity": "sha1-5hWhbha0ehmlFXZhM9Hj6Zt4UuU=" + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" + } + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "1.4.0", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.8.0", + "caseless": "0.12.0", + "combined-stream": "1.0.7", + "extend": "3.0.2", + "forever-agent": "0.6.1", + "form-data": "2.3.3", + "har-validator": "5.1.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.22", + "oauth-sign": "0.9.0", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.4.3", + "tunnel-agent": "0.6.0", + "uuid": "3.3.2" + }, + "dependencies": { + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "1.1.31", + "punycode": "1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "dev": true + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "dev": true, + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "1.1.1", + "tough-cookie": "2.5.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, + "requires": { + "glob": "7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + } + }, + "rsvp": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz", + "integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "0.1.15" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "1.0.3", + "anymatch": "2.0.0", + "capture-exit": "2.0.0", + "exec-sh": "0.3.2", + "execa": "1.0.0", + "fb-watchman": "2.0.0", + "micromatch": "3.1.10", + "minimist": "1.2.0", + "walker": "1.0.7" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.6.0", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "3.0.0" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "saxes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.9.tgz", + "integrity": "sha512-FZeKhJglhJHk7eWG5YM0z46VHmI3KJpMBAQm3xa9meDvd+wevB5GuBB0wc0exPInZiBBHqi00DbS8AcvCGCFMw==", + "dev": true, + "requires": { + "xmlchars": "1.3.1" + } + }, + "scheduler": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.1.tgz", + "integrity": "sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==", + "requires": { + "loose-envify": "1.4.0", + "object-assign": "4.1.1" + } + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "5.5.2" + } + }, + "seamless-immutable": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/seamless-immutable/-/seamless-immutable-7.1.4.tgz", + "integrity": "sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==" + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.3", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.4.0" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.2" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.2" + } + }, + "shallowequal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz", + "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=", + "requires": { + "lodash.keys": "3.1.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sisteransi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz", + "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.2", + "use": "3.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "2.1.2", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.3" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "2.2.0", + "spdx-license-ids": "3.0.3" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "3.0.2" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "0.2.4", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.2", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" + } + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "0.2.5", + "object-copy": "0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.6" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "1.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "style-inject": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", + "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", + "dev": true + }, + "style-loader": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.18.2.tgz", + "integrity": "sha512-WPpJPZGUxWYHWIUMNNOYqql7zh85zGmr84FdTVWq52WTIkqlW9xSxD3QYWi/T31cqn9UNSsietVEgGn2aaSCzw==", + "dev": true, + "requires": { + "loader-utils": "1.2.3", + "schema-utils": "0.3.0" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "1.0.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "tapable": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", + "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", + "dev": true + }, + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", + "dev": true, + "requires": { + "arrify": "1.0.1", + "minimatch": "3.0.4", + "read-pkg-up": "4.0.0", + "require-main-filename": "1.0.1" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "3.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "4.1.15", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "3.0.0", + "path-exists": "3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "2.1.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "2.2.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.2", + "json-parse-better-errors": "1.0.2" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "4.0.0", + "normalize-package-data": "2.5.0", + "path-type": "3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "3.0.0", + "read-pkg": "3.0.0" + } + } + } + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "1.0.5" + } + }, + "tiny-invariant": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.3.tgz", + "integrity": "sha512-ytQx8T4DL8PjlX53yYzcIC0WhIZbpR0p1qcYjw2pHu3w6UtgWwFJQ/02cnhOnBBhlFx/edUIfcagCaQSe3KMWg==" + }, + "tiny-warning": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.2.tgz", + "integrity": "sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q==" + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "repeat-string": "1.6.1" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "1.1.31", + "punycode": "2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-jest": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.0.0.tgz", + "integrity": "sha512-o8BO3TkMREpAATaFTrXkovMsCpBl2z4NDBoLJuWZcJJj1ijI49UnvDMfVpj+iogn/Jl8Pbhuei5nc/Ti+frEHw==", + "dev": true, + "requires": { + "bs-logger": "0.2.6", + "buffer-from": "1.1.1", + "fast-json-stable-stringify": "2.0.0", + "json5": "2.1.0", + "make-error": "1.3.5", + "mkdirp": "0.5.1", + "resolve": "1.10.0", + "semver": "5.6.0", + "yargs-parser": "10.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "1.2.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "ts-loader": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-3.5.0.tgz", + "integrity": "sha512-JTia3kObhTk36wPFgy0RnkZReiusYx7Le9IhcUWRrCTcFcr6Dy1zGsFd3x8DG4gevlbN65knI8W50FfoykXcng==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "enhanced-resolve": "3.4.1", + "loader-utils": "1.2.3", + "micromatch": "3.1.10", + "semver": "5.6.0" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.22" + } + }, + "typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + }, + "typescript": { + "version": "3.3.3333", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz", + "integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.19", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", + "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-js": "2.8.29", + "webpack-sources": "1.3.0" + } + }, + "uncontrollable": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-6.1.0.tgz", + "integrity": "sha512-2TzEm0pLKauMBZfAZXsgQvLpZHEp95891frCZdGDrSG7dWYaIQhedwLAzi0X8pR8KHNqlmuYEb2cEgbQzr050A==", + "requires": { + "invariant": "2.2.4" + } + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "0.3.1", + "isobject": "3.0.1" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "1.1.3", + "object.getownpropertydescriptors": "2.0.3" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "3.1.0", + "spdx-expression-parse": "3.0.0" + } + }, + "value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", + "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "0.1.3" + } + }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "dev": true, + "requires": { + "domexception": "1.0.1", + "webidl-conversions": "4.0.2", + "xml-name-validator": "3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.11" + } + }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "1.4.0" + } + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "2.1.0", + "graceful-fs": "4.1.15", + "neo-async": "2.6.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "webpack": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.4.1.tgz", + "integrity": "sha1-TD9PP7MYFVpNsMtqNv8FxWl0GPQ=", + "dev": true, + "requires": { + "acorn": "5.7.3", + "acorn-dynamic-import": "2.0.2", + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "async": "2.6.1", + "enhanced-resolve": "3.4.1", + "escope": "3.6.0", + "interpret": "1.2.0", + "json-loader": "0.5.7", + "json5": "0.5.1", + "loader-runner": "2.4.0", + "loader-utils": "1.2.3", + "memory-fs": "0.4.1", + "mkdirp": "0.5.1", + "node-libs-browser": "2.2.0", + "source-map": "0.5.7", + "supports-color": "4.5.0", + "tapable": "0.2.9", + "uglifyjs-webpack-plugin": "0.4.6", + "watchpack": "1.6.0", + "webpack-sources": "1.3.0", + "yargs": "8.0.2" + } + }, + "webpack-dev-middleware": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.11.0.tgz", + "integrity": "sha1-CWkdCXOjCtH4Ksc6EuIIfwpHVPk=", + "dev": true, + "requires": { + "memory-fs": "0.4.1", + "mime": "1.4.1", + "path-is-absolute": "1.0.1", + "range-parser": "1.2.0" + } + }, + "webpack-hot-middleware": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.18.2.tgz", + "integrity": "sha512-dB7uOnUWsojZIAC6Nwi5v3tuaQNd2i7p4vF5LsJRyoTOgr2fRYQdMKQxRZIZZaz0cTPBX8rvcWU1A6/n7JTITg==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "html-entities": "1.2.1", + "querystring": "0.2.0", + "strip-ansi": "3.0.1" + } + }, + "webpack-sources": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", + "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "dev": true, + "requires": { + "source-list-map": "2.0.1", + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" + } + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "4.1.15", + "imurmurhash": "0.1.4", + "signal-exit": "3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "1.0.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz", + "integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.3", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + } + } +} diff --git a/AnimalRequests/package.json b/AnimalRequests/package.json new file mode 100644 index 000000000..c86c2182c --- /dev/null +++ b/AnimalRequests/package.json @@ -0,0 +1,103 @@ +{ + "name": "animalrequests", + "version": "1.0.0", + "description": "Animal request data entry form", + "main": "index.js", + "scripts": { + "build": "better-npm-run build-prod", + "build-prod": "better-npm-run build-prod", + "build-style": "npm run build-style", + "start": "better-npm-run build-style && better-npm-run build-watch", + "clean": "better-npm-run clean", + "reallyClean": "better-npm-run reallyClean", + "test": "better-npm-run build-jest-test" + }, + "author": "csebranek", + "license": "Apache 2.0", + "dependencies": { + "@types/react": "15.6.0", + "@types/react-bootstrap": "0.32.17", + "@types/react-dom": "15.5.1", + "@types/react-redux": "7.0.3", + "@types/react-router": "4.0.14", + "@types/react-router-dom": "4.3.1", + "@types/redux-actions": "1.2.7", + "@types/redux-form": "6.6.2", + "react": "16.8.1", + "react-dom": "16.8.1", + "@babel/polyfill": "7.4.0", + "redux": "3.7.2", + "react-redux": "6.0.0", + "redux-form": "8.1.0", + "history": "4.7.2", + "react-router-dom": "5.0.0", + "react-router": "5.0.0", + "connected-react-router": "6.3.2", + "redux-thunk": "2.2.0", + "react-bootstrap": "1.0.0-beta.6", + "react-datepicker": "2.1.0", + "moment": "2.24.0", + "redux-form-website-template": "0.0.41", + "react-final-form": "4.1.0", + "react-final-form-arrays": "2.0.3", + "final-form": "4.12.0", + "final-form-arrays": "1.1.2", + "final-form-set-field-data": "1.0.2", + "react-final-form-listeners": "1.0.2", + "bootstrap": "3.4.1" + }, + "devDependencies": { + "@types/jest": "24.0.11", + "better-npm-run": "0.0.15", + "webpack": "3.4.1", + "extract-text-webpack-plugin": "3.0.0", + "typescript": "3.3.3333", + "ts-loader": "3.5.0", + "css-loader": "0.28.7", + "style-loader": "0.18.2", + "babel-loader": "8.0.5", + "@babel/core": "7.4.0", + "redux-devtools-extension": "2.13.2", + "rimraf": "2.6.1", + "express": "4.16.4", + "express-http-proxy": "1.5.1", + "cors": "2.8.5", + "webpack-dev-middleware": "1.11.0", + "webpack-hot-middleware": "2.18.2", + "jest": "24.5.0", + "ts-jest": "24.0.0", + "babel-preset-es2015": "6.24.1", + "@babel/preset-react": "7.0.0", + "@babel/preset-typescript": "7.3.3", + "jest-transform-css": "2.0.0" + }, + "betterScripts": { + "build-prod": { + "command": "webpack --config webpack/prod.config.js", + "env": { + "NODE_ENV": "production" + } + }, + "build-style": { + "command": "webpack --config webpack/dev-style.config.js", + "env": { + "NODE_ENV": "development" + } + }, + "build-watch": { + "command": "node webpack/dev-server.js", + "env": { + "NODE_ENV": "development" + } + }, + "clean": { + "command": "rimraf resources/web/animalrequest/app/ ; rimraf node_modules" + }, + "build-jest-test": { + "command": "jest", + "env": { + "NODE_ENV": "test" + } + } + } +} diff --git a/AnimalRequests/resources/views/app.html b/AnimalRequests/resources/views/app.html new file mode 100644 index 000000000..6c217c628 --- /dev/null +++ b/AnimalRequests/resources/views/app.html @@ -0,0 +1 @@ +
diff --git a/AnimalRequests/resources/views/app.view.xml b/AnimalRequests/resources/views/app.view.xml new file mode 100644 index 000000000..40f5f6488 --- /dev/null +++ b/AnimalRequests/resources/views/app.view.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/AnimalRequests/src/__tests__/main.test.tsx b/AnimalRequests/src/__tests__/main.test.tsx new file mode 100644 index 000000000..d407cc4ab --- /dev/null +++ b/AnimalRequests/src/__tests__/main.test.tsx @@ -0,0 +1,18 @@ +import { + overrideAFieldValue +} from '../client/query/helpers' + + +it('overrideAFieldValue: should replace val1 with val2', () => { + const initialValues = {}; + initialValues['val1'] = 0; + initialValues['val2'] = 1; + + const expectedValues = {}; + expectedValues['val1'] = 1; + expectedValues['val2'] = 1; + + expect(overrideAFieldValue(initialValues,'val2','val1')).toEqual(expectedValues); +}); + +//TODO check that we can get the right content using mock data object diff --git a/AnimalRequests/src/client/app.tsx b/AnimalRequests/src/client/app.tsx new file mode 100644 index 000000000..566f486c6 --- /dev/null +++ b/AnimalRequests/src/client/app.tsx @@ -0,0 +1,12 @@ + +import * as React from 'react'; +import * as ReactDom from 'react-dom'; + +import {AnimalRequestForm} from "./containers/Forms/AnimalRequestForm"; + +jQuery(() => { + ReactDom.render( + , + document.getElementById('app') + ); +}); diff --git a/AnimalRequests/src/client/containers/Forms/AnimalRequestForm.tsx b/AnimalRequests/src/client/containers/Forms/AnimalRequestForm.tsx new file mode 100644 index 000000000..8cdd909b9 --- /dev/null +++ b/AnimalRequests/src/client/containers/Forms/AnimalRequestForm.tsx @@ -0,0 +1,423 @@ +import React from 'react'; +import DatePicker from 'react-datepicker'; + +import { Form, Field } from 'react-final-form' +import arrayMutators from 'final-form-arrays' +import setFieldData from 'final-form-set-field-data'; +import { OnChange } from 'react-final-form-listeners'; + +import { + submitAnimalRequest +} from '../../query/helpers'; +import {getEHRData} from '../../query/actions'; + +const required = value => (value ? undefined : ❗️); + +const renderField = ({ + input, label, warnings, tooltip, type, + meta: { touched, error, warning, asyncValidating } + }) => ( +
+
+ + + {touched && ((error && {error}))} +
+
+); + +const renderDateTimePicker = ({ input : {onChange, value}}) => ( + +); + +interface State { + loading: boolean; + submitted: boolean; + uniqueProtocolInvestigator: Array; + animal_requests_viral_status: Array; + animal_requests_origin: Array; + animal_requests_species: Array; + animal_requests_sex: Array; + animal_requests_active_projects: Array; + protocol: Array; + animal_requests_disposition: Array; + animal_requests_infectiousdisease: Array; + dataArr: Array; +} + +export class AnimalRequestForm extends React.Component { + constructor() { + super(); + //this has to be an array of promises + const dataArr = [ + getEHRData('ehr','uniqueProtocolInvestigator'), + getEHRData('ehr_lookups','animal_requests_viral_status'), + getEHRData('ehr_lookups','animal_requests_origin','meaning'), + getEHRData('ehr_lookups','animal_requests_species','common'), + getEHRData('ehr_lookups','animal_requests_sex'), + getEHRData('ehr_lookups','animal_requests_active_projects','-project','project,enddate'), + getEHRData('ehr','protocol','-protocol'), + getEHRData('ehr_lookups','animal_requests_disposition'), + getEHRData('ehr_lookups','animal_requests_infectiousdisease') + ]; + + this.state = { + loading: true, + submitted: false, + uniqueProtocolInvestigator: [{value: ''}], + animal_requests_viral_status: [{value: ''}], + animal_requests_origin: [{value: ''}], + animal_requests_species: [{value: ''}], + animal_requests_sex: [{value: ''}], + animal_requests_active_projects: [{value: ''}], + protocol: [{value: ''}], + animal_requests_disposition: [{value: ''}], + animal_requests_infectiousdisease: [{value: ''}], + dataArr: dataArr + }; + this.onSubmit = this.onSubmit.bind(this); + this.getSeveralEHRData = this.getSeveralEHRData.bind(this); + } + + + async componentDidMount() { + this.getSeveralEHRData(this.state.dataArr) + } + + getSeveralEHRData(dataArr) { + //fetch and save the data for the dropdown options to our component state + Promise.all(dataArr).then((data) => { + console.log(data); + for (let val of data) { + //TODO remove ts-ignore + //@ts-ignore + this.setState({[val['queryName']]: val['rows']}); + } + }).then(() => { + this.setState({loading:false}); + console.log('All values set!') + }); + }; + + async onSubmit(values) { + + this.setState({submitted: true}); + const QCState = 5; + + submitAnimalRequest(values,QCState) + .then(data => { + let redirectUrl = LABKEY.ActionURL.buildURL('wnprc_ehr','dataEntry.view',LABKEY.Security.currentContainer.path); + window.location = redirectUrl; + }).catch((err) => { + console.log(err.exception) + } + ); + } + + + + render() { + + //component to render dropdowns + const DropdownOptions = ({name,rowkey}) => { + return ( + <> + {this.state[name] && this.state[name].map((x,index) => { + return ( + + ) + })} + + ) + }; + + //component to conditionally render a text input + const Condition = ({ when, is, children }) => ( + + {({ input: { value } }) => (value === is ? children : null)} + + ); + + const loading = this.state.loading; + const submitted = this.state.submitted===true ? 'form-submitted' : ''; + const display = this.state.loading===true ? 'none' : 'block'; + const cancelUrl = LABKEY.ActionURL.buildURL('wnprc_ehr','dataEntry.view','/WNPRC/EHR'); + const formDescription = 'Note: All fields are required except for Account and Comments fields. ' + + 'If there is not yet an existing project and or protocol associated with this animal request, ' + + 'choose "TBD" as the dropdown option and place an explanation in the Comments field.' + + return ( +
{ + return ( +
+
+
+ + + {loading &&
} +
+
+ + + +
+ + + + + + +
+ + + +
+
+ + + +
+
+ + + +
+ + + + + + +
+ + + +
+
+ + + +
+
+ + + +
+
+ + {/*We have to render the datepicker like this because it won't cooperate + And we also have to do some not-so-sexy css adjustments */} +
+ + + +
+
+
+ + + + + +
+
+ + + + + +
+
+ + + +
+
+ + + +
+
+
+
+ + +
+
+
+

{formDescription}

+ + +
+
+
+ ) + } + } + > + + ) + } +} + diff --git a/AnimalRequests/src/client/query/actions.ts b/AnimalRequests/src/client/query/actions.ts new file mode 100644 index 000000000..0de9676df --- /dev/null +++ b/AnimalRequests/src/client/query/actions.ts @@ -0,0 +1,56 @@ +//Expects json row data with commands property, see API docs for saveRows +export const saveRowsDirect = (jsonData) => { + return new Promise((resolve, reject) => { + LABKEY.Query.saveRows({ + commands: jsonData.commands, + method: 'POST', + containerPath: '/WNPRC/EHR', + success: (data) => { + resolve(data); + }, + failure: (data) => { + reject(data); + } + + }) + }) +}; + +//returns a promise to get data from labkey +export const getEHRData = (schemaName,queryName,sort='rowid',columns='',filterArray=[]):any => { + return new Promise((resolve, reject) => { + return LABKEY.Query.selectRows({ + schemaName: schemaName, + queryName: queryName, + columns: columns, + sort: sort, + containerPath:'/WNPRC/EHR', + filterArray: filterArray, + success: (data) => { + resolve(data) + }, + failure: (data) => { + reject(data); + } + + }); + }); +}; + +//TODO need to use a specific queryname and make it an sql file? +export const selectRowsSql = (id) => { + return new Promise((resolve, reject) => { + return LABKEY.Query.selectRows({ + schemaName: 'study', + queryName: 'demographicWeightChange', + columns: 'participantid,weight', + success: (data) => { + resolve(data); + }, + failure: (data) => { + reject(data); + } + + }); + }); +}; diff --git a/AnimalRequests/src/client/query/helpers.ts b/AnimalRequests/src/client/query/helpers.ts new file mode 100644 index 000000000..a0762311c --- /dev/null +++ b/AnimalRequests/src/client/query/helpers.ts @@ -0,0 +1,52 @@ +import {saveRowsDirect} from "./actions"; +import moment from 'moment'; + +//helper method to swap two fields (usecase: user input under a "dropdown" conditional select): +// https://github.com/final-form/react-final-form#conditional-fields +export const overrideAFieldValue = (values:Object, sourceField:string, destinationField:string) => { + values[destinationField] = values[sourceField]; + return values; +}; + +//TODO +export const createTask = (config) => { + //here this job is to run the saveRows query for the task.. just for an insert + +}; + +export const submitAnimalRequest = (values:Object, qcstate:number) => { + let currentDate = moment(new Date()).format(); + let weightValToInsert = []; + let jsonData; + //we need to copy the values before the insert because if we update the values of the form then it messes it up + let valuesToBeInserted = {...values}; + + valuesToBeInserted['date'] = currentDate; + valuesToBeInserted['QCState'] = qcstate; + + //replace the principalinvestigator (PI) field if there's custom input from an external PI + if (valuesToBeInserted['externalprincipalinvestigator']) { + let sourceField = 'externalprincipalinvestigator'; + let destinationField = 'principalinvestigator'; + let newvalues = overrideAFieldValue(valuesToBeInserted, sourceField, destinationField); + valuesToBeInserted = newvalues; + } + + weightValToInsert.push(valuesToBeInserted); + + jsonData = + { + commands: + [ + { + schemaName: "wnprc", + queryName: "animal_requests", + command: "insert", + rows: weightValToInsert + } + ], + }; + return saveRowsDirect(jsonData); +}; + + diff --git a/AnimalRequests/src/client/theme/css/bootstrap.min.css b/AnimalRequests/src/client/theme/css/bootstrap.min.css new file mode 100755 index 000000000..687f9cc09 --- /dev/null +++ b/AnimalRequests/src/client/theme/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.4/customize/) + *//*! + * Bootstrap v3.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{color:#000 !important;text-shadow:none !important;background:transparent !important;-webkit-box-shadow:none !important;box-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{text-decoration:none}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.row-no-gutters{margin-right:0;margin-left:0}.row-no-gutters [class*="col-"]{padding-right:0;padding-left:0}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}table col[class*="col-"]{position:static;display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{position:static;display:table-cell;float:none}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;appearance:none}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"].form-control,input[type="time"].form-control,input[type="datetime-local"].form-control,input[type="month"].form-control{line-height:34px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm,.input-group-sm input[type="date"],.input-group-sm input[type="time"],.input-group-sm input[type="datetime-local"],.input-group-sm input[type="month"]{line-height:30px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg,.input-group-lg input[type="date"],.input-group-lg input[type="time"],.input-group-lg input[type="datetime-local"],.input-group-lg input[type="month"]{line-height:46px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm textarea.form-control,.form-group-sm select[multiple].form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg textarea.form-control,.form-group-lg select[multiple].form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback,.input-group-lg+.form-control-feedback,.form-group-lg .form-control+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback,.input-group-sm+.form-control-feedback,.form-group-sm .form-control+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;-o-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid \9;border-right:4px solid transparent;border-left:4px solid transparent}.dropup,.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid \9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#c7ddef}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,button.list-group-item-success:hover,a.list-group-item-success:focus,button.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,button.list-group-item-success.active,a.list-group-item-success.active:hover,button.list-group-item-success.active:hover,a.list-group-item-success.active:focus,button.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,button.list-group-item-info:hover,a.list-group-item-info:focus,button.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,button.list-group-item-info.active,a.list-group-item-info.active:hover,button.list-group-item-info.active:hover,a.list-group-item-info.active:focus,button.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,button.list-group-item-warning:hover,a.list-group-item-warning:focus,button.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,button.list-group-item-warning.active,a.list-group-item-warning.active:hover,button.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus,button.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,button.list-group-item-danger:hover,a.list-group-item-danger:focus,button.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,button.list-group-item-danger.active,a.list-group-item-danger.active:hover,button.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus,button.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-right:15px;padding-left:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform 0.3s ease-out;-o-transition:-o-transform 0.3s ease-out;transition:transform 0.3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:12px;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:14px;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover>.arrow{border-width:11px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform 0.6s ease-in-out;-o-transition:-o-transform 0.6s ease-in-out;transition:transform 0.6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.next,.carousel-inner>.item.active.right{-webkit-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);left:0}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{-webkit-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-webkit-gradient(linear, left top, right top, color-stop(0, rgba(0,0,0,0.5)), to(rgba(0,0,0,0.0001)));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-webkit-gradient(linear, left top, right top, color-stop(0, rgba(0,0,0,0.0001)), to(rgba(0,0,0,0.5)));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;outline:0;filter:alpha(opacity=90);opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:"\2039"}.carousel-control .icon-next:before{content:"\203a"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:20px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.panel-body:before,.panel-body:after,.modal-header:before,.modal-header:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.panel-body:after,.modal-header:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}} \ No newline at end of file diff --git a/AnimalRequests/src/client/theme/css/index.css b/AnimalRequests/src/client/theme/css/index.css new file mode 100644 index 000000000..f8ea676a2 --- /dev/null +++ b/AnimalRequests/src/client/theme/css/index.css @@ -0,0 +1,154 @@ +.content-wrapper { + margin-bottom: 20px; + background-color: #FFFFFF; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + padding: 15px; + max-width: 620px; + margin-left: 20px; +} + +.card.content-wrapper { + border-radius: 5px; + padding-bottom: 0; + border: 5px solid #edebe0; +} + +.content-wrapper-body { + padding: 15px; +} + +.form-wrapper { + max-width: 600px; +} + +/*override some datepicker css to get it to line up with the other fields*/ +.react-datepicker-wrapper { + width: 100%; +} + +.react-datepicker__input-container { + width: 100%; +} + +.react-datepicker__input-container > input { + width: 100%; + min-height: 1px; + height: 27px; + border: 1px solid rgb(166,166,166); + border-image: initial; + padding-left: 15px; + padding-right: 15px; +} + +#datepicker { + padding-left: 0; + padding-right: 0; +} +/**/ + +.form-wrapper-custom { + max-width: 500px; + padding-left: 15px; + padding-right: 15px; +} + +.remove-record-button { + float: right; + margin-left: 0px; +} + +.remove-record-button { + margin-left: 0px; + float: right; + background-color: #e0e0e0; + border: none; + font-size: 2rem; +} + +.card-body { + margin-bottom: 1rem; +} + +.btn-wrap { + display: inline-flex; + float: right; + margin-right: 15px; +} + +.custom-submit { + margin-right: 5px; +} + +.form-control-textarea { + height: 100px; + border: 1px solid rgb(166,166,166); +} + +.form-control-input { + height: 27px; + border: 1px solid rgb(166,166,166); +} + +.form-control-label { + line-height: 27px; + text-align: right; +} + +.top-buffer { + padding-top: 5px; +} + +/*css for select dropdown boxes since they look bad on safari by default*/ +.select { + position: relative; + height: 47.5px; + background: white; + box-shadow: 0 3px 0 rgba(0, 0, 0, .05); +} + +select { + font-size: 14px; + border: none; + box-shadow: none; + border-radius: 0; + background: transparent; + height: 100%; + width: 100%; + cursor: pointer; + outline: none; + padding-right: 35px; + padding-left: 15px; + border: 1px solid rgb(166, 166, 166); + border-radius: 1px; + -moz-appearance: none; + -webkit-appearance: none; + background: url(/_images/arrow_down.png) right no-repeat !important; + text-transform: Capitalize !important; + +} +/**/ + +.loading { + text-align: center; + display: block; + position: relative; + background: url(/_images/ajax-loading.gif) left no-repeat !important; + background-size: fill; + font-size: 2em; + padding: 20px 0 0 0; + z-index: 3; +} + +#help-tooltip { + font-size: 12px; + top: 0px; +} + +.form-submitted { + cursor:wait !important; +} + +.project-nav ul li { + height: 25px; +} \ No newline at end of file diff --git a/AnimalRequests/src/client/theme/css/react-datepicker.css b/AnimalRequests/src/client/theme/css/react-datepicker.css new file mode 100644 index 000000000..29a7f8468 --- /dev/null +++ b/AnimalRequests/src/client/theme/css/react-datepicker.css @@ -0,0 +1,651 @@ +.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow, +.react-datepicker__month-read-view--down-arrow, +.react-datepicker__month-year-read-view--down-arrow { + margin-left: -8px; + position: absolute; +} + +.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow, +.react-datepicker__month-read-view--down-arrow, +.react-datepicker__month-year-read-view--down-arrow, .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before, +.react-datepicker__month-read-view--down-arrow::before, +.react-datepicker__month-year-read-view--down-arrow::before { + box-sizing: content-box; + position: absolute; + border: 8px solid transparent; + height: 0; + width: 1px; +} + +.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before, +.react-datepicker__month-read-view--down-arrow::before, +.react-datepicker__month-year-read-view--down-arrow::before { + content: ""; + z-index: -1; + border-width: 8px; + left: -8px; + border-bottom-color: #aeaeae; +} + +.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle { + top: 0; + margin-top: -8px; +} + +.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle, .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before { + border-top: none; + border-bottom-color: #f0f0f0; +} + +.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before { + top: -1px; + border-bottom-color: #aeaeae; +} + +.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow, +.react-datepicker__month-read-view--down-arrow, +.react-datepicker__month-year-read-view--down-arrow { + bottom: 0; + margin-bottom: -8px; +} + +.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow, +.react-datepicker__month-read-view--down-arrow, +.react-datepicker__month-year-read-view--down-arrow, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before, +.react-datepicker__month-read-view--down-arrow::before, +.react-datepicker__month-year-read-view--down-arrow::before { + border-bottom: none; + border-top-color: #fff; +} + +.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before, +.react-datepicker__month-read-view--down-arrow::before, +.react-datepicker__month-year-read-view--down-arrow::before { + bottom: -1px; + border-top-color: #aeaeae; +} + +.react-datepicker-wrapper { + display: inline-block; +} + +.react-datepicker { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 0.8rem; + background-color: #fff; + color: #000; + border: 1px solid #aeaeae; + border-radius: 0.3rem; + display: inline-block; + position: relative; +} + +.react-datepicker--time-only .react-datepicker__triangle { + left: 35px; +} + +.react-datepicker--time-only .react-datepicker__time-container { + border-left: 0; +} + +.react-datepicker--time-only .react-datepicker__time { + border-radius: 0.3rem; +} + +.react-datepicker--time-only .react-datepicker__time-box { + border-radius: 0.3rem; +} + +.react-datepicker__triangle { + position: absolute; + left: 50px; +} + +.react-datepicker-popper { + z-index: 1; +} + +.react-datepicker-popper[data-placement^="bottom"] { + margin-top: 10px; +} + +.react-datepicker-popper[data-placement^="top"] { + margin-bottom: 10px; +} + +.react-datepicker-popper[data-placement^="right"] { + margin-left: 8px; +} + +.react-datepicker-popper[data-placement^="right"] .react-datepicker__triangle { + left: auto; + right: 42px; +} + +.react-datepicker-popper[data-placement^="left"] { + margin-right: 8px; +} + +.react-datepicker-popper[data-placement^="left"] .react-datepicker__triangle { + left: 42px; + right: auto; +} + +.react-datepicker__header { + text-align: center; + background-color: #f0f0f0; + border-bottom: 1px solid #aeaeae; + border-top-left-radius: 0.3rem; + border-top-right-radius: 0.3rem; + padding-top: 8px; + position: relative; +} + +.react-datepicker__header--time { + padding-bottom: 8px; + padding-left: 5px; + padding-right: 5px; +} + +.react-datepicker__year-dropdown-container--select, +.react-datepicker__month-dropdown-container--select, +.react-datepicker__month-year-dropdown-container--select, +.react-datepicker__year-dropdown-container--scroll, +.react-datepicker__month-dropdown-container--scroll, +.react-datepicker__month-year-dropdown-container--scroll { + display: inline-block; + margin: 0 2px; +} + +.react-datepicker__current-month, +.react-datepicker-time__header { + margin-top: 0; + color: #000; + font-weight: bold; + font-size: 0.944rem; +} + +.react-datepicker-time__header { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.react-datepicker__navigation { + background: none; + line-height: 1.7rem; + text-align: center; + cursor: pointer; + position: absolute; + top: 10px; + width: 0; + padding: 0; + border: 0.45rem solid transparent; + z-index: 1; + height: 10px; + width: 10px; + text-indent: -999em; + overflow: hidden; +} + +.react-datepicker__navigation--previous { + left: 10px; + border-right-color: #ccc; +} + +.react-datepicker__navigation--previous:hover { + border-right-color: #b3b3b3; +} + +.react-datepicker__navigation--previous--disabled, .react-datepicker__navigation--previous--disabled:hover { + border-right-color: #e6e6e6; + cursor: default; +} + +.react-datepicker__navigation--next { + right: 10px; + border-left-color: #ccc; +} + +.react-datepicker__navigation--next--with-time:not(.react-datepicker__navigation--next--with-today-button) { + right: 80px; +} + +.react-datepicker__navigation--next:hover { + border-left-color: #b3b3b3; +} + +.react-datepicker__navigation--next--disabled, .react-datepicker__navigation--next--disabled:hover { + border-left-color: #e6e6e6; + cursor: default; +} + +.react-datepicker__navigation--years { + position: relative; + top: 0; + display: block; + margin-left: auto; + margin-right: auto; +} + +.react-datepicker__navigation--years-previous { + top: 4px; + border-top-color: #ccc; +} + +.react-datepicker__navigation--years-previous:hover { + border-top-color: #b3b3b3; +} + +.react-datepicker__navigation--years-upcoming { + top: -4px; + border-bottom-color: #ccc; +} + +.react-datepicker__navigation--years-upcoming:hover { + border-bottom-color: #b3b3b3; +} + +.react-datepicker__month-container { + float: left; +} + +.react-datepicker__month { + margin: 0.4rem; + text-align: center; +} + +.react-datepicker__time-container { + float: right; + border-left: 1px solid #aeaeae; + width: 70px; +} + +.react-datepicker__time-container--with-today-button { + display: inline; + border: 1px solid #aeaeae; + border-radius: 0.3rem; + position: absolute; + right: -72px; + top: 0; +} + +.react-datepicker__time-container .react-datepicker__time { + position: relative; + background: white; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box { + width: 70px; + overflow-x: hidden; + margin: 0 auto; + text-align: center; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list { + list-style: none; + margin: 0; + height: calc(195px + (1.7rem / 2)); + overflow-y: scroll; + padding-right: 0px; + padding-left: 0px; + width: 100%; + box-sizing: content-box; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item { + height: 30px; + padding: 5px 10px; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item:hover { + cursor: pointer; + background-color: #f0f0f0; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--selected { + background-color: #216ba5; + color: white; + font-weight: bold; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--selected:hover { + background-color: #216ba5; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--disabled { + color: #ccc; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--disabled:hover { + cursor: default; + background-color: transparent; +} + +.react-datepicker__week-number { + color: #ccc; + display: inline-block; + width: 1.7rem; + line-height: 1.7rem; + text-align: center; + margin: 0.166rem; +} + +.react-datepicker__week-number.react-datepicker__week-number--clickable { + cursor: pointer; +} + +.react-datepicker__week-number.react-datepicker__week-number--clickable:hover { + border-radius: 0.3rem; + background-color: #f0f0f0; +} + +.react-datepicker__day-names, +.react-datepicker__week { + white-space: nowrap; +} + +.react-datepicker__day-name, +.react-datepicker__day, +.react-datepicker__time-name { + color: #000; + display: inline-block; + width: 1.7rem; + line-height: 1.7rem; + text-align: center; + margin: 0.166rem; +} + +.react-datepicker__day { + cursor: pointer; +} + +.react-datepicker__day:hover { + border-radius: 0.3rem; + background-color: #f0f0f0; +} + +.react-datepicker__day--today { + font-weight: bold; +} + +.react-datepicker__day--highlighted { + border-radius: 0.3rem; + background-color: #3dcc4a; + color: #fff; +} + +.react-datepicker__day--highlighted:hover { + background-color: #32be3f; +} + +.react-datepicker__day--highlighted-custom-1 { + color: magenta; +} + +.react-datepicker__day--highlighted-custom-2 { + color: green; +} + +.react-datepicker__day--selected, .react-datepicker__day--in-selecting-range, .react-datepicker__day--in-range { + border-radius: 0.3rem; + background-color: #216ba5; + color: #fff; +} + +.react-datepicker__day--selected:hover, .react-datepicker__day--in-selecting-range:hover, .react-datepicker__day--in-range:hover { + background-color: #1d5d90; +} + +.react-datepicker__day--keyboard-selected { + border-radius: 0.3rem; + background-color: #2a87d0; + color: #fff; +} + +.react-datepicker__day--keyboard-selected:hover { + background-color: #1d5d90; +} + +.react-datepicker__day--in-selecting-range:not(.react-datepicker__day--in-range) { + background-color: rgba(33, 107, 165, 0.5); +} + +.react-datepicker__month--selecting-range .react-datepicker__day--in-range:not(.react-datepicker__day--in-selecting-range) { + background-color: #f0f0f0; + color: #000; +} + +.react-datepicker__day--disabled { + cursor: default; + color: #ccc; +} + +.react-datepicker__day--disabled:hover { + background-color: transparent; +} + +.react-datepicker__input-container { + position: relative; + display: inline-block; +} + +.react-datepicker__year-read-view, +.react-datepicker__month-read-view, +.react-datepicker__month-year-read-view { + border: 1px solid transparent; + border-radius: 0.3rem; +} + +.react-datepicker__year-read-view:hover, +.react-datepicker__month-read-view:hover, +.react-datepicker__month-year-read-view:hover { + cursor: pointer; +} + +.react-datepicker__year-read-view:hover .react-datepicker__year-read-view--down-arrow, +.react-datepicker__year-read-view:hover .react-datepicker__month-read-view--down-arrow, +.react-datepicker__month-read-view:hover .react-datepicker__year-read-view--down-arrow, +.react-datepicker__month-read-view:hover .react-datepicker__month-read-view--down-arrow, +.react-datepicker__month-year-read-view:hover .react-datepicker__year-read-view--down-arrow, +.react-datepicker__month-year-read-view:hover .react-datepicker__month-read-view--down-arrow { + border-top-color: #b3b3b3; +} + +.react-datepicker__year-read-view--down-arrow, +.react-datepicker__month-read-view--down-arrow, +.react-datepicker__month-year-read-view--down-arrow { + border-top-color: #ccc; + float: right; + margin-left: 20px; + top: 8px; + position: relative; + border-width: 0.45rem; +} + +.react-datepicker__year-dropdown, +.react-datepicker__month-dropdown, +.react-datepicker__month-year-dropdown { + background-color: #f0f0f0; + position: absolute; + width: 50%; + left: 25%; + top: 30px; + z-index: 1; + text-align: center; + border-radius: 0.3rem; + border: 1px solid #aeaeae; +} + +.react-datepicker__year-dropdown:hover, +.react-datepicker__month-dropdown:hover, +.react-datepicker__month-year-dropdown:hover { + cursor: pointer; +} + +.react-datepicker__year-dropdown--scrollable, +.react-datepicker__month-dropdown--scrollable, +.react-datepicker__month-year-dropdown--scrollable { + height: 150px; + overflow-y: scroll; +} + +.react-datepicker__year-option, +.react-datepicker__month-option, +.react-datepicker__month-year-option { + line-height: 20px; + width: 100%; + display: block; + margin-left: auto; + margin-right: auto; +} + +.react-datepicker__year-option:first-of-type, +.react-datepicker__month-option:first-of-type, +.react-datepicker__month-year-option:first-of-type { + border-top-left-radius: 0.3rem; + border-top-right-radius: 0.3rem; +} + +.react-datepicker__year-option:last-of-type, +.react-datepicker__month-option:last-of-type, +.react-datepicker__month-year-option:last-of-type { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + border-bottom-left-radius: 0.3rem; + border-bottom-right-radius: 0.3rem; +} + +.react-datepicker__year-option:hover, +.react-datepicker__month-option:hover, +.react-datepicker__month-year-option:hover { + background-color: #ccc; +} + +.react-datepicker__year-option:hover .react-datepicker__navigation--years-upcoming, +.react-datepicker__month-option:hover .react-datepicker__navigation--years-upcoming, +.react-datepicker__month-year-option:hover .react-datepicker__navigation--years-upcoming { + border-bottom-color: #b3b3b3; +} + +.react-datepicker__year-option:hover .react-datepicker__navigation--years-previous, +.react-datepicker__month-option:hover .react-datepicker__navigation--years-previous, +.react-datepicker__month-year-option:hover .react-datepicker__navigation--years-previous { + border-top-color: #b3b3b3; +} + +.react-datepicker__year-option--selected, +.react-datepicker__month-option--selected, +.react-datepicker__month-year-option--selected { + position: absolute; + left: 15px; +} + +.react-datepicker__close-icon { + background-color: transparent; + border: 0; + cursor: pointer; + outline: 0; + padding: 0; + vertical-align: middle; + position: absolute; + height: 16px; + width: 16px; + top: 25%; + right: 7px; +} + +.react-datepicker__close-icon::after { + background-color: #216ba5; + border-radius: 50%; + bottom: 0; + box-sizing: border-box; + color: #fff; + content: "\00d7"; + cursor: pointer; + font-size: 12px; + height: 16px; + width: 16px; + line-height: 1; + margin: -8px auto 0; + padding: 2px; + position: absolute; + right: 0px; + text-align: center; +} + +.react-datepicker__today-button { + background: #f0f0f0; + border-top: 1px solid #aeaeae; + cursor: pointer; + text-align: center; + font-weight: bold; + padding: 5px 0; + clear: left; +} + +.react-datepicker__portal { + position: fixed; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.8); + left: 0; + top: 0; + justify-content: center; + align-items: center; + display: flex; + z-index: 2147483647; +} + +.react-datepicker__portal .react-datepicker__day-name, +.react-datepicker__portal .react-datepicker__day, +.react-datepicker__portal .react-datepicker__time-name { + width: 3rem; + line-height: 3rem; +} + +@media (max-width: 400px), (max-height: 550px) { + .react-datepicker__portal .react-datepicker__day-name, + .react-datepicker__portal .react-datepicker__day, + .react-datepicker__portal .react-datepicker__time-name { + width: 2rem; + line-height: 2rem; + } +} + +.react-datepicker__portal .react-datepicker__current-month, +.react-datepicker__portal .react-datepicker-time__header { + font-size: 1.44rem; +} + +.react-datepicker__portal .react-datepicker__navigation { + border: 0.81rem solid transparent; +} + +.react-datepicker__portal .react-datepicker__navigation--previous { + border-right-color: #ccc; +} + +.react-datepicker__portal .react-datepicker__navigation--previous:hover { + border-right-color: #b3b3b3; +} + +.react-datepicker__portal .react-datepicker__navigation--previous--disabled, .react-datepicker__portal .react-datepicker__navigation--previous--disabled:hover { + border-right-color: #e6e6e6; + cursor: default; +} + +.react-datepicker__portal .react-datepicker__navigation--next { + border-left-color: #ccc; +} + +.react-datepicker__portal .react-datepicker__navigation--next:hover { + border-left-color: #b3b3b3; +} + +.react-datepicker__portal .react-datepicker__navigation--next--disabled, .react-datepicker__portal .react-datepicker__navigation--next--disabled:hover { + border-left-color: #e6e6e6; + cursor: default; +} diff --git a/AnimalRequests/src/client/theme/css/tooltip.css b/AnimalRequests/src/client/theme/css/tooltip.css new file mode 100644 index 000000000..5a1699ed9 --- /dev/null +++ b/AnimalRequests/src/client/theme/css/tooltip.css @@ -0,0 +1,65 @@ +/** + * Tooltip Styles + */ + +/* Add this attribute to the element that needs a tooltip */ +[data-tooltip] { + position: relative; + z-index: 2; + cursor: pointer; + top: 8px; +} + +/* Hide the tooltip content by default */ +[data-tooltip]:before, +[data-tooltip]:after { + visibility: hidden; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + opacity: 0; + pointer-events: none; +} + +/* Position tooltip above the element */ +[data-tooltip]:before { + position: absolute; + bottom: 150%; + left: 50%; + margin-bottom: 5px; + margin-left: -80px; + padding: 7px; + width: 160px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background-color: #000; + background-color: hsla(0, 0%, 20%, 0.9); + color: #fff; + content: attr(data-tooltip); + text-align: center; + font-size: 12px; + line-height: 1.2; +} + +/* Triangle hack to make tooltip look like a speech bubble */ +[data-tooltip]:after { + position: absolute; + bottom: 150%; + left: 50%; + margin-left: -5px; + width: 0; + border-top: 5px solid #000; + border-top: 5px solid hsla(0, 0%, 20%, 0.9); + border-right: 5px solid transparent; + border-left: 5px solid transparent; + content: " "; + font-size: 0; + line-height: 0; +} + +/* Show tooltip content on hover */ +[data-tooltip]:hover:before, +[data-tooltip]:hover:after { + visibility: visible; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + opacity: 1; +} diff --git a/AnimalRequests/src/client/theme/style.js b/AnimalRequests/src/client/theme/style.js new file mode 100644 index 000000000..bfe50120a --- /dev/null +++ b/AnimalRequests/src/client/theme/style.js @@ -0,0 +1,4 @@ +import './css/index.css'; +import './css/react-datepicker.css' +import './css/bootstrap.min.css' +import './css/tooltip.css' diff --git a/AnimalRequests/src/client/typings/globals.d.ts b/AnimalRequests/src/client/typings/globals.d.ts new file mode 100644 index 000000000..47b5eb55b --- /dev/null +++ b/AnimalRequests/src/client/typings/globals.d.ts @@ -0,0 +1,9 @@ + +declare global { + + const LABKEY: any; + + const jQuery: any; +} + +export {} \ No newline at end of file diff --git a/AnimalRequests/src/client/typings/main.d.ts b/AnimalRequests/src/client/typings/main.d.ts new file mode 100644 index 000000000..10044865b --- /dev/null +++ b/AnimalRequests/src/client/typings/main.d.ts @@ -0,0 +1,2 @@ +/* App globals */ +/// \ No newline at end of file diff --git a/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsContainerListener.java b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsContainerListener.java new file mode 100644 index 000000000..da734f19b --- /dev/null +++ b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsContainerListener.java @@ -0,0 +1,39 @@ +package org.labkey.animalrequests; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager.ContainerListener; +import org.labkey.api.security.User; +import java.util.Collections; +import java.util.Collection; + +import java.beans.PropertyChangeEvent; + +public class AnimalRequestsContainerListener implements ContainerListener +{ + @Override + public void containerCreated(Container c, User user) + { + } + + @Override + public void containerDeleted(Container c, User user) + { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + } + + @Override + public void containerMoved(Container c, Container oldParent, User user) + { + } + + @NotNull @Override + public Collection canMove(Container c, Container newParent, User user) + { + return Collections.emptyList(); + } +} diff --git a/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsController.java b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsController.java new file mode 100644 index 000000000..171339ef3 --- /dev/null +++ b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsController.java @@ -0,0 +1,34 @@ +package org.labkey.animalrequests; + +import org.labkey.api.action.SimpleViewAction; +import org.labkey.api.action.SpringActionController; +import org.labkey.api.security.RequiresLogin; +import org.labkey.api.view.JspView; +import org.labkey.api.view.NavTree; +import org.springframework.validation.BindException; +import org.springframework.web.servlet.ModelAndView; + +public class AnimalRequestsController extends SpringActionController +{ + private static final DefaultActionResolver _actionResolver = new DefaultActionResolver(AnimalRequestsController.class); + public static final String NAME = "animalrequests"; + + public AnimalRequestsController() + { + setActionResolver(_actionResolver); + } + + @RequiresLogin + public class BeginAction extends SimpleViewAction + { + @Override + public ModelAndView getView(Object o, BindException errors) + { + return new JspView<>("/org/labkey/animalrequests/view/begin.jsp"); + } + public NavTree appendNavTrail(NavTree root){ + return root; + } + } + +} diff --git a/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsManager.java b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsManager.java new file mode 100644 index 000000000..c1db12abb --- /dev/null +++ b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsManager.java @@ -0,0 +1,16 @@ +package org.labkey.animalrequests; + +public class AnimalRequestsManager +{ + private static final AnimalRequestsManager _instance = new AnimalRequestsManager(); + + private AnimalRequestsManager() + { + // prevent external construction with a private default constructor + } + + public static AnimalRequestsManager get() + { + return _instance; + } +} diff --git a/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsModule.java b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsModule.java new file mode 100644 index 000000000..441bb6817 --- /dev/null +++ b/AnimalRequests/src/org/labkey/animalrequests/AnimalRequestsModule.java @@ -0,0 +1,75 @@ +package org.labkey.animalrequests; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.module.DefaultModule; +import org.labkey.api.module.ModuleContext; +import org.labkey.api.resource.Resource; +import org.labkey.api.view.WebPartFactory; +//import org.labkey.api.ehr.EHRService; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public class AnimalRequestsModule extends DefaultModule +{ + public static final String NAME = "AnimalRequests"; + + @Override + public String getName() + { + return NAME; + } + + @Override + public boolean hasScripts() + { + return false; + } + + @Override + @NotNull + protected Collection createWebPartFactories() + { + return Collections.emptyList(); + } + + @Override + protected void init() + { + addController(AnimalRequestsController.NAME, AnimalRequestsController.class); + } + + @Override + public void doStartup(ModuleContext moduleContext) + { + // add a container listener so we'll know when our container is deleted: + ContainerManager.addContainerListener(new AnimalRequestsContainerListener()); + } + +// @Override +// protected void doStartupAfterSpringConfig(ModuleContext moduleContext) +// { +// EHRService.get().registerModule(this); +// EHRService.get().registerTableCustomizer(this, WNPRC_EHRCustomizer.class); +// Resource r = getModuleResource("/scripts/wnprc_ehr/"); +// assert r != null; +// EHRService.get().registerTriggerScript(this, r); +// }; + + @Override + @NotNull + public Collection getSummary(Container c) + { + return Collections.emptyList(); + } + + @Override + @NotNull + public Set getSchemaNames() + { + return Collections.emptySet(); + } +} diff --git a/AnimalRequests/src/org/labkey/animalrequests/view/begin.jsp b/AnimalRequests/src/org/labkey/animalrequests/view/begin.jsp new file mode 100644 index 000000000..dec020bed --- /dev/null +++ b/AnimalRequests/src/org/labkey/animalrequests/view/begin.jsp @@ -0,0 +1,21 @@ +<%@ page import="org.labkey.api.data.Container" %> +<%@ page import="org.labkey.api.security.User" %> +<%@ page extends="org.labkey.api.jsp.JspBase" %> +<% + Container c = getContainer(); + User user = getUser(); +%> + + + + + +
Begin, and welcome to the AnimalRequests module.
+ diff --git a/AnimalRequests/tsconfig.json b/AnimalRequests/tsconfig.json new file mode 100644 index 000000000..8726bc85d --- /dev/null +++ b/AnimalRequests/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "es6", + "jsx": "react", + "sourceMap": false, + "experimentalDecorators": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true + }, + "exclude": [ + "node_modules", + "resources" + ], + "files": [ + "src/client/typings/main.d.ts", + "src/client/app.tsx" + ] +} diff --git a/AnimalRequests/webpack/dev-server.js b/AnimalRequests/webpack/dev-server.js new file mode 100644 index 000000000..ac81638de --- /dev/null +++ b/AnimalRequests/webpack/dev-server.js @@ -0,0 +1,34 @@ +var express = require('express'); +var webpack = require('webpack'); +var cors = require('cors'); +var config = require('./dev.config'); + +var app = express(); +var compiler = webpack(config); + +app.use(cors()); + +app.use(require('webpack-dev-middleware')(compiler, { + noInfo: true, + stats: { + chunks: false + }, + publicPath: config.output.publicPath +})); + +app.use(require('webpack-hot-middleware')(compiler)); + +/* final catch-all route to index.html defined last */ +app.get('/index.html', (req, res) => { + res.sendFile('/Users/sebranek/labkey/trunk/externalModules/animalRequests/index.html'); +}) + + +app.listen(3000, 'localhost', function (err) { + if (err) { + console.log(err); + return; + } + + console.log('Listening at http://localhost:3000'); +}); diff --git a/AnimalRequests/webpack/dev-style.config.js b/AnimalRequests/webpack/dev-style.config.js new file mode 100644 index 000000000..f35f0bc0f --- /dev/null +++ b/AnimalRequests/webpack/dev-style.config.js @@ -0,0 +1,51 @@ +const path = require("path"); +var ExtractTextPlugin = require('extract-text-webpack-plugin'); + +module.exports = { + context: path.resolve(__dirname, '..'), + + entry: { + 'app': [ + './src/client/theme/style.js' + ] + }, + + output: { + path: path.resolve(__dirname, '../resources/web/animalrequests/app/'), + publicPath: '/', + filename: 'style.js' // do not override app.js + }, + + module: { + rules: [ + { + test: /\.css$/, + loader: ExtractTextPlugin.extract({ + use: [{ + loader: 'css-loader', + options: { + sourceMap: true + } + }], + fallback: 'style-loader' + }) + }, + { + test: /style.js/, + loaders: [{ + loader: 'babel-loader', + options: { + cacheDirectory: true + } + }] + } + ] + }, + + plugins: [ + new ExtractTextPlugin({ + allChunks: true, + filename: '[name].css' + }) + ] +}; \ No newline at end of file diff --git a/AnimalRequests/webpack/dev.config.js b/AnimalRequests/webpack/dev.config.js new file mode 100644 index 000000000..5f35ee140 --- /dev/null +++ b/AnimalRequests/webpack/dev.config.js @@ -0,0 +1,45 @@ +require("babel-polyfill"); +const path = require("path"); +const webpack = require("webpack"); + +module.exports = { + context: path.resolve(__dirname, '..'), + + devtool: 'eval', + + entry: { + 'app': [ + 'babel-polyfill', + 'webpack-hot-middleware/client?path=http://localhost:3000/__webpack_hmr', + './src/client/app.tsx' + ] + }, + + output: { + path: path.resolve(__dirname, '../resources/web/animalrequests/app/'), + publicPath: 'http://localhost:3000/', + filename: '[name].js' + }, + + externals: { + 'react/addons': true, + 'react/lib/ExecutionEnvironment': true, + 'react/lib/ReactContext': true + }, + + module: { + rules: [{ + test: /\.tsx?$/, + loaders: ['babel-loader', 'ts-loader'] + }] + }, + + plugins: [ + new webpack.NoEmitOnErrorsPlugin(), + new webpack.HotModuleReplacementPlugin() + ], + + resolve: { + extensions: [ '.jsx', '.js', '.tsx', '.ts' ] + } +}; diff --git a/AnimalRequests/webpack/prod.config.js b/AnimalRequests/webpack/prod.config.js new file mode 100644 index 000000000..ce8232b82 --- /dev/null +++ b/AnimalRequests/webpack/prod.config.js @@ -0,0 +1,69 @@ +require("@babel/polyfill"); +var webpack = require("webpack"); +var path = require("path"); + +var ExtractTextPlugin = require('extract-text-webpack-plugin'); + +module.exports = { + context: path.resolve(__dirname, '..'), + + devtool: 'source-map', + + entry: { + 'app': [ + '@babel/polyfill', + './src/client/theme/style.js', + './src/client/app.tsx' + ] + }, + module: { + rules: [ + { + test: /\.tsx?$/, + loaders: ['babel-loader', 'ts-loader'] + }, + { + test: /\.css$/, + loader: ExtractTextPlugin.extract({ + use: [{ + loader: 'css-loader', + options: { + sourceMap: false + } + }], + fallback: 'style-loader' + }) + }, + { + test: /style.js/, + loaders: [{ + loader: 'babel-loader', + options: { + cacheDirectory: false + } + }] + } + ] + }, + + output: { + path: path.resolve(__dirname, '../resources/web/animalrequests/app/'), + //path: path.resolve(__dirname, '../../WNPRC_EHR/resources/web/wnprc_ehr/reactjs/animalrequests/'), + publicPath: './', // allows context path to resolve in both js/css + filename: "[name].js" + }, + + resolve: { + extensions: [ '.jsx', '.js', '.tsx', '.ts' ] + }, + + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': '"production"' + }), + new ExtractTextPlugin({ + allChunks: true, + filename: '[name].css' + }) + ] +}; diff --git a/DBUtils/api-src/org/labkey/dbutils/api/SimpleQueryUpdater.java b/DBUtils/api-src/org/labkey/dbutils/api/SimpleQueryUpdater.java index a84d18963..51e54020d 100644 --- a/DBUtils/api-src/org/labkey/dbutils/api/SimpleQueryUpdater.java +++ b/DBUtils/api-src/org/labkey/dbutils/api/SimpleQueryUpdater.java @@ -36,11 +36,78 @@ public SimpleQueryUpdater (User user, Container container, String schemaName, St this.container = container; } + public List> insert(Map... rowArray) throws QueryUpdateServiceException, SQLException, BatchValidationException, DuplicateKeyException { + List> rows = makeRowsCaseInsensitive(rowArray); + return this.insert(rows); + } + + public List> update(Map... rowArray) throws QueryUpdateServiceException, SQLException, BatchValidationException, InvalidKeyException { + List> rows = makeRowsCaseInsensitive(rowArray); + return this.update(rows); + } + public List> upsert(Map... rowArray) throws QueryUpdateServiceException, SQLException, InvalidKeyException, BatchValidationException, DuplicateKeyException { List> rows = makeRowsCaseInsensitive(rowArray); return this.upsert(rows); } + /** + * Inserts a row into the table. It does the entire thing as a transaction, so any failure + * will result in no data being inserted. + * + * @param rows A "list" of {@link Map} objects that represent rows. Note that these can + * be {@link JSONObject}s, if you so choose. + * @return A {@link List} of the rows that were inserted. They will have all been + * converted to be case-insensitive, and will include any fields that were added/changed automatically + * by the INSERT or trigger scripts. + * @throws QueryUpdateServiceException Indicates an internal error in the QueryUpdateService + * @throws SQLException Indicates a communication problem with the SQL database + * @throws BatchValidationException Thrown if the trigger scripts throw an error on any row + * @throws DuplicateKeyException Thrown if there is already a row in the table with the same key + */ + public List> insert(List> rows) throws QueryUpdateServiceException, SQLException, BatchValidationException, DuplicateKeyException { + rows = makeRowListCaseInsensitive(rows); + List> rowsToReturn = new ArrayList<>(); + + // Wrap everything in a transaction to make INSERT operations atomic together. + try(DbScope.Transaction transaction = tableInfo.getSchema().getScope().ensureTransaction()) { + rowsToReturn.addAll(getCaseInsensitiveRowList(doInsert(rows))); + + // Actually commit the changes. + transaction.commit(); + } + return rowsToReturn; + } + + /** + * Updates a row in the table. It does the entire thing as a transaction, so any failure + * will result in no data being updated. + * + * @param rows A "list" of {@link Map} objects that represent rows. Note that these can + * be {@link JSONObject}s, if you so choose. + * @return A {@link List} of the rows that were updated. They will have all been + * converted to be case-insensitive, and will include any fields that were added/changed automatically + * by the UPDATE or trigger scripts. + * @throws QueryUpdateServiceException Indicates an internal error in the QueryUpdateService + * @throws SQLException Indicates a communication problem with the SQL database + * @throws InvalidKeyException Thrown if the key in an updated row doesn't exist in the table + * @throws BatchValidationException Thrown if the trigger scripts throw an error on any row + */ + public List> update(List> rows) throws QueryUpdateServiceException, SQLException, BatchValidationException, InvalidKeyException { + rows = makeRowListCaseInsensitive(rows); + List> rowsToReturn = new ArrayList<>(); + + // Wrap everything in a transaction to make UPDATE operations atomic together. + try(DbScope.Transaction transaction = tableInfo.getSchema().getScope().ensureTransaction()) { + rowsToReturn.addAll(getCaseInsensitiveRowList(doUpdate(rows))); + + // Actually commit the changes. + transaction.commit(); + } + return rowsToReturn; + } + + /** * Inserts or updates a row to ensure it's in the table. It intelligently checks to see if each row exists, @@ -84,44 +151,47 @@ public List> upsert(List> // Wrap everything in a transaction to make both UPDATE and INSERT operations atomic together. try(DbScope.Transaction transaction = tableInfo.getSchema().getScope().ensureTransaction()) { - BatchValidationException validationException = new BatchValidationException(); + rowsToReturn.addAll(getCaseInsensitiveRowList(doInsert(rowsToInsert))); + rowsToReturn.addAll(getCaseInsensitiveRowList(doUpdate(rowsToUpdate))); - if (rowsToInsert.size() > 0) { - List> insertedRows = service.insertRows(user, container, rowsToInsert, validationException, null, null); + // Actually commit the changes. + transaction.commit(); + } + return rowsToReturn; + } - if (validationException.hasErrors()) { - throw validationException; - } - // From my understanding, this shouldn't really happen, if you're checking the BatchValidationException. - // Otherwise, the QueryUpdateService has a tendency to insert as much as it can, and not throw an error - // for the rows that it couldn't. - else if (insertedRows.size() != rowsToInsert.size()) { - throw new QueryUpdateServiceException("Not all rows were inserted properly"); - } - else { - rowsToReturn.addAll(getCaseInsensitiveRowList(insertedRows)); - } + public List> doInsert(List> rows) throws BatchValidationException , DuplicateKeyException, SQLException, QueryUpdateServiceException{ + List> insertedRows = new ArrayList<>(); + if (rows.size() > 0) { + BatchValidationException validationException = new BatchValidationException(); + insertedRows = service.insertRows(user, container, rows, validationException, null, null); + + if (validationException.hasErrors()) { + throw validationException; + } + // From my understanding, this shouldn't really happen, if you're checking the BatchValidationException. + // Otherwise, the QueryUpdateService has a tendency to insert as much as it can, and not throw an error + // for the rows that it couldn't. + else if (insertedRows.size() != rows.size()) { + throw new QueryUpdateServiceException("Not all rows were inserted properly"); } + } + return insertedRows; + } - if (rowsToUpdate.size() > 0) { - List> updatedRows = service.updateRows(user, container, rowsToUpdate, rowsToUpdate, null, null); + public List> doUpdate(List> rows) throws BatchValidationException , InvalidKeyException, SQLException, QueryUpdateServiceException { + List> updatedRows = new ArrayList<>(); + if (rows.size() > 0) { + updatedRows = service.updateRows(user, container, rows, rows, null, null); - if (updatedRows.size() != rowsToUpdate.size()) { - throw new QueryUpdateServiceException("Not all rows updated properly"); - } - else { - rowsToReturn.addAll(getCaseInsensitiveRowList(updatedRows)); - } + if (updatedRows.size() != rows.size()) { + throw new QueryUpdateServiceException("Not all rows updated properly"); } - - // Actually commit the changes. - transaction.commit(); } - - return rowsToReturn; + return updatedRows; } - public List> delete(Map... rowArray) throws QueryUpdateServiceException, SQLException, InvalidKeyException, BatchValidationException, DuplicateKeyException { + public List> delete(Map... rowArray) throws QueryUpdateServiceException, SQLException, InvalidKeyException, BatchValidationException { List> rowsToDelete = makeRowsCaseInsensitive(rowArray); List> rowsToReturn = new ArrayList<>(); diff --git a/ETLChemistryAnalyzer/build.gradle b/ETLChemistryAnalyzer/build.gradle new file mode 100644 index 000000000..561606c60 --- /dev/null +++ b/ETLChemistryAnalyzer/build.gradle @@ -0,0 +1,10 @@ +apply plugin: 'java' +apply plugin: 'org.labkey.module' +compileJava { + options.compilerArgs << "-Xlint:unchecked" + +} + +dependencies { + compile project(":server:modules:wnprc-modules:WNPRC_EHR") +} diff --git a/ETLChemistryAnalyzer/module.properties b/ETLChemistryAnalyzer/module.properties new file mode 100644 index 000000000..69e8a1f24 --- /dev/null +++ b/ETLChemistryAnalyzer/module.properties @@ -0,0 +1,6 @@ +ModuleClass: org.labkey.ETLChemistryAnalyzer.ETLChemistryAnalyzerModule +Label: Marmoset R24 module +License: Apache 2.0 +LicenseURL: http://www.apache.org/licenses/LICENSE-2.0 +ConsolidateScripts: false +ManageVersion: false \ No newline at end of file diff --git a/ETLChemistryAnalyzer/resources/etls/ChemistryAnalyzerPatients.xml b/ETLChemistryAnalyzer/resources/etls/ChemistryAnalyzerPatients.xml new file mode 100644 index 000000000..ca6ce1a6e --- /dev/null +++ b/ETLChemistryAnalyzer/resources/etls/ChemistryAnalyzerPatients.xml @@ -0,0 +1,32 @@ + + + patients + Chemistry Analyzer Patients + + + Copy to target + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingComentOrders.sql b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingComentOrders.sql new file mode 100644 index 000000000..dd4b3b112 --- /dev/null +++ b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingComentOrders.sql @@ -0,0 +1,18 @@ +(SELECT +Laboratory_Assigned_Patient_ID AS Id, PT.Patient_ID, +ORD.Orden_ID as Orden_ID, ORD.Sample_ID AS SampleID, ORD.Requested_Ordered_Date_and_Time AS RequestDateTime, +RST.Universal_Test_ID AS testid, RST.oor, RST.result_value, RST.Unit, +CMO.text as OrderComment + +FROM CHEMISTRYANALYZER.patient_view PT + +JOIN CHEMISTRYANALYZER.order_view ORD +ON PT.Patient_ID = ORD.Patient_ID + +JOIN CHEMISTRYANALYZER.result_view RST +ON ORD.Orden_ID = RST.Orden_ID + +LEFT JOIN CHEMISTRYANALYZER.Comment_Orden CMO +ON ORD.Orden_ID = CMO.Orden_ID + +WHERE startswith(Patient_Name_Name_First_name,'MONKEY') ) diff --git a/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders.sql b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders.sql new file mode 100644 index 000000000..400f0e7f7 --- /dev/null +++ b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders.sql @@ -0,0 +1,59 @@ +SELECT +GROUPRESULTS.Sample_ID, GROUPRESULTS.RequestDateTime as RequestDateTime, +GROUPRESULTS.testid, GROUPRESULTS.resultOORIndicator, GROUPRESULTS.result, GROUPRESULTS.units, +GROUPRESULTS.OrderComment, GROUPRESULTS.OrderDate, GROUPRESULTS.CommentText, +PT.Patient_ID, PT.Laboratory_Assigned_Patient_ID AS Id, PT.Patient_Name_Name_First_name, Birthdate, Patient_Sex, Special_Field_1, +HDR.Header_ID,HDR.Date_and_Time AS headerDate, +-- adding unique identifier for same sample_id if set is ran twice +(GROUPRESULTS.Sample_ID || PT.Laboratory_Assigned_Patient_ID || GROUPRESULTS.RequestDateTime || GROUPRESULTS.testid) AS alternateIdentifier +FROM +( + SELECT + + MAX(ORD.Patient_ID) AS Patient_ID, MAX(ORD.Orden_ID) AS Orden_ID, ORD.Requested_Ordered_Date_and_Time AS RequestDateTime,ORD.Sample_ID, + MAX(CMO.text) as OrderComment, MAX(CMO.comment_text) AS CommentText, + -- MAX(CMO.order_date) AS OrderDate, + + --If there is not comment we add the RequestOrderedDateandTime coming from the order_view table + --OrderDate cannot be null for the ETL process to work. + CASE + WHEN MAX(CMO.text) IS NULL THEN ORD.Requested_Ordered_Date_and_Time + ELSE MAX(CMO.order_date) + END AS OrderDate, + + RST.Universal_Test_ID AS testid, MAX(RST.oor) AS resultOORIndicator , + + -- Check if same test ran twice and have different values displays '-1' + CASE + WHEN MAX(RST.result_value) = MIN(RST.result_value) THEN RST.result_value + + ELSE -1 + + END AS result, + + MAX(RST.Unit) AS units + + FROM CHEMISTRYANALYZER.order_view ORD + + JOIN CHEMISTRYANALYZER.result_view RST + ON ORD.Orden_ID = RST.Orden_ID + + --Duplicating comments from first order in the set to all the orders with the same Orden_ID + LEFT JOIN (SELECT CMO2.text, CMO2.order_date, CMO2.comment_text, CMO2.Orden_ID, ORD2.Patient_ID AS PTID2 + FROM CHEMISTRYANALYZER.comment_order_view CMO2 + JOIN CHEMISTRYANALYZER.order_view ORD2 + ON CMO2.Orden_ID = ORD2.Orden_ID + ) CMO + ON CMO.PTID2 = ORD.Patient_ID + + GROUP BY RST.Universal_Test_ID, ORD.Sample_ID, ORD.Requested_Ordered_Date_and_Time + +) GROUPRESULTS + +JOIN CHEMISTRYANALYZER.patient_view PT +ON PT.Patient_ID = GROUPRESULTS.Patient_ID + +JOIN CHEMISTRYANALYZER.header_view HDR + ON HDR.Header_ID = PT.Header_ID + +WHERE startswith(Patient_Name_Name_First_name,'MONKEY') AND HDR.Date_and_Time >='2019-07-08' diff --git a/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders/.qview.xml b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders/.qview.xml new file mode 100644 index 000000000..545709ac1 --- /dev/null +++ b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders/.qview.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders/development.qview.xml b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders/development.qview.xml new file mode 100644 index 000000000..3a10b63af --- /dev/null +++ b/ETLChemistryAnalyzer/resources/queries/ChemistryAnalyzer/MergingPatientsOrders/development.qview.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ETLChemistryAnalyzer/resources/views/welcome.html b/ETLChemistryAnalyzer/resources/views/welcome.html new file mode 100644 index 000000000..0699d5ea0 --- /dev/null +++ b/ETLChemistryAnalyzer/resources/views/welcome.html @@ -0,0 +1 @@ +

Welcome to the Chemistry Analyzer Integration module

\ No newline at end of file diff --git a/ETLChemistryAnalyzer/resources/views/welcome.view.xml b/ETLChemistryAnalyzer/resources/views/welcome.view.xml new file mode 100644 index 000000000..6492515dd --- /dev/null +++ b/ETLChemistryAnalyzer/resources/views/welcome.view.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/ETLChemistryAnalyzer/resources/views/welcome.webpart.xml b/ETLChemistryAnalyzer/resources/views/welcome.webpart.xml new file mode 100644 index 000000000..d5ef215cd --- /dev/null +++ b/ETLChemistryAnalyzer/resources/views/welcome.webpart.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerContainerListener.java b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerContainerListener.java new file mode 100644 index 000000000..8be963d4f --- /dev/null +++ b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerContainerListener.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.ETLChemistryAnalyzer; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager.ContainerListener; +import org.labkey.api.security.User; +import java.util.Collections; +import java.util.Collection; + +import java.beans.PropertyChangeEvent; + +public class ETLChemistryAnalyzerContainerListener implements ContainerListener +{ + @Override + public void containerCreated(Container c, User user) + { + } + + @Override + public void containerDeleted(Container c, User user) + { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + } + + @Override + public void containerMoved(Container c, Container oldParent, User user) + { + } + + @NotNull @Override + public Collection canMove(Container c, Container newParent, User user) + { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerController.java b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerController.java new file mode 100644 index 000000000..330da3720 --- /dev/null +++ b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerController.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.ETLChemistryAnalyzer; + +import org.labkey.api.action.SimpleViewAction; +import org.labkey.api.action.SpringActionController; +import org.labkey.api.security.RequiresPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.view.JspView; +import org.labkey.api.view.NavTree; +import org.springframework.validation.BindException; +import org.springframework.web.servlet.ModelAndView; + +public class ETLChemistryAnalyzerController extends SpringActionController +{ + private static final DefaultActionResolver _actionResolver = new DefaultActionResolver(org.labkey.ETLChemistryAnalyzer.ETLChemistryAnalyzerController.class); + public static final String NAME = "ETLChemistryAnalyzer"; + + public ETLChemistryAnalyzerController() + { + setActionResolver(_actionResolver); + } + + @RequiresPermission(ReadPermission.class) + public class BeginAction extends SimpleViewAction + { + public ModelAndView getView(Object o, BindException errors) throws Exception + { + return new JspView("/org/labkey/ETLChemistryAnalyzer/view/hello.jsp"); + } + + public NavTree appendNavTrail(NavTree root) + { + return root; + } + } +} \ No newline at end of file diff --git a/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerManager.java b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerManager.java new file mode 100644 index 000000000..19c56256e --- /dev/null +++ b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerManager.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.ETLChemistryAnalyzer; + +public class ETLChemistryAnalyzerManager +{ + private static final ETLChemistryAnalyzerManager _instance = new ETLChemistryAnalyzerManager(); + + private ETLChemistryAnalyzerManager() + { + // prevent external construction with a private default constructor + } + + public static ETLChemistryAnalyzerManager get() + { + return _instance; + } +} \ No newline at end of file diff --git a/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerModule.java b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerModule.java new file mode 100644 index 000000000..adabf495f --- /dev/null +++ b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerModule.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.ETLChemistryAnalyzer; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.module.DefaultModule; +import org.labkey.api.module.ModuleContext; +import org.labkey.api.view.WebPartFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public class ETLChemistryAnalyzerModule extends DefaultModule +{ + public static final String NAME = "ETLChemistryAnalyzer"; + + @Override + public String getName() + { + return NAME; + } + + @Override + public Double getSchemaVersion() + { + return 20.001; + } + + @Override + public boolean hasScripts() + { + return true; + } + + @Override + @NotNull + protected Collection createWebPartFactories() + { + return Collections.emptyList(); + } + + @Override + protected void init() + { + addController(ETLChemistryAnalyzerController.NAME.toLowerCase(), ETLChemistryAnalyzerController.class); + } + + @Override + public void doStartup(ModuleContext moduleContext) + { + // add a container listener so we'll know when our container is deleted: + ContainerManager.addContainerListener(new ETLChemistryAnalyzerContainerListener()); + } + + @Override + @NotNull + public Collection getSummary(Container c) + { + return Collections.emptyList(); + } + + @Override + @NotNull + public Set getSchemaNames() + { + return Collections.singleton(ETLChemistryAnalyzerSchema.NAME); + } +} \ No newline at end of file diff --git a/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerSchema.java b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerSchema.java new file mode 100644 index 000000000..1b988c0d0 --- /dev/null +++ b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/ETLChemistryAnalyzerSchema.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.ETLChemistryAnalyzer; + +import org.labkey.api.data.DbSchema; +import org.labkey.api.data.DbSchemaType; +import org.labkey.api.data.dialect.SqlDialect; + +public class ETLChemistryAnalyzerSchema +{ + private static final ETLChemistryAnalyzerSchema _instance = new ETLChemistryAnalyzerSchema(); + public static final String NAME = "ETLChemistryAnalyzer"; + + public static ETLChemistryAnalyzerSchema getInstance() + { + return _instance; + } + + private ETLChemistryAnalyzerSchema() + { + // private constructor to prevent instantiation from + // outside this class: this singleton should only be + // accessed via org.labkey.ETLChemistryAnalyzer.ETLChemistryAnalyzerSchema.getInstance() + } + + public DbSchema getSchema() + { + return DbSchema.get(NAME, DbSchemaType.Module); + } + + public SqlDialect getSqlDialect() + { + return getSchema().getSqlDialect(); + } +} diff --git a/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/view/hello.jsp b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/view/hello.jsp new file mode 100644 index 000000000..8982bcaf1 --- /dev/null +++ b/ETLChemistryAnalyzer/src/org/labkey/ETLChemistryAnalyzer/view/hello.jsp @@ -0,0 +1,25 @@ +<% +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +%> +<%@ page import="org.labkey.api.data.Container" %> +<%@ page import="org.labkey.api.security.User" %> +<%@ page extends="org.labkey.api.jsp.JspBase" %> +<% + Container c = getContainer(); + User user = getUser(); +%> +Hello, and welcome to the Chemistry Analyzer ETL module. \ No newline at end of file diff --git a/Gringotts/api-src/org/labkey/gringotts/api/GringottsService.java b/Gringotts/api-src/org/labkey/gringotts/api/GringottsService.java new file mode 100644 index 000000000..d14d4531d --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/GringottsService.java @@ -0,0 +1,46 @@ +package org.labkey.gringotts.api; + +import org.apache.xerces.impl.dv.util.Base64; +import org.jetbrains.annotations.NotNull; +import org.labkey.api.security.User; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.model.Vault; + +import java.nio.ByteBuffer; +import java.util.UUID; + +/** + * Created by jon on 10/19/16. + */ +public abstract class GringottsService { + private static GringottsService _gringottsService; + + public static GringottsService get() { + return _gringottsService; + } + + public static void set(@NotNull GringottsService gringottsService) { + _gringottsService = gringottsService; + } + + public static String getNewId() { + UUID uuid = UUID.randomUUID(); + + return base64EncodeUUID(uuid); + } + + public static String base64EncodeUUID(UUID uuid) { + // Adapted from http://stackoverflow.com/questions/2983065/guid-to-bytearray + ByteBuffer bb = ByteBuffer.wrap(new byte[16]); + bb.putLong(uuid.getMostSignificantBits()); + bb.putLong(uuid.getLeastSignificantBits()); + byte[] bytes = bb.array(); + + // Encode the bytes... + return Base64.encode(bytes); + } + + abstract public void saveRecord(Vault.Record record); + abstract public void deleteRecord(Vault.Record record); + abstract public void bindRecord(Vault.Record record); +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/annotation/SerializeField.java b/Gringotts/api-src/org/labkey/gringotts/api/annotation/SerializeField.java new file mode 100644 index 000000000..1d1344e5b --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/annotation/SerializeField.java @@ -0,0 +1,8 @@ +package org.labkey.gringotts.api.annotation; + +/** + * Created by jon on 10/19/16. + */ +public @interface SerializeField { + String columnName() default ""; +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/exception/InvalidVaultException.java b/Gringotts/api-src/org/labkey/gringotts/api/exception/InvalidVaultException.java new file mode 100644 index 000000000..6e6c28e54 --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/exception/InvalidVaultException.java @@ -0,0 +1,10 @@ +package org.labkey.gringotts.api.exception; + +/** + * Created by jon on 11/4/16. + */ +public class InvalidVaultException extends Exception { + public InvalidVaultException(String message) { + super(message); + } +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/exception/RecordNotFoundException.java b/Gringotts/api-src/org/labkey/gringotts/api/exception/RecordNotFoundException.java new file mode 100644 index 000000000..1c17773dd --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/exception/RecordNotFoundException.java @@ -0,0 +1,10 @@ +package org.labkey.gringotts.api.exception; + +/** + * Created by jon on 11/4/16. + */ +public class RecordNotFoundException extends Exception { + public RecordNotFoundException(String message) { + super(message); + } +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/model/ColumnInfo.java b/Gringotts/api-src/org/labkey/gringotts/api/model/ColumnInfo.java new file mode 100644 index 000000000..1a8977ccf --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/model/ColumnInfo.java @@ -0,0 +1,38 @@ +package org.labkey.gringotts.api.model; + +/** + * Created by jon on 11/4/16. + */ +public class ColumnInfo { + public final ValueType type; + public final String columnName; + public final String internalName; + + public ColumnInfo(ValueType type, String columnName, String internalName) { + this.type = type; + this.columnName = columnName; + this.internalName = internalName; + } + + public ColumnInfo(String type, String columnName, String internalName) { + this(ValueType.valueOf(type), columnName, internalName); + } + + @Override + public boolean equals(Object o) { + if (o instanceof ColumnInfo) { + ColumnInfo that = (ColumnInfo) o; + if (this.type.equals(that.type) + && this.columnName.equals(that.columnName) + && this.internalName.equals(that.internalName)) { + return true; + } + else { + return false; + } + } + else { + return false; + } + } +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/model/RawRecordValues.java b/Gringotts/api-src/org/labkey/gringotts/api/model/RawRecordValues.java new file mode 100644 index 000000000..e198930d0 --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/model/RawRecordValues.java @@ -0,0 +1,19 @@ +package org.labkey.gringotts.api.model; + +import org.apache.commons.collections4.map.CaseInsensitiveMap; +import org.joda.time.DateTime; + +/** + * Created by jon on 11/4/16. + */ +public class RawRecordValues { + public final int version; + + public final CaseInsensitiveMap textValues = new CaseInsensitiveMap<>(); + public final CaseInsensitiveMap dateValues = new CaseInsensitiveMap<>(); + public final CaseInsensitiveMap intValues = new CaseInsensitiveMap<>(); + + public RawRecordValues(int version) { + this.version = version; + } +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/model/RecordOriginalValues.java b/Gringotts/api-src/org/labkey/gringotts/api/model/RecordOriginalValues.java new file mode 100644 index 000000000..0de7f9879 --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/model/RecordOriginalValues.java @@ -0,0 +1,17 @@ +package org.labkey.gringotts.api.model; + +import org.apache.commons.collections4.map.CaseInsensitiveMap; + +import java.util.Map; +import java.util.UUID; + +/** + * Created by jon on 10/21/16. + */ +public class RecordOriginalValues { + // This maps the classes in the hierarchy to their record ids + private Map idMap; + + // + private Map> stringValues; +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/model/ValueType.java b/Gringotts/api-src/org/labkey/gringotts/api/model/ValueType.java new file mode 100644 index 000000000..0d0d4fbe3 --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/model/ValueType.java @@ -0,0 +1,39 @@ +package org.labkey.gringotts.api.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joda.time.DateTime; + +/** + * Created by jon on 10/20/16. + */ +public enum ValueType { + TEXT, + DATETIME, + INTEGER; + + @Nullable + public static ValueType getFromName(String name) { + for (ValueType valueType : ValueType.values()) { + if (valueType.name().equalsIgnoreCase(name)) { + return valueType; + } + } + return null; + } + + public static ValueType getFromClass(@NotNull Class clazz) { + if (clazz.isAssignableFrom(DateTime.class)) { + return DATETIME; + } + else if (clazz.isAssignableFrom(Integer.class)) { + return INTEGER; + } + else if (clazz.isAssignableFrom(String.class)) { + return TEXT; + } + else { + return null; + } + } +} diff --git a/Gringotts/api-src/org/labkey/gringotts/api/model/Vault.java b/Gringotts/api-src/org/labkey/gringotts/api/model/Vault.java new file mode 100644 index 000000000..76b5517fe --- /dev/null +++ b/Gringotts/api-src/org/labkey/gringotts/api/model/Vault.java @@ -0,0 +1,205 @@ +package org.labkey.gringotts.api.model; + +import com.google.common.reflect.TypeToken; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.labkey.api.data.Container; +import org.labkey.api.security.User; +import org.labkey.gringotts.api.GringottsService; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.exception.RecordNotFoundException; + +import java.util.HashMap; +import java.util.Map; + +/** + * A Vault is a type-safe persisted object store. To use it, you extend the + * vault as well as the Record class, and then just instantiate the Vault, and + * it's records, saving and deleting them using the methods exposed by Record. + * + * Advantages to using vaults include: + *
    + *
  • + * A simple, type-safe API for interacting with records + *
  • + *
  • + * Automatic handling of relationships between records + *
  • + *
  • + * A full audit log/ledger of all changes to the record, tracking both + * changes over time and QC edits made by administrators. This also + * allows a point-in-time lookback, where you can view the state of a + * record at any time in the past. + *
  • + *
+ * + * Vaults are not great at write performance, so don't use them for something that + * needs to store a new record (or edit) every 10 seconds. The vault ecosystem is + * limited to one transaction per microsecond across all Vaults, since it uses the + * timestamp as the primary key. + * + * @param The class that represents the data record. + * + * Created by Jon Richardson on 10/19/16. + */ +public abstract class Vault { + // Container is used for scoping. + protected Container _container; + + // User is used for auditing. + protected User _user; + + private TypeToken _typeToken; + + /** + * Vaults are not scoped to containers (unlike the Study module), but + * the individual records in a vault ARE scoped to containers, so you + * need to indicate the container view that the vault should expose. + * + * @param container The container to look at for vault records. + * @throws InvalidVaultException + */ + public Vault(Container container) throws InvalidVaultException { + _container = container; + + // Save off the type token for later. + _typeToken = new TypeToken(getClass()) {}; + + initialize(); + } + + /** + * Sets the VaultInfo for the vault to use. + * + * This is synchronized, because only the first call should only run once. + * + * @throws InvalidVaultException + */ + private synchronized void initialize() throws InvalidVaultException { + + } + + public User getUser() { + return _user; + } + + /** + * This is the String that is used in the underlying DB to identify + * the vault, which should NOT conflict with other vaults. By default, + * this is set to the fully qualified canonical name. + * + * You should only need to override this if you want to move an existing + * vault's defining class to a different package or rename it. In that + * case, you'll need to change this to return the old canonical name, otherwise, + * Gringotts will treat it as a new vault, and the vault will lose access + * to all of it's old records. + * + * @return A unique String to identify the Vault. + */ + public String getId() { + return this.getClass().getCanonicalName(); + } + + /** + * Upgrades a record to the current version. The system tries it's best to bind the rawRecordValues + * to the current object, but it's clearly not able to be perfect, so this method is called to finish + * the upgrade. + * + * If this method throws an exception, the upgrade will fail, and the vault will be inaccessible. If + * you want to rely on the default method of upcasting, just override this and return null. Note that + * that can cause data loss (in the case that you remove a persisted field), so you should be careful. + * + * @param recordType + * @param rawRecordValues + */ + public void upgrade(RecordType recordType, RawRecordValues rawRecordValues) { + throw new UnsupportedOperationException("Not implemented"); + } + + /** + * Return a pretty display name. Often, this is very similar to the class name. + * + * @return A string to display as the name of the Vault in UIs, debugs, etc. + */ + public abstract String getDisplayName(); + + public int getCurrentRecordVersion() { + return 0; + } + + public TypeToken getTypeToken() { + return _typeToken; + } + + public abstract class Record { + // We can take advantage of the extends functionality in Java to allow a record to inherit fields + // nicely, but we can't really inherit the id, so we store the id has a hash of all ids for each + // class. + private final Map idMap = new HashMap<>(); + + // A reference to the original values currently in the DB + private RawRecordValues oldValues = null; + + protected int version = Vault.this.getCurrentRecordVersion(); + + // This is a private constructor shared by the two "public" constructors. + private Record(@NotNull String id, @Nullable Object dummyObjectToMakeSignatureUnique) { + idMap.put(getVault().getTypeToken(), id); + } + + public String getId(TypeToken typeToken) { + return idMap.get(typeToken); + } + + /** + * Opens an existing record from the Vault. + * + * @param id the id of the record in the vault to retrieve + * @throws RecordNotFoundException if the id doesn't exist in the database. + */ + protected Record(@NotNull String id) throws RecordNotFoundException { + this(id, null); + + } + + public RawRecordValues getOldValues() { + return oldValues; + } + + /** + * Constructs a brand new record. + */ + protected Record() { + this(GringottsService.getNewId(), null); + } + + private final void bind() { + GringottsService.get().bindRecord(this); + } + + /** + * Utility function to access the containing Vault. + * + * @return the Record's containing vault + */ + public final Vault getVault() { + return Vault.this; + } + + /** + * Persists the record to the database, and updates this.oldValues + */ + public final void save() { + GringottsService.get().saveRecord(this); + } + + /** + * Marks a record as deleted in the database. This prevents it from existing from this point on, but + * it will still technically be stored in the database to allow historical queries and maintain the + * ledger. + */ + public final void delete() { + GringottsService.get().deleteRecord(this); + } + } +} diff --git a/Gringotts/build.gradle b/Gringotts/build.gradle new file mode 100644 index 000000000..482c4c8ff --- /dev/null +++ b/Gringotts/build.gradle @@ -0,0 +1,15 @@ +import org.labkey.gradle.util.BuildUtils + +dependencies { + + BuildUtils.addLabKeyDependency(project: project, config: "compile", depProjectPath: ":server:modules:LabDevKitModules:LDK", depProjectConfig: "apiCompile") + + apiExternal "xerces:xercesImpl:${xercesImplVersion}" + apiExternal "org.apache.commons:commons-collections4:${commonsCollections4Version}" + apiExternal "joda-time:joda-time:2.9.3" + compile "javax.servlet:jsp-api:2.0" + compile files(apiJar) + external "org.jooq:jooq:3.8.4" + external "org.apache.commons:commons-collections4:${commonsCollections4Version}" + external "joda-time:joda-time:2.9.3" +} \ No newline at end of file diff --git a/Gringotts/module.properties b/Gringotts/module.properties new file mode 100644 index 000000000..b9debefcf --- /dev/null +++ b/Gringotts/module.properties @@ -0,0 +1,8 @@ +Label: WNPRC Gringotts Data Store +License: Apache 2.0 +SupportedDatabases: pgsql +LicenseURL: http://www.apache.org/licenses/LICENSE-2.0 +ModuleClass: org.labkey.gringotts.GringottsModule +ModuleDependencies: LDK +Name: Gringotts +Version: 1.0 \ No newline at end of file diff --git a/Gringotts/resources/credits/jars.txt b/Gringotts/resources/credits/jars.txt new file mode 100644 index 000000000..6382209b0 --- /dev/null +++ b/Gringotts/resources/credits/jars.txt @@ -0,0 +1,6 @@ +{table} +Filename|Component|Version|Source|License|LabKey Dev|Purpose +commons-collections4-4.1.jar|Apache Commons Collections|4.1|{link:From Apache|https://git-wip-us.apache.org/repos/asf?p=commons-collections.git}|{link:Apache Software License 2.0|http://www.apache.org/licenses/LICENSE-2.0}|jrichardson|Tools for managing Java collections +joda-time-2.9.3.jar|Joda-Time|2.9.3|{link:From GitHub|https://github.com/JodaOrg/joda-time}|{link:Apache Software License 2.0|http://www.apache.org/licenses/LICENSE-2.0}|jrichardson|Tools for dealing with dates/times in Java +jooq-3.8.4.jar|jOOQ|3.8.4|{link:From GitHub|https://github.com/jOOQ/jOOQ}|{link:Apache Software License 2.0|http://www.apache.org/licenses/LICENSE-2.0}|jrichardson|Database-mapping for Java +{table} \ No newline at end of file diff --git a/Gringotts/resources/schemas/dbscripts/postgresql/gringotts-15.10-15.11.sql b/Gringotts/resources/schemas/dbscripts/postgresql/gringotts-15.10-15.11.sql new file mode 100644 index 000000000..e7a8428fd --- /dev/null +++ b/Gringotts/resources/schemas/dbscripts/postgresql/gringotts-15.10-15.11.sql @@ -0,0 +1,145 @@ +-- Create schema, tables, indexes, and constraints used for Gringotts module here +-- All SQL VIEW definitions should be created in gringotts-create.sql and dropped in gringotts-drop.sql +CREATE SCHEMA gringotts; + +/* + * This is just a lookup from Vault Class name (getId()) on the Vault object to the + * internal vaultid. This is so the "Id" can change in the future, but would never + * need to change internally, because it would use an internally assigned id. + * + * Initially, I do not plan to support changing the id of a vault, but I'd like to + * leave the door open for doing it in the future without introducing a huge headache. + */ +CREATE TABLE gringotts.vaults ( + vaultId TEXT NOT NULL, + vaultClassName TEXT NOT NULL, + + -- Purposely not including modified[By], as vaults are only ever created, not modified + createdby userid, + created TIMESTAMP, + + CONSTRAINT PK_vaults PRIMARY KEY (vaultId, created) +); + +/* + * This is the basic unit of the ledger. Every update to the database is associated + * with a transaction. + * + * Transactions can cover multiple vaults, so that changes to associated records can + * be atomic, and there is less contention over transaction timestamps. + */ +CREATE TABLE gringotts.transactions ( + createdOn TIMESTAMP DEFAULT current_timestamp, + + transactionId TEXT NOT NULL, + "user" userid, + + -- These two are for QC transactions. Essentially, a transaction can "take effect" in + -- the past, which allows you to essentially edit old records while still leaving a + -- perfect ledger. To edit, you'd add a new transaction with a date of now but an + -- effectiveOn of the exact timestamp of the + effectiveOn TIMESTAMP, + comment TEXT, + + CONSTRAINT PK_transactions PRIMARY KEY (createdOn), + CONSTRAINT transactions_id_unique UNIQUE (transactionId) +); +COMMENT ON TABLE gringotts.transactions IS 'This is the basic unit of the ledger. Every update to the database is associated with a transaction.'; + + +/* + * This table essentially holds all of the structures of the various versions of the record. + * This also supplies the mappings between the internal column name and the exposed "column" + * name. In general, they will line up, unless there are changes made to the data structure. + */ +CREATE TABLE gringotts.vault_columns ( + vaultId TEXT NOT NULL, + version INTEGER, + columnName TEXT, + + type TEXT, + columnId TEXT, + + CONSTRAINT PK_vault_columns PRIMARY KEY (vaultId, version, columnName) +); + + +CREATE TABLE gringotts.records ( + vaultId TEXT NOT NULL, + recordId TEXT NOT NULL, + container ENTITYID NOT NULL, + version INTEGER, + + transactionId TEXT NOT NULL, + + CONSTRAINT PK_records PRIMARY KEY (vaultId, recordId, version) +); + +CREATE TABLE gringotts.vault_text_values ( + vaultId TEXT NOT NULL, + recordId TEXT NOT NULL, + columnId TEXT NOT NULL, + transactionId TEXT NOT NULL, + + value TEXT, + effectiveDate TIMESTAMP, + + CONSTRAINT PK_vault_text_values PRIMARY KEY (vaultId, recordId, columnId, transactionId), + CONSTRAINT FK_vault_text_values_transactions FOREIGN KEY (transactionId) REFERENCES gringotts.transactions (transactionId) +); + +CREATE TABLE gringotts.vault_datetime_values ( + vaultId TEXT NOT NULL, + recordId TEXT NOT NULL, + columnId TEXT NOT NULL, + transactionId TEXT NOT NULL, + + value TIMESTAMP, + effectiveDate TIMESTAMP, + + CONSTRAINT PK_vault_datetime_values PRIMARY KEY (vaultId, recordId, columnId, transactionId), + CONSTRAINT FK_vault_datetime_values_transactions FOREIGN KEY (transactionId) REFERENCES gringotts.transactions (transactionId) +); + +CREATE TABLE gringotts.vault_int_values ( + vaultId TEXT NOT NULL, + recordId TEXT NOT NULL, + columnId TEXT NOT NULL, + transactionId TEXT NOT NULL, + + value INTEGER, + effectiveDate TIMESTAMP, + + CONSTRAINT PK_vault_int_values PRIMARY KEY (vaultId, recordId, columnId, transactionId), + CONSTRAINT FK_vault_int_values_transactions FOREIGN KEY (transactionId) REFERENCES gringotts.transactions (transactionId) +); + +/* + * This holds the mappings for records that extend other records. The child vault class must extend the + * parent vault class. + */ +CREATE TABLE gringotts.vault_parent_records ( + childVaultId TEXT NOT NULL, + childRecordId TEXT NOT NULL, + parentVaultId TEXT NOT NULL, + parentRecordId TEXT NOT NULL, + + CONSTRAINT PK_vault_parent_records PRIMARY KEY (childRecordId, childVaultId, parentVaultId, parentRecordId) +); + +CREATE TABLE gringotts.vault_links ( + -- "Primary" primary keys + vaultId1 TEXT NOT NULL, -- source + columnId TEXT NOT NULL, + vaultId2 TEXT NOT NULL, -- target + + -- "Secondary" primary keys + record1 TEXT NOT NULL, -- source + record2 TEXT NOT NULL, -- target + transactionId TEXT NOT NULL, + + isLinked BOOLEAN NOT NULL DEFAULT TRUE, + "order" INTEGER, + + CONSTRAINT PK_vault_links PRIMARY KEY (vaultId1, columnId, vaultId2, record1, record2, transactionId) +); \ No newline at end of file diff --git a/Gringotts/resources/schemas/dbscripts/sqlserver/gringotts-15.10-15.11.sql b/Gringotts/resources/schemas/dbscripts/sqlserver/gringotts-15.10-15.11.sql new file mode 100644 index 000000000..89459245f --- /dev/null +++ b/Gringotts/resources/schemas/dbscripts/sqlserver/gringotts-15.10-15.11.sql @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +-- Create schema, tables, indexes, and constraints used for Gringotts module here +-- All SQL VIEW definitions should be created in gringotts-create.sql and dropped in gringotts-drop.sql +CREATE SCHEMA gringotts; +GO \ No newline at end of file diff --git a/Gringotts/resources/schemas/gringotts.xml b/Gringotts/resources/schemas/gringotts.xml new file mode 100644 index 000000000..bf111e0df --- /dev/null +++ b/Gringotts/resources/schemas/gringotts.xml @@ -0,0 +1,105 @@ + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + +
+
\ No newline at end of file diff --git a/Gringotts/src/org/labkey/gringotts/GringottsContainerListener.java b/Gringotts/src/org/labkey/gringotts/GringottsContainerListener.java new file mode 100644 index 000000000..1a5201894 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/GringottsContainerListener.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringotts; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager.ContainerListener; +import org.labkey.api.security.User; +import java.util.Collections; +import java.util.Collection; + +import java.beans.PropertyChangeEvent; + +public class GringottsContainerListener implements ContainerListener +{ + @Override + public void containerCreated(Container c, User user) + { + } + + @Override + public void containerDeleted(Container c, User user) + { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + } + + @Override + public void containerMoved(Container c, Container oldParent, User user) + { + } + + @NotNull @Override + public Collection canMove(Container c, Container newParent, User user) + { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/Gringotts/src/org/labkey/gringotts/GringottsController.java b/Gringotts/src/org/labkey/gringotts/GringottsController.java new file mode 100644 index 000000000..72063ed5d --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/GringottsController.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringotts; + +import org.labkey.api.action.SimpleViewAction; +import org.labkey.api.action.SpringActionController; +import org.labkey.api.security.RequiresPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.view.JspView; +import org.labkey.api.view.NavTree; +import org.springframework.validation.BindException; +import org.springframework.web.servlet.ModelAndView; + +public class GringottsController extends SpringActionController { + private static final DefaultActionResolver _actionResolver = new DefaultActionResolver(GringottsController.class); + public static final String NAME = "gringotts"; + + public GringottsController() { + setActionResolver(_actionResolver); + } + + @RequiresPermission(ReadPermission.class) + public class BeginAction extends SimpleViewAction { + public ModelAndView getView(Object o, BindException errors) throws Exception { + return new JspView("/org/labkey/gringotts/view/hello.jsp"); + } + + public NavTree appendNavTrail(NavTree root) + { + return root; + } + } +} \ No newline at end of file diff --git a/Gringotts/src/org/labkey/gringotts/GringottsManager.java b/Gringotts/src/org/labkey/gringotts/GringottsManager.java new file mode 100644 index 000000000..538fe3cc0 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/GringottsManager.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringotts; + +public class GringottsManager { + private static final GringottsManager _instance = new GringottsManager(); + + private GringottsManager() { + // prevent external construction with a private default constructor + } + + public static GringottsManager get() + { + return _instance; + } +} \ No newline at end of file diff --git a/Gringotts/src/org/labkey/gringotts/GringottsModule.java b/Gringotts/src/org/labkey/gringotts/GringottsModule.java new file mode 100644 index 000000000..a6fb839bd --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/GringottsModule.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringotts; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.ldk.ExtendedSimpleModule; +import org.labkey.api.module.DefaultModule; +import org.labkey.api.module.ModuleContext; +import org.labkey.api.view.WebPartFactory; +import org.labkey.gringotts.api.GringottsService; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public class GringottsModule extends ExtendedSimpleModule { + public static final String NAME = "Gringotts"; + + @Override + public String getName() { + return NAME; + } + + @Override + public Double getSchemaVersion() { + return 20.000; + } + + @Override + public boolean hasScripts() { + return true; + } + + @Override + @NotNull + protected Collection createWebPartFactories() { + return Collections.emptyList(); + } + + @Override + protected void init() { + addController(GringottsController.NAME, GringottsController.class); + } + + @Override + public void doStartupAfterSpringConfig(ModuleContext moduleContext) { + // add a container listener so we'll know when our container is deleted: + ContainerManager.addContainerListener(new GringottsContainerListener()); + + GringottsService.set(new GringottsServiceImpl()); + } + + @Override + @NotNull + public Collection getSummary(Container c) { + return Collections.emptyList(); + } + + @Override + @NotNull + public Set getSchemaNames() { + return Collections.singleton(GringottsSchema.NAME); + } +} \ No newline at end of file diff --git a/Gringotts/src/org/labkey/gringotts/GringottsSchema.java b/Gringotts/src/org/labkey/gringotts/GringottsSchema.java new file mode 100644 index 000000000..9408d5d10 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/GringottsSchema.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringotts; + +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; +import org.labkey.api.data.DbSchema; +import org.labkey.api.data.DbSchemaType; +import org.labkey.api.data.TableInfo; +import org.labkey.api.data.dialect.SqlDialect; + +import java.sql.Timestamp; + +public class GringottsSchema { + private static final GringottsSchema _instance = new GringottsSchema(); + public static final String NAME = "gringotts"; + + public static GringottsSchema getInstance() + { + return _instance; + } + + private GringottsSchema() { + // private constructor to prevent instantiation from + // outside this class: this singleton should only be + // accessed via org.labkey.gringotts.GringottsSchema.getInstance() + } + + public DbSchema getSchema() { + return DbSchema.get(NAME, DbSchemaType.Module); + } + + public TableInfo getVaultTableInfo() { + return this.getSchema().getTable("vaults"); + } + + public SqlDialect getSqlDialect() { + return getSchema().getSqlDialect(); + } + + static public DSLContext getSQLConnection() { + return DSL.using(SQLDialect.POSTGRES); + } + + public static Timestamp now() { + return new Timestamp(System.currentTimeMillis()); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/GringottsServiceImpl.java b/Gringotts/src/org/labkey/gringotts/GringottsServiceImpl.java new file mode 100644 index 000000000..589642da0 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/GringottsServiceImpl.java @@ -0,0 +1,140 @@ +package org.labkey.gringotts; + +import com.google.common.reflect.TypeToken; +import org.apache.commons.collections4.map.CaseInsensitiveMap; +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; +import org.labkey.gringotts.api.GringottsService; +import org.labkey.gringotts.api.annotation.SerializeField; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.model.Vault; +import org.labkey.gringotts.api.model.ValueType; +import org.labkey.gringotts.model.Transaction; +import org.labkey.gringotts.model.VaultSerializationInfo; +import org.labkey.gringotts.model.jooq.tables.VaultColumns; +import org.labkey.gringotts.model.jooq.tables.Vaults; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +/** + * Created by jon on 10/19/16. + */ +public class GringottsServiceImpl extends GringottsService { + private DSLContext getSQLConnection() { + return DSL.using(SQLDialect.POSTGRES); + } + + private class RowInfo { + public final Field field; + public final ValueType type; + + public RowInfo(Field field, ValueType type) { + this.field = field; + this.type = type; + } + } + + + private CaseInsensitiveMap getRowMap(Class clazz) { + CaseInsensitiveMap map = new CaseInsensitiveMap<>(); + + for (Field field : clazz.getDeclaredFields()) { + if (field.isAnnotationPresent(SerializeField.class)) { + SerializeField fieldAnnotation = field.getAnnotation(SerializeField.class); + + String fieldName = fieldAnnotation.columnName(); + + // Default to using the actual field name from the class as the column name + if ("".equals(fieldName)) { + fieldName = field.getName(); + } + + map.put(fieldName, new RowInfo(field, ValueType.TEXT)); + } + } + + return map; + } + + @Override + public void saveRecord(Vault.Record record) { + // Initialize our tables + Vaults vaults = new Vaults(); + VaultColumns columns = new VaultColumns(); + + try(Transaction transaction = new Transaction(VaultSerializationInfo.getInfo(record.getVault().getTypeToken()))) { + + + } + catch (InvalidVaultException e) { + e.printStackTrace(); + } + catch (Exception e) { + e.printStackTrace(); + } + + + /* Just some exampley code to show how to interact with the record. + VaultsRecord tempVaultRecord = create.fetchOne(vaults, vaults.VAULTNAME.eq(vaultInfo.name())); + if (tempVaultRecord != null) { + this.vaultRecord = tempVaultRecord; + } + else { + if (createIfNotExists) { + this.vaultRecord = vaults.newRecord(); + this.vaultRecord.setVaultname(this.getName()); + this.vaultRecord.store(); + } + else { + throw new NotAVaultException(); + } + } + */ + } + + @Override + public void deleteRecord(Vault.Record record) { + + } + + @Override + public void bindRecord(Vault.Record record) { + + } + + private Map _validationLatches = new HashMap<>(); + private Map _vaultInfoMap = new HashMap<>(); + + public synchronized VaultSerializationInfo validateVault(Vault vault) throws InvalidVaultException { + TypeToken recordType = vault.getTypeToken(); + + // If there's already a validation under way for this record type, await it's completion + if (_validationLatches.containsKey(recordType)) { + CountDownLatch latch = _validationLatches.get(vault.getTypeToken()); + try { + latch.await(); + } + catch (InterruptedException e) { + throw new InvalidVaultException("Vault timed out during validation"); + } + // Otherwise, set a latch and start working on validating the Vault. + } + else { + // Set the latch + CountDownLatch latch = new CountDownLatch(1); + _validationLatches.put(recordType, latch); + + // Generate the vault info + //_vaultInfoMap.put(recordType, VaultUtils.generateVaultInfo(vault)); + + // Release the latch + latch.countDown(); + } + + return _vaultInfoMap.get(recordType); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/Transaction.java b/Gringotts/src/org/labkey/gringotts/model/Transaction.java new file mode 100644 index 000000000..c90822772 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/Transaction.java @@ -0,0 +1,218 @@ +package org.labkey.gringotts.model; + +import com.google.common.reflect.TypeToken; +import org.apache.commons.collections4.map.CaseInsensitiveMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joda.time.DateTime; +import org.jooq.DSLContext; +import org.jooq.impl.DSL; +import org.labkey.gringotts.GringottsSchema; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.model.Vault; +import org.labkey.gringotts.model.jooq.tables.records.VaultDatetimeValuesRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultIntValuesRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultTextValuesRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultsRecord; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.labkey.gringotts.model.jooq.tables.VaultTextValues.VAULT_TEXT_VALUES; +import static org.labkey.gringotts.model.jooq.tables.VaultDatetimeValues.VAULT_DATETIME_VALUES; +import static org.labkey.gringotts.model.jooq.tables.VaultIntValues.VAULT_INT_VALUES; + +/** + * Created by jon on 11/8/16. + */ +public class Transaction implements AutoCloseable { + private final VaultSerializationInfo vaultInfo; + private final String transactionId = VaultUtils.getNewId(); + private final DSLContext sqlConnection = GringottsSchema.getSQLConnection(); + + // Table metadata + private List _vaultsRecords = new ArrayList<>(); + + // Now for the actual record values + private List _textValuesRecords = new ArrayList<>(); + private List _dateTimeValuesRecords = new ArrayList<>(); + private List _intValuesRecords = new ArrayList<>(); + + public Transaction(VaultSerializationInfo vault) { + this.vaultInfo = vault; + } + + public void addTextValueRecord(@NotNull String recordId, @NotNull String internalColumnId, @NotNull String value) { + this.addTextValueRecord(recordId, internalColumnId, value, null); + } + + public void addTextValueRecord(@NotNull String recordId, @NotNull String internalColumnId, @NotNull String value, @Nullable DateTime effectiveDate) { + VaultTextValuesRecord record = sqlConnection.newRecord(VAULT_TEXT_VALUES); + + // Set generic identifiers + record.setVaultid(vaultInfo.getInternalId()); + record.setTransactionid(transactionId); + + // Set specific identifiers + record.setRecordid(recordId); + record.setColumnid(internalColumnId); + + // Set value and effective date + record.setEffectivedate(convertTime(effectiveDate)); + record.setValue(value); + + _textValuesRecords.add(record); + } + + public void addDateTimeValueRecord(@NotNull String recordId, @NotNull String internalColumnId, @NotNull DateTime value) { + this.addDateTimeValueRecord(recordId, internalColumnId, value, null); + } + + public void addDateTimeValueRecord(@NotNull String recordId, @NotNull String internalColumnId, @NotNull DateTime value, @Nullable DateTime effectiveDate) { + VaultDatetimeValuesRecord record = sqlConnection.newRecord(VAULT_DATETIME_VALUES); + + // Set generic identifiers + record.setVaultid(vaultInfo.getInternalId()); + record.setTransactionid(transactionId); + + // Set specific identifiers + record.setRecordid(recordId); + record.setColumnid(internalColumnId); + + // Set value and effective date + //record.setEffectivedate(new Timestamp(effectiveDate.getMillis())); + record.setValue(convertTime(value)); + + _dateTimeValuesRecords.add(record); + } + + public void addIntValueRecord(@NotNull String recordId, @NotNull String internalColumnId, @NotNull Integer value) { + this.addIntValueRecord(recordId, internalColumnId, value, null); + } + + public void addIntValueRecord(@NotNull String recordId, @NotNull String internalColumnId, @NotNull Integer value, @Nullable DateTime effectiveDate) { + VaultIntValuesRecord record = sqlConnection.newRecord(VAULT_INT_VALUES); + + // Set generic identifiers + record.setVaultid(vaultInfo.getInternalId()); + record.setTransactionid(transactionId); + + // Set specific identifiers + record.setRecordid(recordId); + record.setColumnid(internalColumnId); + + // Set value and effective date + //record.setEffectivedate(new Timestamp(effectiveDate.getMillis())); + record.setValue(value); + + _intValuesRecords.add(record); + } + + public boolean hasChanges() { + return (_dateTimeValuesRecords.size() != 0) + || (_textValuesRecords.size() != 0) + || (_intValuesRecords.size() != 0); + } + + @Nullable + private Timestamp convertTime(DateTime dateTime) { + if (dateTime == null) { + return null; + } + + return new Timestamp(dateTime.getMillis()); + } + + public void saveRecord(Vault.Record record) throws InvalidVaultException { + TypeToken typeToken = record.getVault().getTypeToken(); + + TypeToken currentTypeToken = typeToken; + + while(!currentTypeToken.equals(TypeToken.of(Vault.Record.class))) { + saveClass(record, currentTypeToken); + currentTypeToken = TypeToken.of(currentTypeToken.getRawType().getSuperclass()); + } + } + + /** + * This guy saves all of the records associated with this class in the + * class inheritance tree. + * + * @param record + * @param typeToken + * @throws InvalidVaultException + */ + private void saveClass(Vault.Record record, TypeToken typeToken) throws InvalidVaultException { + VaultSerializationInfo info = VaultSerializationInfo.getInfo(record.getVault()); + + // Start by saving the date values + Map curDateValues = info.getTimestampValues(record); + CaseInsensitiveMap oldDateValues = record.getOldValues().dateValues; + + for(String key : curDateValues.keySet()) { + if (!curDateValues.get(key).isEqual(oldDateValues.get(key))) { + addDateTimeValueRecord( + record.getId(typeToken), + key, + curDateValues.get(key) + ); + } + } + + // Now, do the text values. + Map curTextValues = info.getTextValues(record); + CaseInsensitiveMap oldTextValues = record.getOldValues().textValues; + + for(String key : curTextValues.keySet()) { + if (!curTextValues.get(key).equals(oldTextValues.get(key))) { + addTextValueRecord( + record.getId(typeToken), + key, + curTextValues.get(key) + ); + } + } + + // Finally, do the ints + Map curIntValues = info.getIntValues(record); + CaseInsensitiveMap oldIntValues = record.getOldValues().intValues; + + for(String key : curIntValues.keySet()) { + if (!curIntValues.get(key).equals(oldIntValues.get(key))) { + addIntValueRecord( + record.getId(typeToken), + key, + curIntValues.get(key) + ); + } + } + } + + @Override + public void close() throws Exception { + // Don't do anything if we have no changes to write. + if (!hasChanges()) { + return; + } + + sqlConnection.transaction(config -> { + if (!_vaultsRecords.isEmpty()) { + DSL.using(config).batchInsert(_vaultsRecords).execute(); + } + + if (!_textValuesRecords.isEmpty()) { + DSL.using(config).batchInsert(_textValuesRecords).execute(); + } + + if (!_intValuesRecords.isEmpty()) { + DSL.using(config).batchInsert(_intValuesRecords).execute(); + } + + if (!_dateTimeValuesRecords.isEmpty()) { + DSL.using(config).batchInsert(_dateTimeValuesRecords).execute(); + } + }); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/VaultSerializationInfo.java b/Gringotts/src/org/labkey/gringotts/model/VaultSerializationInfo.java new file mode 100644 index 000000000..99b38433f --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/VaultSerializationInfo.java @@ -0,0 +1,389 @@ +package org.labkey.gringotts.model; + +import com.google.common.reflect.TypeToken; +import org.apache.commons.collections4.map.CaseInsensitiveMap; +import org.joda.time.DateTime; +import org.jooq.DSLContext; +import org.jooq.Result; +import org.jooq.impl.DSL; +import org.labkey.gringotts.GringottsSchema; +import org.labkey.gringotts.api.GringottsService; +import org.labkey.gringotts.api.annotation.SerializeField; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.model.ColumnInfo; +import org.labkey.gringotts.api.model.RawRecordValues; +import org.labkey.gringotts.api.model.ValueType; +import org.labkey.gringotts.api.model.Vault; +import org.labkey.gringotts.model.jooq.tables.records.VaultColumnsRecord; + +import java.lang.reflect.Field; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.labkey.gringotts.model.jooq.tables.VaultColumns.VAULT_COLUMNS; + +/** + * Created by jon on 11/4/16. + */ +public class VaultSerializationInfo { + private final TypeToken token; + private VaultSerializationInfo parentInfo; + private final String internalId; + + // A list of the versions + private final List> versions; + + // Current Version FieldMaps + private Map currentDateFields = new HashMap<>(); + private Map currentIntFields = new HashMap<>(); + private Map currentTextFields = new HashMap<>(); + + // A collection of all internal names that have been used. + public Set usedColumnNames = new HashSet<>(); + + public boolean needsToFlushMostRecentColumnMap = false; + + /** + * This method is private to force usage of the #getInfo() factory. + * + * @param token + * @throws InvalidVaultException + */ + private VaultSerializationInfo(TypeToken token) throws InvalidVaultException { + this.token = token; + this.internalId = getInternalId(); + + this.versions = getVersions(); + + Class superClass = token.getRawType().getSuperclass(); + if (superClass == Vault.Record.class) { + parentInfo = null; + } + else { + + } + } + + public Integer getCurrentVersion() { + return versions.size(); + } + + public String getInternalId() { + if (internalId != null) { + return internalId; + } + + return VaultUtils.getInternalId(token); + } + + public List> getVersions() throws InvalidVaultException { + if (this.versions != null) { + return this.versions; + } + + // Create a new list to use + List> versions = new ArrayList<>(); + + // Fetch a map of previous column maps + Map> versionColumnMap = GringottsSchema.getSQLConnection().selectFrom(VAULT_COLUMNS).fetch().intoGroups(VAULT_COLUMNS.VERSION); + + // Figure out the highest version number + int highestIndex = Collections.max(versionColumnMap.keySet()).intValue(); + + // Loop through each version to convert to a ColumnInfo record. + for (int i = 0; i <= highestIndex; i++) { + CaseInsensitiveMap columnMap = new CaseInsensitiveMap(); + versions.add(columnMap); + + for(VaultColumnsRecord columnRecord : versionColumnMap.get(i)) { + ColumnInfo info = new ColumnInfo( + columnRecord.getType(), + columnRecord.getColumnname(), + columnRecord.getColumnid() + ); + + columnMap.put(info.columnName, info); + + usedColumnNames.add(info.internalName); + } + } + + // Possibly add the current map to the pool. + CaseInsensitiveMap currentMap = getColumnMapForClass(token.getRawType()); + if (versions.size() == 0 || !columnMapsAreEqual(currentMap, versions.get(versions.size() - 1))) { + versions.add(currentMap); + needsToFlushMostRecentColumnMap = true; + } + + return versions; + } + + private CaseInsensitiveMap getColumnMapForClass(Class clazz) throws InvalidVaultException { + CaseInsensitiveMap columnMap = new CaseInsensitiveMap(); + + for (Field field : clazz.getFields()) { + if (field.isAnnotationPresent(SerializeField.class)) { + SerializeField fieldInfo = field.getAnnotation(SerializeField.class); + + // If the column name is "", that means that we should just use the field name. + String columnName = fieldInfo.columnName().equals("") ? field.getName().toLowerCase() : fieldInfo.columnName(); + String internalColumnName = internalizeColumnName(columnName); + + ValueType type = ValueType.getFromClass(field.getClass()); + + if (type == null) { + throw new InvalidVaultException(String.format( + "Unrecognized type marked for serialization: %s is of type %s. See %s for valid types.", + field.getName(), + field.getClass(), + ValueType.class.getCanonicalName() + )); + } + + // Check to see if this column existed in the last version in the same form. If so, give + // it the same internal id. + if (versions.size() > 0) { + CaseInsensitiveMap lastMap = versions.get(versions.size() - 1); + + if (lastMap.containsKey(columnName)) { + ColumnInfo oldColumn = lastMap.get(columnName); + + if (oldColumn.type.equals(type)) { + internalColumnName = oldColumn.internalName; + } + } + } + + columnMap.put(field.getName(), new ColumnInfo(type, columnName, internalColumnName)); + } + } + + return columnMap; + } + + Pattern endPattern = Pattern.compile(".*_(?[0-9]+)$"); + private String internalizeColumnName(String originalColumnName) { + String internalColumnName = originalColumnName; + + while (usedColumnNames.contains(internalColumnName)) { + Matcher matcher = endPattern.matcher(internalColumnName); + + if (matcher.matches()) { + // Get the current version + Integer currentVersion = Integer.valueOf(matcher.group("NUM"), 10); + internalColumnName = matcher.replaceAll(""); // Remove the suffix + + // Append an incremented number + internalColumnName = internalColumnName + "_" + (new Integer(currentVersion + 1)).toString(); + } + else { + internalColumnName = internalColumnName + "_2"; + } + } + + return internalColumnName; + } + + private boolean columnMapsAreEqual(CaseInsensitiveMap map1, CaseInsensitiveMap map2) { + if (!map1.keySet().containsAll(map2.keySet()) || !map2.keySet().containsAll(map1.keySet())) { + return false; + } + + for (String key : map1.keySet()) { + ColumnInfo info1 = map1.get(key); + ColumnInfo info2 = map1.get(key); + + if (!info1.equals(info2)) { + return false; + } + } + + return true; + } + + public void beforeWrite() { + if (needsToFlushMostRecentColumnMap) { + this.flushMostRecentColumnMap(); + needsToFlushMostRecentColumnMap = !needsToFlushMostRecentColumnMap; + } + } + + private void flushMostRecentColumnMap() { + CaseInsensitiveMap map = versions.get(versions.size() - 1); + + GringottsSchema.getSQLConnection().transaction(conn -> { + for (String name : map.keySet()) { + ColumnInfo info = map.get(name); + + VaultColumnsRecord rec = DSL.using(conn).newRecord(VAULT_COLUMNS); + + rec.setColumnid(info.internalName); + rec.setColumnname(info.columnName); + rec.setVersion(getCurrentVersion()); + rec.setVaultid(getInternalId()); + rec.setType(info.type.name()); + + rec.store(); + } + }); + } + + public void saveRecord(Vault.Record record) { + CaseInsensitiveMap curMap = versions.get(versions.size() - 1); + + Class recordClass = record.getVault().getTypeToken().getRawType(); + + for (String fieldName : curMap.keySet()) { + // Do something + } + } + + public Map getTimestampValues(Object o) { + Map map = new HashMap<>(); + + if (token.getRawType().isAssignableFrom(o.getClass())) { + for(Field field : currentDateFields.keySet()) { + String columnName = currentDateFields.get(field); + + try(FieldAccessorHelper helper = new FieldAccessorHelper(field)) { + DateTime value = (DateTime) field.get(o); + map.put(columnName, value); + } + catch (IllegalAccessException e) { + // Field Accessor helper should prevent us from getting here... + assert false; + } + } + } + + return map; + } + + public Map getTextValues(Object o) { + Map map = new HashMap<>(); + + if (token.getRawType().isAssignableFrom(o.getClass())) { + for(Field field : currentTextFields.keySet()) { + String columnName = currentTextFields.get(field); + + try(FieldAccessorHelper helper = new FieldAccessorHelper(field)) { + String value = (String) field.get(o); + map.put(columnName, value); + } + catch (IllegalAccessException e) { + // Field Accessor helper should prevent us from getting here... + assert false; + } + } + } + + return map; + } + + public Map getIntValues(Object o) { + Map map = new HashMap<>(); + + if (token.getRawType().isAssignableFrom(o.getClass())) { + for(Field field : currentTextFields.keySet()) { + String columnName = currentTextFields.get(field); + + try(FieldAccessorHelper helper = new FieldAccessorHelper(field)) { + Integer value = (Integer) field.get(o); + map.put(columnName, value); + } + catch (IllegalAccessException e) { + // Field Accessor helper should prevent us from getting here... + assert false; + } + } + } + + return map; + } + + public void bind(Vault.Record record) { + RawRecordValues curValues = getCurrentValues(); + + for (Field field : currentTextFields.keySet()) { + try(FieldAccessorHelper helper = new FieldAccessorHelper(field)) { + field.set(record, curValues.textValues.get(currentTextFields.get(field))); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + for (Field field : currentIntFields.keySet()) { + try(FieldAccessorHelper helper = new FieldAccessorHelper(field)) { + field.set(record, curValues.intValues.get(currentIntFields.get(field))); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + for (Field field : currentDateFields.keySet()) { + try(FieldAccessorHelper helper = new FieldAccessorHelper(field)) { + field.set(record, curValues.dateValues.get(currentDateFields.get(field))); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + + public RawRecordValues getCurrentValues() { + return null; + } + + public static class FieldAccessorHelper implements AutoCloseable { + private boolean originalAccessible; + private Field f; + + public FieldAccessorHelper(Field f) { + this.f = f; + this.originalAccessible = f.isAccessible(); + + if (!f.isAccessible()) { + f.setAccessible(true); + } + } + + @Override + public void close() { + if (originalAccessible != f.isAccessible()) { + f.setAccessible(originalAccessible); + } + } + } + + /* + * Each DBRecord class only needs to be instantiated once, so we use a cache to hold all of the already + * instantiated ones. + */ + private final static Map cache = new HashMap<>(); + + public static VaultSerializationInfo getInfo(TypeToken typeToken) throws InvalidVaultException { + VaultSerializationInfo info = cache.get(typeToken); + + if (info == null) { + info = new VaultSerializationInfo(typeToken); + + cache.put(typeToken, info); + } + + return info; + } + + public static VaultSerializationInfo getInfo(Vault vault) throws InvalidVaultException { + return getInfo(vault.getTypeToken()); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/VaultUtils.java b/Gringotts/src/org/labkey/gringotts/model/VaultUtils.java new file mode 100644 index 000000000..221507375 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/VaultUtils.java @@ -0,0 +1,101 @@ +package org.labkey.gringotts.model; + +import com.google.common.reflect.TypeToken; +import org.apache.xerces.impl.dv.util.Base64; +import org.jooq.DSLContext; +import org.jooq.Result; +import org.labkey.api.security.User; +import org.labkey.gringotts.GringottsSchema; +import org.labkey.gringotts.api.GringottsService; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.model.Vault; +import org.labkey.gringotts.model.jooq.tables.records.VaultsRecord; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.labkey.gringotts.model.jooq.tables.Vaults.VAULTS; + +/** + * Created by jon on 10/19/16. + */ +public class VaultUtils { + public static String getNewId() { + UUID uuid = UUID.randomUUID(); + + // Adapted from http://stackoverflow.com/questions/2983065/guid-to-bytearray + ByteBuffer bb = ByteBuffer.wrap(new byte[16]); + bb.putLong(uuid.getMostSignificantBits()); + bb.putLong(uuid.getLeastSignificantBits()); + byte[] bytes = bb.array(); + + // Encode the bytes... + return Base64.encode(bytes); + } + + public static Map _idCache = new HashMap<>(); + public static synchronized String getInternalId(TypeToken token) { + DSLContext sqlConn = GringottsSchema.getSQLConnection(); + + String className = token.getRawType().getCanonicalName(); + + // Get the vault rows that match this vault's id + Result result = sqlConn.fetch(VAULTS, VAULTS.VAULTCLASSNAME.eq(className)); + + String id; + if (result.isEmpty()) { + VaultsRecord vaultsRecord = sqlConn.newRecord(VAULTS); + + // Generate a new id + id = GringottsService.getNewId(); + + // Set the new values + vaultsRecord.setVaultid(id); + vaultsRecord.setVaultclassname(className); + //vaultsRecord.setCreatedby(user.getUserId()); + vaultsRecord.setCreated(GringottsSchema.now()); + + // Add the new record to the database + //vaultsRecord.store(); + } + else { + VaultsRecord mostRecentRecord = null; + for (VaultsRecord curRecord : result) { + if (mostRecentRecord == null || curRecord.getCreated().after(mostRecentRecord.getCreated())) { + mostRecentRecord = curRecord; + } + } + + id = mostRecentRecord.getVaultid(); + } + + _idCache.put(token, id); + + return id; + } + + public static void bindRecord(Vault.Record record) throws InvalidVaultException { + TypeToken typeToken = record.getVault().getTypeToken(); + + List classes = new ArrayList<>(); + TypeToken currentTypeToken = typeToken; + + // Get the chain, not including Vault.Record + while(!currentTypeToken.equals(TypeToken.of(Vault.Record.class))) { + classes.add(currentTypeToken); + currentTypeToken = TypeToken.of(currentTypeToken.getRawType().getSuperclass()); + } + + // Reverse the list, since we want to start at the root record + Collections.reverse(classes); + + for (TypeToken token : classes) { + VaultSerializationInfo.getInfo(token).bind(record); + } + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/exception/NotAVaultException.java b/Gringotts/src/org/labkey/gringotts/model/exception/NotAVaultException.java new file mode 100644 index 000000000..e407e83ab --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/exception/NotAVaultException.java @@ -0,0 +1,10 @@ +package org.labkey.gringotts.model.exception; + +/** + * Created by jon on 10/20/16. + */ +public class NotAVaultException extends Exception { + public NotAVaultException() { + super("Vaults need to implement the @VaultInfo annotation"); + } +} \ No newline at end of file diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/DefaultCatalog.java b/Gringotts/src/org/labkey/gringotts/model/jooq/DefaultCatalog.java new file mode 100644 index 000000000..b1464ac5c --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/DefaultCatalog.java @@ -0,0 +1,60 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Schema; +import org.jooq.impl.CatalogImpl; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class DefaultCatalog extends CatalogImpl { + + private static final long serialVersionUID = -707072506; + + /** + * The reference instance of + */ + public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog(); + + /** + * The schema gringotts. + */ + public final Gringotts GRINGOTTS = org.labkey.gringotts.model.jooq.Gringotts.GRINGOTTS; + + /** + * No further instances allowed + */ + private DefaultCatalog() { + super(""); + } + + @Override + public final List getSchemas() { + List result = new ArrayList(); + result.addAll(getSchemas0()); + return result; + } + + private final List getSchemas0() { + return Arrays.asList( + Gringotts.GRINGOTTS); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/Gringotts.java b/Gringotts/src/org/labkey/gringotts/model/jooq/Gringotts.java new file mode 100644 index 000000000..c4328bcd5 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/Gringotts.java @@ -0,0 +1,120 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Catalog; +import org.jooq.Table; +import org.jooq.impl.SchemaImpl; +import org.labkey.gringotts.model.jooq.tables.Records; +import org.labkey.gringotts.model.jooq.tables.Transactions; +import org.labkey.gringotts.model.jooq.tables.VaultColumns; +import org.labkey.gringotts.model.jooq.tables.VaultDatetimeValues; +import org.labkey.gringotts.model.jooq.tables.VaultIntValues; +import org.labkey.gringotts.model.jooq.tables.VaultLinks; +import org.labkey.gringotts.model.jooq.tables.VaultTextValues; +import org.labkey.gringotts.model.jooq.tables.Vaults; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Gringotts extends SchemaImpl { + + private static final long serialVersionUID = -1063924478; + + /** + * The reference instance of gringotts + */ + public static final Gringotts GRINGOTTS = new Gringotts(); + + /** + * The table gringotts.records. + */ + public final Records RECORDS = org.labkey.gringotts.model.jooq.tables.Records.RECORDS; + + /** + * This is the basic unit of the ledger. Every update to the database is associated with a transaction. + */ + public final Transactions TRANSACTIONS = org.labkey.gringotts.model.jooq.tables.Transactions.TRANSACTIONS; + + /** + * The table gringotts.vault_columns. + */ + public final VaultColumns VAULT_COLUMNS = org.labkey.gringotts.model.jooq.tables.VaultColumns.VAULT_COLUMNS; + + /** + * The table gringotts.vault_datetime_values. + */ + public final VaultDatetimeValues VAULT_DATETIME_VALUES = org.labkey.gringotts.model.jooq.tables.VaultDatetimeValues.VAULT_DATETIME_VALUES; + + /** + * The table gringotts.vault_int_values. + */ + public final VaultIntValues VAULT_INT_VALUES = org.labkey.gringotts.model.jooq.tables.VaultIntValues.VAULT_INT_VALUES; + + /** + * The table gringotts.vault_links. + */ + public final VaultLinks VAULT_LINKS = org.labkey.gringotts.model.jooq.tables.VaultLinks.VAULT_LINKS; + + /** + * The table gringotts.vault_text_values. + */ + public final VaultTextValues VAULT_TEXT_VALUES = org.labkey.gringotts.model.jooq.tables.VaultTextValues.VAULT_TEXT_VALUES; + + /** + * The table gringotts.vaults. + */ + public final Vaults VAULTS = org.labkey.gringotts.model.jooq.tables.Vaults.VAULTS; + + /** + * No further instances allowed + */ + private Gringotts() { + super("gringotts", null); + } + + + /** + * {@inheritDoc} + */ + @Override + public Catalog getCatalog() { + return DefaultCatalog.DEFAULT_CATALOG; + } + + @Override + public final List> getTables() { + List result = new ArrayList(); + result.addAll(getTables0()); + return result; + } + + private final List> getTables0() { + return Arrays.>asList( + Records.RECORDS, + Transactions.TRANSACTIONS, + VaultColumns.VAULT_COLUMNS, + VaultDatetimeValues.VAULT_DATETIME_VALUES, + VaultIntValues.VAULT_INT_VALUES, + VaultLinks.VAULT_LINKS, + VaultTextValues.VAULT_TEXT_VALUES, + Vaults.VAULTS); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/Keys.java b/Gringotts/src/org/labkey/gringotts/model/jooq/Keys.java new file mode 100644 index 000000000..8518eb83d --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/Keys.java @@ -0,0 +1,92 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq; + + +import javax.annotation.Generated; + +import org.jooq.ForeignKey; +import org.jooq.UniqueKey; +import org.jooq.impl.AbstractKeys; +import org.labkey.gringotts.model.jooq.tables.Records; +import org.labkey.gringotts.model.jooq.tables.Transactions; +import org.labkey.gringotts.model.jooq.tables.VaultColumns; +import org.labkey.gringotts.model.jooq.tables.VaultDatetimeValues; +import org.labkey.gringotts.model.jooq.tables.VaultIntValues; +import org.labkey.gringotts.model.jooq.tables.VaultLinks; +import org.labkey.gringotts.model.jooq.tables.VaultTextValues; +import org.labkey.gringotts.model.jooq.tables.Vaults; +import org.labkey.gringotts.model.jooq.tables.records.RecordsRecord; +import org.labkey.gringotts.model.jooq.tables.records.TransactionsRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultColumnsRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultDatetimeValuesRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultIntValuesRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultLinksRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultTextValuesRecord; +import org.labkey.gringotts.model.jooq.tables.records.VaultsRecord; + + +/** + * A class modelling foreign key relationships between tables of the gringotts + * schema + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Keys { + + // ------------------------------------------------------------------------- + // IDENTITY definitions + // ------------------------------------------------------------------------- + + + // ------------------------------------------------------------------------- + // UNIQUE and PRIMARY KEY definitions + // ------------------------------------------------------------------------- + + public static final UniqueKey PK_RECORDS = UniqueKeys0.PK_RECORDS; + public static final UniqueKey PK_TRANSACTIONS = UniqueKeys0.PK_TRANSACTIONS; + public static final UniqueKey TRANSACTIONS_ID_UNIQUE = UniqueKeys0.TRANSACTIONS_ID_UNIQUE; + public static final UniqueKey PK_VAULT_COLUMNS = UniqueKeys0.PK_VAULT_COLUMNS; + public static final UniqueKey PK_VAULT_DATETIME_VALUES = UniqueKeys0.PK_VAULT_DATETIME_VALUES; + public static final UniqueKey PK_VAULT_INT_VALUES = UniqueKeys0.PK_VAULT_INT_VALUES; + public static final UniqueKey PK_VAULT_LINKS = UniqueKeys0.PK_VAULT_LINKS; + public static final UniqueKey PK_VAULT_TEXT_VALUES = UniqueKeys0.PK_VAULT_TEXT_VALUES; + public static final UniqueKey PK_VAULTS = UniqueKeys0.PK_VAULTS; + + // ------------------------------------------------------------------------- + // FOREIGN KEY definitions + // ------------------------------------------------------------------------- + + public static final ForeignKey VAULT_DATETIME_VALUES__FK_VAULT_DATETIME_VALUES_TRANSACTIONS = ForeignKeys0.VAULT_DATETIME_VALUES__FK_VAULT_DATETIME_VALUES_TRANSACTIONS; + public static final ForeignKey VAULT_INT_VALUES__FK_VAULT_INT_VALUES_TRANSACTIONS = ForeignKeys0.VAULT_INT_VALUES__FK_VAULT_INT_VALUES_TRANSACTIONS; + public static final ForeignKey VAULT_TEXT_VALUES__FK_VAULT_TEXT_VALUES_TRANSACTIONS = ForeignKeys0.VAULT_TEXT_VALUES__FK_VAULT_TEXT_VALUES_TRANSACTIONS; + + // ------------------------------------------------------------------------- + // [#1459] distribute members to avoid static initialisers > 64kb + // ------------------------------------------------------------------------- + + private static class UniqueKeys0 extends AbstractKeys { + public static final UniqueKey PK_RECORDS = createUniqueKey(Records.RECORDS, "pk_records", Records.RECORDS.VAULTID, Records.RECORDS.RECORDID, Records.RECORDS.VERSION); + public static final UniqueKey PK_TRANSACTIONS = createUniqueKey(Transactions.TRANSACTIONS, "pk_transactions", Transactions.TRANSACTIONS.CREATEDON); + public static final UniqueKey TRANSACTIONS_ID_UNIQUE = createUniqueKey(Transactions.TRANSACTIONS, "transactions_id_unique", Transactions.TRANSACTIONS.TRANSACTIONID); + public static final UniqueKey PK_VAULT_COLUMNS = createUniqueKey(VaultColumns.VAULT_COLUMNS, "pk_vault_columns", VaultColumns.VAULT_COLUMNS.VAULTID, VaultColumns.VAULT_COLUMNS.VERSION, VaultColumns.VAULT_COLUMNS.COLUMNNAME); + public static final UniqueKey PK_VAULT_DATETIME_VALUES = createUniqueKey(VaultDatetimeValues.VAULT_DATETIME_VALUES, "pk_vault_datetime_values", VaultDatetimeValues.VAULT_DATETIME_VALUES.VAULTID, VaultDatetimeValues.VAULT_DATETIME_VALUES.RECORDID, VaultDatetimeValues.VAULT_DATETIME_VALUES.COLUMNID, VaultDatetimeValues.VAULT_DATETIME_VALUES.TRANSACTIONID); + public static final UniqueKey PK_VAULT_INT_VALUES = createUniqueKey(VaultIntValues.VAULT_INT_VALUES, "pk_vault_int_values", VaultIntValues.VAULT_INT_VALUES.VAULTID, VaultIntValues.VAULT_INT_VALUES.RECORDID, VaultIntValues.VAULT_INT_VALUES.COLUMNID, VaultIntValues.VAULT_INT_VALUES.TRANSACTIONID); + public static final UniqueKey PK_VAULT_LINKS = createUniqueKey(VaultLinks.VAULT_LINKS, "pk_vault_links", VaultLinks.VAULT_LINKS.VAULTID1, VaultLinks.VAULT_LINKS.COLUMNID, VaultLinks.VAULT_LINKS.VAULTID2, VaultLinks.VAULT_LINKS.RECORD1, VaultLinks.VAULT_LINKS.RECORD2, VaultLinks.VAULT_LINKS.TRANSACTIONID); + public static final UniqueKey PK_VAULT_TEXT_VALUES = createUniqueKey(VaultTextValues.VAULT_TEXT_VALUES, "pk_vault_text_values", VaultTextValues.VAULT_TEXT_VALUES.VAULTID, VaultTextValues.VAULT_TEXT_VALUES.RECORDID, VaultTextValues.VAULT_TEXT_VALUES.COLUMNID, VaultTextValues.VAULT_TEXT_VALUES.TRANSACTIONID); + public static final UniqueKey PK_VAULTS = createUniqueKey(Vaults.VAULTS, "pk_vaults", Vaults.VAULTS.VAULTID, Vaults.VAULTS.CREATED); + } + + private static class ForeignKeys0 extends AbstractKeys { + public static final ForeignKey VAULT_DATETIME_VALUES__FK_VAULT_DATETIME_VALUES_TRANSACTIONS = createForeignKey(org.labkey.gringotts.model.jooq.Keys.TRANSACTIONS_ID_UNIQUE, VaultDatetimeValues.VAULT_DATETIME_VALUES, "vault_datetime_values__fk_vault_datetime_values_transactions", VaultDatetimeValues.VAULT_DATETIME_VALUES.TRANSACTIONID); + public static final ForeignKey VAULT_INT_VALUES__FK_VAULT_INT_VALUES_TRANSACTIONS = createForeignKey(org.labkey.gringotts.model.jooq.Keys.TRANSACTIONS_ID_UNIQUE, VaultIntValues.VAULT_INT_VALUES, "vault_int_values__fk_vault_int_values_transactions", VaultIntValues.VAULT_INT_VALUES.TRANSACTIONID); + public static final ForeignKey VAULT_TEXT_VALUES__FK_VAULT_TEXT_VALUES_TRANSACTIONS = createForeignKey(org.labkey.gringotts.model.jooq.Keys.TRANSACTIONS_ID_UNIQUE, VaultTextValues.VAULT_TEXT_VALUES, "vault_text_values__fk_vault_text_values_transactions", VaultTextValues.VAULT_TEXT_VALUES.TRANSACTIONID); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/Tables.java b/Gringotts/src/org/labkey/gringotts/model/jooq/Tables.java new file mode 100644 index 000000000..799bef04e --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/Tables.java @@ -0,0 +1,71 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq; + + +import javax.annotation.Generated; + +import org.labkey.gringotts.model.jooq.tables.Records; +import org.labkey.gringotts.model.jooq.tables.Transactions; +import org.labkey.gringotts.model.jooq.tables.VaultColumns; +import org.labkey.gringotts.model.jooq.tables.VaultDatetimeValues; +import org.labkey.gringotts.model.jooq.tables.VaultIntValues; +import org.labkey.gringotts.model.jooq.tables.VaultLinks; +import org.labkey.gringotts.model.jooq.tables.VaultTextValues; +import org.labkey.gringotts.model.jooq.tables.Vaults; + + +/** + * Convenience access to all tables in gringotts + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Tables { + + /** + * The table gringotts.records. + */ + public static final Records RECORDS = org.labkey.gringotts.model.jooq.tables.Records.RECORDS; + + /** + * This is the basic unit of the ledger. Every update to the database is associated with a transaction. + */ + public static final Transactions TRANSACTIONS = org.labkey.gringotts.model.jooq.tables.Transactions.TRANSACTIONS; + + /** + * The table gringotts.vault_columns. + */ + public static final VaultColumns VAULT_COLUMNS = org.labkey.gringotts.model.jooq.tables.VaultColumns.VAULT_COLUMNS; + + /** + * The table gringotts.vault_datetime_values. + */ + public static final VaultDatetimeValues VAULT_DATETIME_VALUES = org.labkey.gringotts.model.jooq.tables.VaultDatetimeValues.VAULT_DATETIME_VALUES; + + /** + * The table gringotts.vault_int_values. + */ + public static final VaultIntValues VAULT_INT_VALUES = org.labkey.gringotts.model.jooq.tables.VaultIntValues.VAULT_INT_VALUES; + + /** + * The table gringotts.vault_links. + */ + public static final VaultLinks VAULT_LINKS = org.labkey.gringotts.model.jooq.tables.VaultLinks.VAULT_LINKS; + + /** + * The table gringotts.vault_text_values. + */ + public static final VaultTextValues VAULT_TEXT_VALUES = org.labkey.gringotts.model.jooq.tables.VaultTextValues.VAULT_TEXT_VALUES; + + /** + * The table gringotts.vaults. + */ + public static final Vaults VAULTS = org.labkey.gringotts.model.jooq.tables.Vaults.VAULTS; +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Records.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Records.java new file mode 100644 index 000000000..aad15c312 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Records.java @@ -0,0 +1,136 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.RecordsRecord; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Records extends TableImpl { + + private static final long serialVersionUID = 562893786; + + /** + * The reference instance of gringotts.records + */ + public static final Records RECORDS = new Records(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return RecordsRecord.class; + } + + /** + * The column gringotts.records.vaultid. + */ + public final TableField VAULTID = createField("vaultid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.records.recordid. + */ + public final TableField RECORDID = createField("recordid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.records.container. + */ + public final TableField CONTAINER = createField("container", org.jooq.impl.SQLDataType.VARCHAR.length(36).nullable(false), this, ""); + + /** + * The column gringotts.records.version. + */ + public final TableField VERSION = createField("version", org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, ""); + + /** + * The column gringotts.records.transactionid. + */ + public final TableField TRANSACTIONID = createField("transactionid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * Create a gringotts.records table reference + */ + public Records() { + this("records", null); + } + + /** + * Create an aliased gringotts.records table reference + */ + public Records(String alias) { + this(alias, RECORDS); + } + + private Records(String alias, Table aliased) { + this(alias, aliased, null); + } + + private Records(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, ""); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_RECORDS; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_RECORDS); + } + + /** + * {@inheritDoc} + */ + @Override + public Records as(String alias) { + return new Records(alias, this); + } + + /** + * Rename this table + */ + public Records rename(String name) { + return new Records(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Transactions.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Transactions.java new file mode 100644 index 000000000..84d98fe38 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Transactions.java @@ -0,0 +1,138 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.TransactionsRecord; + + +/** + * This is the basic unit of the ledger. Every update to the database is + * associated with a transaction. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Transactions extends TableImpl { + + private static final long serialVersionUID = 1381190943; + + /** + * The reference instance of gringotts.transactions + */ + public static final Transactions TRANSACTIONS = new Transactions(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return TransactionsRecord.class; + } + + /** + * The column gringotts.transactions.createdon. + */ + public final TableField CREATEDON = createField("createdon", org.jooq.impl.SQLDataType.TIMESTAMP.nullable(false).defaultValue(org.jooq.impl.DSL.field("now()", org.jooq.impl.SQLDataType.TIMESTAMP)), this, ""); + + /** + * The column gringotts.transactions.transactionid. + */ + public final TableField TRANSACTIONID = createField("transactionid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.transactions.user. + */ + public final TableField USER = createField("user", org.jooq.impl.SQLDataType.INTEGER, this, ""); + + /** + * The column gringotts.transactions.effectiveon. + */ + public final TableField EFFECTIVEON = createField("effectiveon", org.jooq.impl.SQLDataType.TIMESTAMP, this, ""); + + /** + * The column gringotts.transactions.comment. + */ + public final TableField COMMENT = createField("comment", org.jooq.impl.SQLDataType.CLOB, this, ""); + + /** + * Create a gringotts.transactions table reference + */ + public Transactions() { + this("transactions", null); + } + + /** + * Create an aliased gringotts.transactions table reference + */ + public Transactions(String alias) { + this(alias, TRANSACTIONS); + } + + private Transactions(String alias, Table aliased) { + this(alias, aliased, null); + } + + private Transactions(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, "This is the basic unit of the ledger. Every update to the database is associated with a transaction."); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_TRANSACTIONS; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_TRANSACTIONS, Keys.TRANSACTIONS_ID_UNIQUE); + } + + /** + * {@inheritDoc} + */ + @Override + public Transactions as(String alias) { + return new Transactions(alias, this); + } + + /** + * Rename this table + */ + public Transactions rename(String name) { + return new Transactions(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultColumns.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultColumns.java new file mode 100644 index 000000000..e10ea2a04 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultColumns.java @@ -0,0 +1,136 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.VaultColumnsRecord; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultColumns extends TableImpl { + + private static final long serialVersionUID = -87633108; + + /** + * The reference instance of gringotts.vault_columns + */ + public static final VaultColumns VAULT_COLUMNS = new VaultColumns(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return VaultColumnsRecord.class; + } + + /** + * The column gringotts.vault_columns.vaultid. + */ + public final TableField VAULTID = createField("vaultid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_columns.version. + */ + public final TableField VERSION = createField("version", org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, ""); + + /** + * The column gringotts.vault_columns.columnname. + */ + public final TableField COLUMNNAME = createField("columnname", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_columns.type. + */ + public final TableField TYPE = createField("type", org.jooq.impl.SQLDataType.CLOB, this, ""); + + /** + * The column gringotts.vault_columns.columnid. + */ + public final TableField COLUMNID = createField("columnid", org.jooq.impl.SQLDataType.CLOB, this, ""); + + /** + * Create a gringotts.vault_columns table reference + */ + public VaultColumns() { + this("vault_columns", null); + } + + /** + * Create an aliased gringotts.vault_columns table reference + */ + public VaultColumns(String alias) { + this(alias, VAULT_COLUMNS); + } + + private VaultColumns(String alias, Table aliased) { + this(alias, aliased, null); + } + + private VaultColumns(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, ""); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_VAULT_COLUMNS; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_VAULT_COLUMNS); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultColumns as(String alias) { + return new VaultColumns(alias, this); + } + + /** + * Rename this table + */ + public VaultColumns rename(String name) { + return new VaultColumns(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultDatetimeValues.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultDatetimeValues.java new file mode 100644 index 000000000..4d954d821 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultDatetimeValues.java @@ -0,0 +1,146 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.ForeignKey; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.VaultDatetimeValuesRecord; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultDatetimeValues extends TableImpl { + + private static final long serialVersionUID = 273910346; + + /** + * The reference instance of gringotts.vault_datetime_values + */ + public static final VaultDatetimeValues VAULT_DATETIME_VALUES = new VaultDatetimeValues(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return VaultDatetimeValuesRecord.class; + } + + /** + * The column gringotts.vault_datetime_values.vaultid. + */ + public final TableField VAULTID = createField("vaultid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_datetime_values.recordid. + */ + public final TableField RECORDID = createField("recordid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_datetime_values.columnid. + */ + public final TableField COLUMNID = createField("columnid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_datetime_values.transactionid. + */ + public final TableField TRANSACTIONID = createField("transactionid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_datetime_values.value. + */ + public final TableField VALUE = createField("value", org.jooq.impl.SQLDataType.TIMESTAMP, this, ""); + + /** + * Create a gringotts.vault_datetime_values table reference + */ + public VaultDatetimeValues() { + this("vault_datetime_values", null); + } + + /** + * Create an aliased gringotts.vault_datetime_values table reference + */ + public VaultDatetimeValues(String alias) { + this(alias, VAULT_DATETIME_VALUES); + } + + private VaultDatetimeValues(String alias, Table aliased) { + this(alias, aliased, null); + } + + private VaultDatetimeValues(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, ""); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_VAULT_DATETIME_VALUES; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_VAULT_DATETIME_VALUES); + } + + /** + * {@inheritDoc} + */ + @Override + public List> getReferences() { + return Arrays.>asList(Keys.VAULT_DATETIME_VALUES__FK_VAULT_DATETIME_VALUES_TRANSACTIONS); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultDatetimeValues as(String alias) { + return new VaultDatetimeValues(alias, this); + } + + /** + * Rename this table + */ + public VaultDatetimeValues rename(String name) { + return new VaultDatetimeValues(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultIntValues.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultIntValues.java new file mode 100644 index 000000000..8f346a21b --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultIntValues.java @@ -0,0 +1,145 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.ForeignKey; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.VaultIntValuesRecord; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultIntValues extends TableImpl { + + private static final long serialVersionUID = -6667998; + + /** + * The reference instance of gringotts.vault_int_values + */ + public static final VaultIntValues VAULT_INT_VALUES = new VaultIntValues(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return VaultIntValuesRecord.class; + } + + /** + * The column gringotts.vault_int_values.vaultid. + */ + public final TableField VAULTID = createField("vaultid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_int_values.recordid. + */ + public final TableField RECORDID = createField("recordid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_int_values.columnid. + */ + public final TableField COLUMNID = createField("columnid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_int_values.transactionid. + */ + public final TableField TRANSACTIONID = createField("transactionid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_int_values.value. + */ + public final TableField VALUE = createField("value", org.jooq.impl.SQLDataType.INTEGER, this, ""); + + /** + * Create a gringotts.vault_int_values table reference + */ + public VaultIntValues() { + this("vault_int_values", null); + } + + /** + * Create an aliased gringotts.vault_int_values table reference + */ + public VaultIntValues(String alias) { + this(alias, VAULT_INT_VALUES); + } + + private VaultIntValues(String alias, Table aliased) { + this(alias, aliased, null); + } + + private VaultIntValues(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, ""); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_VAULT_INT_VALUES; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_VAULT_INT_VALUES); + } + + /** + * {@inheritDoc} + */ + @Override + public List> getReferences() { + return Arrays.>asList(Keys.VAULT_INT_VALUES__FK_VAULT_INT_VALUES_TRANSACTIONS); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultIntValues as(String alias) { + return new VaultIntValues(alias, this); + } + + /** + * Rename this table + */ + public VaultIntValues rename(String name) { + return new VaultIntValues(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultLinks.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultLinks.java new file mode 100644 index 000000000..e90ba0dc5 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultLinks.java @@ -0,0 +1,151 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.VaultLinksRecord; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultLinks extends TableImpl { + + private static final long serialVersionUID = -1537079817; + + /** + * The reference instance of gringotts.vault_links + */ + public static final VaultLinks VAULT_LINKS = new VaultLinks(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return VaultLinksRecord.class; + } + + /** + * The column gringotts.vault_links.vaultid1. + */ + public final TableField VAULTID1 = createField("vaultid1", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_links.columnid. + */ + public final TableField COLUMNID = createField("columnid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_links.vaultid2. + */ + public final TableField VAULTID2 = createField("vaultid2", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_links.record1. + */ + public final TableField RECORD1 = createField("record1", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_links.record2. + */ + public final TableField RECORD2 = createField("record2", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_links.transactionid. + */ + public final TableField TRANSACTIONID = createField("transactionid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_links.islinked. + */ + public final TableField ISLINKED = createField("islinked", org.jooq.impl.SQLDataType.BOOLEAN.nullable(false).defaultValue(org.jooq.impl.DSL.field("true", org.jooq.impl.SQLDataType.BOOLEAN)), this, ""); + + /** + * The column gringotts.vault_links.order. + */ + public final TableField ORDER = createField("order", org.jooq.impl.SQLDataType.INTEGER, this, ""); + + /** + * Create a gringotts.vault_links table reference + */ + public VaultLinks() { + this("vault_links", null); + } + + /** + * Create an aliased gringotts.vault_links table reference + */ + public VaultLinks(String alias) { + this(alias, VAULT_LINKS); + } + + private VaultLinks(String alias, Table aliased) { + this(alias, aliased, null); + } + + private VaultLinks(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, ""); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_VAULT_LINKS; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_VAULT_LINKS); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinks as(String alias) { + return new VaultLinks(alias, this); + } + + /** + * Rename this table + */ + public VaultLinks rename(String name) { + return new VaultLinks(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultTextValues.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultTextValues.java new file mode 100644 index 000000000..ddb92f282 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/VaultTextValues.java @@ -0,0 +1,151 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.ForeignKey; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.VaultTextValuesRecord; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultTextValues extends TableImpl { + + private static final long serialVersionUID = 869022395; + + /** + * The reference instance of gringotts.vault_text_values + */ + public static final VaultTextValues VAULT_TEXT_VALUES = new VaultTextValues(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return VaultTextValuesRecord.class; + } + + /** + * The column gringotts.vault_text_values.vaultid. + */ + public final TableField VAULTID = createField("vaultid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_text_values.recordid. + */ + public final TableField RECORDID = createField("recordid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_text_values.columnid. + */ + public final TableField COLUMNID = createField("columnid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_text_values.transactionid. + */ + public final TableField TRANSACTIONID = createField("transactionid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vault_text_values.value. + */ + public final TableField VALUE = createField("value", org.jooq.impl.SQLDataType.CLOB, this, ""); + + /** + * The column gringotts.vault_text_values.effectivedate. + */ + public final TableField EFFECTIVEDATE = createField("effectivedate", org.jooq.impl.SQLDataType.TIMESTAMP, this, ""); + + /** + * Create a gringotts.vault_text_values table reference + */ + public VaultTextValues() { + this("vault_text_values", null); + } + + /** + * Create an aliased gringotts.vault_text_values table reference + */ + public VaultTextValues(String alias) { + this(alias, VAULT_TEXT_VALUES); + } + + private VaultTextValues(String alias, Table aliased) { + this(alias, aliased, null); + } + + private VaultTextValues(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, ""); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_VAULT_TEXT_VALUES; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_VAULT_TEXT_VALUES); + } + + /** + * {@inheritDoc} + */ + @Override + public List> getReferences() { + return Arrays.>asList(Keys.VAULT_TEXT_VALUES__FK_VAULT_TEXT_VALUES_TRANSACTIONS); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValues as(String alias) { + return new VaultTextValues(alias, this); + } + + /** + * Rename this table + */ + public VaultTextValues rename(String name) { + return new VaultTextValues(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Vaults.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Vaults.java new file mode 100644 index 000000000..855fd587f --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/Vaults.java @@ -0,0 +1,132 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables; + + +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.TableImpl; +import org.labkey.gringotts.model.jooq.Gringotts; +import org.labkey.gringotts.model.jooq.Keys; +import org.labkey.gringotts.model.jooq.tables.records.VaultsRecord; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Vaults extends TableImpl { + + private static final long serialVersionUID = -1329235878; + + /** + * The reference instance of gringotts.vaults + */ + public static final Vaults VAULTS = new Vaults(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return VaultsRecord.class; + } + + /** + * The column gringotts.vaults.vaultid. + */ + public final TableField VAULTID = createField("vaultid", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vaults.vaultclassname. + */ + public final TableField VAULTCLASSNAME = createField("vaultclassname", org.jooq.impl.SQLDataType.CLOB.nullable(false), this, ""); + + /** + * The column gringotts.vaults.createdby. + */ + public final TableField CREATEDBY = createField("createdby", org.jooq.impl.SQLDataType.INTEGER, this, ""); + + /** + * The column gringotts.vaults.created. + */ + public final TableField CREATED = createField("created", org.jooq.impl.SQLDataType.TIMESTAMP.nullable(false), this, ""); + + /** + * Create a gringotts.vaults table reference + */ + public Vaults() { + this("vaults", null); + } + + /** + * Create an aliased gringotts.vaults table reference + */ + public Vaults(String alias) { + this(alias, VAULTS); + } + + private Vaults(String alias, Table aliased) { + this(alias, aliased, null); + } + + private Vaults(String alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, ""); + } + + /** + * {@inheritDoc} + */ + @Override + public Schema getSchema() { + return Gringotts.GRINGOTTS; + } + + /** + * {@inheritDoc} + */ + @Override + public UniqueKey getPrimaryKey() { + return Keys.PK_VAULTS; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getKeys() { + return Arrays.>asList(Keys.PK_VAULTS); + } + + /** + * {@inheritDoc} + */ + @Override + public Vaults as(String alias) { + return new Vaults(alias, this); + } + + /** + * Rename this table + */ + public Vaults rename(String name) { + return new Vaults(name, null); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/RecordsRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/RecordsRecord.java new file mode 100644 index 000000000..1f5c5d93e --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/RecordsRecord.java @@ -0,0 +1,295 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record3; +import org.jooq.Record5; +import org.jooq.Row5; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.Records; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class RecordsRecord extends UpdatableRecordImpl implements Record5 { + + private static final long serialVersionUID = -67593127; + + /** + * Setter for gringotts.records.vaultid. + */ + public void setVaultid(String value) { + set(0, value); + } + + /** + * Getter for gringotts.records.vaultid. + */ + public String getVaultid() { + return (String) get(0); + } + + /** + * Setter for gringotts.records.recordid. + */ + public void setRecordid(String value) { + set(1, value); + } + + /** + * Getter for gringotts.records.recordid. + */ + public String getRecordid() { + return (String) get(1); + } + + /** + * Setter for gringotts.records.container. + */ + public void setContainer(String value) { + set(2, value); + } + + /** + * Getter for gringotts.records.container. + */ + public String getContainer() { + return (String) get(2); + } + + /** + * Setter for gringotts.records.version. + */ + public void setVersion(Integer value) { + set(3, value); + } + + /** + * Getter for gringotts.records.version. + */ + public Integer getVersion() { + return (Integer) get(3); + } + + /** + * Setter for gringotts.records.transactionid. + */ + public void setTransactionid(String value) { + set(4, value); + } + + /** + * Getter for gringotts.records.transactionid. + */ + public String getTransactionid() { + return (String) get(4); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record3 key() { + return (Record3) super.key(); + } + + // ------------------------------------------------------------------------- + // Record5 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row5 fieldsRow() { + return (Row5) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row5 valuesRow() { + return (Row5) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return Records.RECORDS.VAULTID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return Records.RECORDS.RECORDID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return Records.RECORDS.CONTAINER; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return Records.RECORDS.VERSION; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field5() { + return Records.RECORDS.TRANSACTIONID; + } + + /** + * {@inheritDoc} + */ + @Override + public String value1() { + return getVaultid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value2() { + return getRecordid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value3() { + return getContainer(); + } + + /** + * {@inheritDoc} + */ + @Override + public Integer value4() { + return getVersion(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value5() { + return getTransactionid(); + } + + /** + * {@inheritDoc} + */ + @Override + public RecordsRecord value1(String value) { + setVaultid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public RecordsRecord value2(String value) { + setRecordid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public RecordsRecord value3(String value) { + setContainer(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public RecordsRecord value4(Integer value) { + setVersion(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public RecordsRecord value5(String value) { + setTransactionid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public RecordsRecord values(String value1, String value2, String value3, Integer value4, String value5) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached RecordsRecord + */ + public RecordsRecord() { + super(Records.RECORDS); + } + + /** + * Create a detached, initialised RecordsRecord + */ + public RecordsRecord(String vaultid, String recordid, String container, Integer version, String transactionid) { + super(Records.RECORDS); + + set(0, vaultid); + set(1, recordid); + set(2, container); + set(3, version); + set(4, transactionid); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/TransactionsRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/TransactionsRecord.java new file mode 100644 index 000000000..b73bccdf7 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/TransactionsRecord.java @@ -0,0 +1,298 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import java.sql.Timestamp; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record1; +import org.jooq.Record5; +import org.jooq.Row5; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.Transactions; + + +/** + * This is the basic unit of the ledger. Every update to the database is + * associated with a transaction. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class TransactionsRecord extends UpdatableRecordImpl implements Record5 { + + private static final long serialVersionUID = -1828431088; + + /** + * Setter for gringotts.transactions.createdon. + */ + public void setCreatedon(Timestamp value) { + set(0, value); + } + + /** + * Getter for gringotts.transactions.createdon. + */ + public Timestamp getCreatedon() { + return (Timestamp) get(0); + } + + /** + * Setter for gringotts.transactions.transactionid. + */ + public void setTransactionid(String value) { + set(1, value); + } + + /** + * Getter for gringotts.transactions.transactionid. + */ + public String getTransactionid() { + return (String) get(1); + } + + /** + * Setter for gringotts.transactions.user. + */ + public void setUser(Integer value) { + set(2, value); + } + + /** + * Getter for gringotts.transactions.user. + */ + public Integer getUser() { + return (Integer) get(2); + } + + /** + * Setter for gringotts.transactions.effectiveon. + */ + public void setEffectiveon(Timestamp value) { + set(3, value); + } + + /** + * Getter for gringotts.transactions.effectiveon. + */ + public Timestamp getEffectiveon() { + return (Timestamp) get(3); + } + + /** + * Setter for gringotts.transactions.comment. + */ + public void setComment(String value) { + set(4, value); + } + + /** + * Getter for gringotts.transactions.comment. + */ + public String getComment() { + return (String) get(4); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record1 key() { + return (Record1) super.key(); + } + + // ------------------------------------------------------------------------- + // Record5 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row5 fieldsRow() { + return (Row5) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row5 valuesRow() { + return (Row5) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return Transactions.TRANSACTIONS.CREATEDON; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return Transactions.TRANSACTIONS.TRANSACTIONID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return Transactions.TRANSACTIONS.USER; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return Transactions.TRANSACTIONS.EFFECTIVEON; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field5() { + return Transactions.TRANSACTIONS.COMMENT; + } + + /** + * {@inheritDoc} + */ + @Override + public Timestamp value1() { + return getCreatedon(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value2() { + return getTransactionid(); + } + + /** + * {@inheritDoc} + */ + @Override + public Integer value3() { + return getUser(); + } + + /** + * {@inheritDoc} + */ + @Override + public Timestamp value4() { + return getEffectiveon(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value5() { + return getComment(); + } + + /** + * {@inheritDoc} + */ + @Override + public TransactionsRecord value1(Timestamp value) { + setCreatedon(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public TransactionsRecord value2(String value) { + setTransactionid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public TransactionsRecord value3(Integer value) { + setUser(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public TransactionsRecord value4(Timestamp value) { + setEffectiveon(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public TransactionsRecord value5(String value) { + setComment(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public TransactionsRecord values(Timestamp value1, String value2, Integer value3, Timestamp value4, String value5) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached TransactionsRecord + */ + public TransactionsRecord() { + super(Transactions.TRANSACTIONS); + } + + /** + * Create a detached, initialised TransactionsRecord + */ + public TransactionsRecord(Timestamp createdon, String transactionid, Integer user, Timestamp effectiveon, String comment) { + super(Transactions.TRANSACTIONS); + + set(0, createdon); + set(1, transactionid); + set(2, user); + set(3, effectiveon); + set(4, comment); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultColumnsRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultColumnsRecord.java new file mode 100644 index 000000000..da233da42 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultColumnsRecord.java @@ -0,0 +1,295 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record3; +import org.jooq.Record5; +import org.jooq.Row5; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.VaultColumns; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultColumnsRecord extends UpdatableRecordImpl implements Record5 { + + private static final long serialVersionUID = 1041711435; + + /** + * Setter for gringotts.vault_columns.vaultid. + */ + public void setVaultid(String value) { + set(0, value); + } + + /** + * Getter for gringotts.vault_columns.vaultid. + */ + public String getVaultid() { + return (String) get(0); + } + + /** + * Setter for gringotts.vault_columns.version. + */ + public void setVersion(Integer value) { + set(1, value); + } + + /** + * Getter for gringotts.vault_columns.version. + */ + public Integer getVersion() { + return (Integer) get(1); + } + + /** + * Setter for gringotts.vault_columns.columnname. + */ + public void setColumnname(String value) { + set(2, value); + } + + /** + * Getter for gringotts.vault_columns.columnname. + */ + public String getColumnname() { + return (String) get(2); + } + + /** + * Setter for gringotts.vault_columns.type. + */ + public void setType(String value) { + set(3, value); + } + + /** + * Getter for gringotts.vault_columns.type. + */ + public String getType() { + return (String) get(3); + } + + /** + * Setter for gringotts.vault_columns.columnid. + */ + public void setColumnid(String value) { + set(4, value); + } + + /** + * Getter for gringotts.vault_columns.columnid. + */ + public String getColumnid() { + return (String) get(4); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record3 key() { + return (Record3) super.key(); + } + + // ------------------------------------------------------------------------- + // Record5 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row5 fieldsRow() { + return (Row5) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row5 valuesRow() { + return (Row5) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return VaultColumns.VAULT_COLUMNS.VAULTID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return VaultColumns.VAULT_COLUMNS.VERSION; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return VaultColumns.VAULT_COLUMNS.COLUMNNAME; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return VaultColumns.VAULT_COLUMNS.TYPE; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field5() { + return VaultColumns.VAULT_COLUMNS.COLUMNID; + } + + /** + * {@inheritDoc} + */ + @Override + public String value1() { + return getVaultid(); + } + + /** + * {@inheritDoc} + */ + @Override + public Integer value2() { + return getVersion(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value3() { + return getColumnname(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value4() { + return getType(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value5() { + return getColumnid(); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultColumnsRecord value1(String value) { + setVaultid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultColumnsRecord value2(Integer value) { + setVersion(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultColumnsRecord value3(String value) { + setColumnname(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultColumnsRecord value4(String value) { + setType(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultColumnsRecord value5(String value) { + setColumnid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultColumnsRecord values(String value1, Integer value2, String value3, String value4, String value5) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached VaultColumnsRecord + */ + public VaultColumnsRecord() { + super(VaultColumns.VAULT_COLUMNS); + } + + /** + * Create a detached, initialised VaultColumnsRecord + */ + public VaultColumnsRecord(String vaultid, Integer version, String columnname, String type, String columnid) { + super(VaultColumns.VAULT_COLUMNS); + + set(0, vaultid); + set(1, version); + set(2, columnname); + set(3, type); + set(4, columnid); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultDatetimeValuesRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultDatetimeValuesRecord.java new file mode 100644 index 000000000..aef9f5c03 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultDatetimeValuesRecord.java @@ -0,0 +1,297 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import java.sql.Timestamp; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record4; +import org.jooq.Record5; +import org.jooq.Row5; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.VaultDatetimeValues; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultDatetimeValuesRecord extends UpdatableRecordImpl implements Record5 { + + private static final long serialVersionUID = -1963048534; + + /** + * Setter for gringotts.vault_datetime_values.vaultid. + */ + public void setVaultid(String value) { + set(0, value); + } + + /** + * Getter for gringotts.vault_datetime_values.vaultid. + */ + public String getVaultid() { + return (String) get(0); + } + + /** + * Setter for gringotts.vault_datetime_values.recordid. + */ + public void setRecordid(String value) { + set(1, value); + } + + /** + * Getter for gringotts.vault_datetime_values.recordid. + */ + public String getRecordid() { + return (String) get(1); + } + + /** + * Setter for gringotts.vault_datetime_values.columnid. + */ + public void setColumnid(String value) { + set(2, value); + } + + /** + * Getter for gringotts.vault_datetime_values.columnid. + */ + public String getColumnid() { + return (String) get(2); + } + + /** + * Setter for gringotts.vault_datetime_values.transactionid. + */ + public void setTransactionid(String value) { + set(3, value); + } + + /** + * Getter for gringotts.vault_datetime_values.transactionid. + */ + public String getTransactionid() { + return (String) get(3); + } + + /** + * Setter for gringotts.vault_datetime_values.value. + */ + public void setValue(Timestamp value) { + set(4, value); + } + + /** + * Getter for gringotts.vault_datetime_values.value. + */ + public Timestamp getValue() { + return (Timestamp) get(4); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record4 key() { + return (Record4) super.key(); + } + + // ------------------------------------------------------------------------- + // Record5 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row5 fieldsRow() { + return (Row5) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row5 valuesRow() { + return (Row5) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return VaultDatetimeValues.VAULT_DATETIME_VALUES.VAULTID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return VaultDatetimeValues.VAULT_DATETIME_VALUES.RECORDID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return VaultDatetimeValues.VAULT_DATETIME_VALUES.COLUMNID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return VaultDatetimeValues.VAULT_DATETIME_VALUES.TRANSACTIONID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field5() { + return VaultDatetimeValues.VAULT_DATETIME_VALUES.VALUE; + } + + /** + * {@inheritDoc} + */ + @Override + public String value1() { + return getVaultid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value2() { + return getRecordid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value3() { + return getColumnid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value4() { + return getTransactionid(); + } + + /** + * {@inheritDoc} + */ + @Override + public Timestamp value5() { + return getValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultDatetimeValuesRecord value1(String value) { + setVaultid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultDatetimeValuesRecord value2(String value) { + setRecordid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultDatetimeValuesRecord value3(String value) { + setColumnid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultDatetimeValuesRecord value4(String value) { + setTransactionid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultDatetimeValuesRecord value5(Timestamp value) { + setValue(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultDatetimeValuesRecord values(String value1, String value2, String value3, String value4, Timestamp value5) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached VaultDatetimeValuesRecord + */ + public VaultDatetimeValuesRecord() { + super(VaultDatetimeValues.VAULT_DATETIME_VALUES); + } + + /** + * Create a detached, initialised VaultDatetimeValuesRecord + */ + public VaultDatetimeValuesRecord(String vaultid, String recordid, String columnid, String transactionid, Timestamp value) { + super(VaultDatetimeValues.VAULT_DATETIME_VALUES); + + set(0, vaultid); + set(1, recordid); + set(2, columnid); + set(3, transactionid); + set(4, value); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultIntValuesRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultIntValuesRecord.java new file mode 100644 index 000000000..86b5c7893 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultIntValuesRecord.java @@ -0,0 +1,295 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record4; +import org.jooq.Record5; +import org.jooq.Row5; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.VaultIntValues; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultIntValuesRecord extends UpdatableRecordImpl implements Record5 { + + private static final long serialVersionUID = 1432414626; + + /** + * Setter for gringotts.vault_int_values.vaultid. + */ + public void setVaultid(String value) { + set(0, value); + } + + /** + * Getter for gringotts.vault_int_values.vaultid. + */ + public String getVaultid() { + return (String) get(0); + } + + /** + * Setter for gringotts.vault_int_values.recordid. + */ + public void setRecordid(String value) { + set(1, value); + } + + /** + * Getter for gringotts.vault_int_values.recordid. + */ + public String getRecordid() { + return (String) get(1); + } + + /** + * Setter for gringotts.vault_int_values.columnid. + */ + public void setColumnid(String value) { + set(2, value); + } + + /** + * Getter for gringotts.vault_int_values.columnid. + */ + public String getColumnid() { + return (String) get(2); + } + + /** + * Setter for gringotts.vault_int_values.transactionid. + */ + public void setTransactionid(String value) { + set(3, value); + } + + /** + * Getter for gringotts.vault_int_values.transactionid. + */ + public String getTransactionid() { + return (String) get(3); + } + + /** + * Setter for gringotts.vault_int_values.value. + */ + public void setValue(Integer value) { + set(4, value); + } + + /** + * Getter for gringotts.vault_int_values.value. + */ + public Integer getValue() { + return (Integer) get(4); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record4 key() { + return (Record4) super.key(); + } + + // ------------------------------------------------------------------------- + // Record5 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row5 fieldsRow() { + return (Row5) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row5 valuesRow() { + return (Row5) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return VaultIntValues.VAULT_INT_VALUES.VAULTID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return VaultIntValues.VAULT_INT_VALUES.RECORDID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return VaultIntValues.VAULT_INT_VALUES.COLUMNID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return VaultIntValues.VAULT_INT_VALUES.TRANSACTIONID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field5() { + return VaultIntValues.VAULT_INT_VALUES.VALUE; + } + + /** + * {@inheritDoc} + */ + @Override + public String value1() { + return getVaultid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value2() { + return getRecordid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value3() { + return getColumnid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value4() { + return getTransactionid(); + } + + /** + * {@inheritDoc} + */ + @Override + public Integer value5() { + return getValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultIntValuesRecord value1(String value) { + setVaultid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultIntValuesRecord value2(String value) { + setRecordid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultIntValuesRecord value3(String value) { + setColumnid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultIntValuesRecord value4(String value) { + setTransactionid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultIntValuesRecord value5(Integer value) { + setValue(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultIntValuesRecord values(String value1, String value2, String value3, String value4, Integer value5) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached VaultIntValuesRecord + */ + public VaultIntValuesRecord() { + super(VaultIntValues.VAULT_INT_VALUES); + } + + /** + * Create a detached, initialised VaultIntValuesRecord + */ + public VaultIntValuesRecord(String vaultid, String recordid, String columnid, String transactionid, Integer value) { + super(VaultIntValues.VAULT_INT_VALUES); + + set(0, vaultid); + set(1, recordid); + set(2, columnid); + set(3, transactionid); + set(4, value); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultLinksRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultLinksRecord.java new file mode 100644 index 000000000..1de3e60f3 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultLinksRecord.java @@ -0,0 +1,418 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record6; +import org.jooq.Record8; +import org.jooq.Row8; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.VaultLinks; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultLinksRecord extends UpdatableRecordImpl implements Record8 { + + private static final long serialVersionUID = -783416194; + + /** + * Setter for gringotts.vault_links.vaultid1. + */ + public void setVaultid1(String value) { + set(0, value); + } + + /** + * Getter for gringotts.vault_links.vaultid1. + */ + public String getVaultid1() { + return (String) get(0); + } + + /** + * Setter for gringotts.vault_links.columnid. + */ + public void setColumnid(String value) { + set(1, value); + } + + /** + * Getter for gringotts.vault_links.columnid. + */ + public String getColumnid() { + return (String) get(1); + } + + /** + * Setter for gringotts.vault_links.vaultid2. + */ + public void setVaultid2(String value) { + set(2, value); + } + + /** + * Getter for gringotts.vault_links.vaultid2. + */ + public String getVaultid2() { + return (String) get(2); + } + + /** + * Setter for gringotts.vault_links.record1. + */ + public void setRecord1(String value) { + set(3, value); + } + + /** + * Getter for gringotts.vault_links.record1. + */ + public String getRecord1() { + return (String) get(3); + } + + /** + * Setter for gringotts.vault_links.record2. + */ + public void setRecord2(String value) { + set(4, value); + } + + /** + * Getter for gringotts.vault_links.record2. + */ + public String getRecord2() { + return (String) get(4); + } + + /** + * Setter for gringotts.vault_links.transactionid. + */ + public void setTransactionid(String value) { + set(5, value); + } + + /** + * Getter for gringotts.vault_links.transactionid. + */ + public String getTransactionid() { + return (String) get(5); + } + + /** + * Setter for gringotts.vault_links.islinked. + */ + public void setIslinked(Boolean value) { + set(6, value); + } + + /** + * Getter for gringotts.vault_links.islinked. + */ + public Boolean getIslinked() { + return (Boolean) get(6); + } + + /** + * Setter for gringotts.vault_links.order. + */ + public void setOrder(Integer value) { + set(7, value); + } + + /** + * Getter for gringotts.vault_links.order. + */ + public Integer getOrder() { + return (Integer) get(7); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record6 key() { + return (Record6) super.key(); + } + + // ------------------------------------------------------------------------- + // Record8 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row8 fieldsRow() { + return (Row8) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row8 valuesRow() { + return (Row8) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return VaultLinks.VAULT_LINKS.VAULTID1; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return VaultLinks.VAULT_LINKS.COLUMNID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return VaultLinks.VAULT_LINKS.VAULTID2; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return VaultLinks.VAULT_LINKS.RECORD1; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field5() { + return VaultLinks.VAULT_LINKS.RECORD2; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field6() { + return VaultLinks.VAULT_LINKS.TRANSACTIONID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field7() { + return VaultLinks.VAULT_LINKS.ISLINKED; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field8() { + return VaultLinks.VAULT_LINKS.ORDER; + } + + /** + * {@inheritDoc} + */ + @Override + public String value1() { + return getVaultid1(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value2() { + return getColumnid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value3() { + return getVaultid2(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value4() { + return getRecord1(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value5() { + return getRecord2(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value6() { + return getTransactionid(); + } + + /** + * {@inheritDoc} + */ + @Override + public Boolean value7() { + return getIslinked(); + } + + /** + * {@inheritDoc} + */ + @Override + public Integer value8() { + return getOrder(); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value1(String value) { + setVaultid1(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value2(String value) { + setColumnid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value3(String value) { + setVaultid2(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value4(String value) { + setRecord1(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value5(String value) { + setRecord2(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value6(String value) { + setTransactionid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value7(Boolean value) { + setIslinked(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord value8(Integer value) { + setOrder(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultLinksRecord values(String value1, String value2, String value3, String value4, String value5, String value6, Boolean value7, Integer value8) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + value6(value6); + value7(value7); + value8(value8); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached VaultLinksRecord + */ + public VaultLinksRecord() { + super(VaultLinks.VAULT_LINKS); + } + + /** + * Create a detached, initialised VaultLinksRecord + */ + public VaultLinksRecord(String vaultid1, String columnid, String vaultid2, String record1, String record2, String transactionid, Boolean islinked, Integer order) { + super(VaultLinks.VAULT_LINKS); + + set(0, vaultid1); + set(1, columnid); + set(2, vaultid2); + set(3, record1); + set(4, record2); + set(5, transactionid); + set(6, islinked); + set(7, order); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultTextValuesRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultTextValuesRecord.java new file mode 100644 index 000000000..c9df7ab1e --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultTextValuesRecord.java @@ -0,0 +1,338 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import java.sql.Timestamp; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record4; +import org.jooq.Record6; +import org.jooq.Row6; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.VaultTextValues; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultTextValuesRecord extends UpdatableRecordImpl implements Record6 { + + private static final long serialVersionUID = -787080538; + + /** + * Setter for gringotts.vault_text_values.vaultid. + */ + public void setVaultid(String value) { + set(0, value); + } + + /** + * Getter for gringotts.vault_text_values.vaultid. + */ + public String getVaultid() { + return (String) get(0); + } + + /** + * Setter for gringotts.vault_text_values.recordid. + */ + public void setRecordid(String value) { + set(1, value); + } + + /** + * Getter for gringotts.vault_text_values.recordid. + */ + public String getRecordid() { + return (String) get(1); + } + + /** + * Setter for gringotts.vault_text_values.columnid. + */ + public void setColumnid(String value) { + set(2, value); + } + + /** + * Getter for gringotts.vault_text_values.columnid. + */ + public String getColumnid() { + return (String) get(2); + } + + /** + * Setter for gringotts.vault_text_values.transactionid. + */ + public void setTransactionid(String value) { + set(3, value); + } + + /** + * Getter for gringotts.vault_text_values.transactionid. + */ + public String getTransactionid() { + return (String) get(3); + } + + /** + * Setter for gringotts.vault_text_values.value. + */ + public void setValue(String value) { + set(4, value); + } + + /** + * Getter for gringotts.vault_text_values.value. + */ + public String getValue() { + return (String) get(4); + } + + /** + * Setter for gringotts.vault_text_values.effectivedate. + */ + public void setEffectivedate(Timestamp value) { + set(5, value); + } + + /** + * Getter for gringotts.vault_text_values.effectivedate. + */ + public Timestamp getEffectivedate() { + return (Timestamp) get(5); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record4 key() { + return (Record4) super.key(); + } + + // ------------------------------------------------------------------------- + // Record6 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row6 fieldsRow() { + return (Row6) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row6 valuesRow() { + return (Row6) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return VaultTextValues.VAULT_TEXT_VALUES.VAULTID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return VaultTextValues.VAULT_TEXT_VALUES.RECORDID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return VaultTextValues.VAULT_TEXT_VALUES.COLUMNID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return VaultTextValues.VAULT_TEXT_VALUES.TRANSACTIONID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field5() { + return VaultTextValues.VAULT_TEXT_VALUES.VALUE; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field6() { + return VaultTextValues.VAULT_TEXT_VALUES.EFFECTIVEDATE; + } + + /** + * {@inheritDoc} + */ + @Override + public String value1() { + return getVaultid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value2() { + return getRecordid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value3() { + return getColumnid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value4() { + return getTransactionid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value5() { + return getValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public Timestamp value6() { + return getEffectivedate(); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValuesRecord value1(String value) { + setVaultid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValuesRecord value2(String value) { + setRecordid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValuesRecord value3(String value) { + setColumnid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValuesRecord value4(String value) { + setTransactionid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValuesRecord value5(String value) { + setValue(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValuesRecord value6(Timestamp value) { + setEffectivedate(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultTextValuesRecord values(String value1, String value2, String value3, String value4, String value5, Timestamp value6) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + value6(value6); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached VaultTextValuesRecord + */ + public VaultTextValuesRecord() { + super(VaultTextValues.VAULT_TEXT_VALUES); + } + + /** + * Create a detached, initialised VaultTextValuesRecord + */ + public VaultTextValuesRecord(String vaultid, String recordid, String columnid, String transactionid, String value, Timestamp effectivedate) { + super(VaultTextValues.VAULT_TEXT_VALUES); + + set(0, vaultid); + set(1, recordid); + set(2, columnid); + set(3, transactionid); + set(4, value); + set(5, effectivedate); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultsRecord.java b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultsRecord.java new file mode 100644 index 000000000..f68ba2840 --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/model/jooq/tables/records/VaultsRecord.java @@ -0,0 +1,256 @@ +/** + * This class is generated by jOOQ + */ +package org.labkey.gringotts.model.jooq.tables.records; + + +import java.sql.Timestamp; + +import javax.annotation.Generated; + +import org.jooq.Field; +import org.jooq.Record2; +import org.jooq.Record4; +import org.jooq.Row4; +import org.jooq.impl.UpdatableRecordImpl; +import org.labkey.gringotts.model.jooq.tables.Vaults; + + +/** + * This class is generated by jOOQ. + */ +@Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.8.4" + }, + comments = "This class is generated by jOOQ" +) +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class VaultsRecord extends UpdatableRecordImpl implements Record4 { + + private static final long serialVersionUID = 1723757199; + + /** + * Setter for gringotts.vaults.vaultid. + */ + public void setVaultid(String value) { + set(0, value); + } + + /** + * Getter for gringotts.vaults.vaultid. + */ + public String getVaultid() { + return (String) get(0); + } + + /** + * Setter for gringotts.vaults.vaultclassname. + */ + public void setVaultclassname(String value) { + set(1, value); + } + + /** + * Getter for gringotts.vaults.vaultclassname. + */ + public String getVaultclassname() { + return (String) get(1); + } + + /** + * Setter for gringotts.vaults.createdby. + */ + public void setCreatedby(Integer value) { + set(2, value); + } + + /** + * Getter for gringotts.vaults.createdby. + */ + public Integer getCreatedby() { + return (Integer) get(2); + } + + /** + * Setter for gringotts.vaults.created. + */ + public void setCreated(Timestamp value) { + set(3, value); + } + + /** + * Getter for gringotts.vaults.created. + */ + public Timestamp getCreated() { + return (Timestamp) get(3); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Record2 key() { + return (Record2) super.key(); + } + + // ------------------------------------------------------------------------- + // Record4 type implementation + // ------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public Row4 fieldsRow() { + return (Row4) super.fieldsRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Row4 valuesRow() { + return (Row4) super.valuesRow(); + } + + /** + * {@inheritDoc} + */ + @Override + public Field field1() { + return Vaults.VAULTS.VAULTID; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field2() { + return Vaults.VAULTS.VAULTCLASSNAME; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field3() { + return Vaults.VAULTS.CREATEDBY; + } + + /** + * {@inheritDoc} + */ + @Override + public Field field4() { + return Vaults.VAULTS.CREATED; + } + + /** + * {@inheritDoc} + */ + @Override + public String value1() { + return getVaultid(); + } + + /** + * {@inheritDoc} + */ + @Override + public String value2() { + return getVaultclassname(); + } + + /** + * {@inheritDoc} + */ + @Override + public Integer value3() { + return getCreatedby(); + } + + /** + * {@inheritDoc} + */ + @Override + public Timestamp value4() { + return getCreated(); + } + + /** + * {@inheritDoc} + */ + @Override + public VaultsRecord value1(String value) { + setVaultid(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultsRecord value2(String value) { + setVaultclassname(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultsRecord value3(Integer value) { + setCreatedby(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultsRecord value4(Timestamp value) { + setCreated(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public VaultsRecord values(String value1, String value2, Integer value3, Timestamp value4) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached VaultsRecord + */ + public VaultsRecord() { + super(Vaults.VAULTS); + } + + /** + * Create a detached, initialised VaultsRecord + */ + public VaultsRecord(String vaultid, String vaultclassname, Integer createdby, Timestamp created) { + super(Vaults.VAULTS); + + set(0, vaultid); + set(1, vaultclassname); + set(2, createdby); + set(3, created); + } +} diff --git a/Gringotts/src/org/labkey/gringotts/view/hello.jsp b/Gringotts/src/org/labkey/gringotts/view/hello.jsp new file mode 100644 index 000000000..05847603b --- /dev/null +++ b/Gringotts/src/org/labkey/gringotts/view/hello.jsp @@ -0,0 +1,25 @@ +<% +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +%> +<%@ page import="org.labkey.api.data.Container" %> +<%@ page import="org.labkey.api.security.User" %> +<%@ page extends="org.labkey.api.jsp.JspBase" %> +<% + Container c = getContainer(); + User user = getUser(); +%> +Hello, and welcome to the Gringotts module. \ No newline at end of file diff --git a/GringottsTest/module.properties b/GringottsTest/module.properties new file mode 100644 index 000000000..bf096332e --- /dev/null +++ b/GringottsTest/module.properties @@ -0,0 +1,6 @@ +Label: Test module for the Gringotts Module +License: Apache 2.0 +LicenseURL: http://www.apache.org/licenses/LICENSE-2.0 +ModuleClass: org.labkey.gringottstest.GringottsTestModule +ModuleDependencies: WebUtils +Name: WNPRC_Gringotts_Test \ No newline at end of file diff --git a/GringottsTest/resources/schemas/dbscripts/postgresql/gringottstest-15.10-15.11.sql b/GringottsTest/resources/schemas/dbscripts/postgresql/gringottstest-15.10-15.11.sql new file mode 100644 index 000000000..c6398729d --- /dev/null +++ b/GringottsTest/resources/schemas/dbscripts/postgresql/gringottstest-15.10-15.11.sql @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +-- Create schema, tables, indexes, and constraints used for GringottsTest module here +-- All SQL VIEW definitions should be created in gringottstest-create.sql and dropped in gringottstest-drop.sql +CREATE SCHEMA gringottstest; diff --git a/GringottsTest/resources/schemas/dbscripts/sqlserver/gringottstest-15.10-15.11.sql b/GringottsTest/resources/schemas/dbscripts/sqlserver/gringottstest-15.10-15.11.sql new file mode 100644 index 000000000..ab234e038 --- /dev/null +++ b/GringottsTest/resources/schemas/dbscripts/sqlserver/gringottstest-15.10-15.11.sql @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +-- Create schema, tables, indexes, and constraints used for GringottsTest module here +-- All SQL VIEW definitions should be created in gringottstest-create.sql and dropped in gringottstest-drop.sql +CREATE SCHEMA gringottstest; +GO \ No newline at end of file diff --git a/GringottsTest/resources/schemas/gringottstest.xml b/GringottsTest/resources/schemas/gringottstest.xml new file mode 100644 index 000000000..498ccdd0f --- /dev/null +++ b/GringottsTest/resources/schemas/gringottstest.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/GringottsTest/src/org/labkey/gringottstest/GringottsTestContainerListener.java b/GringottsTest/src/org/labkey/gringottstest/GringottsTestContainerListener.java new file mode 100644 index 000000000..6716c76a5 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/GringottsTestContainerListener.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringottstest; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager.ContainerListener; +import org.labkey.api.security.User; +import java.util.Collections; +import java.util.Collection; + +import java.beans.PropertyChangeEvent; + +public class GringottsTestContainerListener implements ContainerListener +{ + @Override + public void containerCreated(Container c, User user) + { + } + + @Override + public void containerDeleted(Container c, User user) + { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + } + + @Override + public void containerMoved(Container c, Container oldParent, User user) + { + } + + @NotNull @Override + public Collection canMove(Container c, Container newParent, User user) + { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/GringottsTest/src/org/labkey/gringottstest/GringottsTestController.java b/GringottsTest/src/org/labkey/gringottstest/GringottsTestController.java new file mode 100644 index 000000000..641b776cf --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/GringottsTestController.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringottstest; + +import com.google.common.reflect.TypeToken; +import junit.framework.TestSuite; +import org.json.JSONObject; +import org.labkey.api.action.ApiAction; +import org.labkey.api.action.SimpleViewAction; +import org.labkey.api.action.SpringActionController; +import org.labkey.api.security.RequiresNoPermission; +import org.labkey.api.security.RequiresPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.view.JspView; +import org.labkey.api.view.NavTree; +import org.labkey.gringottstest.test.AbstractTestSuite; +import org.labkey.gringottstest.test.BasicFunctionality; +import org.springframework.validation.BindException; +import org.springframework.web.servlet.ModelAndView; + +import java.time.LocalDateTime; +import java.time.Month; + +public class GringottsTestController extends SpringActionController { + private static final DefaultActionResolver _actionResolver = new DefaultActionResolver(GringottsTestController.class); + public static final String NAME = "gringottstest"; + + public GringottsTestController() + { + setActionResolver(_actionResolver); + } + + @RequiresPermission(ReadPermission.class) + public class BeginAction extends SimpleViewAction { + public ModelAndView getView(Object o, BindException errors) throws Exception { + ModelAndView view = new JspView("/org/labkey/gringottstest/view/hello.jsp"); + return view; + } + + public NavTree appendNavTrail(NavTree root) + { + return root; + } + } + + @RequiresNoPermission + public class TestAction extends ApiAction { + @Override + public Object execute(Void v, BindException errors) throws Exception { + AbstractTestSuite suite = new BasicFunctionality(getUser(), getContainer()); + + return suite.runTests(); + } + } +} \ No newline at end of file diff --git a/GringottsTest/src/org/labkey/gringottstest/GringottsTestManager.java b/GringottsTest/src/org/labkey/gringottstest/GringottsTestManager.java new file mode 100644 index 000000000..157371d34 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/GringottsTestManager.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringottstest; + +public class GringottsTestManager +{ + private static final GringottsTestManager _instance = new GringottsTestManager(); + + private GringottsTestManager() + { + // prevent external construction with a private default constructor + } + + public static GringottsTestManager get() + { + return _instance; + } +} \ No newline at end of file diff --git a/GringottsTest/src/org/labkey/gringottstest/GringottsTestModule.java b/GringottsTest/src/org/labkey/gringottstest/GringottsTestModule.java new file mode 100644 index 000000000..e8c6daab8 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/GringottsTestModule.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringottstest; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.ehr.EHRService; +import org.labkey.api.module.DefaultModule; +import org.labkey.api.module.ModuleContext; +import org.labkey.api.view.WebPartFactory; +import org.labkey.api.view.template.ClientDependency; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +public class GringottsTestModule extends DefaultModule +{ + public static final String NAME = "GringottsTest"; + + @Override + public String getName() + { + return NAME; + } + + @Override + public Double getSchemaVersion() + { + return 15.11; + } + + @Override + public boolean hasScripts() + { + return true; + } + + @Override + @NotNull + protected Collection createWebPartFactories() + { + return Collections.emptyList(); + } + + @Override + protected void init() + { + addController(GringottsTestController.NAME, GringottsTestController.class); + } + + @Override + public void doStartup(ModuleContext moduleContext) + { + // add a container listener so we'll know when our container is deleted: + ContainerManager.addContainerListener(new GringottsTestContainerListener()); + } + + @Override + @NotNull + public Collection getSummary(Container c) + { + return Collections.emptyList(); + } + + @Override + @NotNull + public Set getSchemaNames() + { + return Collections.singleton(GringottsTestSchema.NAME); + } +} \ No newline at end of file diff --git a/GringottsTest/src/org/labkey/gringottstest/GringottsTestSchema.java b/GringottsTest/src/org/labkey/gringottstest/GringottsTestSchema.java new file mode 100644 index 000000000..a62e6f46a --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/GringottsTestSchema.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.gringottstest; + +import org.labkey.api.data.DbSchema; +import org.labkey.api.data.DbSchemaType; +import org.labkey.api.data.dialect.SqlDialect; + +public class GringottsTestSchema +{ + private static final GringottsTestSchema _instance = new GringottsTestSchema(); + public static final String NAME = "gringottstest"; + + public static GringottsTestSchema getInstance() + { + return _instance; + } + + private GringottsTestSchema() + { + // private constructor to prevent instantiation from + // outside this class: this singleton should only be + // accessed via org.labkey.gringottstest.GringottsTestSchema.getInstance() + } + + public DbSchema getSchema() + { + return DbSchema.get(NAME, DbSchemaType.Module); + } + + public SqlDialect getSqlDialect() + { + return getSchema().getSqlDialect(); + } +} diff --git a/GringottsTest/src/org/labkey/gringottstest/model/Employee.java b/GringottsTest/src/org/labkey/gringottstest/model/Employee.java new file mode 100644 index 000000000..5e0f13094 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/model/Employee.java @@ -0,0 +1,27 @@ +package org.labkey.gringottstest.model; + +import org.labkey.gringotts.api.annotation.SerializeField; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.exception.RecordNotFoundException; +import org.labkey.gringotts.api.model.Vault; + +/** + * Created by jon on 11/14/16. + */ +public class Employee extends Person { + public Employee(Vault vault) throws InvalidVaultException, RecordNotFoundException { + super(vault); + } + + public Employee(Vault vault, String id) throws InvalidVaultException, RecordNotFoundException { + super(vault, id); + } + + /* + * Note here that we can't just assign here. The class body gets executed after the call to + * super() but before the rest of the constructor body, so not checking for null overrides + * any value that might have been bound from the database. + */ + @SerializeField + public EmployeeTypes employeeType = (this.employeeType == null) ? EmployeeTypes.FULL_TIME : this.employeeType; +} diff --git a/GringottsTest/src/org/labkey/gringottstest/model/EmployeeTypes.java b/GringottsTest/src/org/labkey/gringottstest/model/EmployeeTypes.java new file mode 100644 index 000000000..5357f8a51 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/model/EmployeeTypes.java @@ -0,0 +1,11 @@ +package org.labkey.gringottstest.model; + +/** + * Created by jon on 11/13/16. + */ +public enum EmployeeTypes { + TEMP, + STUDENT, + FULL_TIME, + HOURLY +} diff --git a/GringottsTest/src/org/labkey/gringottstest/model/Person.java b/GringottsTest/src/org/labkey/gringottstest/model/Person.java new file mode 100644 index 000000000..e3e8e86b8 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/model/Person.java @@ -0,0 +1,33 @@ +package org.labkey.gringottstest.model; + +import org.jetbrains.annotations.Nullable; +import org.labkey.gringotts.api.annotation.SerializeField; +import org.labkey.gringotts.api.exception.InvalidVaultException; +import org.labkey.gringotts.api.exception.RecordNotFoundException; +import org.labkey.gringotts.api.model.Record; +import org.labkey.gringotts.api.model.Vault; + +import java.time.LocalDateTime; + +/** + * Created by jon on 11/14/16. + */ +public class Person extends Record { + @SerializeField public String firstName; + @SerializeField public String middleName; + @SerializeField public String lastName; + + @SerializeField + public Integer age; // I know this doesn't make sense to store, but I can't think of another integer to test with + + @SerializeField + public LocalDateTime birthdate; + + public Person(Vault vault, @Nullable String id) throws InvalidVaultException, RecordNotFoundException { + super(vault, id); + } + + public Person(Vault vault) throws InvalidVaultException, RecordNotFoundException { + super(vault); + } +} diff --git a/GringottsTest/src/org/labkey/gringottstest/test/AbstractTestSuite.java b/GringottsTest/src/org/labkey/gringottstest/test/AbstractTestSuite.java new file mode 100644 index 000000000..12a9ffc77 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/test/AbstractTestSuite.java @@ -0,0 +1,111 @@ +package org.labkey.gringottstest.test; + +import com.google.common.reflect.TypeToken; +import org.json.JSONObject; +import org.labkey.api.data.Container; +import org.labkey.api.security.User; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jon on 11/14/16. + */ +public abstract class AbstractTestSuite { + private final User user; + private final Container container; + + private final Class thisClass; + + public AbstractTestSuite(User user, Container container) { + this.user = user; + this.container = container; + this.thisClass = this.getClass(); + } + + public User getUser() { + return user; + } + + public Container getContainer() { + return container; + } + + public JSONObject runTests() { + JSONObject results = new JSONObject(); + JSONObject summary = new JSONObject(); + JSONObject details = new JSONObject(); + + this.beforeAll(results); + + for (Test test : getTests()) { + String name = test.getClass().getName(); + + JSONObject testResult = new JSONObject(); + boolean passed = false; + + try { + test.runTest(); + passed = true; + } + catch (AssertionError|Exception e) { + testResult.put("error", e); + } + + testResult.put("passed", passed); + summary.put(name, passed); + details.put(name, testResult); + } + + this.afterAll(results); + + results.put("summary", summary); + results.put("details", details); + + return results; + } + + public void beforeAll(JSONObject results) { + // Override for hooks + } + + public void afterAll(JSONObject results) { + // Override for hooks + } + + public List getTests() { + List tests = new ArrayList<>(); + + for (Class clazz : thisClass.getDeclaredClasses()) { + if (Test.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) { + try { + Constructor constructor = clazz.getConstructor(thisClass); + Test test = (Test) constructor.newInstance(this); + tests.add(test); + } + catch (NoSuchMethodException|InstantiationException|InvocationTargetException|IllegalAccessException e) { + throw new RuntimeException("Couldn't instantiate test for " + clazz.getCanonicalName()); + } + } + } + + return tests; + } + + public abstract class Test { + public Test() {} + + public User getUser() { + return AbstractTestSuite.this.user; + } + + public Container getContainer() { + return AbstractTestSuite.this.container; + } + + abstract void runTest() throws Exception; + } +} diff --git a/GringottsTest/src/org/labkey/gringottstest/test/BasicFunctionality.java b/GringottsTest/src/org/labkey/gringottstest/test/BasicFunctionality.java new file mode 100644 index 000000000..9ea9a64f6 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/test/BasicFunctionality.java @@ -0,0 +1,92 @@ +package org.labkey.gringottstest.test; + +import com.google.common.reflect.TypeToken; +import org.json.JSONObject; +import org.labkey.api.data.Container; +import org.labkey.api.security.User; +import org.labkey.gringotts.api.model.Vault; +import org.labkey.gringottstest.model.Employee; +import org.labkey.gringottstest.model.EmployeeTypes; +import org.labkey.gringottstest.model.Person; + +import java.time.LocalDateTime; +import java.time.Month; + +/** + * Created by jon on 11/14/16. + */ +public class BasicFunctionality extends AbstractTestSuite { + public BasicFunctionality(User user, Container container) { + super(user, container); + } + + @Override + public void afterAll(JSONObject results) { + // TODO: delete all test records. + } + + public class PrimativeValueStorageAndRetrieval extends Test { + @Override + void runTest() throws Exception { + String firstName = "Edward"; + String middleName = "Percival"; + String lastName = "Nygma"; + Integer age = 3; + LocalDateTime birthdate = LocalDateTime.of(1985, Month.APRIL, 1, 0, 0, 0); + + + Vault vault = new Vault(getContainer(), getUser()) {}; + Person jon = vault.create(); + + jon.firstName = firstName; + jon.middleName = middleName; + jon.lastName = lastName; + jon.birthdate = birthdate; + jon.age = age; + + jon.save(); + + String jonsId = jon.getId(TypeToken.of(jon.getClass())); + + Person jon2 = vault.load(jonsId); + + assert jon2.age.equals(age); + assert jon2.birthdate.isEqual(birthdate); + assert jon2.firstName.equals(firstName); + assert jon2.lastName.equals(lastName); + assert jon2.middleName.equals(middleName); + + // Sometimes the guy can take the girl's name... + jon2.lastName = "Kringle"; + + jon2.save(); + + Person jon3 = vault.load(jonsId); + + assert jon3.lastName.equals("Kringle"); + } + } + + public class SimpleInheritanceAndEnumValues extends Test { + @Override + void runTest() throws Exception { + Vault employeeVault = new Vault(getContainer(), getUser()) {}; + + Employee jGordon = employeeVault.create(); + + jGordon.firstName = "James"; + jGordon.middleName = "Worthington"; + jGordon.lastName = "Gordon"; + + jGordon.age = 40; + jGordon.birthdate = LocalDateTime.of(1985, Month.JULY, 6, 0, 0); + jGordon.employeeType = EmployeeTypes.STUDENT; + + jGordon.save(); + + Employee jG2 = employeeVault.load(jGordon.getId(TypeToken.of(jGordon.getClass()))); + + assert jG2.employeeType.equals(EmployeeTypes.STUDENT); + } + } +} diff --git a/GringottsTest/src/org/labkey/gringottstest/view/hello.jsp b/GringottsTest/src/org/labkey/gringottstest/view/hello.jsp new file mode 100644 index 000000000..1fb6d27c9 --- /dev/null +++ b/GringottsTest/src/org/labkey/gringottstest/view/hello.jsp @@ -0,0 +1,62 @@ +<% +/* + * Copyright (c) 2015 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +%> +<%@ page import="org.labkey.api.data.Container" %> +<%@ page import="org.labkey.api.security.User" %> +<%@ page import="org.labkey.api.module.ModuleLoader" %> +<%@ page import="org.labkey.gringottstest.test.BasicFunctionality" %> +<%@ page import="org.json.JSONObject" %> +<%@ page extends="org.labkey.api.jsp.JspBase" %> +<% + Container c = getContainer(); + User user = getUser(); + + BasicFunctionality test = new BasicFunctionality(getUser(), getContainer()); + + JSONObject results = test.runTests(); +%> +Hello, and welcome to the GringottsTest module. + + +
    +<% + for (String key: results.getJSONObject("summary").keySet()) { + boolean result = results.getJSONObject("summary").getBoolean(key); + + String reason = ""; + if (!result) { + reason = results.getJSONObject("details").getJSONObject(key).getString("error"); + } + + String color = (result) ? "green" : "red"; +%> +
  • + <%= key %> + <% + if (!result) { + %> +
      +
    • <%= reason %>
    • +
    + <% + } + %> +
  • +<% + } +%> +
\ No newline at end of file diff --git a/SelfRegistration/README.md b/SelfRegistration/README.md new file mode 100644 index 000000000..c5222dfb5 --- /dev/null +++ b/SelfRegistration/README.md @@ -0,0 +1 @@ +Go [here](https://github.com/WNPRC-EHR-Services/EHR_Documentation/tree/master/notes). \ No newline at end of file diff --git a/SelfRegistration/build.gradle b/SelfRegistration/build.gradle new file mode 100644 index 000000000..06ad95939 --- /dev/null +++ b/SelfRegistration/build.gradle @@ -0,0 +1,3 @@ +apply plugin: 'java' +apply plugin: 'org.labkey.module' + diff --git a/SelfRegistration/module.properties b/SelfRegistration/module.properties new file mode 100644 index 000000000..66bb483a0 --- /dev/null +++ b/SelfRegistration/module.properties @@ -0,0 +1,8 @@ +ModuleClass: org.labkey.selfregistration.SelfRegistrationModule +Label: Provides a mechanism keeping track of self registration submissions +Description: This module provides a custom login page and extends LabKey's self registration \ + page for users creating guest accounts. +URL: https://github.com/WNPRC-EHR-Services/wnprc-modules/SelfRegistration +License: Apache 2.0 +LicenseURL: http://www.apache.org/licenses/LICENSE-2.0 +Name: SelfRegistration \ No newline at end of file diff --git a/SelfRegistration/resources/views/login.html b/SelfRegistration/resources/views/login.html new file mode 100644 index 000000000..193cd6300 --- /dev/null +++ b/SelfRegistration/resources/views/login.html @@ -0,0 +1,38 @@ +
+
Sign In
+
+
+ + + + + Remember my email address + + +
+ + + + Register + +
+ + + + + +
+
+ diff --git a/SelfRegistration/resources/views/login.view.xml b/SelfRegistration/resources/views/login.view.xml new file mode 100644 index 000000000..ec29417cd --- /dev/null +++ b/SelfRegistration/resources/views/login.view.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationContainerListener.java b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationContainerListener.java new file mode 100644 index 000000000..a9e119a5e --- /dev/null +++ b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationContainerListener.java @@ -0,0 +1,39 @@ +package org.labkey.selfregistration; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager.ContainerListener; +import org.labkey.api.security.User; +import java.util.Collections; +import java.util.Collection; + +import java.beans.PropertyChangeEvent; + +public class SelfRegistrationContainerListener implements ContainerListener +{ + @Override + public void containerCreated(Container c, User user) + { + } + + @Override + public void containerDeleted(Container c, User user) + { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + } + + @Override + public void containerMoved(Container c, Container oldParent, User user) + { + } + + @NotNull @Override + public Collection canMove(Container c, Container newParent, User user) + { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationController.java b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationController.java new file mode 100644 index 000000000..1ee4655ff --- /dev/null +++ b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationController.java @@ -0,0 +1,396 @@ +package org.labkey.selfregistration; + +import org.apache.log4j.Logger; +import org.junit.*; +import org.labkey.api.action.ApiResponse; +import org.labkey.api.action.ApiSimpleResponse; +import org.labkey.api.action.MutatingApiAction; +import org.labkey.api.action.SimpleViewAction; +import org.labkey.api.action.SpringActionController; +import org.labkey.api.collections.CaseInsensitiveHashMap; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.data.Sort; +import org.labkey.api.data.TableInfo; +import org.labkey.api.data.TableSelector; +import org.labkey.api.exp.ChangePropertyDescriptorException; +import org.labkey.api.exp.property.Domain; +import org.labkey.api.exp.property.DomainProperty; +import org.labkey.api.gwt.client.model.PropertyValidatorType; +import org.labkey.api.issues.IssuesListDefService; +import org.labkey.api.module.AllowedDuringUpgrade; +import org.labkey.api.module.Module; +import org.labkey.api.module.ModuleLoader; +import org.labkey.api.query.BatchValidationException; +import org.labkey.api.query.QueryService; +import org.labkey.api.query.QueryUpdateService; +import org.labkey.api.security.Group; +import org.labkey.api.security.GroupManager; +import org.labkey.api.security.IgnoresTermsOfUse; +import org.labkey.api.security.InvalidGroupMembershipException; +import org.labkey.api.security.MutableSecurityPolicy; +import org.labkey.api.security.RequiresPermission; +import org.labkey.api.security.SecurityManager; +import org.labkey.api.security.SecurityPolicyManager; +import org.labkey.api.security.User; +import org.labkey.api.security.UserManager; +import org.labkey.api.security.ValidEmail; +import org.labkey.api.security.permissions.InsertPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.roles.RoleManager; +import org.labkey.api.security.roles.SubmitterRole; +import org.labkey.api.util.ConfigurationException; +import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.view.JspView; +import org.labkey.api.view.NavTree; +import org.labkey.security.xml.GroupEnumType; +import org.springframework.validation.BindException; +import org.springframework.web.servlet.ModelAndView; +import org.labkey.api.query.UserSchema; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class SelfRegistrationController extends SpringActionController +{ + private static final DefaultActionResolver _actionResolver = new DefaultActionResolver(SelfRegistrationController.class); + public static final String NAME = "selfregistration"; + protected static final Logger _log = Logger.getLogger(SelfRegistrationController.class); + + public SelfRegistrationController() + { + setActionResolver(_actionResolver); + } + + public static class SelfRegistrationForm { + + private String assignedTo; + private String title; + private String priority; + private String issueDefName; + private String containerPath; + private String firstname; + private String lastname; + private String email; + private String institution; + private String project; + private String reason; + private String hostname; + + public String getAssignedTo() + { + return assignedTo; + } + + public void setAssignedTo(String assignedTo) + { + this.assignedTo = assignedTo; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public String getPriority() + { + return priority; + } + + public void setPriority(String priority) + { + this.priority = priority; + } + + public String getIssueDefName() + { + return issueDefName; + } + + public void setIssueDefName(String issueDefName) + { + this.issueDefName = issueDefName; + } + + public String getContainerPath() + { + return containerPath; + } + + public void setContainerPath(String containerPath) + { + this.containerPath = containerPath; + } + + public String getFirstname() + { + return firstname; + } + + public void setFirstname(String firstname) + { + this.firstname = firstname; + } + + public String getLastname() + { + return lastname; + } + + public void setLastname(String lastname) + { + this.lastname = lastname; + } + + public String getEmail() + { + return email; + } + + public void setEmail(String email) + { + this.email = email; + } + + public String getInstitution() + { + return institution; + } + + public void setInstitution(String institution) + { + this.institution = institution; + } + + public String getProject() + { + return project; + } + + public void setProject(String project) + { + this.project = project; + } + + public String getReason() + { + return reason; + } + + public void setReason(String reason) + { + this.reason = reason; + } + + public String getHostname() + { + return hostname; + } + + public void setHostname(String hostname) + { + this.hostname = hostname; + } + } + + @IgnoresTermsOfUse + @AllowedDuringUpgrade + @RequiresPermission(InsertPermission.class) + public static class UpdateSelfRegistrationListAction extends MutatingApiAction + { + public static final String _issueStatus = "open"; + public static final String _schemaPath = "issues"; + + @Override + public ApiResponse execute(SelfRegistrationForm form, BindException errors) + { + Container container = ContainerManager.getForPath(form.getContainerPath()); + User user = getViewContext().getUser(); + saveIssue(user, container, form); + return new ApiSimpleResponse(); + } + + // takes the form data and inserts a new issue into the issue tracker (value of issueDefName) + public static void saveIssue(User user, Container container, SelfRegistrationForm form) + { + String hostname = form.getHostname(); + + Map row = new CaseInsensitiveHashMap<>(); + row.put("Title", form.getTitle()); + row.put("AssignedTo", form.getAssignedTo()); + row.put("Status", _issueStatus); + row.put("firstname", form.getFirstname()); + row.put("lastname", form.getLastname()); + row.put("email", form.getEmail()); + row.put("institution", form.getInstitution()); + row.put("project", form.getProject()); + row.put("reason", form.getReason()); + row.put("priority", form.getPriority()); + + // get issue table and insert the issue row + UserSchema userSchema = QueryService.get().getUserSchema(user, container, _schemaPath); + TableInfo table = userSchema.getTable(form.getIssueDefName()); + QueryService.get().getSelectSQL(table,null,null,null,100,0,false); + QueryUpdateService qus = table.getUpdateService(); + + BatchValidationException batchErrors = new BatchValidationException(); + List> results; + + try + { + results = qus.insertRows(user, container, Collections.singletonList(row), batchErrors, null, null); + if (!batchErrors.hasErrors()) + { + assert results.size() == 1; + //send in the list id + String id; + Map formresult = results.get(0); + id = formresult.get("IssueId").toString(); + + SelfRegistrationNotification t = new SelfRegistrationNotification(id,hostname); + t.sendManually(container,user); + } + else + throw batchErrors; + } catch (Exception e) + { + _log.error(e.getMessage()); + throw new RuntimeException(e); + } + + + } + + } + public static class TestCase extends Assert + { + private static final String adminUser = "admin_user_test@primate.wisc.edu"; + private static final String containerPath = "/PrivateTest"; + private static final String schemaName = "issues"; + private static final String issueTable = "userregistrations"; + + // creates fields in issue tracker + public static void createTextFields(Domain d, String[] fields, User user) throws ChangePropertyDescriptorException + { + String typeUri = d.getTypeURI(); + for (String field : fields){ + DomainProperty prop = d.addProperty(); + prop.setName(field); + prop.setPropertyURI(typeUri + "#" + field); + //to test different field types: + //prop.setType(PropertyService.get().getType(c, PropertyType.MULTI_LINE.getXmlName())); + } + d.save(user); + } + + @BeforeClass + public static void setUp() throws ValidEmail.InvalidEmailException, ChangePropertyDescriptorException, SecurityManager.UserManagementException, InvalidGroupMembershipException + { + // create container + Container rootContainer = ContainerManager.getRoot(); + Container container = ContainerManager.createContainer(rootContainer,"PrivateTest"); + Group group = GroupManager.getGroup(rootContainer, "Guests", GroupEnumType.SITE); + if (null == group) + { + throw new ConfigurationException("Could not add group specified in startup properties GroupRoles: " + "Guest"); + } + // give guest submit perms + MutableSecurityPolicy policy = new MutableSecurityPolicy(container); + RoleManager.getAllRoles(); + //what is the roleName for submitter? + policy.addRoleAssignment(group, SubmitterRole.class); + SecurityPolicyManager.savePolicy(policy); + + // ensure the issue module is enabled for this folder + Module issueModule = ModuleLoader.getInstance().getModule("Issues"); + Set activeModules = container.getActiveModules(); + if (!activeModules.contains(issueModule)) + { + Set newActiveModules = new HashSet<>(); + newActiveModules.addAll(activeModules); + newActiveModules.add(issueModule); + + container.setActiveModules(newActiveModules); + } + + // teamcity doesn't know about this user since it's an ephemeral DB, need to create an admin user and assign admin role. + SecurityManager.NewUserStatus newUserStatus = SecurityManager.addUser(new ValidEmail(adminUser), null); + User adminUser = newUserStatus.getUser(); + Group adminGroup = GroupManager.getGroup(rootContainer, "Administrators", GroupEnumType.SITE); + SecurityManager.addMember(adminGroup, adminUser); + + // create issue tracker + int issueDefId = IssuesListDefService.get().createIssueListDef(container, adminUser,"IssueDefinition","User Registrations", null,null); + // The Domain object is the definition of the "table" that contains the custom fields. + Domain d = IssuesListDefService.get().getDomainFromIssueDefId(issueDefId, container, adminUser); + String[] fieldnames = {"firstname","lastname","email","institution","project","reason"}; + createTextFields(d,fieldnames,adminUser); + + SelfRegistrationForm f = new SelfRegistrationForm(); + f.setTitle("testtitle"); + f.setAssignedTo("0"); + f.setPriority("2"); + f.setFirstname("testfirstname"); + f.setLastname("testlastname"); + f.setEmail("testemail@email.com"); + f.setInstitution("testinstitution"); + f.setProject("testproject"); + f.setReason("testreason"); + f.setIssueDefName(issueTable); + f.setContainerPath(containerPath); + + User guestUser = UserManager.getGuestUser(); + // create issue in issue tracker + UpdateSelfRegistrationListAction.saveIssue(guestUser, container, f); + + } + + + @Test + public void testIssueWasCreated() throws Exception + { + //see if issue was created + User us = UserManager.getUser(new ValidEmail(adminUser)); + Container container = ContainerManager.getForPath(containerPath); + + UserSchema userSchema = QueryService.get().getUserSchema(us, container, schemaName); + TableInfo table = userSchema.getTable(issueTable); + + TableSelector ts = new TableSelector(table, PageFlowUtil.set("issueid","title","assignedto","firstname","lastname","email","institution","project","reason"),null,new Sort("-issueid")); + Map[] mp = ts.getMapArray(); + ts.getRowCount(); + Map issue = mp[0]; + + Assert.assertEquals("testfirstname",issue.get("firstname")); + Assert.assertEquals("testlastname",issue.get("lastname")); + Assert.assertEquals("testemail@email.com",issue.get("email")); + Assert.assertEquals("testinstitution",issue.get("institution")); + Assert.assertEquals("testproject",issue.get("project")); + Assert.assertEquals("testreason",issue.get("reason")); + Assert.assertEquals(0,issue.get("assignedto")); + Assert.assertEquals("testtitle",issue.get("title")); + + } + + @AfterClass + public static void cleanUp() throws ValidEmail.InvalidEmailException, SecurityManager.UserManagementException + { + //remove the container, not really needed in TeamCity, but good for local testing + User adminuser = UserManager.getUser(new ValidEmail(adminUser)); + Container container = ContainerManager.getForPath(containerPath); + ContainerManager.delete(container,UserManager.getUser(new ValidEmail(adminUser))); + + //also delete the admin user + UserManager.deleteUser(adminuser.getUserId()); + } + } + +} \ No newline at end of file diff --git a/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationManager.java b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationManager.java new file mode 100644 index 000000000..53f42894b --- /dev/null +++ b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationManager.java @@ -0,0 +1,16 @@ +package org.labkey.selfregistration; + +public class SelfRegistrationManager +{ + private static final SelfRegistrationManager _instance = new SelfRegistrationManager(); + + private SelfRegistrationManager() + { + // prevent external construction with a private default constructor + } + + public static SelfRegistrationManager get() + { + return _instance; + } +} \ No newline at end of file diff --git a/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationModule.java b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationModule.java new file mode 100644 index 000000000..523d38cb8 --- /dev/null +++ b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationModule.java @@ -0,0 +1,57 @@ +package org.labkey.selfregistration; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.module.CodeOnlyModule; +import org.labkey.api.module.ModuleContext; +import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.view.WebPartFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public class SelfRegistrationModule extends CodeOnlyModule +{ + public static final String NAME = "SelfRegistration"; + + @Override + public String getName() + { + return NAME; + } + + @Override + @NotNull + protected Collection createWebPartFactories() + { + return Collections.emptyList(); + } + + @Override + protected void init() + { + addController(SelfRegistrationController.NAME, SelfRegistrationController.class); + } + + @Override + public void doStartup(ModuleContext moduleContext) + { + // add a container listener so we'll know when our container is deleted: + ContainerManager.addContainerListener(new SelfRegistrationContainerListener()); + } + + @Override + @NotNull + public Collection getSummary(Container c) + { + return Collections.emptyList(); + } + + @Override + public @NotNull Set getIntegrationTests() + { + return PageFlowUtil.set(SelfRegistrationController.TestCase.class); + } +} \ No newline at end of file diff --git a/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationNotification.java b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationNotification.java new file mode 100644 index 000000000..ba2190725 --- /dev/null +++ b/SelfRegistration/src/org/labkey/selfregistration/SelfRegistrationNotification.java @@ -0,0 +1,119 @@ +package org.labkey.selfregistration; + +import org.labkey.api.data.Container; +import org.labkey.api.security.User; +import org.labkey.api.util.MailHelper; +import org.apache.commons.lang3.StringUtils; + +import javax.mail.Message; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.labkey.api.search.SearchService._log; + +public class SelfRegistrationNotification +{ + public String rowId; + public String hostName; + + protected final static SimpleDateFormat _dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm"); + protected final static SimpleDateFormat _dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + protected final static SimpleDateFormat _timeFormat = new SimpleDateFormat("kk:mm"); + protected final static String _recepientEmail = "ehrservices@g-groups.wisc.edu"; + protected final static String _fromEmail = "ehr-do-not-reply@primate.wisc.edu"; + protected final static String _issueTrackerDefName = "userregistrations"; + protected final static String _issueTrackerFolderName = "Private"; + + public SelfRegistrationNotification(String rowid, String hostname) + { + rowId = rowid; + hostName = hostname; + } + + public String getName() + { + return "Self Registration Notification"; + } + + public String getScheduleDescription() + { + return "As soon as Self Registration is submitted"; + } + + public String getDescription() + { + return "This notification gets sent every time there is a new Self Registration form submitted"; + } + + public String getEmailSubject(Container c) + { + return "[EHR Services] New Self Registration Form Submitted on " + _dateTimeFormat.format(new Date()); + } + + public String getMessageBodyHTML() + { + final StringBuilder msg = new StringBuilder(); + Date now = new Date(); + msg.append("

There was a new self registration request submitted on: " + + _dateFormat.format(now) + + " at " + + _timeFormat.format(now) + + ".

"); + + msg.append("

Click here to review the request.

"); + + msg.append("

View all of the self registrations " + + "here.

"); + + return msg.toString(); + } + + public void sendManually (Container container, User user) + { + //Collection recipients = getRecipients(container); + sendMessage(getEmailSubject(container),getMessageBodyHTML(),user,container); + + } + + public void sendMessage(String subject, String bodyHtml, User currentUser, Container container) + { + _log.info("SelfRegistrationNotification.java: sending self registration email..."); + try + { + //List
addresses = NotificationService.get().getEmailsForPrincipal(u); + MailHelper.MultipartMessage msg = MailHelper.createMultipartMessage(); + msg.setFrom(_fromEmail); + msg.setSubject(subject); + + //in case we want to add more than one email later + List emails = new ArrayList<>(); + emails.add(_recepientEmail); + + if (emails.size() == 0) + { + _log.warn("SelfRegistrationNotification.java: no email addresses, unable to send email"); + return; + } + + msg.setRecipients(Message.RecipientType.TO, StringUtils.join(emails, ",")); + msg.setEncodedHtmlContent(bodyHtml); + + MailHelper.send(msg, currentUser, container); + _log.info("SelfRegistrationNotification.java: email sent."); + } + catch (Exception e) + { + _log.error("SelfRegistrationNotification.java: unable to send email", e); + } + } + +} diff --git a/WNPRC_Compliance/module.properties b/WNPRC_Compliance/module.properties index 442fd34d6..149ff7554 100644 --- a/WNPRC_Compliance/module.properties +++ b/WNPRC_Compliance/module.properties @@ -6,4 +6,4 @@ ModuleClass: org.labkey.wnprc_compliance.WNPRC_ComplianceModule ModuleDependencies: LDK, DBUtils, WebUtils Name: WNPRC_Compliance SchemaVersion: 20.000 -SupportedDatabases: pgsql \ No newline at end of file +SupportedDatabases: pgsql diff --git a/WNPRC_Compliance/resources/queries/wnprc_compliance/mapMeaslesClearances.sql b/WNPRC_Compliance/resources/queries/wnprc_compliance/mapMeaslesClearances.sql new file mode 100644 index 000000000..c0e3b1a2f --- /dev/null +++ b/WNPRC_Compliance/resources/queries/wnprc_compliance/mapMeaslesClearances.sql @@ -0,0 +1,35 @@ +-- noinspection SqlNoDataSourceInspectionForFile + +SELECT +personid, +first_name, +middle_name, +last_name, +notes, +measlesResults.mid as id, +measlesResults.mrequired as required, +to_char(measlesResults.mdate, 'MM/DD/YYYY') as date, +'measles_clearances' as table_name + +FROM persons + +LEFT JOIN ( + + SELECT + p_m_map.person_id, + m.id as mid, + m.required as mrequired, + CAST(m.date as DATE) as mdate + + FROM measles_clearances m + + LEFT JOIN persons_measles_clearances p_m_map + ON ( + m.id = p_m_map.clearance_id + ) + + ORDER BY mdate DESC + +) measlesResults + +ON measlesResults.person_id = persons.personid diff --git a/WNPRC_Compliance/resources/queries/wnprc_compliance/mapTBClearances.sql b/WNPRC_Compliance/resources/queries/wnprc_compliance/mapTBClearances.sql new file mode 100644 index 000000000..2f206ff0a --- /dev/null +++ b/WNPRC_Compliance/resources/queries/wnprc_compliance/mapTBClearances.sql @@ -0,0 +1,36 @@ +-- noinspection SqlNoDataSourceInspectionForFile + +SELECT +personid, +first_name, +middle_name, +last_name, +notes, +tbResults.tbid as id, +to_char(tbResults.tbdate,'MM/DD/YYYY') as date, +'tb_clearances' as table_name + +FROM persons + +LEFT JOIN ( + + SELECT + p_tb_map.person_id, + tb.id as tbid, + CAST(tb.date as DATE) as tbdate + + FROM tb_clearances tb + + LEFT JOIN persons_tb_clearances p_tb_map + ON ( + tb.id = p_tb_map.clearance_id + ) + + ORDER BY tbdate DESC + +) tbResults + +ON tbResults.person_id = persons.personid + + + diff --git a/WNPRC_Compliance/resources/queries/wnprc_compliance/personsList.sql b/WNPRC_Compliance/resources/queries/wnprc_compliance/personsList.sql index 10211c0da..d593c4b89 100644 --- a/WNPRC_Compliance/resources/queries/wnprc_compliance/personsList.sql +++ b/WNPRC_Compliance/resources/queries/wnprc_compliance/personsList.sql @@ -1,13 +1,14 @@ SELECT persons.personid, +last_name, first_name, middle_name, -last_name, date_of_birth, cardInfo.employee_number, notes, tbResults.lastClearance as lastTbClearance, measlesResults.lastClearance as measlesClearance, +measlesResults.mrequired as measlesRequired, archived_for_access_purposes as isArchived FROM persons @@ -35,6 +36,7 @@ LEFT JOIN ( SELECT p_m_map.person_id, + m.required as mrequired, MAX(m.date) as lastClearance FROM measles_clearances m @@ -44,7 +46,7 @@ LEFT JOIN ( m.id = p_m_map.clearance_id ) - GROUP BY (p_m_map.person_id) + GROUP BY p_m_map.person_id, m.required ) measlesResults ON measlesResults.person_id = persons.personid; @@ -58,4 +60,7 @@ LEFT JOIN FROM wnprc_compliance.card_info GROUP BY card_info.card_id, card_info.employee_number ) cardInfo -ON (pers_to_card.cardid = cardInfo.card_id) \ No newline at end of file +ON (pers_to_card.cardid = cardInfo.card_id) + +ORDER BY last_name ASC + diff --git a/WNPRC_Compliance/resources/queries/wnprc_compliance/searchResults.sql b/WNPRC_Compliance/resources/queries/wnprc_compliance/searchResults.sql index 19017b256..ace514a3b 100644 --- a/WNPRC_Compliance/resources/queries/wnprc_compliance/searchResults.sql +++ b/WNPRC_Compliance/resources/queries/wnprc_compliance/searchResults.sql @@ -1,5 +1,12 @@ +-- noinspection SqlNoDataSourceInspectionForFile + +-- noinspection SqlDialectInspectionForFile,SqlNoDataSourceInspection + SELECT id, +first_name, +middle_name, +last_name, display, LCASE(display) as displayLcase, notes, @@ -8,6 +15,9 @@ notes, FROM ( SELECT CAST(userid as VARCHAR) as id, + firstName as first_name, + '' as middle_name, + lastName as last_name, COALESCE( firstName || ' ' || lastName || ' (' || displayName || ')', displayName, @@ -22,6 +32,9 @@ FROM ( SELECT card_id as id, + first_name, + middle_name, + last_name, COALESCE(first_name, '') || ' ' || COALESCE(middle_name, '') || ' ' || COALESCE(last_name, '') || ' (' || card_id || ')' as display, COALESCE(department || ';', '') || COALESCE(info2 || ';', '') || COALESCE(info3 || ';', '') as notes, 'UW CARD' as type @@ -34,9 +47,12 @@ FROM ( SELECT personid as id, + first_name, + middle_name, + last_name, COALESCE(first_name, '') || ' ' || COALESCE(middle_name, '') || ' ' || COALESCE(last_name, '') as display, notes, 'PERSONS' as type FROM wnprc_compliance.persons -) \ No newline at end of file +) ORDER BY last_name ASC \ No newline at end of file diff --git a/WNPRC_Compliance/resources/queries/wnprc_compliance/unidentifiedCards.sql b/WNPRC_Compliance/resources/queries/wnprc_compliance/unidentifiedCards.sql index d7cf1874c..21bd8607a 100644 --- a/WNPRC_Compliance/resources/queries/wnprc_compliance/unidentifiedCards.sql +++ b/WNPRC_Compliance/resources/queries/wnprc_compliance/unidentifiedCards.sql @@ -1,7 +1,7 @@ SELECT cards.card_id, -first_name, last_name, +first_name, middle_name, department, employee_number, diff --git a/WNPRC_Compliance/resources/schemas/dbscripts/postgresql/wnprc_compliance-18.10-18.11.sql b/WNPRC_Compliance/resources/schemas/dbscripts/postgresql/wnprc_compliance-18.10-18.11.sql new file mode 100644 index 000000000..04f121285 --- /dev/null +++ b/WNPRC_Compliance/resources/schemas/dbscripts/postgresql/wnprc_compliance-18.10-18.11.sql @@ -0,0 +1 @@ +ALTER TABLE wnprc_compliance.measles_clearances ADD COLUMN required BOOLEAN DEFAULT true; \ No newline at end of file diff --git a/WNPRC_Compliance/resources/schemas/wnprc_compliance.xml b/WNPRC_Compliance/resources/schemas/wnprc_compliance.xml index 28c16cf2f..1ba2b3d2d 100644 --- a/WNPRC_Compliance/resources/schemas/wnprc_compliance.xml +++ b/WNPRC_Compliance/resources/schemas/wnprc_compliance.xml @@ -118,6 +118,7 @@ + diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/AccessReportRowParser.java b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/AccessReportRowParser.java index c046c8671..ddf333310 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/AccessReportRowParser.java +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/AccessReportRowParser.java @@ -3,6 +3,7 @@ import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.util.NumberToTextConverter; import org.labkey.api.action.ApiUsageException; import org.labkey.api.data.Container; import org.labkey.api.util.Pair; @@ -115,7 +116,16 @@ else if (cell.getCellType() == CellType.BLANK) { values.put(columnName, value); } else { - values.put(columnName, cell.getStringCellValue()); + //For whatever reason apache ROI library thinks some of these cells are numeric, + //Even though excel says they are text + String value; + if (cell.getCellType() == CellType.NUMERIC) { + value = NumberToTextConverter.toText(cell.getNumericCellValue()); + } + else { + value = cell.getStringCellValue(); + } + values.put(columnName, value); } } } diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/PersonService.java b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/PersonService.java index 842aabf9c..e001ec32a 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/PersonService.java +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/PersonService.java @@ -76,6 +76,7 @@ public String addClearance(String personId, String tableName, String lookupTable requirementInfo.put("date", form.dateCompleted); requirementInfo.put("comment", form.notes); requirementInfo.put("container", container.getId()); + requirementInfo.put("required", form.required); queryUpdater.upsert(requirementInfo); JSONObject lookupInfo = new JSONObject(); diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceController.java b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceController.java index f378449cf..115e35cab 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceController.java +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceController.java @@ -1,11 +1,12 @@ package org.labkey.wnprc_compliance; +import com.fasterxml.jackson.annotation.JsonFormat; import org.json.JSONObject; import org.labkey.api.action.AbstractFileUploadAction; import org.labkey.api.action.MutatingApiAction; -import org.labkey.api.data.DbSchemaType; import org.labkey.api.action.Marshal; import org.labkey.api.action.Marshaller; +import org.labkey.api.action.ReadOnlyApiAction; import org.labkey.api.action.SpringActionController; import org.labkey.api.data.CompareType; import org.labkey.api.data.DbSchema; @@ -13,6 +14,7 @@ import org.labkey.api.data.SimpleFilter; import org.labkey.api.module.Module; import org.labkey.api.module.ModuleLoader; +import org.labkey.api.query.FieldKey; import org.labkey.api.security.ActionNames; import org.labkey.api.security.CSRF; import org.labkey.api.security.RequiresPermission; @@ -121,6 +123,20 @@ public String getTitle() { } } + @ActionNames("editTBPage") + @RequiresPermission(ComplianceAdminPermission.class) + public class EditTBPage extends HRJspPageAction { + @Override + public String getPathToJsp() { + return "view/editTB.jsp"; + } + + @Override + public String getTitle() { + return "Edit TB"; + } + } + @ActionNames("editUserPage") @RequiresPermission(ComplianceAdminPermission.class) public class EditUserPage extends HRJspPageAction { @@ -147,6 +163,37 @@ public String getQuery() { } } + public static class SearchPersonFromCardForm { + public String query; + public void setQuery(String term) { + this.query = term; + } + + public String getQuery() { + return this.query; + } + + } + public static class SearchClearanceFromPersonForm { + public String query; + public String table; + public void setQuery(String term) { + this.query = term; + } + + public String getQuery() { + return this.query; + } + public void setTable(String table) { + this.table = table; + } + + public String getTable() { + return this.table; + } + + } + public static class AddDataToExistingPersonForm { public String personid; public RequirementForm tbInfo; @@ -163,7 +210,7 @@ public class UpdatePersonClearanceAPI extends MutatingApiAction { + public class SearchUserAPI extends ReadOnlyApiAction { @Override public Object execute(SearchPersonForm form, BindException errors) throws Exception { JSONObject json = new JSONObject(); @@ -340,38 +386,155 @@ public Object execute(SearchPersonForm form, BindException errors) throws Except public static class CardExemptForm { public Integer cardId; public String reason; + public String personId; } - public static class CardExemptionsForm { - public CardExemptForm[] exemptions; + public static class CardLinkForm { + public Integer cardId; + public String personId; } + @ActionNames("markCardsExempt") @RequiresPermission(ComplianceAdminPermission.class) @Marshal(Marshaller.Jackson) @CSRF(CSRF.Method.POST) - public class MarkCardExemptAPI extends MutatingApiAction { + public class MarkCardExemptAPI extends MutatingApiAction { @Override - public Object execute(CardExemptionsForm form, BindException errors) throws Exception { + public Object execute(CardExemptForm form, BindException errors) throws Exception { JSONObject json = new JSONObject(); - try (DbScope.Transaction transaction = DbSchema.get(WNPRC_ComplianceSchema.NAME,DbSchemaType.Module).getScope().ensureTransaction()) { + try (DbScope.Transaction transaction = DbSchema.get(WNPRC_ComplianceSchema.NAME).getScope().ensureTransaction()) { SimpleQueryUpdater cardUpdater = new SimpleQueryUpdater(getUser(), getContainer(), WNPRC_ComplianceSchema.NAME, "cards"); - List> cardsToUpdate = new ArrayList<>(); - for (CardExemptForm cardExemptForm : form.exemptions) { - JSONObject card = new JSONObject(); + JSONObject card = new JSONObject(); + + card.put("card_id", form.cardId.toString()); + card.put("exempt_reason", form.reason); + card.put("container", getContainer().getId()); + card.put("exempt", true); + + cardUpdater.upsert(card); + + json.put("success", true); + + transaction.commit(); + } + + return json; + } + } + @ActionNames("getPersons") + @RequiresPermission(ComplianceAdminPermission.class) + @Marshal(Marshaller.Jackson) + public class GetPersonFromCardAPI extends ReadOnlyApiAction { + public Object execute(SearchPersonFromCardForm form, BindException errors) throws Exception { + JSONObject json = new JSONObject(); + Map> results = new HashMap<>(); + + // Construct an "OR" clause based on space-delimited queries. + SimpleFilter.OrClause orClause = new SimpleFilter.OrClause(); + if (!form.getQuery().equals("")) { + orClause.addClause(new SimplerFilter("displayLcase", CompareType.CONTAINS, form.getQuery()).getClauses().get(0)); + } + + SimpleFilter filter = new SimpleFilter(); + filter.addClause(orClause); + + SimpleQueryFactory factory = new SimpleQueryFactory(getUser(), getContainer()); + + for(JSONObject row : factory.selectRows(WNPRC_ComplianceSchema.NAME, "searchResults", filter).toJSONObjectArray()) { + String type = row.getString("type"); + + List rows = results.get(type); + if (rows == null) { + rows = new ArrayList<>(); + results.put(type, rows); + } + + rows.add(row); + } + + json.put("results", results); + + return json; + } + } + + @ActionNames("getClearances") + @RequiresPermission(ComplianceAdminPermission.class) + @Marshal(Marshaller.Jackson) + @CSRF(CSRF.Method.NONE) + public class GetClearancesFromPerson extends ReadOnlyApiAction { + public Object execute(SearchClearanceFromPersonForm form, BindException errors) throws Exception { - card.put("card_id", cardExemptForm.cardId.toString()); - card.put("container", getContainer().getId()); + int resultLimit = 3; + JSONObject json = new JSONObject(); + Map> results = new HashMap<>(); + + SimpleFilter filter = new SimpleFilter(); + filter.addCondition(FieldKey.fromString("personid"), form.getQuery(), CompareType.EQUAL); + + SimpleQueryFactory factory = new SimpleQueryFactory(getUser(), getContainer()); + List rows = new ArrayList<>(); + int resultCount = 0; + for(JSONObject row : factory.selectRows(WNPRC_ComplianceSchema.NAME, form.getTable(), filter).toJSONObjectArray()) { + if (resultCount < resultLimit) + { + rows.add(row); + } + resultCount++; + } + + json.put("results", rows); + + return json; + } + } + + public static class ClearanceForm { + public String notes; + public String first_name; + public String last_name; + public String middle_name; + public String personid; + @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss") + public Date date; + public String id; + public String _row; + public String table_name; + public String required; + public boolean mutated; + } + public static class Clearances { + public ClearanceForm[] clearances; + public String table_name; + } + + @ActionNames("updateClearance") + @RequiresPermission(ComplianceAdminPermission.class) + @Marshal(Marshaller.Jackson) + @CSRF(CSRF.Method.POST) + public class UpdateClearanceAPI extends MutatingApiAction { + @Override + public Object execute(Clearances form, BindException errors) throws Exception { + JSONObject json = new JSONObject(); - card.put("exempt", true); - card.put("exempt_reason", cardExemptForm.reason); + try (DbScope.Transaction transaction = DbSchema.get(WNPRC_ComplianceSchema.NAME).getScope().ensureTransaction()) { + SimpleQueryUpdater tbClearanceUpdater = new SimpleQueryUpdater(getUser(), getContainer(), WNPRC_ComplianceSchema.NAME, form.table_name); + List> clearancesToUpdate = new ArrayList<>(); - cardsToUpdate.add(card); + for (ClearanceForm tbform : form.clearances) + { + JSONObject tbClearance = new JSONObject(); + tbClearance.put("id", tbform.id); + tbClearance.put("date", tbform.date); + tbClearance.put("required", tbform.required); + tbClearance.put("container", getContainer().getId()); + clearancesToUpdate.add(tbClearance); } - cardUpdater.upsert(cardsToUpdate); + tbClearanceUpdater.upsert(clearancesToUpdate); json.put("success", true); @@ -381,10 +544,60 @@ public Object execute(CardExemptionsForm form, BindException errors) throws Exce return json; } } + @ActionNames("getMeaslesClearances") + @RequiresPermission(ComplianceAdminPermission.class) + @Marshal(Marshaller.Jackson) + @CSRF(CSRF.Method.NONE) + public class GetMeaslesClearanceFromPerson extends ReadOnlyApiAction { + public Object execute(SearchPersonFromCardForm form, BindException errors) throws Exception { + JSONObject json = new JSONObject(); + Map> results = new HashMap<>(); + + SimpleFilter filter = new SimpleFilter(); + filter.addCondition(FieldKey.fromString("personid"), form.getQuery(), CompareType.EQUAL); + + SimpleQueryFactory factory = new SimpleQueryFactory(getUser(), getContainer()); + List rows = new ArrayList<>(); + for(JSONObject row : factory.selectRows(WNPRC_ComplianceSchema.NAME, "mapMeaslesClearances", filter).toJSONObjectArray()) { + rows.add(row); + } + json.put("results", rows); + + return json; + } + } + + @ActionNames("linkCards") + @RequiresPermission(ComplianceAdminPermission.class) + @Marshal(Marshaller.Jackson) + public class LinkCardAPI extends MutatingApiAction { + @Override + public Object execute(CardLinkForm form, BindException errors) throws Exception { + JSONObject json = new JSONObject(); + + try (DbScope.Transaction transaction = DbSchema.get(WNPRC_ComplianceSchema.NAME).getScope().ensureTransaction()) { + SimpleQueryUpdater cardUpdater = new SimpleQueryUpdater(getUser(), getContainer(), WNPRC_ComplianceSchema.NAME, "persons_to_cards"); + JSONObject personToCard = new JSONObject(); + + personToCard.put("cardid", form.cardId.toString()); + personToCard.put("personid", form.personId); + personToCard.put("container", getContainer().getId()); + + cardUpdater.upsert(personToCard); + + json.put("success", true); + + transaction.commit(); + } + + return json; + } + } public static class ResolvePendingTBResultsForm { public String[] pendingTBIds; public String notes; + @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ssXXX") public Date date; } @@ -392,14 +605,13 @@ public static class ResolvePendingTBResultsForm { @RequiresPermission(ComplianceAdminPermission.class) @CSRF(CSRF.Method.POST) @Marshal(Marshaller.Jackson) - public class ResolvePendingTBResultsAPI extends MutatingApiAction - { + public class ResolvePendingTBResultsAPI extends MutatingApiAction { @Override public Object execute(ResolvePendingTBResultsForm form, BindException errors) throws Exception { JSONObject json = new JSONObject(); SimpleQueryFactory queryFactory = new SimpleQueryFactory(getUser(), getContainer()); - try (DbScope.Transaction transaction = DbSchema.get(WNPRC_ComplianceSchema.NAME, DbSchemaType.Module).getScope().ensureTransaction()) { + try (DbScope.Transaction transaction = DbSchema.get(WNPRC_ComplianceSchema.NAME).getScope().ensureTransaction()) { SimpleQueryUpdater pendingTbUpdater = new SimpleQueryUpdater(getUser(), getContainer(), WNPRC_ComplianceSchema.NAME, "pending_tb_clearances"); SimpleQueryUpdater tbUpdater = new SimpleQueryUpdater(getUser(), getContainer(), WNPRC_ComplianceSchema.NAME, "tb_clearances"); SimpleQueryUpdater tbMapUpdater = new SimpleQueryUpdater(getUser(), getContainer(), WNPRC_ComplianceSchema.NAME, "persons_tb_clearances"); @@ -447,4 +659,4 @@ public Object execute(ResolvePendingTBResultsForm form, BindException errors) th return json; } } -} +} \ No newline at end of file diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceModule.java b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceModule.java index 9860b22ac..15f82ec14 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceModule.java +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/WNPRC_ComplianceModule.java @@ -31,10 +31,6 @@ protected Collection createWebPartFactories() { @Override protected void init() { addController(WNPRC_ComplianceController.NAME, WNPRC_ComplianceController.class); - } - - @Override - protected void doStartupAfterSpringConfig(ModuleContext moduleContext) { RoleManager.registerPermission(new ComplianceAdminPermission()); RoleManager.registerRole(new ComplianceAdminRole()); } diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/NewUserForm.java b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/NewUserForm.java index 79b4990e9..0473719a1 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/NewUserForm.java +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/NewUserForm.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; /** * Created by jmrichar on 2/8/2017. @@ -10,6 +11,7 @@ public class NewUserForm { public String firstName; public String lastName; public String middleName; + @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss") public Date dateOfBirth; public String description; public boolean isEmployee; diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/RequirementForm.java b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/RequirementForm.java index 8f0dfccd0..ea55d072b 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/RequirementForm.java +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/form/RequirementForm.java @@ -1,12 +1,16 @@ package org.labkey.wnprc_compliance.form; +import com.fasterxml.jackson.annotation.JsonFormat; + import java.util.Date; /** * Created by jmrichar on 2/8/2017. */ public class RequirementForm { + @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ssXXX") public Date dateCompleted; public String notes; public boolean pending = false; + public boolean required = false; } diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/begin.jsp b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/begin.jsp index 304dd50e1..b3f8822a6 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/begin.jsp +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/begin.jsp @@ -18,6 +18,9 @@
  • Enter TB Results
  • +
  • + Edit TB Results +
  • View Pending TB Results
  • @@ -46,7 +49,7 @@ View Most Recent Access Report Summary
  • - View Unidentified Cards + Manage Unidentified Cards
  • @@ -77,4 +80,4 @@ }) } })(); - \ No newline at end of file + diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/editTB.jsp b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/editTB.jsp new file mode 100644 index 000000000..862ca67c9 --- /dev/null +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/editTB.jsp @@ -0,0 +1,302 @@ +<%@ page import="org.labkey.wnprc_compliance.WNPRC_ComplianceSchema" %> +<%@ page import="org.labkey.wnprc_compliance.WNPRC_ComplianceController" %> +<%@ page import="org.labkey.api.view.ActionURL" %> +<%@ page extends="org.labkey.api.jsp.JspBase" %> + +<% + String url = (new ActionURL(WNPRC_ComplianceController.BeginAction.class, getContainer())).toString(); +%> + + +
    +
    +
    +
    Persons List
    + +
    + +
    + + +
    +
    +
    +
    TB Clearances
    +
    + +
    Loading...
    +
    + +
    Please select a person.
    + + + +
    No results, please enter a measles clearance here.
    + + +
    Displaying recent (up to 3) clearance dates for the selected person:
    + +
    +
    + +
    +
    + + +
    + + +
    + + +
    +
    + +
    +
    +
    Measles Clearances
    +
    + +
    Loading...
    +
    + +
    Please select a person.
    + + + +
    No results, please enter a measles clearance here.
    + + + +
    Displaying recent (up to 3) clearance dates for the selected person:
    +
    +
    +
    + Required

    +
    +
    + + +
    + + +
    + + +
    +
    +
    + +
    + + + \ No newline at end of file diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/enterTB.jsp b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/enterTB.jsp index b2459c317..bc5c408de 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/enterTB.jsp +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/enterTB.jsp @@ -260,21 +260,34 @@
    +
    -
    +
    +
    +
    + +
    +
    +
    +
    -
    +
    -
    - -
    - -
    -
    +
    +
    +
    +
    + + +
    + +
    @@ -426,21 +439,22 @@ $element: $('#measles-form-body'), disabled: ko.observable(), notes: ko.observable(''), - date: ko.observable(moment()) + date: ko.observable(''), + required: ko.observable(false) }; VM.measlesForm = measlesForm; (function() { measlesForm.clear = function() { measlesForm.notes(''); - measlesForm.date(moment()); + measlesForm.date(''); measlesForm.disabled(true); }; measlesForm.$element.collapse({toggle: true}); measlesForm.disabled.subscribe(function(val) { if (val) { measlesForm.notes(''); - measlesForm.date(moment()); + measlesForm.date(''); } measlesForm.$element.collapse(val ? 'hide' : 'show'); }); @@ -489,9 +503,16 @@ }; if (!measlesForm.disabled()) { + // Enter a blank date if it is blank + if (measlesForm.date() != ''){ + var dateCompleted = moment(measlesForm.date()).format(); + } else { + var dateCompleted = ''; + } submission.data.measlesInfo = { notes: measlesForm.notes(), - dateCompleted: moment(measlesForm.date()).format() + dateCompleted: dateCompleted, + required: measlesForm.required() }; } @@ -511,9 +532,16 @@ }; if (!measlesForm.disabled()) { + // Enter a blank date if it is blank + if (measlesForm.date() != ''){ + var dateCompleted = moment(measlesForm.date()).format(); + } else { + var dateCompleted = ''; + } submission.data.measlesInfo = { notes: measlesForm.notes(), - dateCompleted: moment(measlesForm.date()).format() + dateCompleted: dateCompleted, + required: measlesForm.required() }; } diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/unidentifiedCards.jsp b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/unidentifiedCards.jsp index 4d57554af..bcf93e1bb 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/unidentifiedCards.jsp +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/unidentifiedCards.jsp @@ -20,12 +20,12 @@ - + + + + +
    +
    +
    +
    Unidentified Cards
    -
    -
    Unidentified Cards
    +
    + +
    +
    +
    + +
    +
    +
    Person(s)
    +
    + +
    Loading...
    +
    + +
    Please select a card.
    + + +
    Displaying all potential persons for the selected card:
    + -
    -

    Give this guy a second to load...

    +
    +
    + +
    +
    +
    + + +
    + + +
    + + +
    - +
    \ No newline at end of file + + diff --git a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/uploadAccessReport.jsp b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/uploadAccessReport.jsp index 086501314..fe44a7d67 100644 --- a/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/uploadAccessReport.jsp +++ b/WNPRC_Compliance/src/org/labkey/wnprc_compliance/view/uploadAccessReport.jsp @@ -1,3 +1,4 @@ +<%@ taglib prefix="labkey" uri="http://www.labkey.org/taglib" %> <%@ page import="org.labkey.api.view.ActionURL" %> <%@ page import="org.labkey.wnprc_compliance.WNPRC_ComplianceController" %> <%@ page extends="org.labkey.api.jsp.JspBase" %> @@ -17,7 +18,9 @@
    Upload Access Report
    -
    +
    + +
    diff --git a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data.query.xml b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data.query.xml index ff5c2ac70..e4ffa3d79 100644 --- a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data.query.xml +++ b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data.query.xml @@ -9,7 +9,7 @@ http://cpas.labkey.com/Study#ParticipantId - The date this samle was collected + The date this sample was collected Nucleic Acid Type @@ -58,7 +58,7 @@ Source Material Size (ml or mg) - This is the volume or mass of the source material + This is the volume or mass of the source material. If it is a batched sample enter the volume of a single sample (most likely 0.1mL). false false diff --git a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/.qview.xml b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/.qview.xml index 2af2216f2..a884bfb25 100644 --- a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/.qview.xml +++ b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/.qview.xml @@ -8,6 +8,7 @@ + diff --git a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/By Column.qview.xml b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/By Column.qview.xml new file mode 100644 index 000000000..68fe2f7f8 --- /dev/null +++ b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/By Column.qview.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/By Row.qview.xml b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/By Row.qview.xml index c0fb1234d..20ea96acc 100644 --- a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/By Row.qview.xml +++ b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Data/By Row.qview.xml @@ -8,6 +8,7 @@ + diff --git a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.query.xml b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.query.xml index 8baa8875b..7d76b3acc 100644 --- a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.query.xml +++ b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.query.xml @@ -29,6 +29,9 @@ well + + Batched + true diff --git a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.sql b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.sql index f3c38afa4..0368a21e4 100644 --- a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.sql +++ b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary.sql @@ -24,8 +24,9 @@ SELECT group_concat(distinct v.qcflag, ';') as qcflags, group_concat(distinct v.comment, ';') as comments, cast(min(v.well) as varchar) as lowestWell,~ + v.batched, v.run, v.folder FROM Data v -GROUP BY v.run, v.subjectid, v.date, v.assayId, v.category, v.folder \ No newline at end of file +GROUP BY v.run, v.subjectid, v.date, v.assayId, v.category, v.batched, v.folder \ No newline at end of file diff --git a/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary/.qview.xml b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary/.qview.xml new file mode 100644 index 000000000..a980500ca --- /dev/null +++ b/WNPRC_EHR/resources/assay/Viral_Loads/queries/Viral_Load_Summary/.qview.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr/Tasks_DataEntry.query.xml b/WNPRC_EHR/resources/queries/ehr/Tasks_DataEntry.query.xml index 9ef2026b8..056046a9e 100644 --- a/WNPRC_EHR/resources/queries/ehr/Tasks_DataEntry.query.xml +++ b/WNPRC_EHR/resources/queries/ehr/Tasks_DataEntry.query.xml @@ -150,9 +150,6 @@ - - Paging -
    diff --git a/WNPRC_EHR/resources/queries/ehr/investigators.query.xml b/WNPRC_EHR/resources/queries/ehr/investigators.query.xml index f5d66f497..88f007ac1 100644 --- a/WNPRC_EHR/resources/queries/ehr/investigators.query.xml +++ b/WNPRC_EHR/resources/queries/ehr/investigators.query.xml @@ -3,7 +3,6 @@ Investigators - lastName Investigator Id diff --git a/WNPRC_EHR/resources/queries/ehr/project/.qview.xml b/WNPRC_EHR/resources/queries/ehr/project/.qview.xml new file mode 100644 index 000000000..811077e3d --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr/project/.qview.xml @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr/project/Search Panel.qview.xml b/WNPRC_EHR/resources/queries/ehr/project/Search Panel.qview.xml index 049ee8f4b..a4f3e98d1 100644 --- a/WNPRC_EHR/resources/queries/ehr/project/Search Panel.qview.xml +++ b/WNPRC_EHR/resources/queries/ehr/project/Search Panel.qview.xml @@ -2,25 +2,29 @@ - + - + - - - + + + - - - + + + + + + + + + + - - - diff --git a/WNPRC_EHR/resources/queries/ehr/protocol/Max Animals Per Species.qview.xml b/WNPRC_EHR/resources/queries/ehr/protocol/Max Animals Per Species.qview.xml new file mode 100644 index 000000000..9d1892d3d --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr/protocol/Max Animals Per Species.qview.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/WNPRC_EHR/resources/queries/ehr/protocolCountsBySpecies.sql b/WNPRC_EHR/resources/queries/ehr/protocolCountsBySpecies.sql new file mode 100644 index 000000000..d8ca058b5 --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr/protocolCountsBySpecies.sql @@ -0,0 +1,7 @@ + +SELECT +protocol,species, MAX(allowed) as countsBySpecies +FROM ehr.protocol_counts + +GROUP BY species,protocol +PIVOT countsBySpecies by species \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr/protocolExpirationDate.query.xml b/WNPRC_EHR/resources/queries/ehr/protocolExpirationDate.query.xml new file mode 100644 index 000000000..f9e71d0e2 --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr/protocolExpirationDate.query.xml @@ -0,0 +1,20 @@ + + + +
    + + + true + + ehr + protocol + protocol + + + + + +
    +
    + + diff --git a/WNPRC_EHR/resources/queries/ehr/protocolExpirationDate.sql b/WNPRC_EHR/resources/queries/ehr/protocolExpirationDate.sql new file mode 100644 index 000000000..6b829995b --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr/protocolExpirationDate.sql @@ -0,0 +1,14 @@ +-- noinspection SqlNoDataSourceInspectionForFile + +/* + * Copyright (c) 2013-2014 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ + + --we add 3 years to the approve date to get the expiration date +SELECT + p.protocol, + TIMESTAMPADD('SQL_TSI_YEAR', 3, p.approve) as expirationDate + +FROM ehr.protocol p diff --git a/WNPRC_EHR/resources/queries/ehr/tasks.query.xml b/WNPRC_EHR/resources/queries/ehr/tasks.query.xml index 2c9d9dba2..6c5b0df75 100644 --- a/WNPRC_EHR/resources/queries/ehr/tasks.query.xml +++ b/WNPRC_EHR/resources/queries/ehr/tasks.query.xml @@ -147,9 +147,6 @@ Print - - Paging - diff --git a/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/.qview.xml b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/.qview.xml new file mode 100644 index 000000000..5a6c2cd59 --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/.qview.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/All SOPs.qview.xml b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/All SOPs.qview.xml new file mode 100644 index 000000000..90619d6fa --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/All SOPs.qview.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/To Read Standard.qview.xml b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/To Read Standard.qview.xml new file mode 100644 index 000000000..7d295302f --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/To Read Standard.qview.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/To Read.qview.xml b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/To Read.qview.xml new file mode 100644 index 000000000..ca0dc3593 --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_compliancedb/SOPrequirements/To Read.qview.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_active_projects.sql b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_active_projects.sql new file mode 100644 index 000000000..2504540dd --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_active_projects.sql @@ -0,0 +1,34 @@ +SELECT * +FROM ( + SELECT + project.project AS project, + project.protocol AS protocol, + COALESCE(project$protocol$.external_id, project$protocol$.protocol) AS "protocol$displayName", + project.account AS account, + project.inves AS inves, + project.inves2 AS inves2, + project.avail AS avail, + project$avail$.value AS "avail$value", + project.title AS title, + project.research AS research, + project.use_category AS use_category, + project.reqname AS reqname, + project.contact_emails AS contact_emails, + project.startdate AS startdate, + project.enddate AS enddate, + project.projecttype AS projecttype, + project.shortname AS shortname, + project.container AS container, + COALESCE(project$container$.title, project$container$.name) AS "container$DisplayName", + COALESCE(project.name, CAST(project.project AS varchar)) AS displayName, + project$protocol$.protocol AS protocol_fs_protocol, + project$protocol$.container AS protocol_fs_container, + project$avail$.container AS avail_fs_container + FROM (SELECT * FROM ehr.project) project + LEFT OUTER JOIN (SELECT * FROM ehr.protocol) project$protocol$ ON (project.protocol = project$protocol$.protocol) + LEFT OUTER JOIN (SELECT * FROM ehr_lookups.lookups + WHERE (set_name = 'avail_codes') AND (container='29e3860b-02b5-102d-b524-493dbd27b599'/* EHR */)) project$avail$ ON (project.avail = project$avail$.value) + LEFT OUTER JOIN (SELECT * FROM core.containers + WHERE (1=1)) project$container$ ON (project.container = project$container$.entityid)) x +WHERE ("protocol$displayName" IS NOT NULL) +ORDER BY project ASC \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_origin.sql b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_origin.sql new file mode 100644 index 000000000..044747fa1 --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_origin.sql @@ -0,0 +1,6 @@ +SELECT geographic_origins.rowid, +geographic_origins.meaning, +geographic_origins.description +FROM ehr_lookups.geographic_origins + +where geographic_origins.meaning in ('india', 'china', 'mauritius','indonesia','laos','vietnam') \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_species.sql b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_species.sql new file mode 100644 index 000000000..5037a8bbc --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_species.sql @@ -0,0 +1,14 @@ +SELECT species.common, +species.scientific_name, +species.id_prefix, +species.mhc_prefix, +species.blood_per_kg, +species.max_draw_pct, +species.blood_draw_interval, +species.cites_code, +species.dateDisabled, +species.USDA, +species.Gestation +FROM ehr_lookups.species + +where species.common in ('Macaque','Cynomolgus','Rhesus','Marmoset') \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_viral_status.sql b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_viral_status.sql new file mode 100644 index 000000000..6f9fd1514 --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_lookups/animal_requests_viral_status.sql @@ -0,0 +1,9 @@ +SELECT viral_status.rowid, +viral_status.value, +viral_status.title, +viral_status.category, +viral_status.description, +viral_status.sort_order, +viral_status.date_disabled +FROM ehr_lookups.viral_status +WHERE viral_status.value IN ('SPF4', 'SPF5 (AAV-)', 'SPF5 (RRV-)', 'Conventional') \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/ehr_lookups/currentBirthTypes.sql b/WNPRC_EHR/resources/queries/ehr_lookups/currentBirthTypes.sql new file mode 100644 index 000000000..86d137310 --- /dev/null +++ b/WNPRC_EHR/resources/queries/ehr_lookups/currentBirthTypes.sql @@ -0,0 +1,5 @@ +SELECT + bt.value, + bt.description +FROM ehr_lookups.birth_type bt +WHERE (bt.date_disabled IS NULL) OR (curdate() < bt.date_disabled); \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/lists/vl_sample_queue.query.xml b/WNPRC_EHR/resources/queries/lists/vl_sample_queue.query.xml new file mode 100644 index 000000000..ff5036974 --- /dev/null +++ b/WNPRC_EHR/resources/queries/lists/vl_sample_queue.query.xml @@ -0,0 +1,35 @@ + + + + + + + + var url = LABKEY.ActionURL.buildURL('query', 'updateQueryRows.view', null, { + schemaName: dataRegion.schemaName, + 'query.queryName': dataRegion.queryName, + dataRegionSelectionKey: dataRegion.selectionKey + }); + var form = dataRegion.form; + if (form && verifySelected.call(this, form, url, 'POST', 'rows')) { + submitForm(form); + } + return false; + + + + + + WNPRC_EHR.DatasetButtons.batchCompleteRecords(dataRegion.name); + + + + + +
    +
    +
    +
    + diff --git a/WNPRC_EHR/resources/queries/study/ActiveAssignments/.qview.xml b/WNPRC_EHR/resources/queries/study/ActiveAssignments/.qview.xml index d1e55567f..404a038f2 100644 --- a/WNPRC_EHR/resources/queries/study/ActiveAssignments/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/ActiveAssignments/.qview.xml @@ -26,7 +26,7 @@
    - + @@ -55,7 +55,7 @@ - + @@ -71,4 +71,4 @@ - \ No newline at end of file + diff --git a/WNPRC_EHR/resources/queries/study/ActiveAssignments/Research Assignments.qview.xml b/WNPRC_EHR/resources/queries/study/ActiveAssignments/Research Assignments.qview.xml index c1fbdaa47..02a5fd93b 100644 --- a/WNPRC_EHR/resources/queries/study/ActiveAssignments/Research Assignments.qview.xml +++ b/WNPRC_EHR/resources/queries/study/ActiveAssignments/Research Assignments.qview.xml @@ -22,7 +22,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/ActiveAssignments/Tracking Assignments.qview.xml b/WNPRC_EHR/resources/queries/study/ActiveAssignments/Tracking Assignments.qview.xml index 7bf5e43ba..5397edb2e 100644 --- a/WNPRC_EHR/resources/queries/study/ActiveAssignments/Tracking Assignments.qview.xml +++ b/WNPRC_EHR/resources/queries/study/ActiveAssignments/Tracking Assignments.qview.xml @@ -22,7 +22,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/ActiveAssignments/With Projected Release.qview.xml b/WNPRC_EHR/resources/queries/study/ActiveAssignments/With Projected Release.qview.xml index 82d207d96..845de3eab 100644 --- a/WNPRC_EHR/resources/queries/study/ActiveAssignments/With Projected Release.qview.xml +++ b/WNPRC_EHR/resources/queries/study/ActiveAssignments/With Projected Release.qview.xml @@ -22,7 +22,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/Behavior Abstract.js b/WNPRC_EHR/resources/queries/study/BehaviorAbstract.js similarity index 100% rename from WNPRC_EHR/resources/queries/study/Behavior Abstract.js rename to WNPRC_EHR/resources/queries/study/BehaviorAbstract.js diff --git a/WNPRC_EHR/resources/queries/study/Behavior Abstract.query.xml b/WNPRC_EHR/resources/queries/study/BehaviorAbstract.query.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Behavior Abstract.query.xml rename to WNPRC_EHR/resources/queries/study/BehaviorAbstract.query.xml diff --git a/WNPRC_EHR/resources/queries/study/Behavior Abstract/.qview.xml b/WNPRC_EHR/resources/queries/study/BehaviorAbstract/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Behavior Abstract/.qview.xml rename to WNPRC_EHR/resources/queries/study/BehaviorAbstract/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Biopsies/.qview.xml b/WNPRC_EHR/resources/queries/study/Biopsy/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Biopsies/.qview.xml rename to WNPRC_EHR/resources/queries/study/Biopsy/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Birth.query.xml b/WNPRC_EHR/resources/queries/study/Birth.query.xml new file mode 100644 index 000000000..cbdc75a5b --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/Birth.query.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + Birth Date + + + Date Type + + ehr_lookups + birth_date_type + value + + + + Birth Condition + + + Birth Room + true + true + false + + + + + + ehr_lookups + rooms + room + + + + Birth Cage + true + true + false + /EHR/cageDetails.view? + room=${room}& + cage=${cage} + + + + + Dam + + + + + + /ehr/participantView.view?participantId=${dam} + true + + + Gender + + ehr_lookups + gender_codes + code + + + + # Upper Teeth + + + Weight + + + Weight Date + + + Birth Type + + ehr_lookups + birth_type + value + description + + + + Species + + ehr_lookups + species + common + + + + + Geographic Origin + + ehr_lookups + geographic_origins + meaning + + + + + Sire + + + + + + /ehr/participantView.view?participantId=${sire} + true + + + + Condition + + + Origin + + ehr_lookups + source + code + + + + + + + + + + + Birthdate Is Estimated? + + + Conception + + + Conceptual Day + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Breeding Encounters.js b/WNPRC_EHR/resources/queries/study/Breeding Encounters.js deleted file mode 100644 index 72d57b2b7..000000000 --- a/WNPRC_EHR/resources/queries/study/Breeding Encounters.js +++ /dev/null @@ -1 +0,0 @@ -require("ehr/triggers").initScript(this); \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Breeding Remarks.js b/WNPRC_EHR/resources/queries/study/Breeding Remarks.js deleted file mode 100644 index 72d57b2b7..000000000 --- a/WNPRC_EHR/resources/queries/study/Breeding Remarks.js +++ /dev/null @@ -1 +0,0 @@ -require("ehr/triggers").initScript(this); \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml b/WNPRC_EHR/resources/queries/study/Current Blood.query.xml index d6d4af091..4e8ff40d4 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml +++ b/WNPRC_EHR/resources/queries/study/Current Blood.query.xml @@ -8,7 +8,6 @@
    - 40 study Animal diff --git a/WNPRC_EHR/resources/queries/study/Clinical Encounters/.qview.xml b/WNPRC_EHR/resources/queries/study/Encounters/.qview.xml similarity index 97% rename from WNPRC_EHR/resources/queries/study/Clinical Encounters/.qview.xml rename to WNPRC_EHR/resources/queries/study/Encounters/.qview.xml index 0a9dc14c4..ac5487017 100644 --- a/WNPRC_EHR/resources/queries/study/Clinical Encounters/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Encounters/.qview.xml @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Biopsies.qview.xml b/WNPRC_EHR/resources/queries/study/Encounters/Biopsies.qview.xml similarity index 96% rename from WNPRC_EHR/resources/queries/study/Clinical Encounters/Biopsies.qview.xml rename to WNPRC_EHR/resources/queries/study/Encounters/Biopsies.qview.xml index e7bcd2a3d..591f1252b 100644 --- a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Biopsies.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Encounters/Biopsies.qview.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Necropsies.qview.xml b/WNPRC_EHR/resources/queries/study/Encounters/Necropsies.qview.xml similarity index 96% rename from WNPRC_EHR/resources/queries/study/Clinical Encounters/Necropsies.qview.xml rename to WNPRC_EHR/resources/queries/study/Encounters/Necropsies.qview.xml index 0fab7d715..ab5567a36 100644 --- a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Necropsies.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Encounters/Necropsies.qview.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Clinical Encounters/PE.qview.xml b/WNPRC_EHR/resources/queries/study/Encounters/PE.qview.xml similarity index 97% rename from WNPRC_EHR/resources/queries/study/Clinical Encounters/PE.qview.xml rename to WNPRC_EHR/resources/queries/study/Encounters/PE.qview.xml index 54cf2ef3c..76ba9b272 100644 --- a/WNPRC_EHR/resources/queries/study/Clinical Encounters/PE.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Encounters/PE.qview.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Surgeries Plus Codes.qview.xml b/WNPRC_EHR/resources/queries/study/Encounters/Surgeries Plus Codes.qview.xml similarity index 96% rename from WNPRC_EHR/resources/queries/study/Clinical Encounters/Surgeries Plus Codes.qview.xml rename to WNPRC_EHR/resources/queries/study/Encounters/Surgeries Plus Codes.qview.xml index d781a3b25..1ab9d8824 100644 --- a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Surgeries Plus Codes.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Encounters/Surgeries Plus Codes.qview.xml @@ -1,22 +1,22 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Surgeries.qview.xml b/WNPRC_EHR/resources/queries/study/Encounters/Surgeries.qview.xml similarity index 97% rename from WNPRC_EHR/resources/queries/study/Clinical Encounters/Surgeries.qview.xml rename to WNPRC_EHR/resources/queries/study/Encounters/Surgeries.qview.xml index 4ff640f43..d66632ecb 100644 --- a/WNPRC_EHR/resources/queries/study/Clinical Encounters/Surgeries.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Encounters/Surgeries.qview.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Housing.query.xml b/WNPRC_EHR/resources/queries/study/Housing.query.xml index 8fe386f47..9e3571728 100644 --- a/WNPRC_EHR/resources/queries/study/Housing.query.xml +++ b/WNPRC_EHR/resources/queries/study/Housing.query.xml @@ -56,10 +56,14 @@ ehr_lookups housing_reason - value - title + title + + + Ejaculation Confirmed + true + Restraint Type diff --git a/WNPRC_EHR/resources/queries/study/Immunology Results/.qview.xml b/WNPRC_EHR/resources/queries/study/ImmunologyResults/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Immunology Results/.qview.xml rename to WNPRC_EHR/resources/queries/study/ImmunologyResults/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Immunology Results/Plus Ref Range.qview.xml b/WNPRC_EHR/resources/queries/study/ImmunologyResults/Plus Ref Range.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Immunology Results/Plus Ref Range.qview.xml rename to WNPRC_EHR/resources/queries/study/ImmunologyResults/Plus Ref Range.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/MHCHaplotypes.query.xml b/WNPRC_EHR/resources/queries/study/MHCHaplotypes.query.xml index 90cd860c8..c5197540d 100644 --- a/WNPRC_EHR/resources/queries/study/MHCHaplotypes.query.xml +++ b/WNPRC_EHR/resources/queries/study/MHCHaplotypes.query.xml @@ -11,47 +11,13 @@ yyyy-MM-dd - - - - - - - - - Haplotypes Concatenated - - study - MHCHaplotypeConcatenated - id - - - - /query/executeQuery.view?schemaName=lists& - query.queryName=rhesusHaplotypesDefinitions& - query.haplotype~eq=${mamuAHaplotype1} - - - - /query/executeQuery.view?schemaName=lists& - query.queryName=rhesusHaplotypesDefinitions& - query.haplotype~eq=${mamuAHaplotype2} - - - /query/executeQuery.view?schemaName=lists& - query.queryName=rhesusHaplotypesDefinitions& - query.haplotype~eq=${mamuBHaplotype1} - + - - /query/executeQuery.view?schemaName=lists& - query.queryName=rhesusHaplotypesDefinitions& - query.haplotype~eq=${mamuBHaplotype2} - + diff --git a/WNPRC_EHR/resources/queries/study/MHCHaplotypes/.qview.xml b/WNPRC_EHR/resources/queries/study/MHCHaplotypes/.qview.xml index d7f05177e..f4ef625fd 100644 --- a/WNPRC_EHR/resources/queries/study/MHCHaplotypes/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/MHCHaplotypes/.qview.xml @@ -2,12 +2,8 @@ - - - - - - + + diff --git a/WNPRC_EHR/resources/queries/study/Necropsy/.qview.xml b/WNPRC_EHR/resources/queries/study/Necropsy/.qview.xml index 555aeb745..15774dfb1 100644 --- a/WNPRC_EHR/resources/queries/study/Necropsy/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Necropsy/.qview.xml @@ -9,6 +9,8 @@ + + @@ -27,4 +29,4 @@ - \ No newline at end of file + diff --git a/WNPRC_EHR/resources/queries/study/Pedigree.sql b/WNPRC_EHR/resources/queries/study/Pedigree.sql index 5a0f65c85..fdca8c3eb 100644 --- a/WNPRC_EHR/resources/queries/study/Pedigree.sql +++ b/WNPRC_EHR/resources/queries/study/Pedigree.sql @@ -1,88 +1,86 @@ -/* - * Copyright (c) 2010-2014 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -SELECT - -d.id as Id, -d.dam as Dam, -d.sire as Sire, -'' as Display, - ---TODO: handle gender better -/* -CASE d.gender - WHEN 'm' THEN 'male' - WHEN 'f' THEN 'female' - WHEN 'e' THEN 'male' - WHEN 'c' THEN 'female' - WHEN 'v' THEN 'male' - ELSE 'unknown' -END AS gender, -*/ --- CONVERT( -CASE (d.gender) - WHEN 'm' THEN 1 - WHEN 'f' THEN 2 - WHEN 'e' THEN 1 - WHEN 'c' THEN 2 - WHEN 'v' THEN 1 - ELSE 3 -END --- , INTEGER) -AS gender, -d.gender as gender_code, -CASE (d.calculated_status) - WHEN 'Alive' THEN 0 - ELSE 1 -END -AS status, -d.calculated_status as status_code, -'Demographics' as source, -d.species as Species - ---d.qcstate - -FROM study.demographics d - -WHERE d.gender != '' AND d.gender != 'h' ---AND (d.dam is not NULL or d.sire is not null) - -UNION ALL - -SELECT - -p.id as Id, -p.dam as Dam, -p.sire as Sire, -CASE (p.gender) - WHEN 'm' THEN 1 - WHEN 'f' THEN 2 - WHEN 'e' THEN 1 - WHEN 'c' THEN 2 - WHEN 'v' THEN 1 - ELSE 3 -END AS gender, -p.gender as gender_code, -CASE (p.departdate) - WHEN NULL THEN 0 - ELSE 1 -END -AS status, -CAST(p.departdate AS SQL_VARCHAR) as status_code, -'Supplemental Pedigree' as source, ---'Rhesus' as Species ---null as qcstate - -CASE - WHEN (p.id LIKE 'r%') THEN 'Rhesus' - WHEN (p.id LIKE 'cy%') THEN 'Marmoset' - ELSE 'other' -END AS Species - -FROM ehr.supplemental_pedigree p -LEFT JOIN study.demographics d ON (d.id=p.id) -WHERE -d.id is null AND p.gender != '' and p.gender is not null ---AND (p.dam is not NULL or p.sire is not null) +/* + * Copyright (c) 2010-2014 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +SELECT + +d.id as Id, +d.dam as Dam, +d.sire as Sire, +'' as Display, + +--TODO: handle gender better +/* +CASE d.gender + WHEN 'm' THEN 'male' + WHEN 'f' THEN 'female' + WHEN 'e' THEN 'male' + WHEN 'c' THEN 'female' + WHEN 'v' THEN 'male' + ELSE 'unknown' +END AS gender, +*/ +-- CONVERT( +CASE (d.gender) + WHEN 'm' THEN 1 + WHEN 'f' THEN 2 + WHEN 'e' THEN 1 + WHEN 'c' THEN 2 + WHEN 'v' THEN 1 + WHEN 'h' THEN 2 + ELSE 3 +END +-- , INTEGER) +AS gender, +d.gender as gender_code, +CASE (d.calculated_status) + WHEN 'Alive' THEN 0 + ELSE 1 +END +AS status, +d.calculated_status as status_code, +'Demographics' as source, +d.species as Species + +--d.qcstate + +FROM study.demographics d + +WHERE d.gender != '' +--AND (d.dam is not NULL or d.sire is not null) + +UNION ALL + +SELECT + +p.id as Id, +p.dam as Dam, +p.sire as Sire, +'' as Display, +CASE (p.gender) + WHEN 'm' THEN 1 + WHEN 'f' THEN 2 + WHEN 'e' THEN 1 + WHEN 'c' THEN 2 + WHEN 'v' THEN 1 + ELSE 3 +END AS gender, +p.gender as gender_code, +CASE (p.departdate) + WHEN NULL THEN 0 + ELSE 1 +END +AS status, +CAST(p.departdate AS SQL_VARCHAR) as status_code, +'Supplemental Pedigree' as source, +--'Rhesus' as Species +--null as qcstate + +p.species AS species + +FROM ehr.supplemental_pedigree p +LEFT JOIN study.demographics d ON (d.id=p.id) +WHERE +d.id is null AND p.gender != '' and p.gender is not null +--AND (p.dam is not NULL or p.sire is not null) diff --git a/WNPRC_EHR/resources/queries/study/Pregnancies.js b/WNPRC_EHR/resources/queries/study/Pregnancies.js deleted file mode 100644 index 43f227b86..000000000 --- a/WNPRC_EHR/resources/queries/study/Pregnancies.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2011-2014 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ - -require("ehr/triggers").initScript(this); - -function onUpsert(scriptContext, errors, row, oldRow){ - //make sure the anmimal is female - if(row.id) - EHR.Server.Validation.verifyIsFemale(row, errors, scriptContext); -} - -function setDescription(row, helper){ - //we need to set description for every field - var description = new Array(); - - if(row.method) - description.push('Method: '+row.method); - - description.push('Is Pregnant: '+row.isPregnant); - - if(row.conception) - description.push('Conception: '+row.conception); - if(row.sire) - description.push('Sire: '+row.sire); - - return description; -} \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Pregnancies.query.xml b/WNPRC_EHR/resources/queries/study/Pregnancies.query.xml deleted file mode 100644 index c37b9d5b2..000000000 --- a/WNPRC_EHR/resources/queries/study/Pregnancies.query.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - Participant ID - Participant identifier - false - - - yyyy-MM-dd HH:mm - - - - - - Parent Id - urn:ehr.labkey.org/#ParentId - - - - - - - - Ultrasound - Ultrasound -
    -
    -
    -
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Pregnancies/.qview.xml b/WNPRC_EHR/resources/queries/study/Pregnancies/.qview.xml deleted file mode 100644 index b171f098c..000000000 --- a/WNPRC_EHR/resources/queries/study/Pregnancies/.qview.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Pregnancy Outcomes.js b/WNPRC_EHR/resources/queries/study/Pregnancy Outcomes.js deleted file mode 100644 index 72d57b2b7..000000000 --- a/WNPRC_EHR/resources/queries/study/Pregnancy Outcomes.js +++ /dev/null @@ -1 +0,0 @@ -require("ehr/triggers").initScript(this); \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/PregnancyInfo.query.xml b/WNPRC_EHR/resources/queries/study/PregnancyInfo.query.xml index a41441245..e03b39817 100644 --- a/WNPRC_EHR/resources/queries/study/PregnancyInfo.query.xml +++ b/WNPRC_EHR/resources/queries/study/PregnancyInfo.query.xml @@ -1,20 +1,13 @@ - + - - - /ehr/dataEntryForm.view?formType=Breeding%20Encounter&taskid=${taskid} - _blank - true - - true - - + Dam @@ -23,61 +16,70 @@ study animal - id + Id + - - Breeding Start - MM/dd/yyyy - - - Breeding End - MM/dd/yyyy - - - Breeding Remark - - - Ejaculation Confirmed? + + Est. Conception Date + yyyy-MM-dd - - Est. Conception - MM/dd/yyyy + + Conception Range + yyyy-MM-dd - + + 30 - MM/dd/yyyy + yyyy-MM-dd - + + 60 - MM/dd/yyyy + yyyy-MM-dd - + + 90 - MM/dd/yyyy + yyyy-MM-dd - + + 120 - MM/dd/yyyy + yyyy-MM-dd - + + 150 - MM/dd/yyyy + yyyy-MM-dd - + + 165 - MM/dd/yyyy + yyyy-MM-dd + + + Due Date Range + yyyy-MM-dd + + + Current Gestation Range (days) + 0 + + + Est. Due Date + yyyy-MM-dd - Current Gestation + Current Est. Gestation (days) 0 Outcome + + ehr_lookups + birth_type + value + description + Outcome Date/Time - MM/dd/yyyy hh:mm + yyyy-MM-dd hh:mm Outcome Remark @@ -88,7 +90,7 @@ study animal - id + Id diff --git a/WNPRC_EHR/resources/queries/study/PregnancyInfo.sql b/WNPRC_EHR/resources/queries/study/PregnancyInfo.sql index eef0c9f99..5028e3ef2 100644 --- a/WNPRC_EHR/resources/queries/study/PregnancyInfo.sql +++ b/WNPRC_EHR/resources/queries/study/PregnancyInfo.sql @@ -1,38 +1,75 @@ -SELECT be.objectid - ,be.taskid - ,be.id - ,be.sireid - ,be.date - ,be.dateend - ,be.reason - ,br.remark - ,be.conceptiondate - ,timestampadd('SQL_TSI_DAY', 30, be.conceptiondate) conceptiondate_plus_30 - ,timestampadd('SQL_TSI_DAY', 60, be.conceptiondate) conceptiondate_plus_60 - ,timestampadd('SQL_TSI_DAY', 90, be.conceptiondate) conceptiondate_plus_90 - ,timestampadd('SQL_TSI_DAY', 120, be.conceptiondate) conceptiondate_plus_120 - ,timestampadd('SQL_TSI_DAY', 150, be.conceptiondate) conceptiondate_plus_150 - ,timestampadd('SQL_TSI_DAY', 165, be.conceptiondate) conceptiondate_plus_165 - ,timestampdiff('SQL_TSI_DAY', be.conceptiondate, coalesce(po.date, curdate())) gestation_day - ,be.ejaculation +SELECT p.objectid + ,p.id + ,p.sireid + ,p.date + ,to_char(p.date_conception, 'yyyy-MM-dd') AS date_conception + , CASE + WHEN p.date_conception_early IS NOT NULL AND p.date_conception_late IS NOT NULL THEN + (to_char(p.date_conception_early, 'yyyy-MM-dd') || ' to ' || to_char(p.date_conception_late, 'yyyy-MM-dd')) + ELSE + 'N/A' + END AS conception_range + , CASE + WHEN p.date_conception_early IS NOT NULL AND p.date_conception_late IS NOT NULL THEN + (to_char(timestampadd('SQL_TSI_DAY', 30, p.date_conception_early), 'yyyy-MM-dd') || ' to ' || to_char(timestampadd('SQL_TSI_DAY', 30, p.date_conception_late), 'yyyy-MM-dd')) + ELSE + (to_char(timestampadd('SQL_TSI_DAY', 30, p.date_conception), 'yyyy-MM-dd')) + END AS date_conception_plus_30 + , CASE + WHEN p.date_conception_early IS NOT NULL AND p.date_conception_late IS NOT NULL THEN + (to_char(timestampadd('SQL_TSI_DAY', 60, p.date_conception_early), 'yyyy-MM-dd') || ' to ' || to_char(timestampadd('SQL_TSI_DAY', 60, p.date_conception_late), 'yyyy-MM-dd')) + ELSE + (to_char(timestampadd('SQL_TSI_DAY', 60, p.date_conception), 'yyyy-MM-dd')) + END AS date_conception_plus_60 + , CASE + WHEN p.date_conception_early IS NOT NULL AND p.date_conception_late IS NOT NULL THEN + (to_char(timestampadd('SQL_TSI_DAY', 90, p.date_conception_early), 'yyyy-MM-dd') || ' to ' || to_char(timestampadd('SQL_TSI_DAY', 90, p.date_conception_late), 'yyyy-MM-dd')) + ELSE + (to_char(timestampadd('SQL_TSI_DAY', 90, p.date_conception), 'yyyy-MM-dd')) + END AS date_conception_plus_90 + , CASE + WHEN p.date_conception_early IS NOT NULL AND p.date_conception_late IS NOT NULL THEN + (to_char(timestampadd('SQL_TSI_DAY', 120, p.date_conception_early), 'yyyy-MM-dd') || ' to ' || to_char(timestampadd('SQL_TSI_DAY', 120, p.date_conception_late), 'yyyy-MM-dd')) + ELSE + (to_char(timestampadd('SQL_TSI_DAY', 120, p.date_conception), 'yyyy-MM-dd')) + END AS date_conception_plus_120 + , CASE + WHEN p.date_conception_early IS NOT NULL AND p.date_conception_late IS NOT NULL THEN + (to_char(timestampadd('SQL_TSI_DAY', 150, p.date_conception_early), 'yyyy-MM-dd') || ' to ' || to_char(timestampadd('SQL_TSI_DAY', 150, p.date_conception_late), 'yyyy-MM-dd')) + ELSE + (to_char(timestampadd('SQL_TSI_DAY', 150, p.date_conception), 'yyyy-MM-dd')) + END AS date_conception_plus_150 + , CASE + WHEN p.date_conception_early IS NOT NULL AND p.date_conception_late IS NOT NULL THEN + (to_char(timestampadd('SQL_TSI_DAY', 165, p.date_conception_early), 'yyyy-MM-dd') || ' to ' || to_char(timestampadd('SQL_TSI_DAY', 165, p.date_conception_late), 'yyyy-MM-dd')) + ELSE + (to_char(timestampadd('SQL_TSI_DAY', 165, p.date_conception), 'yyyy-MM-dd')) + END AS date_conception_plus_165 + , CASE + WHEN p.date_due_early IS NOT NULL AND p.date_due_late IS NOT NULL THEN + (to_char(p.date_due_early, 'yyyy-MM-dd') || ' to ' || to_char(p.date_due_late, 'yyyy-MM-dd')) + ELSE + 'N/A' + END AS date_due_range + , CASE + WHEN p.date_conception_late IS NOT NULL AND p.date_conception_early IS NOT NULL THEN + (timestampdiff('SQL_TSI_DAY', p.date_conception_late, coalesce(po.date, curdate())) || ' to ' || timestampdiff('SQL_TSI_DAY', p.date_conception_early, coalesce(po.date, curdate()))) + ELSE + 'N/A' + END AS gestation_day_range + ,to_char(p.date_due, 'yyyy-MM-dd') AS date_due + ,timestampdiff('SQL_TSI_DAY', p.date_conception, coalesce(po.date, curdate())) AS gestation_day ,po.outcome ,po.date outcome_date ,po.remark outcome_remark ,po.infantid - ,'EDIT' updatelink - FROM breeding_encounters be + FROM pregnancies p -- select only the most recent outcome, in case there are multiple outcomes -- (note that we do not expect there to be multiples, but just in case) LEFT OUTER JOIN pregnancy_outcomes po ON po.objectid = (SELECT objectid FROM pregnancy_outcomes - WHERE taskid = be.taskid + WHERE pregnancyid = p.lsid ORDER BY date DESC LIMIT 1) - -- select the most recent remark to show in the list - LEFT OUTER JOIN breeding_remarks br - ON br.objectid = (SELECT objectid - FROM breeding_remarks - WHERE taskid = be.taskid - ORDER BY date DESC - LIMIT 1) \ No newline at end of file +ORDER BY p.date_conception DESC \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/PregnancyInfo/.qview.xml b/WNPRC_EHR/resources/queries/study/PregnancyInfo/.qview.xml index 54786671b..2e3531281 100644 --- a/WNPRC_EHR/resources/queries/study/PregnancyInfo/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/PregnancyInfo/.qview.xml @@ -3,24 +3,21 @@ - - - - - - - - - - - + + + + + + + + + + + + - - - - \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/PregnancyInfo/_details.qview.xml b/WNPRC_EHR/resources/queries/study/PregnancyInfo/_details.qview.xml index c795e0314..e8c0b4127 100644 --- a/WNPRC_EHR/resources/queries/study/PregnancyInfo/_details.qview.xml +++ b/WNPRC_EHR/resources/queries/study/PregnancyInfo/_details.qview.xml @@ -1,20 +1,20 @@ \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/UltrasoundInfo.query.xml b/WNPRC_EHR/resources/queries/study/UltrasoundInfo.query.xml deleted file mode 100644 index 4a76ea1a8..000000000 --- a/WNPRC_EHR/resources/queries/study/UltrasoundInfo.query.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - -
    - - - true - - - Dam - - - MM/dd/yyyy hh:mm - - - - -
    -
    -
    -
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/UltrasoundInfo.sql b/WNPRC_EHR/resources/queries/study/UltrasoundInfo.sql deleted file mode 100644 index 9816f0ad6..000000000 --- a/WNPRC_EHR/resources/queries/study/UltrasoundInfo.sql +++ /dev/null @@ -1,6 +0,0 @@ -SELECT u.objectid - ,u.id - ,u.date - ,u.performedby - ,u.remark - FROM ultrasounds u \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Ultrasounds.js b/WNPRC_EHR/resources/queries/study/Ultrasounds.js deleted file mode 100644 index 72d57b2b7..000000000 --- a/WNPRC_EHR/resources/queries/study/Ultrasounds.js +++ /dev/null @@ -1 +0,0 @@ -require("ehr/triggers").initScript(this); \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Ultrasounds/.qview.xml b/WNPRC_EHR/resources/queries/study/Ultrasounds/.qview.xml new file mode 100644 index 000000000..535a4d87c --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/Ultrasounds/.qview.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/ViralLoads.sql b/WNPRC_EHR/resources/queries/study/ViralLoads.sql index 752f65795..dece1df7f 100644 --- a/WNPRC_EHR/resources/queries/study/ViralLoads.sql +++ b/WNPRC_EHR/resources/queries/study/ViralLoads.sql @@ -1,33 +1,25 @@ -/* - * Copyright (c) 2010-2012 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -SELECT - v.rowid, - v.SubjectId as Id, - v.Date as date, - v.assayId.virus AS Virus, - - CASE - WHEN (v.ViralLoad < 50) - THEN 50 - else - v.ViralLoad - END - as ViralLoad, - - round( - CASE - WHEN (v.ViralLoad < 50) - THEN log10(50) - else - log10(v.ViralLoad) - END, 1) - as LogVL - -FROM "/WNPRC/WNPRC_Units/Research_Services/Virology_Services/VL_DB/".assay."Viral_Load Data" v - ---TODO ---WHERE v.qcstate.publicdata = true - +/* + * Copyright (c) 2010-2012 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +SELECT + pv.rowid, + pv.Id as Id, + pv.date as date, + pv.Virus AS Virus, + pv.Comments as Comments, + + AVG(pv.ViralLoad) AS AverageViralLoad, + log10(AVG(pv.ViralLoad)) as LogVL, + pv.SampleType as SampleType, + pv.VL_ExpNumber + +FROM study.preViralLoad pv +WHERE pv.QC_Pass = 'TRUE' + +GROUP BY pv.date,pv.Id, pv.Virus, pv.Comments, pv.SampleType, pv.VL_ExpNumber,pv.rowid + +--TODO + + diff --git a/WNPRC_EHR/resources/queries/study/ViralLoads/.qview.xml b/WNPRC_EHR/resources/queries/study/ViralLoads/.qview.xml index 755cc8e95..562c93464 100644 --- a/WNPRC_EHR/resources/queries/study/ViralLoads/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/ViralLoads/.qview.xml @@ -1,13 +1,15 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/ViralLoadsPlusWpi.sql b/WNPRC_EHR/resources/queries/study/ViralLoadsPlusWpi.sql index 76f8c2170..f1ec50f5d 100644 --- a/WNPRC_EHR/resources/queries/study/ViralLoadsPlusWpi.sql +++ b/WNPRC_EHR/resources/queries/study/ViralLoadsPlusWpi.sql @@ -1,26 +1,26 @@ -/* - * Copyright (c) 2010-2011 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -SELECT - v.rowid, - v.Id, - v.Virus, - v.Date, - vc.date as ChallengeDate, - vc.code, - v.ViralLoad, - v.LogVL, - TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date) as DPI, - TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date)/7 as WPI - -FROM study.ViralLoads v - -LEFT JOIN ViralChallenges vc - ON (v.id = vc.id) - -WHERE vc.challenge_type like 'SIV%' AND vc.challenge_Type NOT LIKE '%Vaccine%' - -AND vc.date is not null - +/* + * Copyright (c) 2010-2011 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +SELECT + v.rowid, + v.Id, + v.Virus, + v.Date, + vc.date as ChallengeDate, + vc.code, + v.ViralLoad, + v.LogVL, + TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date) as DPI, + TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date)/7 as WPI + +FROM study.ViralLoads v + +LEFT JOIN ViralChallenges vc + ON (v.id = vc.id) + +WHERE ((vc.challenge_type like 'SIV%' OR vc.challenge_type like '%virus' ) AND vc.challenge_Type NOT LIKE '%Vaccine%') + +AND vc.date is not null + diff --git a/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.query.xml b/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.query.xml index e485c7d46..34a26440c 100644 --- a/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.query.xml +++ b/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.query.xml @@ -1,42 +1,42 @@ - - - - - - rowid - - - true - true - - - 60 - - /wnprc/ehr/ - study - animal - id - - - - WPI - 280 - - - DPI - 280 - - - true - - - true - - - Challenge Date(s) - - -
    -
    -
    + + + + + + rowid + + + true + true + + + 60 + + /wnprc/ehr/ + study + animal + id + + + + WPI + 280 + + + DPI + 280 + + + true + + + false + + + Challenge Date(s) + + +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.sql b/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.sql index f9d8d6ca8..3767f7fdc 100644 --- a/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.sql +++ b/WNPRC_EHR/resources/queries/study/ViralLoadsWpi.sql @@ -1,50 +1,59 @@ -/* - * Copyright (c) 2010-2011 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ - -select - - v.rowid, - - max(v.Id) as Id, --- max(v.Virus) as Virus, - max(v.Date) as date, --- max(v.ChallengeDate) as ChallengeDate, - max(v.code) as code, - max(v.ViralLoad) as ViralLoad, - max(v.LogVL) as LogVL, - group_concat(WPI) as WPI, - group_concat(DPI) as DPI, - - -FROM ( - -SELECT - v.rowid, - v.Id, - v.Virus, - v.Date, --- vc.date as ChallengeDate, --- vc.challenge_type as ChallengeType, - vc.code, - v.ViralLoad, - v.LogVL, - chr(10) || cast(vc.date as date) || ' (' || vc.challenge_type || '): ' || TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date) as DPI, - chr(10) || cast(vc.date as date) || ' (' || vc.challenge_type || '): ' || cast(round(TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date)/7, 1) as numeric) as WPI, - - vc.challenge_Type - -FROM study.ViralLoads v - -LEFT JOIN study.ViralChallenges vc - ON (v.id = vc.id) - -WHERE vc.challenge_type like 'SIV%' --AND vc.challenge_Type NOT LIKE '%Vaccine%' - -AND vc.date is not null - -) v - -group by v.rowid \ No newline at end of file +/* + * Copyright (c) 2010-2011 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ + +select + + v.rowid, + + max(v.Id) as Id, + max(v.ChallengeType) AS ChallengeType, + max(v.Virus) as Virus, + max(v.Date) as date, + max(v.ChallengeDate) as ChallengeDate, + max(v.code) as code, + max(v.AverageViralLoad) as AverageViralLoad, + max(v.LogVL) as LogVL, + group_concat(SampleType) AS SampleType, + group_concat(Comments) AS Comments, + group_concat(WPI) as WPI, + group_concat(DPI) as DPI, + + +FROM ( + +SELECT + v.rowid, + v.Id, + v.Virus, + v.Date, + vc.date as ChallengeDate, + vc.challenge_type AS ChallengeType, + vc.code, + v.AverageViralLoad, + v.LogVL, + v.SampleType, + v.Comments, + chr(10) || cast(vc.date as date) || ' (' || vc.challenge_type || '): ' || TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date) as DPI, + chr(10) || cast(vc.date as date) || ' (' || vc.challenge_type || '): ' || cast(round(TIMESTAMPDIFF('SQL_TSI_DAY', vc.date, v.Date)/7, 1) as numeric) as WPI, + + vc.challenge_Type + +FROM study.ViralLoads v + +LEFT JOIN study.ViralChallenges vc + ON (v.id = vc.id) + + +WHERE ((vc.challenge_type like 'SIV%' OR vc.challenge_type like '%virus') AND vc.challenge_type NOT LIKE '%Vaccine%' + --match the name of the challenge wiht the name of the virus, SIV has a difference name + AND ((upper(vc.challenge_type) LIKE upper(v.virus)) OR (locate(upper(vc.challenge_type),upper(v.virus)) >= 0) + ) + +AND vc.date is not null) + +) v +GROUP BY v.rowid--, v.ChallengeType + diff --git a/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId.query.xml b/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId.query.xml new file mode 100644 index 000000000..d29e5639a --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId.query.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId.sql b/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId.sql new file mode 100644 index 000000000..1a181d959 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId.sql @@ -0,0 +1,15 @@ +PARAMETERS ( PARENT_RECORD_ID VARCHAR ) +SELECT + be.date, + be.enddate, + be.sireid, + be.ejaculation, + be.project, + be.remark, + be.performedby, + be.outcome +FROM breeding_encounters be +WHERE be.lsid = (SELECT p.breedingencounterid + FROM pregnancies p + WHERE p.objectid = PARENT_RECORD_ID + LIMIT 1) \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/UltrasoundInfo/.qview.xml b/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId/.qview.xml similarity index 58% rename from WNPRC_EHR/resources/queries/study/UltrasoundInfo/.qview.xml rename to WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId/.qview.xml index 4d310aeff..dc1c0775d 100644 --- a/WNPRC_EHR/resources/queries/study/UltrasoundInfo/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/_BreedingEncounterByBreedingId/.qview.xml @@ -1,9 +1,13 @@ - + - - + + + + + + diff --git a/WNPRC_EHR/resources/queries/study/_BreedingRemarkInfoByTaskId.query.xml b/WNPRC_EHR/resources/queries/study/_BreedingRemarkInfoByTaskId.query.xml deleted file mode 100644 index 4b9100c38..000000000 --- a/WNPRC_EHR/resources/queries/study/_BreedingRemarkInfoByTaskId.query.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - MM/dd/yyyy hh:mm - - - - -
    -
    -
    -
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_BreedingRemarkInfoByTaskId.sql b/WNPRC_EHR/resources/queries/study/_BreedingRemarkInfoByTaskId.sql deleted file mode 100644 index 08e20268f..000000000 --- a/WNPRC_EHR/resources/queries/study/_BreedingRemarkInfoByTaskId.sql +++ /dev/null @@ -1,7 +0,0 @@ -PARAMETERS ( TASK_ID VARCHAR ) - SELECT br.date - ,br.remark - ,br.performedby - FROM breeding_remarks br - WHERE br.taskid = TASK_ID - ORDER BY br.date DESC \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_PregnancyInfoByTaskId.query.xml b/WNPRC_EHR/resources/queries/study/_PregnancyInfoByTaskId.query.xml deleted file mode 100644 index efe7be11a..000000000 --- a/WNPRC_EHR/resources/queries/study/_PregnancyInfoByTaskId.query.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - true - - - Sire - /ehr/participantView.view?participantId=${sireid} - - study - animal - id - - - - Breeding Start - MM/dd/yyyy - - - Breeding End - MM/dd/yyyy - - - Breeding Remark - - - Est. Conception - MM/dd/yyyy - - - + 30 - MM/dd/yyyy - - - + 60 - MM/dd/yyyy - - - + 90 - MM/dd/yyyy - - - + 120 - MM/dd/yyyy - - - + 150 - MM/dd/yyyy - - - + 165 - MM/dd/yyyy - - - Current Gestation - 0 - - - Outcome - - - Outcome Date/Time - MM/dd/yyyy hh:mm - - - Outcome Remark - - - Infant - /ehr/participantView.view?participantId=${infantid} - - study - animal - id - - - -
    -
    -
    -
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_PregnancyInfoByTaskId.sql b/WNPRC_EHR/resources/queries/study/_PregnancyInfoByTaskId.sql deleted file mode 100644 index aa03d7212..000000000 --- a/WNPRC_EHR/resources/queries/study/_PregnancyInfoByTaskId.sql +++ /dev/null @@ -1,42 +0,0 @@ -PARAMETERS ( TASK_ID VARCHAR ) - SELECT be.objectid - ,CASE WHEN (be.taskid = TASK_ID) THEN ('*') ELSE NULL END "*" - ,be.sireid - ,be.date - ,be.dateend - ,be.reason - ,br.remark - ,be.conceptiondate - ,timestampadd('SQL_TSI_DAY', 30, be.conceptiondate) conceptiondate_plus_30 - ,timestampadd('SQL_TSI_DAY', 60, be.conceptiondate) conceptiondate_plus_60 - ,timestampadd('SQL_TSI_DAY', 90, be.conceptiondate) conceptiondate_plus_90 - ,timestampadd('SQL_TSI_DAY', 120, be.conceptiondate) conceptiondate_plus_120 - ,timestampadd('SQL_TSI_DAY', 150, be.conceptiondate) conceptiondate_plus_150 - ,timestampadd('SQL_TSI_DAY', 165, be.conceptiondate) conceptiondate_plus_165 - ,timestampdiff('SQL_TSI_DAY', be.conceptiondate, coalesce(po.date, curdate())) gestation_day - ,be.ejaculation - ,po.outcome - ,po.date outcome_date - ,po.remark outcome_remark - ,po.infantid - FROM breeding_encounters be - -- select only the most recent outcome, in case there are multiple outcomes - -- (note that we do not expect there to be multiples, but just in case) - LEFT OUTER JOIN pregnancy_outcomes po - ON po.objectid = (SELECT objectid - FROM pregnancy_outcomes - WHERE taskid = be.taskid - ORDER BY date DESC - LIMIT 1) - -- select the most recent remark to show in the list - LEFT OUTER JOIN breeding_remarks br - ON br.objectid = (SELECT objectid - FROM breeding_remarks - WHERE taskid = be.taskid - ORDER BY date DESC - LIMIT 1) - -- select all the pregnancies for the dam of the selected parent record - WHERE be.id IN (SELECT id - FROM breeding_encounters be2 - WHERE be2.taskid = TASK_ID) - ORDER BY be.date DESC \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_PregnancyOutcomeInfoByTaskId.sql b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomeInfoByTaskId.sql deleted file mode 100644 index 91e0fdf7a..000000000 --- a/WNPRC_EHR/resources/queries/study/_PregnancyOutcomeInfoByTaskId.sql +++ /dev/null @@ -1,9 +0,0 @@ -PARAMETERS ( TASK_ID VARCHAR ) - SELECT po.date - ,po.outcome - ,po.infantid - ,po.remark - ,po.performedby - FROM pregnancy_outcomes po - WHERE po.taskid = TASK_ID - ORDER BY po.date DESC \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_PregnancyOutcomeInfoByTaskId.xml b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomeInfoByTaskId.xml deleted file mode 100644 index 94be092d3..000000000 --- a/WNPRC_EHR/resources/queries/study/_PregnancyOutcomeInfoByTaskId.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - MM/dd/yyyy hh:mm - - - - Infant - /ehr/participantView.view?participantId=${infantid} - - study - animal - id - - - - - -
    -
    -
    -
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId.query.xml b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId.query.xml new file mode 100644 index 000000000..d6f805510 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId.query.xml @@ -0,0 +1,38 @@ + + + + + + + MM/dd/yyyy hh:mm + + + Outcome + + ehr_lookups + birth_type + value + description + + + + Infant + /ehr/participantView.view?participantId=${infantid} + + + study + animal + Id + + + + + + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId.sql b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId.sql new file mode 100644 index 000000000..580149d67 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId.sql @@ -0,0 +1,15 @@ +PARAMETERS ( PARENT_RECORD_ID VARCHAR ) +SELECT + po.date, + po.outcome, + po.infantid, + po.rejected, + po.protected, + po.project, + po.remark, + po.performedby +FROM pregnancy_outcomes po +WHERE po.pregnancyid = (SELECT p.lsid + FROM pregnancies p + WHERE p.objectid = PARENT_RECORD_ID + LIMIT 1) \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId/.qview.xml b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId/.qview.xml new file mode 100644 index 000000000..322f6eca1 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_PregnancyOutcomesByPregnancyId/.qview.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_UltrasoundInfoByTaskId.query.xml b/WNPRC_EHR/resources/queries/study/_UltrasoundInfoByTaskId.query.xml deleted file mode 100644 index 5af1be62e..000000000 --- a/WNPRC_EHR/resources/queries/study/_UltrasoundInfoByTaskId.query.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - MM/dd/yyyy hh:mm - - - - -
    -
    -
    -
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_UltrasoundInfoByTaskId.sql b/WNPRC_EHR/resources/queries/study/_UltrasoundInfoByTaskId.sql deleted file mode 100644 index 7d1369972..000000000 --- a/WNPRC_EHR/resources/queries/study/_UltrasoundInfoByTaskId.sql +++ /dev/null @@ -1,7 +0,0 @@ -PARAMETERS ( TASK_ID VARCHAR ) - SELECT u.date - ,u.remark - ,u.performedby - FROM ultrasounds u - WHERE u.taskid = TASK_ID - ORDER BY u.date DESC \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId.query.xml b/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId.query.xml new file mode 100644 index 000000000..2f15abcb9 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId.query.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId.sql b/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId.sql new file mode 100644 index 000000000..5eebcb6cd --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId.sql @@ -0,0 +1,26 @@ +PARAMETERS ( PARENT_RECORD_ID VARCHAR ) +SELECT + u.date, + u.project, + u.restraint, + u.fetal_heartbeat, + u.beats_per_minute, + u.gest_sac_mm, + u.gest_sac_gest_day, + u.crown_rump_mm, + u.crown_rump_gest_day, + u.biparietal_diameter_mm, + u.biparietal_diameter_gest_day, + u.femur_length_mm, + u.femur_length_gest_day, + u.yolk_sac_diameter_mm, + u.head_circumference_mm, + u.code, + u.remark, + u.performedby, + u.followup_required +FROM ultrasounds u +WHERE u.pregnancyid = (SELECT p.lsid + FROM pregnancies p + WHERE p.objectid = PARENT_RECORD_ID + LIMIT 1) \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId/.qview.xml b/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId/.qview.xml new file mode 100644 index 000000000..a7bed1011 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/_UltrasoundsByPregnancyId/.qview.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wnprc_billing/resources/queries/wnprc_billing/groups.query.xml b/WNPRC_EHR/resources/queries/study/animalBillableDaysReport.query.xml similarity index 54% rename from wnprc_billing/resources/queries/wnprc_billing/groups.query.xml rename to WNPRC_EHR/resources/queries/study/animalBillableDaysReport.query.xml index 68f166b10..bbb2cb87c 100644 --- a/wnprc_billing/resources/queries/wnprc_billing/groups.query.xml +++ b/WNPRC_EHR/resources/queries/study/animalBillableDaysReport.query.xml @@ -1,8 +1,8 @@ - - Departments +
    + Animals Billable Days Report
    diff --git a/WNPRC_EHR/resources/queries/study/animalBillableDaysReport.sql b/WNPRC_EHR/resources/queries/study/animalBillableDaysReport.sql new file mode 100644 index 000000000..fb637b108 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/animalBillableDaysReport.sql @@ -0,0 +1,13 @@ +PARAMETERS +(START_DATE TIMESTAMP, END_DATE TIMESTAMP) + +SELECT id + , GROUP_CONCAT(project, ', ') as Projects + , GROUP_CONCAT(date, ', ') as AssignmentDates + , GROUP_CONCAT(enddate, ', ') as ReleaseDates + , GROUP_CONCAT(project.avail, ', ') as ProjectAvails +FROM study.assignment +WHERE date <= END_DATE + AND (enddate >= START_DATE OR enddate IS NULL) + AND (project.avail = 'r' OR project.avail = 'rr' OR project.avail = 'n') +GROUP BY id; diff --git a/WNPRC_EHR/resources/queries/study/assignment/.qview.xml b/WNPRC_EHR/resources/queries/study/assignment/.qview.xml index abf769529..3fa221dad 100644 --- a/WNPRC_EHR/resources/queries/study/assignment/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/assignment/.qview.xml @@ -22,7 +22,7 @@
    - + diff --git a/WNPRC_EHR/resources/queries/study/assignment/Research Assignments.qview.xml b/WNPRC_EHR/resources/queries/study/assignment/Research Assignments.qview.xml index f93eb9176..e92742e15 100644 --- a/WNPRC_EHR/resources/queries/study/assignment/Research Assignments.qview.xml +++ b/WNPRC_EHR/resources/queries/study/assignment/Research Assignments.qview.xml @@ -22,7 +22,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/assignment/Search Panel.qview.xml b/WNPRC_EHR/resources/queries/study/assignment/Search Panel.qview.xml index 8a9054df7..e2a636103 100644 --- a/WNPRC_EHR/resources/queries/study/assignment/Search Panel.qview.xml +++ b/WNPRC_EHR/resources/queries/study/assignment/Search Panel.qview.xml @@ -32,7 +32,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/assignment/Tracking Assignments.qview.xml b/WNPRC_EHR/resources/queries/study/assignment/Tracking Assignments.qview.xml index eaa24f297..113c17735 100644 --- a/WNPRC_EHR/resources/queries/study/assignment/Tracking Assignments.qview.xml +++ b/WNPRC_EHR/resources/queries/study/assignment/Tracking Assignments.qview.xml @@ -22,7 +22,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/assignment/With Projected Release.qview.xml b/WNPRC_EHR/resources/queries/study/assignment/With Projected Release.qview.xml index 7d6003c48..c3188c451 100644 --- a/WNPRC_EHR/resources/queries/study/assignment/With Projected Release.qview.xml +++ b/WNPRC_EHR/resources/queries/study/assignment/With Projected Release.qview.xml @@ -22,7 +22,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/Bacteriology Results/.qview.xml b/WNPRC_EHR/resources/queries/study/bacteriologyResults/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Bacteriology Results/.qview.xml rename to WNPRC_EHR/resources/queries/study/bacteriologyResults/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Body Condition/.qview.xml b/WNPRC_EHR/resources/queries/study/bcs/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Body Condition/.qview.xml rename to WNPRC_EHR/resources/queries/study/bcs/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Behavior Remarks/.qview.xml b/WNPRC_EHR/resources/queries/study/behavetrem/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Behavior Remarks/.qview.xml rename to WNPRC_EHR/resources/queries/study/behavetrem/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/behaviorRelatedIrregularObs.sql b/WNPRC_EHR/resources/queries/study/behaviorRelatedIrregularObs.sql new file mode 100644 index 000000000..cedcd51f1 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/behaviorRelatedIrregularObs.sql @@ -0,0 +1,13 @@ +PARAMETERS +(START_DATE TIMESTAMP, END_DATE TIMESTAMP) + +SELECT o.id + , o.housingattime.roomattime + , o.housingattime.cageattime + --, o.id.curlocation.cage + , o.date + , o.behavior + , o.otherbehavior +FROM study.obs o +WHERE o.date <= END_DATE AND o.date >= START_DATE +AND (o.behavior IS NOT NULL OR o.otherbehavior IS NOT NULL) \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/breedingEncounterWindow.sql b/WNPRC_EHR/resources/queries/study/breedingEncounterWindow.sql new file mode 100644 index 000000000..4df62933e --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/breedingEncounterWindow.sql @@ -0,0 +1,2 @@ +SELECT lsid, to_char(date, 'yyyy-MM-dd HH24:MI') || ' to ' || COALESCE(to_char(enddate, 'yyyy-MM-dd HH24:MI'), 'Ongoing') AS window +FROM study.breeding_encounters \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/breeding_encounters.js b/WNPRC_EHR/resources/queries/study/breeding_encounters.js new file mode 100644 index 000000000..5b5804908 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/breeding_encounters.js @@ -0,0 +1,62 @@ +require("ehr/triggers").initScript(this); + +function onUpsert(helper, scriptErrors, row, oldRow){ + + //validate that the dam is female and alive + if (row.Id){ + EHR.Server.Validation.verifyIsFemale(row, scriptErrors, helper); + + EHR.Server.Utils.findDemographics({ + participant: row.Id, + helper: helper, + scope: this, + callback: function (data) { + if (data) { + if (data['calculated_status'] && data['calculated_status'] !== 'Alive'){ + EHR.Server.Utils.addError(scriptErrors, 'sireid', 'This animal (' + row.Id + ') is not alive', 'ERROR'); + } + } + } + }); + + if (row.date && row.enddate) { + //row.QCState = EHR.Server.Security.getQCStateByLabel('Completed').RowId; + row.QCStateLabel = EHR.Server.Security.getQCStateByLabel('Completed').Label; + } + row.ejaculation = !!row.ejaculation; + row.outcome = !!row.outcome; + } + + //validate that the sire(s) are male, alive, and not duplicated + //also strip any non alphanumeric characters and separate sire ids by a comma + if (row.sireid) { + row.sireid = row.sireid.replace(/[^A-Za-z0-9]+/g, ','); + let ids = row.sireid.split(','); + let duplicateCount = []; + + for (let i = 0; i < ids.length; i++) { + let id = ids[i]; + EHR.Server.Utils.findDemographics({ + participant: id, + helper: helper, + scope: this, + callback: function (data) { + if (data) { + if (data['gender/origGender'] && data['gender/origGender'] !== 'm') { + EHR.Server.Utils.addError(scriptErrors, 'sireid', 'This animal (' + id + ') is not male', 'ERROR'); + } + if (data['calculated_status'] && data.calculated_status !== 'Alive'){ + EHR.Server.Utils.addError(scriptErrors, 'sireid', 'This animal (' + id + ') is not alive', 'ERROR'); + } + } + } + }); + + if (duplicateCount[id] === undefined) { + duplicateCount[id] = 1; + } else { + EHR.Server.Utils.addError(scriptErrors, 'sireid', 'This animal (' + id + ') is listed more than once', 'ERROR'); + } + } + } +} \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/breeding_encounters.query.xml b/WNPRC_EHR/resources/queries/study/breeding_encounters.query.xml new file mode 100644 index 000000000..2241a4474 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/breeding_encounters.query.xml @@ -0,0 +1,32 @@ + + + + + + + + Encounter Start Time + false + + + Encounter End Time + true + + + Female + false + + + false + + + + + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/breeding_encounters/.qview.xml b/WNPRC_EHR/resources/queries/study/breeding_encounters/.qview.xml new file mode 100644 index 000000000..6c388ad87 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/breeding_encounters/.qview.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Cage Observations/.qview.xml b/WNPRC_EHR/resources/queries/study/cageObs/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Cage Observations/.qview.xml rename to WNPRC_EHR/resources/queries/study/cageObs/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/chemPivot.query.xml b/WNPRC_EHR/resources/queries/study/chemPivot.query.xml index c6498bbcb..7ebdca701 100644 --- a/WNPRC_EHR/resources/queries/study/chemPivot.query.xml +++ b/WNPRC_EHR/resources/queries/study/chemPivot.query.xml @@ -17,115 +17,6 @@ Id
    - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 140 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - - 120 - - diff --git a/WNPRC_EHR/resources/queries/study/Clinpath Runs/.qview.xml b/WNPRC_EHR/resources/queries/study/clinpathRuns/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Clinpath Runs/.qview.xml rename to WNPRC_EHR/resources/queries/study/clinpathRuns/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Clinpath Runs/Clinpath Requests.qview.xml b/WNPRC_EHR/resources/queries/study/clinpathRuns/Clinpath Requests.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Clinpath Runs/Clinpath Requests.qview.xml rename to WNPRC_EHR/resources/queries/study/clinpathRuns/Clinpath Requests.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Clinpath Runs/Completed Requests.qview.xml b/WNPRC_EHR/resources/queries/study/clinpathRuns/Completed Requests.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Clinpath Runs/Completed Requests.qview.xml rename to WNPRC_EHR/resources/queries/study/clinpathRuns/Completed Requests.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Clinpath Runs/Plus Room.qview.xml b/WNPRC_EHR/resources/queries/study/clinpathRuns/Plus Room.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Clinpath Runs/Plus Room.qview.xml rename to WNPRC_EHR/resources/queries/study/clinpathRuns/Plus Room.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Clinpath Runs/Unreviewed.qview.xml b/WNPRC_EHR/resources/queries/study/clinpathRuns/Unreviewed.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Clinpath Runs/Unreviewed.qview.xml rename to WNPRC_EHR/resources/queries/study/clinpathRuns/Unreviewed.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Clinical Remarks/.qview.xml b/WNPRC_EHR/resources/queries/study/clinremarks/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Clinical Remarks/.qview.xml rename to WNPRC_EHR/resources/queries/study/clinremarks/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Clinical Remarks/Remark Only.qview.xml b/WNPRC_EHR/resources/queries/study/clinremarks/Remark Only.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Clinical Remarks/Remark Only.qview.xml rename to WNPRC_EHR/resources/queries/study/clinremarks/Remark Only.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Cytology Automated Evaluation/.qview.xml b/WNPRC_EHR/resources/queries/study/cytologyAutomatedResults/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Cytology Automated Evaluation/.qview.xml rename to WNPRC_EHR/resources/queries/study/cytologyAutomatedResults/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Cytology Manual Evaluation/.qview.xml b/WNPRC_EHR/resources/queries/study/cytologyManualResults/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Cytology Manual Evaluation/.qview.xml rename to WNPRC_EHR/resources/queries/study/cytologyManualResults/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/demographicsAssignmentSummary.sql b/WNPRC_EHR/resources/queries/study/demographicsAssignmentSummary.sql index b9d99f2b5..44b8e437a 100644 --- a/WNPRC_EHR/resources/queries/study/demographicsAssignmentSummary.sql +++ b/WNPRC_EHR/resources/queries/study/demographicsAssignmentSummary.sql @@ -42,53 +42,53 @@ FROM study.demographics d --we find the number of active research project assignments LEFT JOIN - (SELECT T1.Id, count(DISTINCT T1.project) AS Total, group_concat(DISTINCT project) AS Projects - FROM study.Assignment T1 - WHERE T1.qcstate.publicdata = true AND cast(T1.date as date) <= curdate() AND (T1.enddate IS NULL or cast(T1.enddate as date) >= curdate()) AND (T1.project.avail = 'r' OR T1.project.avail = 'n') - GROUP BY T1.Id) T1 + (SELECT Id, count(DISTINCT project) AS Total, group_concat(DISTINCT project) AS Projects + FROM study.Assignment + WHERE qcstate.publicdata = true AND cast(date as date) <= curdate() AND (enddate IS NULL or cast(enddate as date) >= curdate()) AND (project.avail = 'r' OR project.avail = 'n') + GROUP BY Id) T1 ON (T1.Id = d.Id) --we find the number of pending project assignments LEFT JOIN - (SELECT T2.Id, count(DISTINCT T2.project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment T2 WHERE T2.qcstate.publicdata = true AND cast(T2.date as date) <= curdate() AND (T2.enddate IS NULL or cast(T2.enddate as date) >= curdate()) AND (T2.project.avail = 'p') GROUP BY T2.Id) T2 + (SELECT Id, count(DISTINCT project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment WHERE qcstate.publicdata = true AND cast(date as date) <= curdate() AND (enddate IS NULL or cast(enddate as date) >= curdate()) AND (project.avail = 'p') GROUP BY Id) T2 ON (T2.Id = d.Id) --we find the number of active vet project assignments LEFT JOIN - (SELECT T3.Id, count(DISTINCT T3.project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment T3 WHERE T3.qcstate.publicdata = true AND cast(T3.date as date) <= curdate() AND (T3.enddate IS NULL or cast(T3.enddate as date) >= curdate()) AND T3.project.avail = 'v' GROUP BY T3.Id) T3 + (SELECT Id, count(DISTINCT project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment WHERE qcstate.publicdata = true AND cast(date as date) <= curdate() AND (enddate IS NULL or cast(enddate as date) >= curdate()) AND project.avail = 'v' GROUP BY Id) T3 ON (T3.Id = d.Id) --we find the number of active breeding project assignments LEFT JOIN - (SELECT T9.Id, count(DISTINCT T9.project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment T9 WHERE T9.qcstate.publicdata = true AND cast(T9.date as date) <= curdate() AND (T9.enddate IS NULL or cast(T9.enddate as date) >= curdate()) AND T9.project.avail = 'b' GROUP BY T9.Id) T9 + (SELECT Id, count(DISTINCT project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment WHERE qcstate.publicdata = true AND cast(date as date) <= curdate() AND (enddate IS NULL or cast(enddate as date) >= curdate()) AND project.avail = 'b' GROUP BY Id) T9 ON (T9.Id = d.Id) --we find the number of active training project assignments LEFT JOIN - (SELECT T10.Id, count(DISTINCT T10.project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment T10 WHERE T10.qcstate.publicdata = true AND cast(T10.date as date) <= curdate() AND (T10.enddate IS NULL or cast(T10.enddate as date) >= curdate()) AND T10.project.avail = 't' GROUP BY T10.Id) T10 + (SELECT Id, count(DISTINCT project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment WHERE qcstate.publicdata = true AND cast(date as date) <= curdate() AND (enddate IS NULL or cast(enddate as date) >= curdate()) AND project.avail = 't' GROUP BY Id) T10 ON (T10.Id = d.Id) --we find the number of total active project assignments LEFT JOIN - (SELECT T4.Id, count(DISTINCT T4.project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment T4 WHERE t4.qcstate.publicdata = true AND cast(T4.date as date) <= curdate() AND (T4.enddate IS NULL or cast(T4.enddate as date) >= curdate()) GROUP BY T4.Id) T4 + (SELECT Id, count(DISTINCT project) AS Total, group_concat(DISTINCT project) AS Projects FROM study.Assignment WHERE qcstate.publicdata = true AND cast(date as date) <= curdate() AND (enddate IS NULL or cast(enddate as date) >= curdate()) GROUP BY Id) T4 ON (T4.Id = d.Id) --we find the number of active stock project assignments ---spf stock animals (20020201) ---conventional stock animals (20070202) ---marmoset stock animals (20070801) +--spf stock animals (20150902) +--conventional stock animals (20150903) +--marmoset stock animals (20150904) LEFT JOIN - (select t5.id, count(DISTINCT T5.project) AS Total, group_concat(DISTINCT project) AS Projects, group_concat(DISTINCT category) AS categories FROM ( - SELECT T5.Id, t5.project, + (select id, count(DISTINCT project) AS Total, group_concat(DISTINCT project) AS Projects, group_concat(DISTINCT category) AS categories FROM ( + SELECT Id, project, case - when project = 20020201 then 'SPF' - when project = 20070202 then 'Conventional' - when project = 20070801 then 'Marmoset Stock' + when project = 20150902 then 'SPF' + when project = 20150903 then 'Conventional' + when project = 20150904 then 'Marmoset Stock' else null end as category - FROM study.Assignment T5 - WHERE t5.qcstate.publicdata = true AND cast(T5.date as date) <= curdate() AND (T5.enddate IS NULL or cast(T5.enddate as date) >= curdate()) AND (t5.project = '20020201' OR t5.project = '20070202' OR t5.project = '20070801') - ) T5 GROUP BY T5.Id + FROM study.Assignment + WHERE qcstate.publicdata = true AND cast(date as date) <= curdate() AND (enddate IS NULL or cast(enddate as date) >= curdate()) + ) filteredAssignment WHERE category IS NOT NULL GROUP BY Id ) t5 ON (T5.Id = d.Id) diff --git a/WNPRC_EHR/resources/queries/study/demographicsPrimateId.query.xml b/WNPRC_EHR/resources/queries/study/demographicsPrimateId.query.xml new file mode 100644 index 000000000..4495b1101 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/demographicsPrimateId.query.xml @@ -0,0 +1,16 @@ + + + + + + + true + + + + + Primate Id +
    +
    +
    +
    diff --git a/WNPRC_EHR/resources/queries/study/demographicsPrimateId.sql b/WNPRC_EHR/resources/queries/study/demographicsPrimateId.sql new file mode 100644 index 000000000..56ca0b9b0 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/demographicsPrimateId.sql @@ -0,0 +1,6 @@ +SELECT +UT.primateId, +UT.participantid AS Id + +FROM primateid.unique_ids UT +--WHERE UT.participantId = id \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/demographicsVL.sql b/WNPRC_EHR/resources/queries/study/demographicsVL.sql index 47cbc45a9..e82f381c7 100644 --- a/WNPRC_EHR/resources/queries/study/demographicsVL.sql +++ b/WNPRC_EHR/resources/queries/study/demographicsVL.sql @@ -5,11 +5,11 @@ */ SELECT v.Id, - max(v.ViralLoad) as MaxViralLoad, - min(v.ViralLoad) as MinViralLoad, + max(v.AverageViralLoad) as MaxViralLoad, + min(v.AverageViralLoad) as MinViralLoad, min(v.date) as FirstViralLoadDate, max(v.date) as LastViralLoadDate, - (select avg(v1.viralLoad) as viralLoad FROM study.ViralLoads v1 WHERE v1.Id=v.Id AND max(v.date)=v1.date) as LatestViralLoad + (select avg(v1.AverageViralLoad) as viralLoad FROM study.ViralLoads v1 WHERE v1.Id=v.Id AND max(v.date)=v1.date) as LatestViralLoad FROM study.ViralLoads v diff --git a/WNPRC_EHR/resources/queries/study/Dental Status/.qview.xml b/WNPRC_EHR/resources/queries/study/dentalStatus/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Dental Status/.qview.xml rename to WNPRC_EHR/resources/queries/study/dentalStatus/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Drug Administration/.qview.xml b/WNPRC_EHR/resources/queries/study/drug/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Drug Administration/.qview.xml rename to WNPRC_EHR/resources/queries/study/drug/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Drug Administration/Surgery Drugs.qview.xml b/WNPRC_EHR/resources/queries/study/drug/Surgery Drugs.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Drug Administration/Surgery Drugs.qview.xml rename to WNPRC_EHR/resources/queries/study/drug/Surgery Drugs.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Drug Administration/Treatments.qview.xml b/WNPRC_EHR/resources/queries/study/drug/Treatments.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Drug Administration/Treatments.qview.xml rename to WNPRC_EHR/resources/queries/study/drug/Treatments.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Final Reports/.qview.xml b/WNPRC_EHR/resources/queries/study/final_reports/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Final Reports/.qview.xml rename to WNPRC_EHR/resources/queries/study/final_reports/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/foodDeprives.js b/WNPRC_EHR/resources/queries/study/foodDeprives.js index 979a7f573..6f36bf985 100644 --- a/WNPRC_EHR/resources/queries/study/foodDeprives.js +++ b/WNPRC_EHR/resources/queries/study/foodDeprives.js @@ -68,8 +68,9 @@ function onUpsert(helper, scriptErrors, row, oldRow){ } function beforeUpdate(row, oldRow, scriptErrors){ - if (row.QCStateLabel=='Started' && oldRow.QCStateLabel=='Scheduled' && !row.depriveStartTime){ + if (row.QCStateLabel=='Started' && oldRow.QCStateLabel=='Scheduled' && !row.depriveStartTime && !row.depriveStartedBy) { EHR.Server.Utils.addError(scriptErrors, 'depriveStartTime', 'Need to enter a start time to start food deprive', 'ERROR'); + EHR.Server.Utils.addError(scriptErrors, 'depriveStartedBy', 'Need to enter a initials to start food deprive', 'ERROR'); } if (row.QCStateLabel=='Complete' && oldRow.QCStateLabel=='Started' && (row.depriveStartTime > row.restoredTime)){ diff --git a/WNPRC_EHR/resources/queries/study/foodDeprives.query.xml b/WNPRC_EHR/resources/queries/study/foodDeprives.query.xml index b2653361d..e95b9db67 100644 --- a/WNPRC_EHR/resources/queries/study/foodDeprives.query.xml +++ b/WNPRC_EHR/resources/queries/study/foodDeprives.query.xml @@ -19,7 +19,8 @@ ehr_lookups husbandry_assigned - title + value + title
    diff --git a/WNPRC_EHR/resources/queries/study/foodDeprives/.qview.xml b/WNPRC_EHR/resources/queries/study/foodDeprives/.qview.xml index 2ad76c6af..30f45791e 100644 --- a/WNPRC_EHR/resources/queries/study/foodDeprives/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/foodDeprives/.qview.xml @@ -5,6 +5,7 @@ + diff --git a/WNPRC_EHR/resources/queries/study/Hematology Morphology/.qview.xml b/WNPRC_EHR/resources/queries/study/hematologyMorphology/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Hematology Morphology/.qview.xml rename to WNPRC_EHR/resources/queries/study/hematologyMorphology/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/housing.js b/WNPRC_EHR/resources/queries/study/housing.js new file mode 100644 index 000000000..14bf7710f --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/housing.js @@ -0,0 +1,77 @@ +var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; + +require("ehr/triggers").initScript(this); + +function onInit(event, helper) { + helper.setScriptOptions({ + skipHousingCheck: true + }); + + helper.decodeExtraContextProperty('housingInTransaction'); +} + +function onUpsert(helper, scriptErrors, row, oldRow){ + let breedingDataSaved = helper.getProperty('breedingEncountersSaved'); + + if (row.reason) { + let reasons = row.reason.split(','); + let breeding = false; + let breedingEnded = false; + let none = false; + for (let i = 0; i < reasons.length; i++) { + if (reasons[i] === 'Breeding') { + breeding = true; + } else if (reasons[i] === 'Breeding ended') { + breedingEnded = true; + } else if (reasons[i] === '') { + none = true; + } + } + if (breeding && breedingEnded) { + EHR.Server.Utils.addError(scriptErrors, 'reason', 'Reason For Move cannot contain both \'Breeding\' and \'Breeding ended\'.', 'ERROR'); + } + if (none && reasons.length > 1) { + EHR.Server.Utils.addError(scriptErrors, 'reason', '\'[none]\' cannot be used in tandem with another reason.'); + } + } + + if (helper.isValidateOnly() || (!helper.isValidateOnly() && !breedingDataSaved)) { + let housingRows = helper.getProperty('housingInTransaction'); + let housingArray = []; + + //loop through all housing change rows and add them to the housing array + //if they have all of the correct fields filled in. + for (let propertyName in housingRows) { + if (housingRows.hasOwnProperty(propertyName)) { + for (let i = 0; i < housingRows[propertyName].length; i++) { + if (housingRows[propertyName][i].event === 'insert' && !housingRows[propertyName][i].enddate + && housingRows[propertyName][i].reason && housingRows[propertyName][i].room + && housingRows[propertyName][i].cage && housingRows[propertyName][i].date + && housingRows[propertyName][i].Id) { + housingRows[propertyName][i].date = new Date(housingRows[propertyName][i].date); + housingRows[propertyName][i].currentId = row.Id; + housingRows[propertyName][i].validateOnly = helper.isValidateOnly(); + housingArray.push(housingRows[propertyName][i]); + } + } + } + } + + //call java method to create the breeding encounter records from the housing changes + //add any errors that are returned to the page + if (housingArray.length > 0) { + let javaErrors = WNPRC.Utils.getJavaHelper().createBreedingRecordsFromHousingChanges(housingArray); + if (javaErrors) { + for (let i = 0; i < javaErrors.length; i++) { + let error = javaErrors[i]; + console.log('Field: ' + error.field + ', Message: ' + error.message + ', Severity: ' + error.severity); + EHR.Server.Utils.addError(scriptErrors, error.field, error.message, error.severity); + } + } + } + + //set data saved to true so that it doesn't save for every row + //this is necessary because we're saving everything all at once + helper.setProperty('breedingEncountersSaved', true); + } +} \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/irregularObsById.query.xml b/WNPRC_EHR/resources/queries/study/irregularObsById.query.xml index ca65b5794..f9f557b3f 100644 --- a/WNPRC_EHR/resources/queries/study/irregularObsById.query.xml +++ b/WNPRC_EHR/resources/queries/study/irregularObsById.query.xml @@ -8,7 +8,6 @@ yyyy-MM-dd HH:mm - 40 study Animal diff --git a/WNPRC_EHR/resources/queries/study/irregularObsTreatment.query.xml b/WNPRC_EHR/resources/queries/study/irregularObsTreatment.query.xml index 153f27ae7..aebc3ad63 100644 --- a/WNPRC_EHR/resources/queries/study/irregularObsTreatment.query.xml +++ b/WNPRC_EHR/resources/queries/study/irregularObsTreatment.query.xml @@ -8,7 +8,6 @@ yyyy-MM-dd HH:mm - 40 study Animal diff --git a/WNPRC_EHR/resources/queries/study/irregularObsTreatmentById.query.xml b/WNPRC_EHR/resources/queries/study/irregularObsTreatmentById.query.xml index d51c1dad4..187eb65d6 100644 --- a/WNPRC_EHR/resources/queries/study/irregularObsTreatmentById.query.xml +++ b/WNPRC_EHR/resources/queries/study/irregularObsTreatmentById.query.xml @@ -8,7 +8,7 @@ yyyy-MM-dd HH:mm - 40 + 60 study Animal @@ -16,7 +16,8 @@ - 40 + 100 + Room (current) ehr_lookups rooms_quick diff --git a/WNPRC_EHR/resources/queries/study/Morphologic Diagnosis/.qview.xml b/WNPRC_EHR/resources/queries/study/morphologicDiagnosis/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Morphologic Diagnosis/.qview.xml rename to WNPRC_EHR/resources/queries/study/morphologicDiagnosis/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/necropsy.query.xml b/WNPRC_EHR/resources/queries/study/necropsy.query.xml index 5f4d87dd8..b9310b4c0 100644 --- a/WNPRC_EHR/resources/queries/study/necropsy.query.xml +++ b/WNPRC_EHR/resources/queries/study/necropsy.query.xml @@ -15,7 +15,7 @@ false - Date + yyyy-MM-dd Necropsy Date false http://cpas.labkey.com/Study#VisitDate @@ -42,7 +42,13 @@ urn:ehr.labkey.org/#Account - Pathologist + Pathologist Gross + + + Pathologist Histology + + + Pathologist Review Prosector @@ -53,6 +59,9 @@ Tissue Distribution + + true + Final Summary Comments @@ -83,18 +92,17 @@ - true - DateTime + true Perfusion Time 1 + yyyy-MM-dd HH:mm - true + true Perfusion Time 2 - DateTime + yyyy-MM-dd HH:mm Body Condition - true ehr_lookups necropsy_condition diff --git a/WNPRC_EHR/resources/queries/study/obs.js b/WNPRC_EHR/resources/queries/study/obs.js index bd2f0bc6f..dd1aba7ca 100644 --- a/WNPRC_EHR/resources/queries/study/obs.js +++ b/WNPRC_EHR/resources/queries/study/obs.js @@ -28,6 +28,16 @@ function onUpsert(helper, scriptErrors, row, oldRow){ row.isIrregular = false; } + if (row.behavior && !row.otherbehavior){ + let behaviorList = row.behavior.split(';'); + for (let i=0; i + + yyyy-MM-dd HH:mm + @@ -58,11 +61,12 @@ Behavior - - - - - + Breeding @@ -98,4 +102,4 @@ - \ No newline at end of file + diff --git a/WNPRC_EHR/resources/queries/study/Irregular Observations/.qview.xml b/WNPRC_EHR/resources/queries/study/obs/.qview.xml similarity index 96% rename from WNPRC_EHR/resources/queries/study/Irregular Observations/.qview.xml rename to WNPRC_EHR/resources/queries/study/obs/.qview.xml index 2c7f184fc..6c49aa400 100644 --- a/WNPRC_EHR/resources/queries/study/Irregular Observations/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/obs/.qview.xml @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Irregular Observations/In Rooms.qview.xml b/WNPRC_EHR/resources/queries/study/obs/In Rooms.qview.xml similarity index 96% rename from WNPRC_EHR/resources/queries/study/Irregular Observations/In Rooms.qview.xml rename to WNPRC_EHR/resources/queries/study/obs/In Rooms.qview.xml index 79db4a745..0130edce6 100644 --- a/WNPRC_EHR/resources/queries/study/Irregular Observations/In Rooms.qview.xml +++ b/WNPRC_EHR/resources/queries/study/obs/In Rooms.qview.xml @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Irregular Observations/Irregular Obs.qview.xml b/WNPRC_EHR/resources/queries/study/obs/Irregular Obs.qview.xml similarity index 97% rename from WNPRC_EHR/resources/queries/study/Irregular Observations/Irregular Obs.qview.xml rename to WNPRC_EHR/resources/queries/study/obs/Irregular Obs.qview.xml index 78173b369..193198824 100644 --- a/WNPRC_EHR/resources/queries/study/Irregular Observations/Irregular Obs.qview.xml +++ b/WNPRC_EHR/resources/queries/study/obs/Irregular Obs.qview.xml @@ -1,36 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Irregular Observations/Today Only.qview.xml b/WNPRC_EHR/resources/queries/study/obs/Today Only.qview.xml similarity index 97% rename from WNPRC_EHR/resources/queries/study/Irregular Observations/Today Only.qview.xml rename to WNPRC_EHR/resources/queries/study/obs/Today Only.qview.xml index 78b4f6187..63eb280a5 100644 --- a/WNPRC_EHR/resources/queries/study/Irregular Observations/Today Only.qview.xml +++ b/WNPRC_EHR/resources/queries/study/obs/Today Only.qview.xml @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Pair Tests/.qview.xml b/WNPRC_EHR/resources/queries/study/pairtest/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Pair Tests/.qview.xml rename to WNPRC_EHR/resources/queries/study/pairtest/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Parasitology Results/.qview.xml b/WNPRC_EHR/resources/queries/study/parasitologyResults/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Parasitology Results/.qview.xml rename to WNPRC_EHR/resources/queries/study/parasitologyResults/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/preViralLoad.sql b/WNPRC_EHR/resources/queries/study/preViralLoad.sql new file mode 100644 index 000000000..500f2305d --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/preViralLoad.sql @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010-2012 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +SELECT + v.rowid, + v.SubjectId as Id, + v.Date as date, + v.assayId.virus AS Virus, + v.comment as Comments, + + CASE + WHEN (v.ViralLoad < 100) + THEN 100 + else + v.ViralLoad + END + as ViralLoad, + v.sourcematerial.type as SampleType, + v.run.exptNumber AS VL_ExpNumber, + QC.Expt_nr AS QC_ExptNumber, + QC.QC_Pass AS QC_Pass + + +FROM "/WNPRC/WNPRC_Units/Research_Services/Virology_Services/VL_DB/".assay."Viral_Load Data" v + +LEFT JOIN "/WNPRC/WNPRC_Units/Research_Services/Virology_Services/VS_group_wiki/".lists."QPCR_QC_list" QC +ON CAST (v.run.exptNumber AS FLOAT) = QC.Expt_nr +--WHERE QC.QC_Pass = 'FALSE' + + + +--TODO +--WHERE v.qcstate.publicdata = true + diff --git a/WNPRC_EHR/resources/queries/study/pregnancies.js b/WNPRC_EHR/resources/queries/study/pregnancies.js new file mode 100644 index 000000000..c4726730d --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/pregnancies.js @@ -0,0 +1,78 @@ +var console = require('console'); +require("ehr/triggers").initScript(this); +var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; + +function onUpsert(helper, scriptErrors, row, oldRow){ + + //validate that the dam is female + if (row.Id){ + EHR.Server.Validation.verifyIsFemale(row, scriptErrors, helper); + //row.QCState = EHR.Server.Security.getQCStateByLabel('Completed').RowId; + row.QCStateLabel = EHR.Server.Security.getQCStateByLabel('Completed').Label; + } + + //validate that the sire is male + if (row.sireid) { + //validate that the sire(s) are male, alive, and not duplicated + //also strip any non alphanumeric characters and separate sire ids by a comma + if (row.sireid) { + row.sireid = row.sireid.replace(/[^A-Za-z0-9]+/g, ','); + let ids = row.sireid.split(','); + let duplicateCount = []; + + for (let i = 0; i < ids.length; i++) { + let id = ids[i]; + EHR.Server.Utils.findDemographics({ + participant: id, + helper: helper, + scope: this, + callback: function (data) { + if (data) { + if (data['gender/origGender'] && data['gender/origGender'] !== 'm') { + EHR.Server.Utils.addError(scriptErrors, 'sireid', 'This animal (' + id + ') is not male', 'ERROR'); + } + if (data['calculated_status'] && data.calculated_status !== 'Alive'){ + EHR.Server.Utils.addError(scriptErrors, 'sireid', 'This animal (' + id + ') is not alive', 'ERROR'); + } + } + } + }); + + if (duplicateCount[id] === undefined) { + duplicateCount[id] = 1; + } else { + EHR.Server.Utils.addError(scriptErrors, 'sireid', 'This animal (' + id + ') is listed more than once', 'ERROR'); + } + } + } + } + + if (!row.breedingencounterid) { + EHR.Server.Utils.addError(scriptErrors, 'breedingencounterid', 'Field should ALWAYS be filled in unless actually unknown', 'WARN'); + } +} + +function onComplete(event, errors, helper){ + let pregnancyRows = helper.getRows(); + let updateRows = []; + + if (pregnancyRows){ + for (let i = 0; i < pregnancyRows.length; i++) { + var updateRow = {}; + if (pregnancyRows[i].row.breedingencounterid) { + updateRows.push(pregnancyRows[i].row.breedingencounterid); + } + } + WNPRC.Utils.getJavaHelper().updateBreedingOutcome(updateRows); + } + + // let ids = helper.getRows().map(function (pregnancy) { + // return pregnancy.row.Id; + // }); + // + // let objectids = helper.getRows().map(function (pregnancy) { + // return pregnancy.row.objectid; + // }); + // + // WNPRC.Utils.getJavaHelper().sendPregnancyNotification(ids, objectids); +} \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/pregnancies.query.xml b/WNPRC_EHR/resources/queries/study/pregnancies.query.xml new file mode 100644 index 000000000..8dc13c2fa --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/pregnancies.query.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + Breeding Encounter + + study + breedingEncounterWindow + lsid + window + + yyyy-MM-dd + + + false + + + + true + + + false + + + false + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/pregnancies/abstract.qview.xml b/WNPRC_EHR/resources/queries/study/pregnancies/abstract.qview.xml new file mode 100644 index 000000000..2615bd4c4 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/pregnancies/abstract.qview.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/pregnancyConceptionDate.sql b/WNPRC_EHR/resources/queries/study/pregnancyConceptionDate.sql new file mode 100644 index 000000000..b35b229cd --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/pregnancyConceptionDate.sql @@ -0,0 +1,2 @@ +SELECT lsid, to_char(date_conception, 'yyyy-MM-dd') || ' (Sire: ' || sireid || ')' AS date_conception +FROM study.pregnancies \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/pregnancy_outcomes.js b/WNPRC_EHR/resources/queries/study/pregnancy_outcomes.js new file mode 100644 index 000000000..6f9f95e1e --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/pregnancy_outcomes.js @@ -0,0 +1,12 @@ +require("ehr/triggers").initScript(this); + +function onInsert(helper, scriptErrors, row, oldRow){ + + + if (row && row.Id){ + row.protected = !!row.protected; + row.rejected = !!row.rejected; + //row.QCState = EHR.Server.Security.getQCStateByLabel('Completed').RowId; + row.QCStateLabel = EHR.Server.Security.getQCStateByLabel('Completed').Label; + } +} \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/pregnancy_outcomes.query.xml b/WNPRC_EHR/resources/queries/study/pregnancy_outcomes.query.xml new file mode 100644 index 000000000..2607c46f8 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/pregnancy_outcomes.query.xml @@ -0,0 +1,46 @@ + + + + + + + + + Outcome + + ehr_lookups + birth_type + value + description + + false + + + Delivery Date + + + Pregnancy (Conc. Date) + + study + pregnancies + lsid + date_conception + + false + + + + + + Offered To + + + + false + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Prenatal Deaths/.qview.xml b/WNPRC_EHR/resources/queries/study/prenatal/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Prenatal Deaths/.qview.xml rename to WNPRC_EHR/resources/queries/study/prenatal/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Problem List/.qview.xml b/WNPRC_EHR/resources/queries/study/problem/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Problem List/.qview.xml rename to WNPRC_EHR/resources/queries/study/problem/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Problem List/Unresolved Problems.qview.xml b/WNPRC_EHR/resources/queries/study/problem/Unresolved Problems.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Problem List/Unresolved Problems.qview.xml rename to WNPRC_EHR/resources/queries/study/problem/Unresolved Problems.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Procedure Codes/.qview.xml b/WNPRC_EHR/resources/queries/study/procedures/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Procedure Codes/.qview.xml rename to WNPRC_EHR/resources/queries/study/procedures/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/TB Tests/.qview.xml b/WNPRC_EHR/resources/queries/study/tb/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/TB Tests/.qview.xml rename to WNPRC_EHR/resources/queries/study/tb/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Tissue Requests/.qview.xml b/WNPRC_EHR/resources/queries/study/tissue_requests/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Tissue Requests/.qview.xml rename to WNPRC_EHR/resources/queries/study/tissue_requests/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Tissue Samples/.qview.xml b/WNPRC_EHR/resources/queries/study/tissue_samples/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Tissue Samples/.qview.xml rename to WNPRC_EHR/resources/queries/study/tissue_samples/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/totalResearchAssignmentsDuringRange.query.xml b/WNPRC_EHR/resources/queries/study/totalResearchAssignmentsDuringRange.query.xml new file mode 100644 index 000000000..2b5e144fe --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/totalResearchAssignmentsDuringRange.query.xml @@ -0,0 +1,9 @@ + + + + + Animals Assigned to Research Projects During Given Date Range +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/totalResearchAssignmentsDuringRange.sql b/WNPRC_EHR/resources/queries/study/totalResearchAssignmentsDuringRange.sql new file mode 100644 index 000000000..17567c2af --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/totalResearchAssignmentsDuringRange.sql @@ -0,0 +1,13 @@ +PARAMETERS + (START_DATE TIMESTAMP, END_DATE TIMESTAMP) + +SELECT id + , GROUP_CONCAT(project, ', ') as Projects + , GROUP_CONCAT(date, ', ') as AssignmentDates + , GROUP_CONCAT(enddate, ', ') as ReleaseDates + , GROUP_CONCAT(project.avail, ', ') as ProjectAvails +FROM study.assignment +WHERE date <= END_DATE + AND (enddate >= START_DATE OR enddate IS NULL) + AND (project.avail = 'r') +GROUP BY id; \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Treatment Orders/.qview.xml b/WNPRC_EHR/resources/queries/study/treatment_order/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Treatment Orders/.qview.xml rename to WNPRC_EHR/resources/queries/study/treatment_order/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Treatment Orders/Active Treatments.qview.xml b/WNPRC_EHR/resources/queries/study/treatment_order/Active Treatments.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Treatment Orders/Active Treatments.qview.xml rename to WNPRC_EHR/resources/queries/study/treatment_order/Active Treatments.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/ultrasounds.js b/WNPRC_EHR/resources/queries/study/ultrasounds.js new file mode 100644 index 000000000..d1a994070 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/ultrasounds.js @@ -0,0 +1,94 @@ +var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; +require("ehr/triggers").initScript(this); + +function onInsert(helper, scriptErrors, row, oldRow){ + if (row && row.Id){ + WNPRC.Utils.getJavaHelper().updateUltrasoundFollowup(row.Id, row.date); + + //row.QCState = EHR.Server.Security.getQCStateByLabel('Completed').RowId; + row.QCStateLabel = EHR.Server.Security.getQCStateByLabel('Completed').Label; + } +} + +function onUpsert(helper, scriptErrors, row, oldRow){ + if (row && row.Id){ + row.followup_required = !!row.followup_required; + row.fetal_heartbeat = !!row.fetal_heartbeat; + + let gestation_fields = ['gest_sac_mm', 'crown_rump_mm', 'biparietal_diameter_mm', 'femur_length_mm']; + + EHR.Server.Utils.findDemographics({ + participant: row.Id, + helper: helper, + scope: this, + callback: function (demographics) { + if (demographics) { + if (demographics['species']) { + let species = demographics['species']; + + gestation_fields.forEach(function(gestationField) { + LABKEY.Query.selectRows({ + schemaName: 'wnprc', + queryName: 'getGestationalDay', + parameters: { + SPECIES: species, + SEARCH_COLUMN_NAME: gestationField, + SEARCH_VALUE: row[gestationField] + }, + success: function(data){ + let gestationDayField = gestationField.slice(0, -3) + '_gest_day'; + if(data && data.rows && data.rows.length){ + row[gestationDayField] = data.rows[0].gestational_day; + } else { + row[gestationDayField] = null; + } + }, + failure: EHR.Server.Utils.onFailure + }); + }); + } + } + } + }); + } +} + +function setDescription(row, helper){ + var description = []; + + description.push('Type: Imaging'); + if(row.reason) { + description.push('Date: ' + row.date); + } + if(row.fetal_heartbeat) { + description.push('Fetal HB: ' + (!!row.beats_per_minute ? row.beats_per_minute : 'true')); + } else { + description.push('Fetal HB: false'); + } + if (row.gest_sac_mm) { + description.push('Gestational Sac (mm): ' + Number(row.gest_sac_mm.toFixed(2))); + } + if(row.crown_rump_mm) { + description.push('Crown Rump (mm): ' + Number(row.crown_rump_mm.toFixed(2))); + } + if (row.biparietal_diameter_mm) { + description.push('Biparietal Diameter (mm): ' + Number(row.biparietal_diameter_mm.toFixed(2))); + } + if (row.femur_length_mm) { + description.push('Femur Length (mm): ' + Number(row.femur_length_mm.toFixed(2))); + } + if (row.yolk_sac_diameter_mm) { + description.push('Yolk Sac Diameter (mm): ' + Number(row.yolk_sac_diameter_mm.toFixed(2))); + } + if (row.head_circumference_mm) { + description.push('Head Circumference (mm): ' + Number(row.head_circumference_mm.toFixed(2))); + } + if (row.followup_required) { + description.push('Followup Required: ' + row.followup_required); + } + if (row.performedby) { + description.push('Performed By: ' + row.performedby); + } + + return description; +} \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/ultrasounds.query.xml b/WNPRC_EHR/resources/queries/study/ultrasounds.query.xml new file mode 100644 index 000000000..ea4b7de0e --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/ultrasounds.query.xml @@ -0,0 +1,51 @@ + + + + + + + + + + Pregnancy (Conc. Date) + + study + pregnancyConceptionDate + lsid + date_conception + + yyyy-MM-dd + + + + + + + + + + + + + + + + + SNOMED + + ehr_lookups + snomed + code + + + + + false + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/Urinalysis Results/.qview.xml b/WNPRC_EHR/resources/queries/study/urinalysisResults/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Urinalysis Results/.qview.xml rename to WNPRC_EHR/resources/queries/study/urinalysisResults/.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Urinalysis Results/Plus Ref Range.qview.xml b/WNPRC_EHR/resources/queries/study/urinalysisResults/Plus Ref Range.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Urinalysis Results/Plus Ref Range.qview.xml rename to WNPRC_EHR/resources/queries/study/urinalysisResults/Plus Ref Range.qview.xml diff --git a/WNPRC_EHR/resources/queries/study/Virology Results/.qview.xml b/WNPRC_EHR/resources/queries/study/virologyResults/.qview.xml similarity index 100% rename from WNPRC_EHR/resources/queries/study/Virology Results/.qview.xml rename to WNPRC_EHR/resources/queries/study/virologyResults/.qview.xml diff --git a/WNPRC_EHR/resources/queries/viral_load_assay/source_material.query.xml b/WNPRC_EHR/resources/queries/viral_load_assay/source_material.query.xml new file mode 100644 index 000000000..6411e8aa1 --- /dev/null +++ b/WNPRC_EHR/resources/queries/viral_load_assay/source_material.query.xml @@ -0,0 +1,17 @@ + + + + + + + Units + + org.labkey.wnprc_ehr.query.ViralLoadUnitsDisplayColumnFactory + + + +
    +
    +
    +
    + diff --git a/WNPRC_EHR/resources/queries/wnprc/BCTreatments.sql b/WNPRC_EHR/resources/queries/wnprc/BCTreatments.sql index dfce3acc3..961d11ddb 100644 --- a/WNPRC_EHR/resources/queries/wnprc/BCTreatments.sql +++ b/WNPRC_EHR/resources/queries/wnprc/BCTreatments.sql @@ -15,7 +15,7 @@ code.meaning as treatment, meaning as shortName, qualifier, route.meaning as route, -remark +remark, volume, vol_units as volumeUnits, @@ -30,7 +30,7 @@ date as startdate, enddate, project, project.account as account, -code as treatmentCode, +code as treatmentCode FROM study.treatment_order treatments diff --git a/WNPRC_EHR/resources/queries/wnprc/BreedingReasonOptions.sql b/WNPRC_EHR/resources/queries/wnprc/BreedingReasonOptions.sql new file mode 100644 index 000000000..0c00707f8 --- /dev/null +++ b/WNPRC_EHR/resources/queries/wnprc/BreedingReasonOptions.sql @@ -0,0 +1,6 @@ +SELECT '(Breeding Colony)' AS Name +UNION ALL +SELECT Name +FROM (SELECT DISTINCT inves AS Name + FROM ehr.protocol + ORDER BY inves ASC) _a \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/wnprc/animal_requests.js b/WNPRC_EHR/resources/queries/wnprc/animal_requests.js new file mode 100644 index 000000000..82f830559 --- /dev/null +++ b/WNPRC_EHR/resources/queries/wnprc/animal_requests.js @@ -0,0 +1,36 @@ +//Uses java helper to fire email notification when request is submitted + +var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; +var console = require("console"); +var LABKEY = require("labkey"); + +var exports = {}; + +function onInit(event, helper){ + helper.registerRowProcessor(function(helper, row) { + if (!row) + return; + }) +} + +function beforeInsert(row, errors){ + if (this.extraContext.targetQC) { + row.QCStateLabel = this.extraContext.targetQC; + } +} + +function beforeUpdate(row, oldRow, errors){ + +} + +function onComplete(event,errors, helper) { + +} + +function afterInsert(row, errors){ + var rowid = row.rowId; + var hostName = 'https://' + LABKEY.serverName; + console.log ("animal_requests.js: New request submitted, rowid: "+ rowid); + WNPRC.Utils.getJavaHelper().sendAnimalRequestNotification(rowid, hostName); +} + diff --git a/WNPRC_EHR/resources/queries/wnprc/animal_requests.query.xml b/WNPRC_EHR/resources/queries/wnprc/animal_requests.query.xml new file mode 100644 index 000000000..05aaf4bc1 --- /dev/null +++ b/WNPRC_EHR/resources/queries/wnprc/animal_requests.query.xml @@ -0,0 +1,107 @@ + + + + + Animal Requests + + + + Date Requested + yyyy-MM-dd hh:mm + + + Create By + + + Principal Investigator + + ehr + uniqueProtocolInvestigator + inves + inves + + + + + Origin + ehr_lookups + geographic_origins + meaning + Origin + + + + Species + + ehr_lookups + animal_requests_species + value + Species + + + + # of Animals + + + Date Needed + yyyy-MM-dd + + + Status + + study + qcstate + rowid + + + + Infectious Disease + + + Viral Status + + + Date Approved / Denied + + + Date Ordered + + + Date Arrival + + + Animal Origin + + + + + ehr.context + ehr/studyButtons.js + EHR.DatasetButtons.moreActionsHandler + + Grid Views + + + Export + + + Print + + + + + EHR.DatasetButtons.historyHandler(dataRegion, dataRegionName, 'Assignment'); + + + + + EHR.window.GetDistinctWindow.getDistinctHandler(dataRegionName, 'Assignment'); + + + + +
    +
    +
    +
    + diff --git a/WNPRC_EHR/resources/queries/wnprc/animal_requests/Animal Requests.qview.xml b/WNPRC_EHR/resources/queries/wnprc/animal_requests/Animal Requests.qview.xml new file mode 100644 index 000000000..c282fd767 --- /dev/null +++ b/WNPRC_EHR/resources/queries/wnprc/animal_requests/Animal Requests.qview.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/wnprc/getGestationalDay.sql b/WNPRC_EHR/resources/queries/wnprc/getGestationalDay.sql new file mode 100644 index 000000000..46f3c6770 --- /dev/null +++ b/WNPRC_EHR/resources/queries/wnprc/getGestationalDay.sql @@ -0,0 +1,29 @@ +PARAMETERS ( SPECIES VARCHAR, SEARCH_COLUMN_NAME VARCHAR, SEARCH_VALUE FLOAT ) + +SELECT gestational_day +FROM wnprc.gestational_days a +WHERE a.species = SPECIES AND EXISTS(SELECT 1 + FROM wnprc.gestational_days b + WHERE b.species = SPECIES AND (CASE + WHEN SEARCH_COLUMN_NAME = 'gest_sac_mm' + THEN (abs(SEARCH_VALUE - b.gest_sac_mm) <= 1.3) + WHEN SEARCH_COLUMN_NAME = 'crown_rump_mm' + THEN (abs(SEARCH_VALUE - b.crown_rump_mm) <= 2.8) + WHEN SEARCH_COLUMN_NAME = 'biparietal_diameter_mm' + THEN (abs(SEARCH_VALUE - b.biparietal_diameter_mm) <= 1.5) + WHEN SEARCH_COLUMN_NAME = 'femur_length_mm' + THEN (abs(SEARCH_VALUE - b.femur_length_mm) <= 1.5) + ELSE FALSE + END)) +ORDER BY + CASE + WHEN SEARCH_COLUMN_NAME = 'gest_sac_mm' + THEN abs(SEARCH_VALUE - a.gest_sac_mm) + WHEN SEARCH_COLUMN_NAME = 'crown_rump_mm' + THEN abs(SEARCH_VALUE - a.crown_rump_mm) + WHEN SEARCH_COLUMN_NAME = 'biparietal_diameter_mm' + THEN abs(SEARCH_VALUE - a.biparietal_diameter_mm) + WHEN SEARCH_COLUMN_NAME = 'femur_length_mm' + THEN abs(SEARCH_VALUE - a.femur_length_mm) + END ASC +LIMIT 1 \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/wnprc/getGestationalSpecies.sql b/WNPRC_EHR/resources/queries/wnprc/getGestationalSpecies.sql new file mode 100644 index 000000000..c9159f86f --- /dev/null +++ b/WNPRC_EHR/resources/queries/wnprc/getGestationalSpecies.sql @@ -0,0 +1,2 @@ +SELECT DISTINCT species +FROM wnprc.gestational_days \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/wnprc/vvc.js b/WNPRC_EHR/resources/queries/wnprc/vvc.js index a5e7a6ffd..cb8779642 100644 --- a/WNPRC_EHR/resources/queries/wnprc/vvc.js +++ b/WNPRC_EHR/resources/queries/wnprc/vvc.js @@ -115,8 +115,9 @@ function afterInsert(row, errors){ if (row.QCStateLabel == "Request: Pending" && row.requestId){ var requestid = row.requestId; + var hostName = 'https://' + LABKEY.serverName; console.log ("new request submitted "+ requestid); - WNPRC.Utils.getJavaHelper().sendVvcNotification(requestid); + WNPRC.Utils.getJavaHelper().sendVvcNotification(requestid, hostName); } diff --git a/WNPRC_EHR/resources/queries/wnprc/vvc.query.xml b/WNPRC_EHR/resources/queries/wnprc/vvc.query.xml index f1a778ffc..625e08da1 100644 --- a/WNPRC_EHR/resources/queries/wnprc/vvc.query.xml +++ b/WNPRC_EHR/resources/queries/wnprc/vvc.query.xml @@ -72,9 +72,6 @@ Import Data - - Paging - Delete @@ -89,6 +86,16 @@ EHR.window.GetDistinctWindow.getDistinctHandler(dataRegionName, 'Assignment'); + + + WNPRC_EHR.DatasetButtons.markReviewedButtonHandler(dataRegion); + + + + + WNPRC_EHR.DatasetButtons.approveVVCButtonHandler(dataRegion); + + diff --git a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml index 98bf0348a..a376a610d 100644 --- a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml +++ b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml @@ -5,7 +5,7 @@ - + diff --git a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml index 7a288eb81..4b08ccb6f 100644 --- a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml +++ b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml @@ -2,14 +2,14 @@ - + varchar http://cpas.labkey.com/Study#ParticipantId false study animal - id + Id @@ -21,22 +21,12 @@ timestamp http://cpas.labkey.com/Study#VisitDate - - - varchar - urn:ehr.labkey.org/#RequestId - - - varchar - urn:ehr.labkey.org/#TaskId + false varchar urn:ehr.labkey.org/#PerformedBy - - - varchar - urn:ehr.labkey.org/#Description + false varchar @@ -47,56 +37,152 @@ objectid - - taskid - Breeding EncountersContains one row for each breeding pairing/assignment for a dam at the center. - - End Date + + End Time timestamp - Sire + Male varchar /ehr/participantView.view?participantId=${sire_id} study animal - id + Id + false - - Reason - varchar + + Ejaculation Confirmed? + boolean - - Est. Conception Date - timestamp + + Project + integer + urn:ehr.labkey.org/#Project + + ehr + project + project + - - Ejaculation Confirmed - varchar + + Resulted In Pregnancy + boolean + + + sireid + + + ejaculation + + + project + +
    - - Breeding Remarks - Contains one row for each observation/remark about a breeding encounter. - +
    + Pregnancies + Contains one row for each pregnancy at the center. + + + Sire + varchar + /ehr/participantView.view?participantId=${sire_id} + + study + animal + Id + + + + Breeding Encounter + entityid + + study + breeding_encounters + lsid + sireid + + + + Earliest Est. Conception Date + date + y-M-d + + + Latest Est. Conception Date + date + y-M-d + + + Estimated Date of Conception + date + y-M-d + false + + + Earliest Est. Due Date + date + y-M-d + + + Latest Est. Due Date + date + y-M-d + + + Estimated Due Date + date + y-M-d + false + + + + + sireid + + + date_conception + + + date_due + +
    Pregnancy OutcomesContains one row for the outcome of each pregnancy completed/terminated at the center. + + Pregnancy (Conc. Date) + entityid + + study + pregnancies + lsid + date_conception + + false + Outcome varchar false + + ehr_lookups + birth_type + value + description + Infant @@ -105,14 +191,147 @@ study animal - id + Id + + + + Rejected by Mother + boolean + + + Protected + boolean + + + Offered To + integer + urn:ehr.labkey.org/#Project + + ehr + project + project + + + pregnancyid + + + outcome + + + project + +
    UltrasoundsContains one row for each ultrasound performed at the center. - + + + Pregnancy (Conc. Date) + entityid + + study + pregnancies + lsid + date_conception + + + + Project + integer + urn:ehr.labkey.org/#Project + + ehr + project + project + + + + Restraint + varchar + + ehr_lookups + restraint_type + type + + + + + Fetal HB + boolean + + + BPM + integer + + + Gestational Sac (mm) + float + + + Crown Rump (mm) + float + + + Biparietal Diameter (mm) + float + + + Femur Length (mm) + float + + + Yolk Sac Diameter (mm) + float + + + Head Circ (mm) + float + + + Gest Sac GD + Estimated gestation day based on femur length + integer + + + Crown Rump GD + Estimated gestation day based on crown rump + integer + + + Biparietal GD + Estimated gestation day based on biparietal diameter + integer + + + Femur Length GD + Estimated gestation day based on femur length + integer + + + Code + varchar + + ehr_lookups + snomed + code + + + + Followup Required + Indicates whether or not a followup ultrasound is required + boolean + + + + + pregnancyid + + + project + +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.10-18.11.sql b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.10-18.11.sql new file mode 100644 index 000000000..578c074ba --- /dev/null +++ b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.10-18.11.sql @@ -0,0 +1,306 @@ +DROP TABLE IF EXISTS wnprc.gestational_days; +CREATE TABLE wnprc.gestational_days ( + rowid serial NOT NULL, + species VARCHAR(50), + gestational_day INTEGER, + gest_sac_mm FLOAT8, + crown_rump_mm FLOAT8, + biparietal_diameter_mm FLOAT8, + femur_length_mm FLOAT8, + + CONSTRAINT PK_species PRIMARY KEY (species, gestational_day) +); + +INSERT INTO wnprc.gestational_days (species, gestational_day, gest_sac_mm, crown_rump_mm, biparietal_diameter_mm, femur_length_mm) +VALUES ('Rhesus',15,1.4,NULL,NULL,NULL), + ('Rhesus',16,2.7,NULL,NULL,NULL), + ('Rhesus',17,3.9,NULL,NULL,NULL), + ('Rhesus',18,5.1,NULL,NULL,NULL), + ('Rhesus',19,6.3,NULL,NULL,NULL), + ('Rhesus',20,7.5,NULL,NULL,NULL), + ('Rhesus',21,8.7,2.9,NULL,NULL), + ('Rhesus',22,10,3.3,NULL,NULL), + ('Rhesus',23,11.2,3.8,NULL,NULL), + ('Rhesus',24,12.3,4.3,NULL,NULL), + ('Rhesus',25,13.5,4.9,NULL,NULL), + ('Rhesus',26,14.7,5.5,NULL,NULL), + ('Rhesus',27,15.9,6.2,NULL,NULL), + ('Rhesus',28,17.1,6.9,NULL,NULL), + ('Rhesus',29,18.3,7.7,NULL,NULL), + ('Rhesus',30,19.4,8.5,NULL,NULL), + ('Rhesus',31,20.6,9.4,NULL,NULL), + ('Rhesus',32,21.7,10.3,NULL,NULL), + ('Rhesus',33,22.9,11.3,NULL,NULL), + ('Rhesus',34,24,12.3,NULL,NULL), + ('Rhesus',35,25.1,13.4,NULL,NULL), + ('Rhesus',36,26.2,14.5,NULL,NULL), + ('Rhesus',37,27.4,15.7,NULL,NULL), + ('Rhesus',38,28.7,16.9,NULL,NULL), + ('Rhesus',39,29.6,18.2,NULL,NULL), + ('Rhesus',40,30.7,19.5,NULL,NULL), + ('Rhesus',41,31.7,20.9,NULL,NULL), + ('Rhesus',42,32.8,22.4,NULL,NULL), + ('Rhesus',43,33.9,23.9,NULL,NULL), + ('Rhesus',44,34.9,25.5,NULL,NULL), + ('Rhesus',45,36,27.1,NULL,NULL), + ('Rhesus',46,37,28.8,NULL,NULL), + ('Rhesus',47,38,30.5,10.9,NULL), + ('Rhesus',48,39,32.3,11.44,NULL), + ('Rhesus',49,40.1,34.2,11.97,NULL), + ('Rhesus',50,41.1,36.1,12.5,2.61), + ('Rhesus',51,NULL,38.1,13.03,3), + ('Rhesus',52,NULL,40.1,13.56,3.4), + ('Rhesus',53,NULL,42.2,14.09,3.79), + ('Rhesus',54,NULL,44.4,14.61,4.19), + ('Rhesus',55,NULL,46.7,15.13,4.6), + ('Rhesus',56,NULL,49,15.64,5), + ('Rhesus',57,NULL,51.3,16.16,5.41), + ('Rhesus',58,NULL,53.8,16.67,5.82), + ('Rhesus',59,NULL,56.3,17.18,6.23), + ('Rhesus',60,NULL,58.8,17.68,6.64), + ('Rhesus',61,NULL,NULL,18.19,7.06), + ('Rhesus',62,NULL,NULL,18.69,7.47), + ('Rhesus',63,NULL,NULL,19.18,7.89), + ('Rhesus',64,NULL,NULL,19.68,8.31), + ('Rhesus',65,NULL,NULL,20.17,8.73), + ('Rhesus',66,NULL,NULL,20.66,9.15), + ('Rhesus',67,NULL,NULL,21.13,9.58), + ('Rhesus',68,NULL,NULL,21.62,10), + ('Rhesus',69,NULL,NULL,22.1,10.43), + ('Rhesus',70,NULL,NULL,22.58,10.85), + ('Rhesus',71,NULL,NULL,23.05,11.28), + ('Rhesus',72,NULL,NULL,23.52,11.71), + ('Rhesus',73,NULL,NULL,23.98,12.14), + ('Rhesus',74,NULL,NULL,24.44,12.57), + ('Rhesus',75,NULL,NULL,24.9,13), + ('Rhesus',76,NULL,NULL,25.36,13.43), + ('Rhesus',77,NULL,NULL,25.81,13.87), + ('Rhesus',78,NULL,NULL,26.26,14.3), + ('Rhesus',79,NULL,NULL,26.7,14.73), + ('Rhesus',80,NULL,NULL,27.15,15.16), + ('Rhesus',81,NULL,NULL,27.58,15.59), + ('Rhesus',82,NULL,NULL,28.02,16.03), + ('Rhesus',83,NULL,NULL,28.45,16.46), + ('Rhesus',84,NULL,NULL,28.88,16.89), + ('Rhesus',85,NULL,NULL,29.3,17.32), + ('Rhesus',86,NULL,NULL,29.72,17.76), + ('Rhesus',87,NULL,NULL,30.14,18.19), + ('Rhesus',88,NULL,NULL,30.55,18.62), + ('Rhesus',89,NULL,NULL,30.96,19.05), + ('Rhesus',90,NULL,NULL,31.36,19.48), + ('Rhesus',91,NULL,NULL,31.76,19.91), + ('Rhesus',92,NULL,NULL,32.16,20.33), + ('Rhesus',93,NULL,NULL,32.55,20.76), + ('Rhesus',94,NULL,NULL,32.94,21.19), + ('Rhesus',95,NULL,NULL,33.33,21.61), + ('Rhesus',96,NULL,NULL,33.71,22.04), + ('Rhesus',97,NULL,NULL,34.09,22.46), + ('Rhesus',98,NULL,NULL,34.46,22.88), + ('Rhesus',99,NULL,NULL,34.83,23.3), + ('Rhesus',100,NULL,NULL,35.19,23.72), + ('Rhesus',101,NULL,NULL,35.55,24.13), + ('Rhesus',102,NULL,NULL,35.91,24.55), + ('Rhesus',103,NULL,NULL,36.26,24.96), + ('Rhesus',104,NULL,NULL,36.61,25.37), + ('Rhesus',105,NULL,NULL,36.95,25.78), + ('Rhesus',106,NULL,NULL,37.29,26.19), + ('Rhesus',107,NULL,NULL,37.63,26.6), + ('Rhesus',108,NULL,NULL,37.96,27), + ('Rhesus',109,NULL,NULL,38.28,27.4), + ('Rhesus',110,NULL,NULL,38.6,27.8), + ('Rhesus',111,NULL,NULL,38.92,28.2), + ('Rhesus',112,NULL,NULL,39.23,28.59), + ('Rhesus',113,NULL,NULL,39.54,28.98), + ('Rhesus',114,NULL,NULL,39.84,29.37), + ('Rhesus',115,NULL,NULL,40.14,29.75), + ('Rhesus',116,NULL,NULL,40.44,30.14), + ('Rhesus',117,NULL,NULL,40.72,30.52), + ('Rhesus',118,NULL,NULL,41.01,30.89), + ('Rhesus',119,NULL,NULL,41.29,31.27), + ('Rhesus',120,NULL,NULL,41.56,31.64), + ('Rhesus',121,NULL,NULL,41.83,32), + ('Rhesus',122,NULL,NULL,42.1,32.37), + ('Rhesus',123,NULL,NULL,42.36,32.73), + ('Rhesus',124,NULL,NULL,42.61,33.09), + ('Rhesus',125,NULL,NULL,42.86,33.44), + ('Rhesus',126,NULL,NULL,43.11,33.79), + ('Rhesus',127,NULL,NULL,43.35,34.13), + ('Rhesus',128,NULL,NULL,43.58,34.48), + ('Rhesus',129,NULL,NULL,43.81,34.81), + ('Rhesus',130,NULL,NULL,44.03,35.15), + ('Rhesus',131,NULL,NULL,44.25,35.48), + ('Rhesus',132,NULL,NULL,44.47,35.8), + ('Rhesus',133,NULL,NULL,44.68,36.13), + ('Rhesus',134,NULL,NULL,44.88,36.44), + ('Rhesus',135,NULL,NULL,45.08,36.76), + ('Rhesus',136,NULL,NULL,45.27,37.06), + ('Rhesus',137,NULL,NULL,45.46,37.37), + ('Rhesus',138,NULL,NULL,45.64,37.66), + ('Rhesus',139,NULL,NULL,45.82,37.96), + ('Rhesus',140,NULL,NULL,45.99,38.25), + ('Rhesus',141,NULL,NULL,46.15,38.53), + ('Rhesus',142,NULL,NULL,46.31,38.81), + ('Rhesus',143,NULL,NULL,46.47,39.08), + ('Rhesus',144,NULL,NULL,46.62,39.35), + ('Rhesus',145,NULL,NULL,46.76,39.62), + ('Rhesus',146,NULL,NULL,46.9,39.87), + ('Rhesus',147,NULL,NULL,47.03,40.13), + ('Rhesus',148,NULL,NULL,47.16,40.37), + ('Rhesus',149,NULL,NULL,47.28,40.62), + ('Rhesus',150,NULL,NULL,47.39,40.85), + ('Rhesus',151,NULL,NULL,47.5,41.08), + ('Rhesus',152,NULL,NULL,47.6,41.3), + ('Rhesus',153,NULL,NULL,47.7,41.52), + ('Rhesus',154,NULL,NULL,47.79,41.73), + ('Rhesus',155,NULL,NULL,47.87,41.94), + ('Rhesus',156,NULL,NULL,47.95,42.14), + ('Rhesus',157,NULL,NULL,48.03,42.33), + ('Rhesus',158,NULL,NULL,48.09,42.52), + ('Rhesus',159,NULL,NULL,48.15,42.7), + ('Rhesus',160,NULL,NULL,48.21,42.87), + ('Rhesus',161,NULL,NULL,48.26,43.04), + ('Rhesus',162,NULL,NULL,48.3,43.2), + ('Rhesus',163,NULL,NULL,48.33,43.36), + ('Rhesus',164,NULL,NULL,48.36,43.5), + ('Rhesus',165,NULL,NULL,48.39,43.64), + ('Cynomolgus',15,1.4,NULL,NULL,NULL), + ('Cynomolgus',16,2.7,NULL,NULL,NULL), + ('Cynomolgus',17,3.9,NULL,NULL,NULL), + ('Cynomolgus',18,5.1,NULL,NULL,NULL), + ('Cynomolgus',19,6.3,NULL,NULL,NULL), + ('Cynomolgus',20,7.5,NULL,NULL,NULL), + ('Cynomolgus',21,8.7,2.9,NULL,NULL), + ('Cynomolgus',22,10,3.3,NULL,NULL), + ('Cynomolgus',23,11.2,3.8,NULL,NULL), + ('Cynomolgus',24,12.3,4.3,NULL,NULL), + ('Cynomolgus',25,13.5,4.9,NULL,NULL), + ('Cynomolgus',26,14.7,5.5,NULL,NULL), + ('Cynomolgus',27,15.9,6.2,NULL,NULL), + ('Cynomolgus',28,17.1,6.9,NULL,NULL), + ('Cynomolgus',29,18.3,7.7,NULL,NULL), + ('Cynomolgus',30,19.4,8.5,NULL,NULL), + ('Cynomolgus',31,20.6,9.4,NULL,NULL), + ('Cynomolgus',32,21.7,10.3,NULL,NULL), + ('Cynomolgus',33,22.9,11.3,NULL,NULL), + ('Cynomolgus',34,24,12.3,NULL,NULL), + ('Cynomolgus',35,25.1,13.4,NULL,NULL), + ('Cynomolgus',36,26.2,14.5,NULL,NULL), + ('Cynomolgus',37,27.4,15.7,NULL,NULL), + ('Cynomolgus',38,28.7,16.9,NULL,NULL), + ('Cynomolgus',39,29.6,18.2,NULL,NULL), + ('Cynomolgus',40,30.7,19.5,NULL,NULL), + ('Cynomolgus',41,31.7,20.9,NULL,NULL), + ('Cynomolgus',42,32.8,22.4,NULL,NULL), + ('Cynomolgus',43,33.9,23.9,NULL,NULL), + ('Cynomolgus',44,34.9,25.5,NULL,NULL), + ('Cynomolgus',45,36,27.1,NULL,NULL), + ('Cynomolgus',46,37,28.8,NULL,NULL), + ('Cynomolgus',47,38,30.5,10.91,NULL), + ('Cynomolgus',48,39,32.3,11.44,NULL), + ('Cynomolgus',49,40.1,34.2,11.96,NULL), + ('Cynomolgus',50,41.1,36.1,12.48,2.84), + ('Cynomolgus',51,NULL,38.1,13,3.27), + ('Cynomolgus',52,NULL,40.1,13.51,3.7), + ('Cynomolgus',53,NULL,42.2,14.02,4.13), + ('Cynomolgus',54,NULL,44.4,14.53,4.56), + ('Cynomolgus',55,NULL,46.7,15.03,4.99), + ('Cynomolgus',56,NULL,49,15.54,5.42), + ('Cynomolgus',57,NULL,51.3,16.03,5.84), + ('Cynomolgus',58,NULL,53.8,16.53,6.27), + ('Cynomolgus',59,NULL,56.3,17.02,6.69), + ('Cynomolgus',60,NULL,58.8,17.51,7.12), + ('Cynomolgus',61,NULL,NULL,18,7.54), + ('Cynomolgus',62,NULL,NULL,18.48,7.96), + ('Cynomolgus',63,NULL,NULL,18.96,8.38), + ('Cynomolgus',64,NULL,NULL,19.44,8.8), + ('Cynomolgus',65,NULL,NULL,19.91,9.22), + ('Cynomolgus',66,NULL,NULL,20.38,9.63), + ('Cynomolgus',67,NULL,NULL,20.85,10.05), + ('Cynomolgus',68,NULL,NULL,21.31,10.46), + ('Cynomolgus',69,NULL,NULL,21.77,10.88), + ('Cynomolgus',70,NULL,NULL,22.23,11.29), + ('Cynomolgus',71,NULL,NULL,22.68,11.7), + ('Cynomolgus',72,NULL,NULL,23.13,12.11), + ('Cynomolgus',73,NULL,NULL,23.58,12.52), + ('Cynomolgus',74,NULL,NULL,24.02,12.92), + ('Cynomolgus',75,NULL,NULL,24.46,13.33), + ('Cynomolgus',76,NULL,NULL,24.89,13.73), + ('Cynomolgus',77,NULL,NULL,25.32,14.13), + ('Cynomolgus',78,NULL,NULL,25.75,14.53), + ('Cynomolgus',79,NULL,NULL,26.17,14.93), + ('Cynomolgus',80,NULL,NULL,26.59,15.33), + ('Cynomolgus',81,NULL,NULL,27.01,15.73), + ('Cynomolgus',82,NULL,NULL,27.42,16.12), + ('Cynomolgus',83,NULL,NULL,27.83,16.52), + ('Cynomolgus',84,NULL,NULL,28.23,16.91), + ('Cynomolgus',85,NULL,NULL,28.64,17.3), + ('Cynomolgus',86,NULL,NULL,29.03,17.68), + ('Cynomolgus',87,NULL,NULL,29.42,18.07), + ('Cynomolgus',88,NULL,NULL,29.81,18.45), + ('Cynomolgus',89,NULL,NULL,30.2,18.84), + ('Cynomolgus',90,NULL,NULL,30.58,19.22), + ('Cynomolgus',91,NULL,NULL,30.95,19.6), + ('Cynomolgus',92,NULL,NULL,31.32,19.97), + ('Cynomolgus',93,NULL,NULL,31.69,20.35), + ('Cynomolgus',94,NULL,NULL,32.05,20.72), + ('Cynomolgus',95,NULL,NULL,32.41,21.09), + ('Cynomolgus',96,NULL,NULL,32.76,21.46), + ('Cynomolgus',97,NULL,NULL,33.11,21.83), + ('Cynomolgus',98,NULL,NULL,33.46,22.2), + ('Cynomolgus',99,NULL,NULL,33.8,22.56), + ('Cynomolgus',100,NULL,NULL,34.14,22.92), + ('Cynomolgus',101,NULL,NULL,34.47,23.28), + ('Cynomolgus',102,NULL,NULL,34.8,23.64), + ('Cynomolgus',103,NULL,NULL,35.12,23.99), + ('Cynomolgus',104,NULL,NULL,35.44,24.34), + ('Cynomolgus',105,NULL,NULL,35.75,24.7), + ('Cynomolgus',106,NULL,NULL,36.06,25.04), + ('Cynomolgus',107,NULL,NULL,36.36,25.39), + ('Cynomolgus',108,NULL,NULL,36.66,25.73), + ('Cynomolgus',109,NULL,NULL,36.96,26.07), + ('Cynomolgus',110,NULL,NULL,37.25,26.41), + ('Cynomolgus',111,NULL,NULL,37.53,26.75), + ('Cynomolgus',112,NULL,NULL,37.81,27.08), + ('Cynomolgus',113,NULL,NULL,38.08,27.42), + ('Cynomolgus',114,NULL,NULL,38.35,27.74), + ('Cynomolgus',115,NULL,NULL,38.62,28.07), + ('Cynomolgus',116,NULL,NULL,38.88,28.4), + ('Cynomolgus',117,NULL,NULL,39.13,28.72), + ('Cynomolgus',118,NULL,NULL,39.38,29.04), + ('Cynomolgus',119,NULL,NULL,39.63,29.35), + ('Cynomolgus',120,NULL,NULL,39.87,29.67), + ('Cynomolgus',121,NULL,NULL,40.1,29.98), + ('Cynomolgus',122,NULL,NULL,40.33,30.29), + ('Cynomolgus',123,NULL,NULL,40.55,30.59), + ('Cynomolgus',124,NULL,NULL,40.77,30.9), + ('Cynomolgus',125,NULL,NULL,40.98,31.19), + ('Cynomolgus',126,NULL,NULL,41.19,31.49), + ('Cynomolgus',127,NULL,NULL,41.39,31.79), + ('Cynomolgus',128,NULL,NULL,41.59,32.08), + ('Cynomolgus',129,NULL,NULL,41.78,32.37), + ('Cynomolgus',130,NULL,NULL,41.96,32.65), + ('Cynomolgus',131,NULL,NULL,42.14,32.94), + ('Cynomolgus',132,NULL,NULL,42.32,33.22), + ('Cynomolgus',133,NULL,NULL,42.49,33.49), + ('Cynomolgus',134,NULL,NULL,42.65,33.77), + ('Cynomolgus',135,NULL,NULL,42.81,34.04), + ('Cynomolgus',136,NULL,NULL,42.96,34.31), + ('Cynomolgus',137,NULL,NULL,43.1,34.57), + ('Cynomolgus',138,NULL,NULL,43.24,34.83), + ('Cynomolgus',139,NULL,NULL,43.38,35.09), + ('Cynomolgus',140,NULL,NULL,43.51,35.35), + ('Cynomolgus',141,NULL,NULL,43.63,35.6), + ('Cynomolgus',142,NULL,NULL,43.75,35.85), + ('Cynomolgus',143,NULL,NULL,43.86,36.1), + ('Cynomolgus',144,NULL,NULL,43.96,36.34), + ('Cynomolgus',145,NULL,NULL,44.06,36.58), + ('Cynomolgus',146,NULL,NULL,44.15,36.81), + ('Cynomolgus',147,NULL,NULL,44.24,37.05), + ('Cynomolgus',148,NULL,NULL,44.32,37.27), + ('Cynomolgus',149,NULL,NULL,44.39,37.5), + ('Cynomolgus',150,NULL,NULL,44.46,37.72), + ('Cynomolgus',151,NULL,NULL,44.52,37.94), + ('Cynomolgus',152,NULL,NULL,44.57,38.16), + ('Cynomolgus',153,NULL,NULL,44.62,38.37), + ('Cynomolgus',154,NULL,NULL,44.67,38.58), + ('Cynomolgus',155,NULL,NULL,44.7,38.78); \ No newline at end of file diff --git a/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.11-18.12.sql b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.11-18.12.sql new file mode 100644 index 000000000..a03c530fc --- /dev/null +++ b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.11-18.12.sql @@ -0,0 +1,68 @@ +DROP TABLE IF EXISTS wnprc.animal_requests; +CREATE TABLE wnprc.animal_requests( + rowid serial NOT NULL, + principalinvestigator varchar (100) NOT NULL, + date TIMESTAMP, + numberofanimals integer, + speciesneeded varchar (100) NOT NULL, /*new table?*/ + originneeded varchar (100) NOT NULL, + sex varchar (255) NOT NULL, /*new table?*/ + age varchar (100) NOT NULL, + weight varchar (255) NOT NULL, + mhctype varchar (255) NOT NULL, + disposition varchar (255) NOT NULL, + infectiousdisease varchar (255) NOT NULL, + viralstatus varchar(255), + dateneeded TIMESTAMP, + protocol varchar (100) NOT NULL, + project varchar (100), + account varchar (100), + comments TEXT, + requestid varchar(100), + taskid varchar(100), + QCState integer , + + -- Fields for after approval/denial + dateapprovedordenied TIMESTAMP, + dateordered TIMESTAMP, + datearrival TIMESTAMP, + animalsorigin TEXT, + + -- Default fields for LabKey. + container entityid NOT NULL, + createdby userid, + created TIMESTAMP, + modifiedby userid, + modified TIMESTAMP, + + CONSTRAINT pk_animal_requests PRIMARY KEY (rowid) + --CONSTRAINT fk_animal_requests_viral_status FOREIGN KEY (container,viralstatus) REFERENCES ehr_lookups.viral_status (container,rowid) + +); + + +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'SPF4' as value from ehr_lookups.lookup_sets where setname='viral_status'; +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'SPF5 (AAV-)' as value from ehr_lookups.lookup_sets where setname='viral_status'; +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'SPF5 (RRV-)' as value from ehr_lookups.lookup_sets where setname='viral_status'; + +insert into ehr_lookups.lookup_sets (setname,container) select 'animal_requests_sex' as setname, container from ehr_lookups.lookup_sets where setname='viral_status'; + +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'M' as value from ehr_lookups.lookup_sets where setname='animal_requests_sex'; +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'F' as value from ehr_lookups.lookup_sets where setname='animal_requests_sex'; +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'M or F' as value from ehr_lookups.lookup_sets where setname='animal_requests_sex'; +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'Equal # M & F' as value from ehr_lookups.lookup_sets where setname='animal_requests_sex'; + + +insert into ehr_lookups.lookup_sets (setname,container) select 'animal_requests_disposition' as setname, container from ehr_lookups.lookup_sets where setname='viral_status'; + +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'Terminal' as value from ehr_lookups.lookup_sets where setname='animal_requests_disposition'; +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'Return to Colony' as value from ehr_lookups.lookup_sets where setname='animal_requests_disposition'; + +insert into ehr_lookups.lookup_sets (setname,container) select 'animal_requests_infectiousdisease' as setname, container from ehr_lookups.lookup_sets where setname='viral_status'; + +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'Yes' as value from ehr_lookups.lookup_sets where setname='animal_requests_infectiousdisease'; +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'No' as value from ehr_lookups.lookup_sets where setname='animal_requests_infectiousdisease'; + +INSERT INTO ehr_lookups.geographic_origins (meaning, container) SELECT meaning, container FROM (SELECT 'laos' AS Meaning, MAX(Container) AS Container FROM ehr_lookups.geographic_origins WHERE (NOT EXISTS (SELECT meaning FROM ehr_lookups.geographic_origins WHERE meaning = 'laos'))) x WHERE Container IS NOT NULL ; + +INSERT INTO ehr_lookups.geographic_origins (meaning, container) SELECT meaning, container FROM (SELECT 'vietnam' AS Meaning, MAX(Container) AS Container FROM ehr_lookups.geographic_origins WHERE (NOT EXISTS (SELECT meaning FROM ehr_lookups.geographic_origins WHERE meaning = 'vietnam'))) x WHERE Container IS NOT NULL ; diff --git a/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.12-18.13.sql b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.12-18.13.sql new file mode 100644 index 000000000..a6fbba2bd --- /dev/null +++ b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.12-18.13.sql @@ -0,0 +1,12 @@ +insert into ehr_lookups.species (common, scientific_name, id_prefix, mhc_prefix, blood_per_kg, max_draw_pct, blood_draw_interval, container) + SELECT common, scientific_name, id_prefix, mhc_prefix, blood_per_kg, max_draw_pct, blood_draw_interval, container FROM + (SELECT + 'Macaque' AS common, + '' AS scientific_name, + '' as id_prefix, + '' as mhc_prefix, + 60.0 AS blood_per_kg, + 0.2 as max_draw_pct, + 30.0 as blood_draw_interval, + MAX(Container) as container FROM ehr_lookups.species) + x WHERE container IS NOT NULL; \ No newline at end of file diff --git a/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.13-18.14.sql b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.13-18.14.sql new file mode 100644 index 000000000..a1071aa98 --- /dev/null +++ b/WNPRC_EHR/resources/schemas/dbscripts/postgresql/wnprc-18.13-18.14.sql @@ -0,0 +1 @@ +insert into ehr_lookups.lookups (set_name,container,value) select setname, container, 'Planned death as a result of experimental procedure' as value from ehr_lookups.lookup_sets where setname='death_manner'; \ No newline at end of file diff --git a/WNPRC_EHR/resources/schemas/wnprc.xml b/WNPRC_EHR/resources/schemas/wnprc.xml index e779f7aec..ffdfb5004 100644 --- a/WNPRC_EHR/resources/schemas/wnprc.xml +++ b/WNPRC_EHR/resources/schemas/wnprc.xml @@ -1,63 +1,198 @@ - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    -
    \ No newline at end of file + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + Animal Requests + + + + false + true + + ehr + uniqueProtocolInvestigator + inves + + + + + false + true + + ehr_lookups + geographic_origin + meaning + + + + false + true + + ehr_lookups + species_codes + common_name + + + + + + + + false + true + + ehr_lookups + animal_requests_disposition + value + + + + false + true + + ehr_lookups + animal_requests_infectiousdisease + value + + + + + + false + true + + ehr_lookups + viral_status + value + + + + + false + true + + ehr + protocol + protocol + + + + false + true + + ehr + project + project + + + + + + false + true + + ehr + requests + rowid + + + + false + true + + ehr + tasks + rowid + + + + false + true + + study + QCState + RowId + + + + + + + + + + + + +
    + + + + + + + + + + +
    + diff --git a/WNPRC_EHR/resources/scripts/wnprc_ehr/lib/Validator.js b/WNPRC_EHR/resources/scripts/wnprc_ehr/lib/Validator.js index 768358cf7..e9e88e8ae 100644 --- a/WNPRC_EHR/resources/scripts/wnprc_ehr/lib/Validator.js +++ b/WNPRC_EHR/resources/scripts/wnprc_ehr/lib/Validator.js @@ -36,31 +36,57 @@ Validator.new = function(EHR, row, scriptErrors, helper) { value = row[fieldName]; } - logger.debug("Checking to see if " + value + " is a user..."); - LABKEY.Query.selectRows({ - schemaName: 'core', - queryName: 'users', - filterArray:[ - LABKEY.Filter.create(isDisplayName ? 'DisplayName' : 'UserId', value, LABKEY.Filter.Types.EQUAL) + schemaName: 'study', + queryName: 'necropsy', + filterArray: [ + LABKEY.Filter.create('objectid', row.objectid, LABKEY.Filter.Types.EQUAL) ], - success: function(data) { - if (data.rows && data.rows.length > 0) { - retVal = true; + success: function(results) { + let matches = false; + let users = results.rows && results.rows.length > 0 && results.rows[0][fieldName] ? results.rows[0][fieldName].split(',') : ''.split(','); + for (let i = 0; i < users.length; i++) { + if (users[i] === value) { + matches = true; + break; + } } - else { - var message = "\"" + value + "\" is not a user in EHR."; - if (!Ext.isDefined(severity)) { - severity = Validator.Severity.ERROR; - } - addToScriptErrors(fieldName, message, severity); + // if there is no existing necropsy record for this objectid (this is an insert), + // or if there is an existing record (it's an update) and the user doesn't match + // a user from the original record then check to make sure that the user is + // actually a current user in the system + if (!results.rows || results.rows.length === 0 || (results.rows && results.rows.length > 0 && !matches)) { + logger.debug("Checking to see if " + value + " is a user..."); + + LABKEY.Query.selectRows({ + schemaName: 'core', + queryName: 'users', + filterArray:[ + LABKEY.Filter.create(isDisplayName ? 'DisplayName' : 'UserId', value, LABKEY.Filter.Types.EQUAL) + ], + success: function(data) { + if (data.rows && data.rows.length > 0) { + retVal = true; + } + else { + var message = "\"" + value + "\" is not a user in EHR."; + + if (!Ext.isDefined(severity)) { + severity = Validator.Severity.ERROR; + } + addToScriptErrors(fieldName, message, severity); + } + } + }); + logger.debug(value + " is a " + (!retVal ? "not " : "") + "user..."); + } else { + retVal = true; + logger.debug('User \'' + value + '\' was already present in initial record for field \'' + fieldName + '\''); } } }); - logger.debug(value + " is a " + (!retVal ? "not " : "") + "user..."); - return retVal; }, @@ -72,22 +98,40 @@ Validator.new = function(EHR, row, scriptErrors, helper) { } LABKEY.Query.selectRows({ - schemaName: 'ehr_lookups', - queryName: 'pathologists', - filterArray:[ - LABKEY.Filter.create(isDisplayName ? 'UserId' : 'internalUserId', value, LABKEY.Filter.Types.EQUAL) + schemaName: 'study', + queryName: 'necropsy', + filterArray: [ + LABKEY.Filter.create('objectid', row.objectid, LABKEY.Filter.Types.EQUAL) ], - success: function(data) { - if (data.rows && data.rows.length > 0) { + success: function(results) { + // if there is no existing necropsy record for this objectid (this is an insert), + // or if there is an existing record (it's an update) and the pathologist doesn't + // match the pathologist from the original record then check to make sure that the + // pathologist is actually a current pathologist in the system + if (!results.rows || results.rows.length === 0 || (results.rows && results.rows.length > 0 && row.performedby !== results.rows[0].performedby)) { + LABKEY.Query.selectRows({ + schemaName: 'ehr_lookups', + queryName: 'pathologists', + filterArray:[ + LABKEY.Filter.create(isDisplayName ? 'UserId' : 'internalUserId', value, LABKEY.Filter.Types.EQUAL) + ], + success: function(data) { + if (data.rows && data.rows.length > 0) { + retVal = true; + } + else { + var message = "\"" + value + "\" is not a Pathologist in EHR."; + + if (!Ext.isDefined(severity)) { + severity = Validator.Severity.ERROR; + } + addToScriptErrors(fieldName, message, severity); + } + } + }); + } else { retVal = true; - } - else { - var message = "\"" + value + "\" is not a Pathologist in EHR."; - - if (!Ext.isDefined(severity)) { - severity = Validator.Severity.ERROR; - } - addToScriptErrors(fieldName, message, severity); + logger.debug('Value of performedby field (' + row.performedby + ') was not modified during record update'); } } }); diff --git a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js index 1c657042c..3f8759001 100644 --- a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js +++ b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js @@ -1,710 +1,721 @@ -/* - * Copyright (c) 2012-2014 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -var console = require("console"); -var LABKEY = require("labkey"); -var Ext = require("Ext4").Ext; -var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; - -// Some shortcuts to imported modules -var logger = WNPRC.Logger; - -// noinspection JSUnresolvedVariable -exports.init = function (EHR) { - // Here is the list of trigger scripts to execute: - var scriptsToLoad = [ - "study/Deaths.js", - "study/PrenatalDeaths.js", - "study/Necropsies.js" - /*, - "wnprc/vvc.js"*/ - ]; - - // Set up a shorthand function. - var registerHandler = function (event, schema, query, callback) { - return EHR.Server.TriggerManager.registerHandlerForQuery(event, schema, query, callback); - }; - - // Loop over each of the above-mentioned scripts and execute their registerTriggers call. - Ext.each(scriptsToLoad, function (scriptName) { - scriptName = scriptName.replace(/\.js$/, ''); - var trigger = {}; - - try { - trigger = require("wnprc_ehr/queries/" + scriptName); - logger.debug("Successfully loaded script: " + scriptName); - } - catch (e) { - logger.error("Failed to load trigger: " + scriptName); - } - - if (Ext.isFunction(trigger.registerTriggers)) { - trigger.registerTriggers(EHR, registerHandler, EHR.Server.TriggerManager.Events); - } - else { - logger.error("Trigger script (" + scriptName + ") doesn't expose a 'registerTriggers' function.") - } - }); - - //NOTE: this is getting passed the LK errors object, rather than the EHR wrapper - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'ehr', 'cage', function (helper, scriptErrors, row) { - //pad cage to 4 digits if numeric - if (row.cage && !isNaN(row.cage)) { - row.cage = EHR.Server.Utils.padDigits(row.cage, 4); - } - - if (row.room) - row.room = row.room.toLowerCase(); - - row.location = row.room; - if (row.cage) - row.location += '-' + row.cage; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'treatment_order', function (event, helper) { - helper.setScriptOptions({ - removeTimeFromDate: true, - removeTimeFromEndDate: true - }); - }); - - // This allows the client to signal that it is saving a scheduled record, and so it is unnecessary to check - // the dates for future dates, since they're supposed to be in the future. - var allowFutureDatesForScheduledRecords = function (helper) { - if (helper.getExtraContext().isScheduledTask) { - helper.setScriptOptions({ - allowFutureDates: true - }); - } - }; - - // Allow future records for the Necropsy sections that care, so that we can edit Scheduled Necropsies. - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'weight', function (event, helper) { - allowFutureDatesForScheduledRecords(helper); - }); - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'bcs', function (event, helper) { - allowFutureDatesForScheduledRecords(helper); - }); - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'alopecia', function (event, helper) { - allowFutureDatesForScheduledRecords(helper); - }); - - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'treatment_order', function (helper, scriptErrors, row) { - if (row.date && row.enddate) { - var startDate = EHR.Server.Utils.normalizeDate(row.date); - var endDate = EHR.Server.Utils.normalizeDate(row.enddate); - - if (startDate - endDate === 0) { - EHR.Server.Utils.addError(scriptErrors, 'enddate', 'Single Day Treatment', 'INFO'); - } - } - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'drug', function (helper, scriptErrors, row) { - if (row.volume && row.concentration) { - var expected = Math.round(row.volume * row.concentration * 1000) / 1000; - if (Math.abs(row.amount - expected) > 0.2) { //allow for rounding - EHR.Server.Utils.addError(scriptErrors, 'amount', 'Amount does not match volume for this concentration. Expected: ' + expected, 'INFO'); - //EHR.Server.Utils.addError(scriptErrors, 'volume', 'Volume does not match amount for this concentration. Expected: '+expected, 'WARN'); - } - } - - EHR.Server.Validation.checkRestraint(row, scriptErrors); - }); - - /** - * A helper that will infer the species based on regular expression patterns and the animal ID - * @param row The row object, provided by LabKey - * @param errors The errors object, provided by LabKey - */ - EHR.Server.TriggerManager.registerHandler(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, function (helper, scriptErrors, row) { - var species; - if (row.Id && !helper.isQuickValidation() && !helper.isETL()) { - if (row.Id.match(/(^rh([0-9]{4})$)|(^r([0-9]{5})$)|(^rh-([0-9]{3})$)|(^rh[a-z]{2}([0-9]{2})$)/)) - species = 'Rhesus'; - else if (row.Id.match(/(^cy?([0-9]{4,5})$)|(^c([0-9]{5})$)/)) - species = 'Cynomolgus'; - else if (row.Id.match(/^ag([0-9]{4})$/)) - species = 'Vervet'; - else if (row.Id.match(/^cj([0-9]{4})$/)) - species = 'Marmoset'; - else if (row.Id.match(/^so([0-9]{4})$/)) - species = 'Cotton-top Tamarin'; - else if (row.Id.match(/^pt([0-9]{4})$/)) - species = 'Pigtail'; - else if (row.Id.match(/^pd([0-9]{4})$/)) { - if (row.species) - species = row.species; - else - species = 'Infant'; - } - - //these are to handle legacy data: - else if (row.Id.match(/(^rha([a-z])([0-9]{2}))$/)) - species = 'Rhesus'; - else if (row.Id.match(/(^rh-([a-z])([0-9]{2}))$/)) - species = 'Rhesus'; - else if (row.Id.match(/^cja([0-9]{3})$/)) - species = 'Marmoset'; - else if (row.Id.match(/^m([0-9]{5})$/)) - species = 'Marmoset'; - else if (row.Id.match(/^tx([0-9]{4})$/)) - species = 'Marmoset'; - //and this is to handle automated tests - else if (row.Id.match(/^test[0-9]+$/)) - species = 'Rhesus'; - else - species = 'Unknown'; - } - row.species = species; - - //check Id format - if (!helper.isETL() && !helper.isSkipIdFormatCheck()) { - if (row.Id && species) { - if (species === 'Unknown') { - EHR.Server.Utils.addError(scriptErrors, 'Id', 'Invalid Id Format', 'INFO'); - } - else if (species === 'Infant') { - species = null; - } - } - } - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'arrival', function (row) { - var description = []; - - if (row.source) - description.push('Source: ' + row.source); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'assignment', function (row, helper) { - //we need to set description for every field - var description = []; - - description.push('Start Date: ' + helper.getJavaHelper().formatDate(row.Date, null, true)); - description.push('Removal Date: ' + (row.enddate ? helper.getJavaHelper().formatDate(row.enddate, null, true): '')); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'birth', function (row) { - //we need to set description for every field - var description = []; - - if (row.conception) - description.push('Conception: ' + row.conception); - - if (row.gender) - description.push('Gender: ' + EHR.Server.Utils.nullToString(row.gender)); - if (row.dam) - description.push('Dam: ' + EHR.Server.Utils.nullToString(row.dam)); - if (row.sire) - description.push('Sire: ' + EHR.Server.Utils.nullToString(row.sire)); - if (row.room) - description.push('Room: ' + EHR.Server.Utils.nullToString(row.room)); - if (row.cage) - description.push('Cage: ' + EHR.Server.Utils.nullToString(row.cage)); - if (row.cond) - description.push('Cond: ' + EHR.Server.Utils.nullToString(row.cond)); - if (row.weight) - description.push('Weight: ' + EHR.Server.Utils.nullToString(row.weight)); - if (row.wdate) - description.push('Weigh Date: ' + EHR.Server.Utils.nullToString(row.wdate)); - if (row.origin) - description.push('Origin: ' + row.origin); - if (row.type) - description.push('Type: ' + row.type); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'chemistryresults', function (row) { - //we need to set description for every field - var description = []; - - if (row.testid) - description.push('Test: ' + EHR.Server.Utils.nullToString(row.testid)); - if (row.method) - description.push('Method: ' + row.method); - - if (row.result) - description.push('Result: ' + EHR.Server.Utils.nullToString(row.result) + ' ' + EHR.Server.Utils.nullToString(row.units)); - if (row.qualResult) - description.push('Qual Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'encounters', function (row) { - //we need to set description for every field - var description = []; - - if (row.type) - description.push('Type: ' + row.type); - if (row.title) - description.push('Title: ' + row.title); - if (row.caseno) - description.push('CaseNo: ' + row.caseno); - if (row.major) - description.push('Is Major?: ' + row.major); - if (row.performedby) - description.push('Performed By: ' + row.performedby); - if (row.enddate) - description.push('Completed: ' + EHR.Server.Utils.datetimeToString(row.enddate)); - - //NOTE: only show this for non-final data - if (row.servicerequested && row.QCStateLabel && EHR.Server.Security.getQCStateByLabel(row.QCStateLabel).PublicData === false) - description.push('Service Requested: ' + row.servicerequested); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'clinical_observations', function (row) { - //we need to set description for every field - var description = []; - - if (row.category) - description.push('Category: ' + row.category); - if (row.area) - description.push('Area: ' + row.area); - if (row.observation) - description.push('Observation: ' + row.observation); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'clinpathruns', function (row) { - //we need to set description for every field - var description = []; - - if (row.type) - description.push('Type: ' + row.type); - - if (row.serviceRequested) - description.push('Service Requested: ' + row.servicerequested); - - if (row.sampleType) - description.push('Sample Type: ' + row.sampleType); - - if (row.sampleId) - description.push('Sample Id: ' + row.sampleId); - - if (row.collectedBy) - description.push('Collected By: ' + row.collectedBy); - - if (row.collectionMethod) - description.push('Collection Method: ' + row.collectionMethod); - - if (row.clinremark) - description.push('Clinical Remark: ' + row.clinremark); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'deaths', function (row) { - //we need to set description for every field - var description = []; - - if (row.cause) - description.push('Cause: ' + row.cause); - if (row.manner) - description.push('Manner: ' + row.manner); - if (row.necropsy) - description.push('Necropsy #: ' + row.necropsy); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'departure', function (row) { - //we need to set description for every field - var description = []; - - if (row.authorize) - description.push('Authorized By: ' + row.authorize); - - if (row.destination) - description.push('Destination: ' + row.destination); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'drug', function (row, helper) { - //we need to set description for every field - var description = []; - - if (row.code) - description.push('Code: ' + EHR.Server.Utils.snomedToString(row.code, row.meaning, helper)); - if (row.route) - description.push('Route: ' + row.route); - if (row.volume) - description.push('Volume: ' + row.volume + ' ' + EHR.Server.Utils.nullToString(row.vol_units)); - if (row.amount) - description.push('Amount: ' + row.amount + ' ' + EHR.Server.Utils.nullToString(row.amount_units)); - - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'hematologyresults', function (row) { - //we need to set description for every field - var description = []; - - if (row.testid) - description.push('Test: ' + EHR.Server.Utils.nullToString(row.testid)); - if (row.method) - description.push('Method: ' + row.method); - - if (row.result) - description.push('Result: ' + EHR.Server.Utils.nullToString(row.result)); - - if (row.qualResult) - description.push('Qualitative Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'histology', function (row, helper) { - //we need to set description for every field - var description = []; - - if (row.slideNum) - description.push('Slide No: ' + row.slideNum); - if (row.tissue) - description.push('Tissue: ' + EHR.Server.Utils.snomedToString(row.tissue, null, helper)); - if (row.diagnosis) - description.push('Diagnosis: ' + row.diagnosis); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'housing', function (row) { - //we need to set description for every field - var description = []; - - if (row.room) - description.push('Room: ' + row.room); - if (row.cage) - description.push('Cage: ' + row.cage); - if (row.cond) - description.push('Condition: ' + row.cond); - - description.push('In Time: ' + row.Date); - description.push('Out Time: ' + EHR.Server.Utils.nullToString(row.enddate)); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'notes', function (row) { - //we need to set description for every field - var description = []; - - description.push('Start Date: ' + (row.Date ? EHR.Server.Utils.datetimeToString(row.Date) : '')); - description.push('End Date: ' + (row.EndDate ? EHR.Server.Utils.datetimeToString(row.EndDate) : '')); - - if (row.category) - description.push('Category: ' + row.category); - if (row.value) - description.push('Value: ' + row.value); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'organ_weights', function (row, helper) { - //we need to set description for every field - var description = []; - - if (row.tissue) - description.push('Organ/Tissue: ' + EHR.Server.Utils.snomedToString(row.tissue, row.tissueMeaning, helper)); - if (row.weight) - description.push('Weight: ' + row.weight); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'parasitologyresults', function (row, helper) { - //we need to set description for every field - var description = []; - - if (row.organism || row.meaning) - description.push('Organism: ' + EHR.Server.Utils.snomedToString(row.organism, row.meaning, helper)); - if (row.method) - description.push('Method: ' + row.method); - - if (row.result) - description.push('Result: ' + EHR.Server.Utils.nullToString(row.result) + ' ' + EHR.Server.Utils.nullToString(row.units)); - if (row.qualResult) - description.push('Qual Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'problem', function (row) { - //we need to set description for every field - var description = []; - - if (row.category) - description.push('Category: ' + row.problem_no); - - if (row.problem_no) - description.push('Problem No: ' + row.problem_no); - - description.push('Date Observed: ' + EHR.Server.Utils.datetimeToString(row.date)); - description.push('Date Resolved: ' + EHR.Server.Utils.datetimeToString(row.enddate)); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'tissue_samples', function (row, helper) { - //we need to set description for every field - var description = []; - - if (row.tissue) - description.push('Tissue: ' + EHR.Server.Utils.snomedToString(row.tissue, helper)); - if (row.qualifier) - description.push('Qualifier: ' + row.qualifier); - if (row.diagnosis) - description.push('Diagnosis: ' + row.diagnosis); - if (row.recipient) - description.push('Recipient: ' + row.recipient); - if (row.container_type) - description.push('Container: ' + row.container_type); - if (row.accountToCharge) - description.push('Account to Charge: ' + row.accountToCharge); - if (row.ship_to) - description.push('Ship To: ' + row.ship_to); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'treatment_order', function (row, helper) { - //we need to set description for every field - var description = []; - - if (row.meaning) - description.push('Meaning: ' + row.meaning); - if (row.code || row.snomedMeaning) - description.push('Code: ' + EHR.Server.Utils.snomedToString(row.code, row.snomedMeaning, helper)); - if (row.route) - description.push('Route: ' + row.route); - if (row.concentration) - description.push('Conc: ' + row.concentration + ' ' + EHR.Server.Utils.nullToString(row.conc_units)); - if (row.dosage) - description.push('Dosage: ' + row.dosage + ' ' + EHR.Server.Utils.nullToString(row.dosage_units)); - if (row.volume) - description.push('Volume: ' + row.volume + ' ' + EHR.Server.Utils.nullToString(row.vol_units)); - if (row.amount) - description.push('Amount: ' + row.amount + ' ' + EHR.Server.Utils.nullToString(row.amount_units)); - - description.push('EndDate: ' + (row.enddate ? row.enddate : 'none')); - - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'urinalysisresults', function (row) { - var description = []; - - if (row.testid) - description.push('Test: ' + EHR.Server.Utils.nullToString(row.testid)); - if (row.method) - description.push('Method: ' + row.method); - - if (row.result) - description.push('Result: ' + EHR.Server.Utils.nullToString(row.result) + ' ' + EHR.Server.Utils.nullToString(row.units)); - if (row.qualResult) - description.push('Qual Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'weight', function (row) { - //we need to set description for every field - var description = []; - - if (row.weight) - description.push('Weight: ' + row.weight); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_INSERT, 'study', 'problem', function (helper, scriptErrors, row) { - //autocalculate problem # - //TODO: testing needed - if (!helper.isETL() && row.Id) { - LABKEY.Query.executeSql({ - schemaName: 'study', - sql: "SELECT MAX(problem_no)+1 as problem_no FROM study.problem WHERE id='" + row.Id + "'", - //NOTE: remove QC filter because of potential conflicts: +" AND qcstate.publicdata = TRUE", - success: function (data) { - if (data && data.rows && data.rows.length === 1) { - //console.log('problemno: '+data.rows[0].problem_no); - row.problem_no = data.rows[0].problem_no || 1; - } - else { - row.problem_no = 1; - } - }, - failure: EHR.Server.Utils.onFailure - }); - } - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'blood', function (row) { - //we need to set description for every field - var description = []; - - if (row.quantity) - description.push('Total Quantity: ' + row.quantity); - if (row.performedby) - description.push('Performed By: ' + row.performedby); - if (row.billedby) - description.push('Billed By: ' + row.billedby); - if (row.assayCode) - description.push('Assay Code', row.assayCode); - if (row.tube_type) - description.push('Tube Type: ' + row.tube_type); - if (row.num_tubes) - description.push('# of Tubes: ' + row.num_tubes); - if (row.additionalServices) - description.push('Additional Services: ' + row.additionalServices); - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'housing', function (helper, scriptErrors, row) { - if (row.cage) { - row.cage = row.cage.toLowerCase(); - } - if (!helper.isETL()) { - if (row.cond && row.cond.match(/x/) && !row.remark) { - EHR.Server.Utils.addError(scriptErrors, 'cond', 'If you pick a special housing condition (x), you need to enter a remark stating the type', 'ERROR'); - } - } - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'obs', function (helper, scriptErrors, row) { - // Enforce that a trauma location must always be supplied when "Trauma" is selected as an "other observation". - if (row.other) { - var other = row.other.split(","); - if ((other.length > 0) && (other.indexOf("T") >= 0)) { - if ((row.tlocation === null) || !(row.tlocation)) { - EHR.Server.Utils.addError(scriptErrors, 'tlocation', "You must specify a location when indicating trauma to an animal.", 'ERROR'); - } - } - } - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'ehr', 'protocol', function (helper, scriptErrors, row) { - if (row.protocol) - row.protocol = row.protocol.toLowerCase(); - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'blood', function (helper, scriptErrors, row) { - if (row.additionalServices) { - // We do not permit requests of 6mL in EDTA with CBC - if (row.tube_type === 'EDTA' && row.tube_vol === 6 && row.additionalServices.indexOf('CBC') >= 0) { - EHR.Server.Utils.addError(scriptErrors, 'tube_type', 'May not request draw of 6mL in EDTA with CBC', 'ERROR'); - } - } - - // WNPRC#4350 - Require restraints for blood draws, but not for requests - if (row.QCStateLabel === 'Completed') { - if (!row.restraintDuration) { - EHR.Server.Utils.addError(scriptErrors, 'restraintDuration', 'You must indicate the restraint time for blood draws.', 'ERROR'); - } - if (!row.restraint) { - EHR.Server.Utils.addError(scriptErrors, 'restraint', 'You must indicate the restraint used for blood draws.', 'ERROR'); - } - } - }); - - function getHousingSQL(row) { - var date = row.Date; - date = EHR.Server.Utils.normalizeDate(date); - var sqlDate = LABKEY.Query.sqlDateTimeLiteral(date); - - var sql = "SELECT Id, room, cage, lsid FROM study.housing h " + - "WHERE h.room='" + row.room + "' AND " + - "h.date <= " + sqlDate + " AND " + - "(h.enddate >= " + sqlDate + " OR h.enddate IS NULL) AND " + - "h.qcstate.publicdata = true "; - - if (row.cage) - sql += " AND h.cage='" + row.cage + "'"; - return sql; - } - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'ehr', 'cage_observations', function (helper, scriptErrors, row) { - row.performedby = row.performedby || row.userid || null; - - if (row.cage && !isNaN(row.cage)) { - row.cage = EHR.Server.Utils.padDigits(row.cage, 4); - } - - // Do not allow someone to mark a cage as okay with observations. - if (row.no_observations && row.feces) { - EHR.Server.Utils.addError(scriptErrors, 'no_observations', 'You cannot mark a cage as "OK" if there is an abnormal feces observation.', 'ERROR'); - } - - //verify an animal is housed here - if (row.Date && row.room) { - var sql = getHousingSQL(row); - LABKEY.Query.executeSql({ - schemaName: 'study', - sql: sql, - success: function (data) { - if (!data || !data.rows || !data.rows.length) { - if (!row.cage) - EHR.Server.Utils.addError(scriptErrors, 'room', 'No animals are housed in this room on this date', 'WARN'); - else - EHR.Server.Utils.addError(scriptErrors, 'cage', 'No animals are housed in this cage on this date', 'WARN'); - } - }, - failure: EHR.Server.Utils.onFailure - }); - } - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'ehr', 'cage_observations', function (row) { - var description = []; - - if (row.no_observations === true) { - if (row.cage) { - description = ["Cage Okay"] - } - else { - description = ["Room Okay"] - } - } - else { - description = ['Cage Observation']; - - if (row.feces) { - description.push('Feces: ' + row.feces); - } - } - - return description; - }); - - EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPDATE, 'wnprc', 'vvc', function (helper, scriptErrors, row, oldRow) { - console.log("wnprc_trigger gets called"); - if (row.QCStateLabel === "Request: Approved" && oldRow.QCStateLabel === "Request: Pending") { - row.dateapproved = new Date(); - } - }); - - /*EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_INSERT, 'wnprc', 'vvc', function(helper, scriptErrors, row){ - if (row.QCStateLabel == "Request: Pending" && row.requestId){ - var requestid = row.requestId; - console.log ("new request submitted "+ requestid); - WNPRC.Utils.getJavaHelper().sendVvcNotification(requestid); - } - });*/ +/* + * Copyright (c) 2012-2014 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +var console = require("console"); +var LABKEY = require("labkey"); +var Ext = require("Ext4").Ext; +var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; + +// Some shortcuts to imported modules +var logger = WNPRC.Logger; + +// noinspection JSUnresolvedVariable +exports.init = function (EHR) { + // Here is the list of trigger scripts to execute: + var scriptsToLoad = [ + "study/Deaths.js", + "study/PrenatalDeaths.js", + "study/Necropsies.js" + /*, + "wnprc/vvc.js"*/ + ]; + + // Set up a shorthand function. + var registerHandler = function (event, schema, query, callback) { + return EHR.Server.TriggerManager.registerHandlerForQuery(event, schema, query, callback); + }; + + // Loop over each of the above-mentioned scripts and execute their registerTriggers call. + Ext.each(scriptsToLoad, function (scriptName) { + scriptName = scriptName.replace(/\.js$/, ''); + var trigger = {}; + + try { + trigger = require("wnprc_ehr/queries/" + scriptName); + logger.debug("Successfully loaded script: " + scriptName); + } + catch (e) { + logger.error("Failed to load trigger: " + scriptName); + } + + if (Ext.isFunction(trigger.registerTriggers)) { + trigger.registerTriggers(EHR, registerHandler, EHR.Server.TriggerManager.Events); + } + else { + logger.error("Trigger script (" + scriptName + ") doesn't expose a 'registerTriggers' function.") + } + }); + + //NOTE: this is getting passed the LK errors object, rather than the EHR wrapper + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'ehr', 'cage', function (helper, scriptErrors, row) { + //pad cage to 4 digits if numeric + if (row.cage && !isNaN(row.cage)) { + row.cage = EHR.Server.Utils.padDigits(row.cage, 4); + } + + if (row.room) + row.room = row.room.toLowerCase(); + + row.location = row.room; + if (row.cage) + row.location += '-' + row.cage; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'treatment_order', function (event, helper) { + helper.setScriptOptions({ + removeTimeFromDate: true, + removeTimeFromEndDate: true + }); + }); + + // This allows the client to signal that it is saving a scheduled record, and so it is unnecessary to check + // the dates for future dates, since they're supposed to be in the future. + var allowFutureDatesForScheduledRecords = function (helper) { + if (helper.getExtraContext().isScheduledTask) { + helper.setScriptOptions({ + allowFutureDates: true + }); + } + }; + + // Allow future records for the Necropsy sections that care, so that we can edit Scheduled Necropsies. + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'weight', function (event, helper) { + allowFutureDatesForScheduledRecords(helper); + }); + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'bcs', function (event, helper) { + allowFutureDatesForScheduledRecords(helper); + }); + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'alopecia', function (event, helper) { + allowFutureDatesForScheduledRecords(helper); + }); + + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'treatment_order', function (helper, scriptErrors, row) { + if (row.date && row.enddate) { + var startDate = EHR.Server.Utils.normalizeDate(row.date); + var endDate = EHR.Server.Utils.normalizeDate(row.enddate); + + if (startDate - endDate === 0) { + EHR.Server.Utils.addError(scriptErrors, 'enddate', 'Single Day Treatment', 'INFO'); + } + } + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'drug', function (helper, scriptErrors, row) { + if (row.volume && row.concentration) { + var expected = Math.round(row.volume * row.concentration * 1000) / 1000; + if (Math.abs(row.amount - expected) > 0.2) { //allow for rounding + EHR.Server.Utils.addError(scriptErrors, 'amount', 'Amount does not match volume for this concentration. Expected: ' + expected, 'INFO'); + //EHR.Server.Utils.addError(scriptErrors, 'volume', 'Volume does not match amount for this concentration. Expected: '+expected, 'WARN'); + } + } + + EHR.Server.Validation.checkRestraint(row, scriptErrors); + }); + + /** + * A helper that will infer the species based on regular expression patterns and the animal ID + * @param row The row object, provided by LabKey + * @param errors The errors object, provided by LabKey + */ + EHR.Server.TriggerManager.registerHandler(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, function (helper, scriptErrors, row) { + var species; + if (row.Id && !helper.isETL()) { + if (row.Id.match(/(^rh([0-9]{4})$)|(^r([0-9]{5})$)|(^rh-([0-9]{3})$)|(^rh[a-z]{2}([0-9]{2})$)/)) + species = 'Rhesus'; + else if (row.Id.match(/(^cy?([0-9]{4,5})$)|(^c([0-9]{5})$)/)) + species = 'Cynomolgus'; + else if (row.Id.match(/(^ag([0-9]{4})$)|(^v([0-9]{5})$)/)) + species = 'Vervet'; + else if (row.Id.match(/^cj([0-9]{4})$/)) + species = 'Marmoset'; + else if (row.Id.match(/^so([0-9]{4})$/)) + species = 'Cotton-top Tamarin'; + else if (row.Id.match(/(^pt([0-9,a-z]{4})$)|(^p[0-9]{5})/)) + species = 'Pigtail'; + else if (row.Id.match(/^pd([0-9]{4})$/)) { + if (row.species) + species = row.species; + else + species = 'Infant'; + } + + //these are to handle legacy data: + else if (row.Id.match(/(^rha([a-z])([0-9]{2}))$/)) + species = 'Rhesus'; + else if (row.Id.match(/(^rh-([a-z])([0-9]{2}))$/)) + species = 'Rhesus'; + else if (row.Id.match(/(^rh([0-9,a-z]{4})$)|(^rh\+([0-9]{3})$)/)) + species = 'Rhesus'; + //Special naming for a rhesus and stump tail monkey from the 70s. + else if (row.Id.match(/(^sr-n([0-9]{2})$)/)) + species = 'Rhesus'; + else if (row.Id.match(/^cja([0-9]{3})$/)) + species = 'Marmoset'; + else if (row.Id.match(/^m([0-9]{5})$/)) + species = 'Marmoset'; + else if (row.Id.match(/^tx([0-9]{4})$/)) + species = 'Marmoset'; + //and this is to handle automated tests + else if (row.Id.match(/^test[0-9]+$/)) + species = 'Rhesus'; + else if (row.Id.match(/(^st([0-9]{4})$)|(^s([0-9]{5})$)|(^st([0-9,a-z]{4})$)|(^st-([0-9,a-z]{3})$)/)) + species = 'Stump Tailed'; + else if (row.id.match(/(^ca([0-9]{4})$)|(^a([0-9]{5})$)/)) + species = 'Capuchin'; + else if (row.id.match(/(^gc([0-9]{4})$)/)) + species = 'Galago Crassicaudatus'; + else + species = 'Unknown'; + } + row.species = species; + + //check Id format + if (!helper.isETL() && !helper.isSkipIdFormatCheck()) { + if (row.Id && species) { + if (species === 'Unknown') { + EHR.Server.Utils.addError(scriptErrors, 'Id', 'Invalid Id Format', 'INFO'); + } + else if (species === 'Infant') { + species = null; + } + } + } + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'arrival', function (row) { + var description = []; + + if (row.source) + description.push('Source: ' + row.source); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'assignment', function (row, helper) { + //we need to set description for every field + var description = []; + + description.push('Start Date: ' + helper.getJavaHelper().formatDate(row.Date, null, true)); + description.push('Removal Date: ' + (row.enddate ? helper.getJavaHelper().formatDate(row.enddate, null, true): '')); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'birth', function (row) { + //we need to set description for every field + var description = []; + + if (row.conception) + description.push('Conception: ' + row.conception); + + if (row.gender) + description.push('Gender: ' + EHR.Server.Utils.nullToString(row.gender)); + if (row.dam) + description.push('Dam: ' + EHR.Server.Utils.nullToString(row.dam)); + if (row.sire) + description.push('Sire: ' + EHR.Server.Utils.nullToString(row.sire)); + if (row.room) + description.push('Room: ' + EHR.Server.Utils.nullToString(row.room)); + if (row.cage) + description.push('Cage: ' + EHR.Server.Utils.nullToString(row.cage)); + if (row.cond) + description.push('Cond: ' + EHR.Server.Utils.nullToString(row.cond)); + if (row.weight) + description.push('Weight: ' + EHR.Server.Utils.nullToString(row.weight)); + if (row.wdate) + description.push('Weigh Date: ' + EHR.Server.Utils.nullToString(row.wdate)); + if (row.origin) + description.push('Origin: ' + row.origin); + if (row.type) + description.push('Type: ' + row.type); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'chemistryresults', function (row) { + //we need to set description for every field + var description = []; + + if (row.testid) + description.push('Test: ' + EHR.Server.Utils.nullToString(row.testid)); + if (row.method) + description.push('Method: ' + row.method); + + if (row.result) + description.push('Result: ' + EHR.Server.Utils.nullToString(row.result) + ' ' + EHR.Server.Utils.nullToString(row.units)); + if (row.qualResult) + description.push('Qual Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'encounters', function (row) { + //we need to set description for every field + var description = []; + + if (row.type) + description.push('Type: ' + row.type); + if (row.title) + description.push('Title: ' + row.title); + if (row.caseno) + description.push('CaseNo: ' + row.caseno); + if (row.major) + description.push('Is Major?: ' + row.major); + if (row.performedby) + description.push('Performed By: ' + row.performedby); + if (row.enddate) + description.push('Completed: ' + EHR.Server.Utils.datetimeToString(row.enddate)); + + //NOTE: only show this for non-final data + if (row.servicerequested && row.QCStateLabel && EHR.Server.Security.getQCStateByLabel(row.QCStateLabel).PublicData === false) + description.push('Service Requested: ' + row.servicerequested); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'clinical_observations', function (row) { + //we need to set description for every field + var description = []; + + if (row.category) + description.push('Category: ' + row.category); + if (row.area) + description.push('Area: ' + row.area); + if (row.observation) + description.push('Observation: ' + row.observation); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'clinpathruns', function (row) { + //we need to set description for every field + var description = []; + + if (row.type) + description.push('Type: ' + row.type); + + if (row.serviceRequested) + description.push('Service Requested: ' + row.servicerequested); + + if (row.sampleType) + description.push('Sample Type: ' + row.sampleType); + + if (row.sampleId) + description.push('Sample Id: ' + row.sampleId); + + if (row.collectedBy) + description.push('Collected By: ' + row.collectedBy); + + if (row.collectionMethod) + description.push('Collection Method: ' + row.collectionMethod); + + if (row.clinremark) + description.push('Clinical Remark: ' + row.clinremark); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'deaths', function (row) { + //we need to set description for every field + var description = []; + + if (row.cause) + description.push('Cause: ' + row.cause); + if (row.manner) + description.push('Manner: ' + row.manner); + if (row.necropsy) + description.push('Necropsy #: ' + row.necropsy); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'departure', function (row) { + //we need to set description for every field + var description = []; + + if (row.authorize) + description.push('Authorized By: ' + row.authorize); + + if (row.destination) + description.push('Destination: ' + row.destination); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'drug', function (row, helper) { + //we need to set description for every field + var description = []; + + if (row.code) + description.push('Code: ' + EHR.Server.Utils.snomedToString(row.code, row.meaning, helper)); + if (row.route) + description.push('Route: ' + row.route); + if (row.volume) + description.push('Volume: ' + row.volume + ' ' + EHR.Server.Utils.nullToString(row.vol_units)); + if (row.amount) + description.push('Amount: ' + row.amount + ' ' + EHR.Server.Utils.nullToString(row.amount_units)); + + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'hematologyresults', function (row) { + //we need to set description for every field + var description = []; + + if (row.testid) + description.push('Test: ' + EHR.Server.Utils.nullToString(row.testid)); + if (row.method) + description.push('Method: ' + row.method); + + if (row.result) + description.push('Result: ' + EHR.Server.Utils.nullToString(row.result)); + + if (row.qualResult) + description.push('Qualitative Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'histology', function (row, helper) { + //we need to set description for every field + var description = []; + + if (row.slideNum) + description.push('Slide No: ' + row.slideNum); + if (row.tissue) + description.push('Tissue: ' + EHR.Server.Utils.snomedToString(row.tissue, null, helper)); + if (row.diagnosis) + description.push('Diagnosis: ' + row.diagnosis); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'housing', function (row) { + //we need to set description for every field + var description = []; + + if (row.room) + description.push('Room: ' + row.room); + if (row.cage) + description.push('Cage: ' + row.cage); + if (row.cond) + description.push('Condition: ' + row.cond); + + description.push('In Time: ' + row.Date); + description.push('Out Time: ' + EHR.Server.Utils.nullToString(row.enddate)); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'notes', function (row) { + //we need to set description for every field + var description = []; + + description.push('Start Date: ' + (row.Date ? EHR.Server.Utils.datetimeToString(row.Date) : '')); + description.push('End Date: ' + (row.EndDate ? EHR.Server.Utils.datetimeToString(row.EndDate) : '')); + + if (row.category) + description.push('Category: ' + row.category); + if (row.value) + description.push('Value: ' + row.value); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'organ_weights', function (row, helper) { + //we need to set description for every field + var description = []; + + if (row.tissue) + description.push('Organ/Tissue: ' + EHR.Server.Utils.snomedToString(row.tissue, row.tissueMeaning, helper)); + if (row.weight) + description.push('Weight: ' + row.weight); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'parasitologyresults', function (row, helper) { + //we need to set description for every field + var description = []; + + if (row.organism || row.meaning) + description.push('Organism: ' + EHR.Server.Utils.snomedToString(row.organism, row.meaning, helper)); + if (row.method) + description.push('Method: ' + row.method); + + if (row.result) + description.push('Result: ' + EHR.Server.Utils.nullToString(row.result) + ' ' + EHR.Server.Utils.nullToString(row.units)); + if (row.qualResult) + description.push('Qual Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'problem', function (row) { + //we need to set description for every field + var description = []; + + if (row.category) + description.push('Category: ' + row.problem_no); + + if (row.problem_no) + description.push('Problem No: ' + row.problem_no); + + description.push('Date Observed: ' + EHR.Server.Utils.datetimeToString(row.date)); + description.push('Date Resolved: ' + EHR.Server.Utils.datetimeToString(row.enddate)); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'tissue_samples', function (row, helper) { + //we need to set description for every field + var description = []; + + if (row.tissue) + description.push('Tissue: ' + EHR.Server.Utils.snomedToString(row.tissue, helper)); + if (row.qualifier) + description.push('Qualifier: ' + row.qualifier); + if (row.diagnosis) + description.push('Diagnosis: ' + row.diagnosis); + if (row.recipient) + description.push('Recipient: ' + row.recipient); + if (row.container_type) + description.push('Container: ' + row.container_type); + if (row.accountToCharge) + description.push('Account to Charge: ' + row.accountToCharge); + if (row.ship_to) + description.push('Ship To: ' + row.ship_to); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'treatment_order', function (row, helper) { + //we need to set description for every field + var description = []; + + if (row.meaning) + description.push('Meaning: ' + row.meaning); + if (row.code || row.snomedMeaning) + description.push('Code: ' + EHR.Server.Utils.snomedToString(row.code, row.snomedMeaning, helper)); + if (row.route) + description.push('Route: ' + row.route); + if (row.concentration) + description.push('Conc: ' + row.concentration + ' ' + EHR.Server.Utils.nullToString(row.conc_units)); + if (row.dosage) + description.push('Dosage: ' + row.dosage + ' ' + EHR.Server.Utils.nullToString(row.dosage_units)); + if (row.volume) + description.push('Volume: ' + row.volume + ' ' + EHR.Server.Utils.nullToString(row.vol_units)); + if (row.amount) + description.push('Amount: ' + row.amount + ' ' + EHR.Server.Utils.nullToString(row.amount_units)); + + description.push('EndDate: ' + (row.enddate ? row.enddate : 'none')); + + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'urinalysisresults', function (row) { + var description = []; + + if (row.testid) + description.push('Test: ' + EHR.Server.Utils.nullToString(row.testid)); + if (row.method) + description.push('Method: ' + row.method); + + if (row.result) + description.push('Result: ' + EHR.Server.Utils.nullToString(row.result) + ' ' + EHR.Server.Utils.nullToString(row.units)); + if (row.qualResult) + description.push('Qual Result: ' + EHR.Server.Utils.nullToString(row.qualResult)); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'weight', function (row) { + //we need to set description for every field + var description = []; + + if (row.weight) + description.push('Weight: ' + row.weight); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_INSERT, 'study', 'problem', function (helper, scriptErrors, row) { + //autocalculate problem # + //TODO: testing needed + if (!helper.isETL() && row.Id) { + LABKEY.Query.executeSql({ + schemaName: 'study', + sql: "SELECT MAX(problem_no)+1 as problem_no FROM study.problem WHERE id='" + row.Id + "'", + //NOTE: remove QC filter because of potential conflicts: +" AND qcstate.publicdata = TRUE", + success: function (data) { + if (data && data.rows && data.rows.length === 1) { + //console.log('problemno: '+data.rows[0].problem_no); + row.problem_no = data.rows[0].problem_no || 1; + } + else { + row.problem_no = 1; + } + }, + failure: EHR.Server.Utils.onFailure + }); + } + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'study', 'blood', function (row) { + //we need to set description for every field + var description = []; + + if (row.quantity) + description.push('Total Quantity: ' + row.quantity); + if (row.performedby) + description.push('Performed By: ' + row.performedby); + if (row.billedby) + description.push('Billed By: ' + row.billedby); + if (row.assayCode) + description.push('Assay Code', row.assayCode); + if (row.tube_type) + description.push('Tube Type: ' + row.tube_type); + if (row.num_tubes) + description.push('# of Tubes: ' + row.num_tubes); + if (row.additionalServices) + description.push('Additional Services: ' + row.additionalServices); + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'housing', function (helper, scriptErrors, row) { + if (row.cage) { + row.cage = row.cage.toLowerCase(); + } + if (!helper.isETL()) { + if (row.cond && row.cond.match(/x/) && !row.remark) { + EHR.Server.Utils.addError(scriptErrors, 'cond', 'If you pick a special housing condition (x), you need to enter a remark stating the type', 'ERROR'); + } + } + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'obs', function (helper, scriptErrors, row) { + // Enforce that a trauma location must always be supplied when "Trauma" is selected as an "other observation". + if (row.other) { + var other = row.other.split(","); + if ((other.length > 0) && (other.indexOf("T") >= 0)) { + if ((row.tlocation === null) || !(row.tlocation)) { + EHR.Server.Utils.addError(scriptErrors, 'tlocation', "You must specify a location when indicating trauma to an animal.", 'ERROR'); + } + } + } + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'ehr', 'protocol', function (helper, scriptErrors, row) { + if (row.protocol) + row.protocol = row.protocol.toLowerCase(); + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'blood', function (helper, scriptErrors, row) { + if (row.additionalServices) { + // We do not permit requests of 6mL in EDTA with CBC + if (row.tube_type === 'EDTA' && row.tube_vol === 6 && row.additionalServices.indexOf('CBC') >= 0) { + EHR.Server.Utils.addError(scriptErrors, 'tube_type', 'May not request draw of 6mL in EDTA with CBC', 'ERROR'); + } + } + + // WNPRC#4350 - Require restraints for blood draws, but not for requests + if (row.QCStateLabel === 'Completed') { + if (!row.restraintDuration) { + EHR.Server.Utils.addError(scriptErrors, 'restraintDuration', 'You must indicate the restraint time for blood draws.', 'ERROR'); + } + if (!row.restraint) { + EHR.Server.Utils.addError(scriptErrors, 'restraint', 'You must indicate the restraint used for blood draws.', 'ERROR'); + } + } + }); + + function getHousingSQL(row) { + var date = row.Date; + date = EHR.Server.Utils.normalizeDate(date); + var sqlDate = LABKEY.Query.sqlDateTimeLiteral(date); + + var sql = "SELECT Id, room, cage, lsid FROM study.housing h " + + "WHERE h.room='" + row.room + "' AND " + + "h.date <= " + sqlDate + " AND " + + "(h.enddate >= " + sqlDate + " OR h.enddate IS NULL) AND " + + "h.qcstate.publicdata = true "; + + if (row.cage) + sql += " AND h.cage='" + row.cage + "'"; + return sql; + } + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'ehr', 'cage_observations', function (helper, scriptErrors, row) { + row.performedby = row.performedby || row.userid || null; + + if (row.cage && !isNaN(row.cage)) { + row.cage = EHR.Server.Utils.padDigits(row.cage, 4); + } + + // Do not allow someone to mark a cage as okay with observations. + if (row.no_observations && row.feces) { + EHR.Server.Utils.addError(scriptErrors, 'no_observations', 'You cannot mark a cage as "OK" if there is an abnormal feces observation.', 'ERROR'); + } + + //verify an animal is housed here + if (row.Date && row.room) { + var sql = getHousingSQL(row); + LABKEY.Query.executeSql({ + schemaName: 'study', + sql: sql, + success: function (data) { + if (!data || !data.rows || !data.rows.length) { + if (!row.cage) + EHR.Server.Utils.addError(scriptErrors, 'room', 'No animals are housed in this room on this date', 'WARN'); + else + EHR.Server.Utils.addError(scriptErrors, 'cage', 'No animals are housed in this cage on this date', 'WARN'); + } + }, + failure: EHR.Server.Utils.onFailure + }); + } + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.DESCRIPTION, 'ehr', 'cage_observations', function (row) { + var description = []; + + if (row.no_observations === true) { + if (row.cage) { + description = ["Cage Okay"] + } + else { + description = ["Room Okay"] + } + } + else { + description = ['Cage Observation']; + + if (row.feces) { + description.push('Feces: ' + row.feces); + } + } + + return description; + }); + + EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPDATE, 'wnprc', 'vvc', function (helper, scriptErrors, row, oldRow) { + console.log("wnprc_trigger gets called"); + if (row.QCStateLabel === "Request: Approved" && oldRow.QCStateLabel === "Request: Pending") { + row.dateapproved = new Date(); + } + }); + + /*EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_INSERT, 'wnprc', 'vvc', function(helper, scriptErrors, row){ + if (row.QCStateLabel == "Request: Pending" && row.requestId){ + var requestid = row.requestId; + console.log ("new request submitted "+ requestid); + WNPRC.Utils.getJavaHelper().sendVvcNotification(requestid); + } + });*/ }; \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/SOPadmin.html b/WNPRC_EHR/resources/views/SOPadmin.html new file mode 100644 index 000000000..2ec8d7f6b --- /dev/null +++ b/WNPRC_EHR/resources/views/SOPadmin.html @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/SOPadmin.view.xml b/WNPRC_EHR/resources/views/SOPadmin.view.xml new file mode 100644 index 000000000..bfe464d68 --- /dev/null +++ b/WNPRC_EHR/resources/views/SOPadmin.view.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/WNPRC_EHR/resources/views/SOPadmin.webpart.xml b/WNPRC_EHR/resources/views/SOPadmin.webpart.xml new file mode 100644 index 000000000..a99864a2a --- /dev/null +++ b/WNPRC_EHR/resources/views/SOPadmin.webpart.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/breeding.html b/WNPRC_EHR/resources/views/breeding.html index 8456d6ad6..e4b7d14d5 100644 --- a/WNPRC_EHR/resources/views/breeding.html +++ b/WNPRC_EHR/resources/views/breeding.html @@ -1,11 +1,8 @@
    -
    - - -
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/breeding.webpart.xml b/WNPRC_EHR/resources/views/breeding.webpart.xml new file mode 100644 index 000000000..61fdfbc83 --- /dev/null +++ b/WNPRC_EHR/resources/views/breeding.webpart.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/dataEntry.html b/WNPRC_EHR/resources/views/dataEntry.html index 2dde88caa..eeefec3f8 100644 --- a/WNPRC_EHR/resources/views/dataEntry.html +++ b/WNPRC_EHR/resources/views/dataEntry.html @@ -1,682 +1,696 @@ diff --git a/WNPRC_EHR/resources/views/ehrAdmin.html b/WNPRC_EHR/resources/views/ehrAdmin.html index aba7e8774..627367320 100644 --- a/WNPRC_EHR/resources/views/ehrAdmin.html +++ b/WNPRC_EHR/resources/views/ehrAdmin.html @@ -1,14 +1,11 @@ - \ No newline at end of file + diff --git a/WNPRC_EHR/resources/views/gestation_calculator.html b/WNPRC_EHR/resources/views/gestation_calculator.html new file mode 100644 index 000000000..f252f4897 --- /dev/null +++ b/WNPRC_EHR/resources/views/gestation_calculator.html @@ -0,0 +1,227 @@ + + + + + + + +
    +
    +
    +
    + + +
    +
    + +
    +
    + Measurements +
    +
    + Calculated Gestational Days +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/gestation_calculator.view.xml b/WNPRC_EHR/resources/views/gestation_calculator.view.xml new file mode 100644 index 000000000..9dc857e6a --- /dev/null +++ b/WNPRC_EHR/resources/views/gestation_calculator.view.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/gestation_calculator.webpart.xml b/WNPRC_EHR/resources/views/gestation_calculator.webpart.xml new file mode 100644 index 000000000..6d32cfa59 --- /dev/null +++ b/WNPRC_EHR/resources/views/gestation_calculator.webpart.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/mhc_main.html b/WNPRC_EHR/resources/views/mhc_main.html index 4723a56fd..061207899 100644 --- a/WNPRC_EHR/resources/views/mhc_main.html +++ b/WNPRC_EHR/resources/views/mhc_main.html @@ -1,18 +1,10 @@ - diff --git a/WNPRC_EHR/resources/views/pregnancy.view.xml b/WNPRC_EHR/resources/views/pregnancy.view.xml deleted file mode 100644 index 33bdd10d5..000000000 --- a/WNPRC_EHR/resources/views/pregnancy.view.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/projectQueries.html b/WNPRC_EHR/resources/views/projectQueries.html new file mode 100644 index 000000000..d4e981621 --- /dev/null +++ b/WNPRC_EHR/resources/views/projectQueries.html @@ -0,0 +1,118 @@ + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/projectQueries.view.xml b/WNPRC_EHR/resources/views/projectQueries.view.xml new file mode 100644 index 000000000..148ae7f9f --- /dev/null +++ b/WNPRC_EHR/resources/views/projectQueries.view.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/views/vl_main.html b/WNPRC_EHR/resources/views/vl_main.html index ae1095bb8..eaf85a3ee 100644 --- a/WNPRC_EHR/resources/views/vl_main.html +++ b/WNPRC_EHR/resources/views/vl_main.html @@ -1,18 +1,10 @@ - - - - -

    - - - - - - - - - - - - - - - - - - -
    - Each WNPRC Unit can create pages for internal or external consumption. At the moment most units only have an issue tracker. If you are interested in creating a page for your group, please submit a request here - -

    -
    - - Animal Services: - -

    -

    - - Operational Services: - -

    -

    - - Research Services: - -

    -

    - - Director's Office: - -

    -

    -
    -

    - **Denotes restricted area -

    -
    -
    -
    -
    -
    -

    - - Misc Pages: - -

    -

    -
    - - - - + + + + +

    +

    + + + + + + + + + + + + + + + + + +
    + Each WNPRC Unit can create pages for internal or external consumption. At the moment most units only have an issue tracker. If you are interested in creating a page for your group, please submit a request here + +

    +
    + + Animal Services: + +

    +

    + + Operational Services: + +

    +

    + + Research Services: + +

    +

    + + Director's Office: + +

    +

    +
    +

    + **Denotes restricted area +

    +
    +
    +
    +
    +
    +

    + + Misc Pages: + +

    +

    +
    +
    + + + diff --git a/WNPRC_EHR/resources/web/ehr/ehr_ext3_api.lib.xml b/WNPRC_EHR/resources/web/ehr/ehr_ext3_api.lib.xml new file mode 100644 index 000000000..cdb709cb6 --- /dev/null +++ b/WNPRC_EHR/resources/web/ehr/ehr_ext3_api.lib.xml @@ -0,0 +1,49 @@ + + + + <% SimpleQueryFactory queryFactory = new SimpleQueryFactory(getUser(), getContainer()); @@ -63,6 +64,15 @@ font-size: 20px; margin: 0; } + + /* Override LK bootstrap */ + .form-control.knockout-bs-form { + width: 100%; + } + .input-group.date { + display: table; + } +
    @@ -210,7 +220,7 @@
    - <% for(JSONObject necropsySuite : necropsySuites) { @@ -227,7 +237,7 @@
    - <% for(JSONObject pathologist : pathologistList) { @@ -245,7 +255,7 @@
    - <% for(JSONObject pathologist : pathologistList) { diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/pages/dataentry/PathologyCaseList.jsp b/WNPRC_EHR/src/org/labkey/wnprc_ehr/pages/dataentry/PathologyCaseList.jsp index f964f72e9..538e2dcb0 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/pages/dataentry/PathologyCaseList.jsp +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/pages/dataentry/PathologyCaseList.jsp @@ -12,6 +12,8 @@ <%@ page import="org.labkey.api.action.Action" %> <%@ page extends="org.labkey.api.jsp.JspBase" %> + + <% Integer year = Calendar.getInstance().get(Calendar.YEAR); @@ -34,6 +36,12 @@ List necropsies = JsonUtils.getListFromJSONArray(necropsyQuery.getResults(dateFilter).getJSONArray("rows")); %> + +
    List of Biopsies and Necropsy Cases
    diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/query/ViralAssayCustomizer.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/query/ViralAssayCustomizer.java index 79aa37f94..fc5a6e1d4 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/query/ViralAssayCustomizer.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/query/ViralAssayCustomizer.java @@ -1,10 +1,12 @@ package org.labkey.wnprc_ehr.query; import org.labkey.api.data.AbstractTableInfo; +import org.labkey.api.data.BaseColumnInfo; import org.labkey.api.data.ColumnInfo; import org.labkey.api.data.DataColumn; import org.labkey.api.data.DisplayColumn; import org.labkey.api.data.DisplayColumnFactory; +import org.labkey.api.data.MutableColumnInfo; import org.labkey.api.data.RenderContext; import org.labkey.api.data.TableCustomizer; import org.labkey.api.data.TableInfo; @@ -94,7 +96,7 @@ public void customizeDataTable(AbstractTableInfo ti) { if (subject != null) { subject.setLabel("Subject Id"); subject.setConceptURI("http://cpas.labkey.com/Study#ParticipantId"); - LDKService.get().applyNaturalSort(ti, "subjectId"); + // LDKService.get().applyNaturalSort(ti, "subjectId"); } var result = ti.getMutableColumn("result"); @@ -149,21 +151,15 @@ public void customizeDataTable(AbstractTableInfo ti) { statusFlags.setDimension(false); } - ColumnInfo sourceMaterialColumn = ti.getColumn("sourceMaterial"); - if (sourceMaterialColumn != null) { - TableInfo sourceMaterialTable = sourceMaterialColumn.getFkTableInfo(); // CONSIDER: replace foreignkey instead attempting surgery on this inner columninfo - if (sourceMaterialTable instanceof AbstractTableInfo) { - var liquidColumn = ((AbstractTableInfo)sourceMaterialTable).getMutableColumn("liquid"); - if (liquidColumn != null) { - liquidColumn.setLabel("Units"); - liquidColumn.setDisplayColumnFactory(new DisplayColumnFactory() { - @Override - public DisplayColumn createRenderer(ColumnInfo colInfo) { - return new ViralLoadUnitsColumn(colInfo); - } - }); + BaseColumnInfo batchedColumn = (BaseColumnInfo)ti.getColumn("batched"); + + if (batchedColumn != null) { + batchedColumn.setDisplayColumnFactory(new DisplayColumnFactory() { + @Override + public DisplayColumn createRenderer(ColumnInfo colInfo) { + return new ViralLoadBatchedColumn(colInfo); } - } + }); } customizeButtonBar(ti, AssayProtocolSchema.DATA_TABLE_NAME); @@ -196,24 +192,22 @@ public void customizeBatchTable(AbstractTableInfo ti) { customizeButtonBar(ti, AssayProtocolSchema.BATCHES_TABLE_NAME); } - public static class ViralLoadUnitsColumn extends DataColumn { - public ViralLoadUnitsColumn(ColumnInfo colInfo) { + public static class ViralLoadBatchedColumn extends DataColumn { + public ViralLoadBatchedColumn(ColumnInfo colInfo) { super(colInfo); } @Override public Object getValue(RenderContext ctx) { + String isBatched = "false"; Object value = super.getValue(ctx); if (value instanceof Boolean) { - boolean liquid = (Boolean) value; - if (liquid) { - return "mL"; - } - else { - return "mg"; + boolean batched = (boolean) value; + if (batched) { + isBatched = "true"; } } - return ""; + return isBatched; } @Override @@ -226,4 +220,5 @@ public String getFormattedValue(RenderContext ctx) { return h(getValue(ctx)); } } + } diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/query/ViralLoadUnitsDisplayColumnFactory.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/query/ViralLoadUnitsDisplayColumnFactory.java new file mode 100644 index 000000000..f4dc54a3a --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/query/ViralLoadUnitsDisplayColumnFactory.java @@ -0,0 +1,47 @@ +package org.labkey.wnprc_ehr.query; + +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.DataColumn; +import org.labkey.api.data.DisplayColumn; +import org.labkey.api.data.DisplayColumnFactory; +import org.labkey.api.data.RenderContext; + +public class ViralLoadUnitsDisplayColumnFactory implements DisplayColumnFactory +{ + @Override + public DisplayColumn createRenderer(ColumnInfo colInfo) { + return new ViralLoadUnitsColumn(colInfo); + } + + public static class ViralLoadUnitsColumn extends DataColumn + { + public ViralLoadUnitsColumn(ColumnInfo colInfo) { + super(colInfo); + } + + @Override + public Object getValue(RenderContext ctx) { + Object value = super.getValue(ctx); + if (value instanceof Boolean) { + boolean liquid = (Boolean) value; + if (liquid) { + return "mL"; + } + else { + return "mg"; + } + } + return ""; + } + + @Override + public Object getDisplayValue(RenderContext ctx) { + return getValue(ctx); + } + + @Override + public String getFormattedValue(RenderContext ctx) { + return h(getValue(ctx)); + } + } +} diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java index 17ead2ebe..ef865161a 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java @@ -17,16 +17,32 @@ import org.labkey.api.data.AbstractTableInfo; import org.labkey.api.data.BaseColumnInfo; -import org.labkey.api.data.ColumnInfo; +//import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; +import org.labkey.api.data.DataColumn; +import org.labkey.api.data.DbSchema; +import org.labkey.api.data.DbSchemaType; +import org.labkey.api.data.JdbcType; +import org.labkey.api.data.RenderContext; +import org.labkey.api.data.SQLFragment; import org.labkey.api.data.TableInfo; +import org.labkey.api.data.TableSelector; import org.labkey.api.data.WrappedColumn; import org.labkey.api.ehr.EHRService; import org.labkey.api.ldk.table.AbstractTableCustomizer; +import org.labkey.api.query.ExprColumn; +import org.labkey.api.query.FieldKey; import org.labkey.api.query.QueryForeignKey; import org.labkey.api.query.QueryService; import org.labkey.api.query.UserSchema; +import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.StringExpressionFactory; +import org.labkey.api.view.ActionURL; +import org.labkey.dbutils.api.SimplerFilter; + +import java.io.IOException; +import java.io.Writer; /** @@ -54,6 +70,15 @@ else if (table.getName().equalsIgnoreCase("Birth") && table.getSchema().getName( customizeBirthTable((AbstractTableInfo) table); else if (table.getName().equalsIgnoreCase("protocol") && table.getSchema().getName().equalsIgnoreCase("ehr")) customizeProtocolTable((AbstractTableInfo)table); + else if (table.getName().equalsIgnoreCase("breeding_encounters") && table.getSchema().getName().equalsIgnoreCase("study")) { + customizeBreedingEncountersTable((AbstractTableInfo) table); + } else if (table.getName().equalsIgnoreCase("pregnancies") && table.getSchema().getName().equalsIgnoreCase("study")) { + customizePregnanciesTable((AbstractTableInfo) table); + } else if (table.getName().equalsIgnoreCase("housing") && table.getSchema().getName().equalsIgnoreCase("study")) { + customizeHousingTable((AbstractTableInfo) table); + } else if (matches(table, "ehr", "project")) { + customizeProjectTable((AbstractTableInfo) table); + } } } @@ -97,6 +122,24 @@ private void customizeRoomCol(AbstractTableInfo ti, String columnName) } } + private void customizeProjectTable(AbstractTableInfo ti) + { + String investigatorName = "investigatorName"; + SQLFragment sql = new SQLFragment("COALESCE((SELECT " + + "(CASE WHEN lastName IS NOT NULL AND firstName IS NOT NULL " + + "THEN (lastName ||', '|| firstName) " + + "WHEN lastName IS NOT NULL AND firstName IS NULL " + + "THEN lastName " + + "ELSE " + + "firstName " + + "END) AS investigatorWithName " + + "from ehr.investigators where rowid = " + ExprColumn.STR_TABLE_ALIAS + ".investigatorId), " + ExprColumn.STR_TABLE_ALIAS + ".inves)"); + ExprColumn newCol = new ExprColumn(ti, investigatorName, sql, JdbcType.VARCHAR); + newCol.setLabel("Investigator"); + newCol.setDescription("This column shows the name of the investigator on the project. It first checks if there is an investigatorId, and if not defaults to the old inves column."); + ti.addColumn(newCol); + } + private void customizeBirthTable(AbstractTableInfo ti) { var cond = ti.getMutableColumn("cond"); @@ -191,6 +234,11 @@ private void customizeAnimalTable(AbstractTableInfo ds) col19.setLabel("Behavior - Current"); col19.setDescription("This calculates the current behavior(s) for the animal, based on the behavior abstract table"); ds.addColumn(col19); + + BaseColumnInfo col20 = getWrappedIdCol(us, ds, "PrimateId", "demographicsPrimateId"); + col20.setLabel("PrimateId"); + col20.setDescription("Unique PrimateID column to be shared across all datasets"); + ds.addColumn(col20); } if (ds.getColumn("totalOffspring") == null) @@ -204,7 +252,7 @@ private void customizeAnimalTable(AbstractTableInfo ds) private void customizeProtocolTable(AbstractTableInfo table) { - ColumnInfo protocolCol = table.getColumn("protocol"); + BaseColumnInfo protocolCol = (BaseColumnInfo) table.getColumn("protocol"); if (protocolCol != null && table.getColumn("pdf") == null) { var col = table.addColumn(new WrappedColumn(protocolCol, "pdf")); @@ -237,8 +285,151 @@ public DisplayColumn createRenderer(ColumnInfo colInfo) return new ContactsColumn(colInfo); } });*/ + if (table.getColumn("expirationDate") == null) + { + UserSchema us = getUserSchema(table, "ehr"); + if (us != null) + { + BaseColumnInfo col2 = (BaseColumnInfo) table.addColumn(new WrappedColumn(protocolCol, "expirationDate")); + col2.setLabel("Expiration Date"); + col2.setUserEditable(false); + col2.setIsUnselectable(true); + col2.setFk(new QueryForeignKey(us, null, "protocolExpirationDate", "protocol", "protocol")); + } + } + + if (table.getColumn("countsBySpecies") == null) + { + UserSchema us = getUserSchema(table, "ehr"); + if (us != null) + { + BaseColumnInfo col2 = (BaseColumnInfo) table.addColumn(new WrappedColumn(protocolCol, "countsBySpecies")); + col2.setLabel("Max Animals Per Species"); + col2.setUserEditable(false); + col2.setIsUnselectable(true); + col2.setFk(new QueryForeignKey(us, null, "protocolCountsBySpecies", "protocol", "protocol")); + } + } + + + } + + private void customizeBreedingEncountersTable(AbstractTableInfo ti) + { + customizeSireIdColumn(ti); + } + + private void customizePregnanciesTable(AbstractTableInfo ti) { + customizeSireIdColumn(ti); + } + + private void customizeHousingTable(AbstractTableInfo ti) { + customizeReasonForMoveColumn(ti); + } + + private void customizeSireIdColumn(AbstractTableInfo ti) { + BaseColumnInfo sireid = (BaseColumnInfo) ti.getColumn("sireid"); + if (sireid != null) + { + UserSchema us = getUserSchema(ti, "study"); + if (us != null) + { + sireid.setDisplayColumnFactory(colInfo -> new DataColumn(colInfo){ + + @Override + public void renderGridCellContents(RenderContext ctx, Writer out) throws IOException + { + ActionURL url = new ActionURL("ehr", "participantView.view", us.getContainer()); + String joinedIds = (String)ctx.get(new FieldKey(getBoundColumn().getFieldKey().getParent(), "sireid")); + if (joinedIds != null) + { + String[] ids = joinedIds.split(","); + String urlString = ""; + for (int i = 0; i < ids.length; i++) + { + String id = ids[i]; + url.replaceParameter("participantId", id); + urlString += ""; + urlString += PageFlowUtil.filter(id); + urlString += ""; + if (i + 1 < ids.length) + { + urlString += ", "; + } + } + out.write(urlString); + } + } + + @Override + public Object getDisplayValue(RenderContext ctx) + { + return ctx.get(new FieldKey(getBoundColumn().getFieldKey().getParent(), "sireid")); + } + }); + } + } + } + private void customizeReasonForMoveColumn(AbstractTableInfo ti) { + BaseColumnInfo reason = (BaseColumnInfo)ti.getColumn("reason"); + if (reason != null) + { + UserSchema us = getUserSchema(ti, "study"); + if (us != null) + { + reason.setDisplayColumnFactory(colInfo -> new DataColumn(colInfo){ + @Override + public void renderGridCellContents(RenderContext ctx, Writer out) throws IOException + { + ActionURL url = new ActionURL("query", "recordDetails.view", us.getContainer()); + String joinedReasons = (String)ctx.get(new FieldKey(getBoundColumn().getFieldKey().getParent(), "reason")); + if (joinedReasons != null) + { + String[] reasons = joinedReasons.split(","); + url.addParameter("schemaName", "ehr_lookups"); + url.addParameter("query.queryName", "housing_reason"); + url.addParameter("keyField", "value"); + + StringBuilder urlString = new StringBuilder(); + for (int i = 0; i < reasons.length; i++) + { + String reasonForMoveValue = reasons[i]; + SimplerFilter filter = new SimplerFilter("set_name", CompareType.EQUAL, "housing_reason").addCondition("value", CompareType.EQUAL, reasonForMoveValue); + DbSchema schema = DbSchema.get("ehr_lookups", DbSchemaType.Module); + TableInfo ti = schema.getTable("lookups"); + TableSelector ts = new TableSelector(ti, filter, null); + String reasonForMoveTitle; + if (ts.getMap() != null && ts.getMap().get("title") != null) + { + reasonForMoveTitle = (String) ts.getMap().get("title"); + url.replaceParameter("key", reasonForMoveValue); + urlString.append(""); + urlString.append(PageFlowUtil.filter(reasonForMoveTitle)); + urlString.append(""); + } + else + { + urlString.append(PageFlowUtil.filter("<" + reasonForMoveValue + ">")); + } + if (i + 1 < reasons.length) + { + urlString.append(", "); + } + } + out.write(urlString.toString()); + } + } + + @Override + public Object getDisplayValue(RenderContext ctx) + { + return ctx.get(new FieldKey(getBoundColumn().getFieldKey().getParent(), "reason")); + } + }); + } + } } private BaseColumnInfo getWrappedIdCol(UserSchema us, AbstractTableInfo ds, String name, String queryName) diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/ModuleUpdate.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/ModuleUpdate.java new file mode 100644 index 000000000..86c1403ca --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/ModuleUpdate.java @@ -0,0 +1,189 @@ +package org.labkey.wnprc_ehr.updates; + +import org.apache.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.labkey.api.module.Module; +import org.labkey.api.module.ModuleContext; +import org.reflections.Reflections; + +import java.lang.reflect.Modifier; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Utility class for executing non-schema-related updates to the WNPRC module + */ +public class ModuleUpdate +{ + /** + * Logger for logging the logs + */ + private static final Logger LOG = Logger.getLogger(ModuleUpdate.class); + + /** + * Cached set of {@link Updater} instances reflected from the package + */ + private static Set updaters; + + /** + * Executes the after update step of each applicable updater in the package + * + * @param ctx Module update context from LabKey + */ + public static void doAfterUpdate(ModuleContext ctx) + { + getApplicableUpdaters(ctx).forEach(x -> x.doAfterUpdate(ctx)); + } + + /** + * Executes the before update step of each applicable updater in the package + * + * @param ctx Module update context from LabKey + */ + public static void doBeforeUpdate(ModuleContext ctx) + { + getApplicableUpdaters(ctx).forEach(x -> x.doBeforeUpdate(ctx)); + } + + /** + * Executes the version update step of each applicable updater in the package + * + * @param ctx Module update context from LabKey + */ + public static void doVersionUpdate(ModuleContext ctx) + { + getApplicableUpdaters(ctx).forEach(x -> x.doVersionUpdate(ctx)); + } + + /** + * Executes any deferred update action that needs to wait until the module has started + * + * @param ctx Module update context from LabKey + */ + public static void onStartup(ModuleContext ctx, Module module) + { + getApplicableUpdaters(ctx).forEach(x -> x.onStartup(ctx, module)); + } + + /** + * Uses reflection to retrieve the set of all the updaters currently in the module classpath (thread-safe). + * + * @return Set of instances of all updater implementations in the classpath + */ + private static Set getAllUpdaters() + { + if (updaters == null) + { + synchronized (ModuleUpdate.class) + { + // double null check for thread safety. one thread might create the object while + // another is in the lock wait + if (updaters == null) + { + LOG.debug("caching list of available Updater implementations"); + updaters = new Reflections(ModuleUpdate.class.getPackage().getName()) + .getSubTypesOf(Updater.class).stream() + .filter(c -> !Modifier.isAbstract(c.getModifiers())) + .map(c -> { + try + { + return c.getConstructor().newInstance(); + } + catch (Exception e) + { + LOG.warn(String.format("unable to create module updater from class: class=%s", c.getCanonicalName()), e); + return null; + } + }) + .filter(Objects::nonNull) + .sorted() + .collect(Collectors.toSet()); + LOG.debug(String.format("found %d Updater implementations for the cache", updaters.size())); + } + } + } + return updaters; + } + + /** + * Returns a stream of all applicable updaters from the current Java module based on the passed context + * + * @param ctx Module update context from LabKey + * @return Stream of {@link Updater} objects to execute + */ + private static Stream getApplicableUpdaters(ModuleContext ctx) + { + return getAllUpdaters().stream().filter(x -> x.applies(ctx)); + } + + /** + * Utility interface for applying individual, non-schema-related module updates + */ + interface Updater extends Comparable + { + /** + * Indicates whether a particular update applies given the passed context + * + * @param ctx Module context from LabKey + * @return True if this updater should be executed, false otherwise + */ + boolean applies(ModuleContext ctx); + + /** + * Executes the after update step of this update + * + * @param ctx Module context from LabKey + */ + void doAfterUpdate(ModuleContext ctx); + + /** + * Executes the before update step of this update + * + * @param ctx Module context from LabKey + */ + void doBeforeUpdate(ModuleContext ctx); + + /** + * Executes the version update step of this update + * + * @param ctx Module context from LabKey + */ + void doVersionUpdate(ModuleContext ctx); + + /** + * Returns the "target" version to which this updater is intended to update. + * + * @return Target version number (e.g., 15.15) + */ + double getTargetVersion(); + + /** + * Executes any deferred actions that need to be done after startup + * + * @param ctx Module context from LabKey + */ + void onStartup(ModuleContext ctx, Module module); + } + + /** + * Base implementation of the {@link Updater} interface that defines the sort order based on the + * target version and defaults the check for applying the module to a comparison of the target + * version and the module context's original version. + */ + static abstract class ComparableUpdater implements Updater + { + @Override + public boolean applies(ModuleContext ctx) + { + return ctx.getOriginalVersion() < this.getTargetVersion(); + } + + @Override + public int compareTo(@NotNull ModuleUpdate.Updater o) + { + return Double.compare(this.getTargetVersion(), o.getTargetVersion()); + } + } +} diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/README.md b/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/README.md new file mode 100644 index 000000000..7f2ab0ab0 --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/README.md @@ -0,0 +1,42 @@ +# Non-Schema Module Updates + +Occasionally, we need to perform updates that are not necessarily related to a schema created by the module, but do +involve data in the database or changes to datasets in the `study` schema. Those updates are perhaps best done in +the Java code of the module rather than in the schema update, and that is what the classes in this folder +(/src/java/org/labkey/wnprc_ehr/updates) is designed to handle. + +### General Overview + +In general, updates/upgrades to modules in LabKey are handled by three overrideable methods defined in the +`org.labkey.api.module.Module` interface: + + | | | + |---:|---| + |`beforeUpdate(ModuleContext ctx)`|Called in reverse dependency order on **all** modules before executing subsequent steps| + |`versionUpdate(ModuleContext ctx)`|Called in no particular order, after **all** modules have executed the before update step| + |`afterUpdate(ModuleContext ctx)`|Called immediately following the update on a given module, regardless of the completion of any other module updates| + +The code in this package--comprised of the two components listed below--leverages those steps to execute its non-schema-related updates at the appropriate time, +including an additional hook for executing any update-related work that needs to wait until all updates have completed +and the module has started up: + + | | | | + |---|---|---| + |`org.labkey.wnprc_ehr.updates.ModuleUpdate`|Class|Utility class used to invoke any applicable updates in the package, based on the versions provided by the context.| + |`org.labkey.wnprc_ehr.updates.ModuleUpdate.Updater`|Interface|Interface defining the functions to be executed at the corresponding steps for a particular version update.| + +To use these classes, we invoke the corresponding static `doXxxxUpdate` methods on the `ModuleUpdate` class from the +`beforeUpdate`, `versionUpdate`, and `afterUpdate` methods defined in the `Module` itself, as well as calling +`ModuleUpdate.onStartup` from the module's startup method (for WNPRC EHR, that's `doStartupAfterSpringConfig`). + +Those +static methods will in turn find all implementations of `ModuleUpdate.Updater` in the `org.labkey.wnprc_ehr.updates` +package (via reflection), invoke each implementation's `applies(ModuleContext ctx)` method (to get the list of applicable +updaters), and will call the update method on each updater corresponding to the static method, in the order of the values +returned by each updater's `getTargetVersion()` method. + +>NOTE: `getTargetVersion()` returns a `double`, so it allows for only two digit groups (e.g., XXX.YYY) rather than an arbitrary +>number, such as would be allowed by SemVer-style versioning (i.e., we cannot use versions like "3.9.20") + +By convention, updater implementations should be named with the target version in the classname--for example, an updater +with a target version of "2.3" should be named `UpdateTo2_3`. \ No newline at end of file diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/UpdateTo15_16.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/UpdateTo15_16.java new file mode 100644 index 000000000..507281ab1 --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/updates/UpdateTo15_16.java @@ -0,0 +1,188 @@ +package org.labkey.wnprc_ehr.updates; + +import org.apache.log4j.Logger; +import org.labkey.api.collections.CaseInsensitiveMapWrapper; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.data.DbScope; +import org.labkey.api.data.Results; +import org.labkey.api.data.SimpleFilter; +import org.labkey.api.data.TableInfo; +import org.labkey.api.ehr.EHRService; +import org.labkey.api.module.Module; +import org.labkey.api.module.ModuleContext; +import org.labkey.api.query.BatchValidationException; +import org.labkey.api.query.FieldKey; +import org.labkey.api.query.QueryService; +import org.labkey.api.query.QueryUpdateService; +import org.labkey.api.query.UserSchema; +import org.labkey.api.security.User; +import org.labkey.dbutils.api.SimpleQueryFactory; +import org.labkey.wnprc_ehr.DatasetImportHelper; +import org.labkey.wnprc_ehr.data.breeding.PregnancyHistoryCreator; + +import java.io.File; +import java.nio.file.Paths; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@SuppressWarnings("unused") // reflection +public class UpdateTo15_16 extends ModuleUpdate.ComparableUpdater +{ + /** + * Logger for logging the logs + */ + private static final Logger LOG = Logger.getLogger(UpdateTo15_16.class); + + /** + * Returns a new animal history report row built from the passed name, title, query, and description as a + * {@link CaseInsensitiveMapWrapper} (which is required by LabKey). The category will default to "Colony Management" + * + * @param reportType Type of the report (e.g., "js", "query") + * @param reportName Name of the report + * @param reportTitle Title to show on the animal history tab + * @param queryName Name of the JavaScript report to load + * @param description Description of the report + * @return Case-insensitive map of fields to data to insert into the database + */ + private static CaseInsensitiveMapWrapper generateReportRecord(String reportType, String reportName, String reportTitle, String queryName, String description) + { + return new CaseInsensitiveMapWrapper<>(Stream.of( + // @formatter:off + new AbstractMap.SimpleEntry<>("reportname", reportName) + , new AbstractMap.SimpleEntry<>("category", "Colony Management") + , new AbstractMap.SimpleEntry<>("reporttype", reportType) + , new AbstractMap.SimpleEntry<>("reporttitle", reportTitle) + , new AbstractMap.SimpleEntry<>("schemaname", "study") + , new AbstractMap.SimpleEntry<>("queryname", queryName) + , new AbstractMap.SimpleEntry<>("description", description) + , new AbstractMap.SimpleEntry<>("visible", true) + , new AbstractMap.SimpleEntry<>("todayonly", false) + , new AbstractMap.SimpleEntry<>("queryhaslocation", false) + // @formatter:on + ).collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue))); + } + + /** + * Returns all EHR module containers + * + * @param module Module being updated + * @param es EHR service used to get the EHR containers + * @return Stream of all containers with EHR and the passed module enabled + */ + private static Stream getEHRContainers(Module module, EHRService es) + { + return ContainerManager.getAllChildrenWithModule(ContainerManager.getRoot(), module).stream() + .map(es::getEHRStudyContainer).distinct(); + } + + /** + * Executes the update on the passed container as the passed user, using the passed file to retrieve the metdata + * + * @param u User executing the update + * @param c Container to update + * @param f File containing the dataset metdata to import + */ + private static void updateContainer(User u, Container c, File f) + { + LOG.debug(String.format("importing WNPRC 15.15 study metadata and updating EHR reports in container: %s", c.getName())); + DatasetImportHelper.safeImportDatasetMetadata(u, c, f); + updateReports(u, c); +// try +// { +// PregnancyHistoryCreator.createPregnanciesAndOutcomes(u, c); +// } +// catch (Exception e) +// { +// LOG.error("unable to generate pregnancy history for existing data, will need done manually", e); +// } + } + + /** + * Replaces the old "pregnancies" report in animal history with three new reports for pregnancies, + * ultrasounds, and breeding encounters + * + * @param user User executing the update + * @param container Container to update + */ + private static void updateReports(User user, Container container) + { + UserSchema schema = QueryService.get().getUserSchema(user, container, "ehr"); + assert schema != null; + + try (DbScope.Transaction tx = schema.getDbSchema().getScope().ensureTransaction()) + { + TableInfo table = schema.getTable("reports"); + assert table != null; + + QueryUpdateService qus = table.getUpdateService(); + assert qus != null; + + SimpleQueryFactory factory = new SimpleQueryFactory(user, container); + try (Results results = factory.makeQuery("ehr", "reports").select(new SimpleFilter(FieldKey.fromString("reportname"), "pregnancies"))) + { + ArrayList> toDelete = new ArrayList<>(); + results.iterator().forEachRemaining(toDelete::add); + + if (toDelete.size() > 0) + { + LOG.debug("deleting old pregnancies report, replacing with new one"); + qus.deleteRows(user, container, toDelete, null, null); + } + } + + LOG.debug("inserting new pregnancies, breeding_encounters, and ultrasounds reports to animal history"); + BatchValidationException bve = new BatchValidationException(); + qus.insertRows(user, container, Arrays.asList( + generateReportRecord("js", "pregnancies", "Pregnancies", "PregnancyReport", "This report contains a list of known pregnancies, including conception dates and sire (where available)"), + generateReportRecord("js", "breeding_encounters", "Breeding Encounters", "breeding_encounters", "This report contains a list of encounters between a breeding dam and a possible sire"), + generateReportRecord("query", "ultrasounds", "Ultrasounds", "ultrasounds", "This report details the ultrasounds performed on breeding dams")), + bve, null, null); + + if (bve.hasErrors()) + throw bve; + + tx.commit(); + } + catch (Exception e) + { + LOG.warn("unable to update EHR animal history reports, will need to be addressed manually", e); + } + } + + @Override + public void doAfterUpdate(ModuleContext ctx) + { + // no-op + } + + @Override + public void doBeforeUpdate(ModuleContext ctx) + { + // no-op + } + + @Override + public void doVersionUpdate(ModuleContext ctx) + { + // no-op + } + + @Override + public double getTargetVersion() + { + return 15.16; + } + + @Override + public void onStartup(ModuleContext ctx, Module module) + { + EHRService es = EHRService.get(); + File file = new File(Paths.get(module.getExplodedPath().getAbsolutePath(), "referenceStudy", "study").toFile(), "study.xml"); + getEHRContainers(module, es).forEach(c -> updateContainer(es.getEHRUser(c), c, file)); + } +} diff --git a/WNPRC_EHR/src/ts/breeding.ts b/WNPRC_EHR/src/ts/breeding.ts index 7ccdbfc10..082bc4a88 100644 --- a/WNPRC_EHR/src/ts/breeding.ts +++ b/WNPRC_EHR/src/ts/breeding.ts @@ -4,81 +4,69 @@ declare const LABKEY: any; import * as $ from 'jquery'; import * as URI from 'urijs'; -export class Breeding { - +export class Breeding +{ // - /** - * Marker class name for the breeding history grid (used for colorizing) - */ - private static readonly BREEDING_HISTORY_GRID_CLASS: string = 'wnprc-breeding-history-grid'; - /** * Placeholder value for the details link. Replaced by a JavaScript click handler * @type {string} */ - private static readonly DETAIL_PLACEHOLDER: string = '__DETAIL__.view?id='; + private static readonly DETAIL_PLACEHOLDER: string = '__DETAIL__.view?Id='; - // noinspection TypeScriptUnresolvedVariable /** * Configuration for all the child records to display in the parent-child detail panel * @type ChildRecordConfiguration[] */ - private static readonly CHILD_RECORDS: ChildRecordConfiguration[] = [{ - buttonBar: { - items: [ - LABKEY.QueryWebPart.standardButtons.exportRows, - LABKEY.QueryWebPart.standardButtons.print, - ], - }, - detailsURL: `/wnprc_ehr/${Breeding.DETAIL_PLACEHOLDER}\${taskid}`, - cls: Breeding.BREEDING_HISTORY_GRID_CLASS, - parametersFactory: Breeding.createQueryParams, - queryName: '_PregnancyInfoByTaskId', - schemaName: 'study', - showDetailsColumn: true, - title: 'Breeding/Pregnancy History', - }, { - parametersFactory: Breeding.createQueryParams, - queryName: '_UltrasoundInfoByTaskId', - schemaName: 'study', - title: 'Ultrasounds', - }, { - parametersFactory: Breeding.createQueryParams, - queryName: '_BreedingRemarkInfoByTaskId', - schemaName: 'study', - title: 'Breeding Remarks', - }, { - parametersFactory: Breeding.createQueryParams, - queryName: '_PregnancyOutcomeInfoByTaskId', - schemaName: 'study', - title: 'Outcome', - }]; + private static readonly CHILD_RECORDS: ChildRecordConfiguration[] = [ + { // breeding encounter + formName: 'Breeding Encounter', + parametersFactory: Breeding.createQueryParams, + queryName: '_BreedingEncounterByBreedingId', + schemaName: 'study', + title: 'Breeding Encounter' + }, { // ultrasounds + formName: 'Ultrasounds', + parametersFactory: Breeding.createQueryParams, + queryName: '_UltrasoundsByPregnancyId', + schemaName: 'study', + title: 'Ultrasounds', + }, { // outcomes + formName: 'Pregnancy Outcomes', + parametersFactory: Breeding.createQueryParams, + queryName: '_PregnancyOutcomesByPregnancyId', + schemaName: 'study', + title: 'Outcomes', + }]; // // /** - * Invokes a simple (success/failure, no return value) API method from the breeding controller. Disables/re-enables - * the button clicked in the UI - * @param {HTMLButtonElement} target - * @param action + * Generates the default button bar config using the passed data entry form name and object id. + * @param {String} formName + * @param {String} objectId + * @returns {{buttonBar: {items: (any | {text: string; url: any})[]}}} */ - private static callSimpleApiButtonAction(target: HTMLButtonElement, action: string) { - $(target).prop('disabled', true); - // noinspection TypeScriptUnresolvedFunction - LABKEY.Ajax.request({ - failure: (error) => { - LABKEY.Utils.onError(error); - $(target).prop('disabled', false); - }, - method: 'POST', - success: () => { - $(target).prop('disabled', false); + private static createDefaultButtonBar(formName: String, objectId: String) + { + return { + buttonBar: { + items: [ + LABKEY.QueryWebPart.standardButtons.exportRows, + LABKEY.QueryWebPart.standardButtons.print, + { + text: 'insert new', + url: LABKEY.ActionURL.buildURL('ehr', 'dataEntryForm', LABKEY.ActionURL.getContainer(), { + formType: formName, + returnUrl: window.location, + pregnancyid: objectId, + }), + }, + ], }, - url: LABKEY.ActionURL.buildURL('wnprc_ehr', action), - }); + } } /** @@ -86,8 +74,9 @@ export class Breeding { * @param {DataSetRecord} record * @returns {{PARENT_RECORD_ID: any}} */ - private static createQueryParams(record: DataSetRecord) { - return {TASK_ID: record.get('taskid')}; + private static createQueryParams(record: DataSetRecord) + { + return {PARENT_RECORD_ID: record.get('objectid')}; } /** @@ -95,17 +84,21 @@ export class Breeding { * @param {string} key * @param {string | null} value */ - private static updateBrowserState(key: keyof PregnancyState, value: string | null) { - if (window.history && window.history.pushState) { + private static updateBrowserState(key: keyof PregnancyState, value: string | null) + { + if (window.history && window.history.pushState) + { const state = window.history.state || {}; - if (state[key] !== value) { + if (state[key] !== value) + { state[key] = value; const uri = URI(document.location); - if (value === null) { - // noinspection TypeScriptUnresolvedFunction + if (value === null) + { uri.removeQuery(key); - } else { - // noinspection TypeScriptUnresolvedFunction + } + else + { uri.setQuery(key, value); } window.history.pushState(state, document.title, uri.href()); @@ -131,69 +124,38 @@ export class Breeding { // - // noinspection JSUnusedGlobalSymbols, JSMethodCanBeStatic: called from HTML - /** - * Initiates the dataset data import by invoking the importDatasetData method in the BreedingController - * @param {HTMLButtonElement} target - */ - public importDatasetData(target: HTMLButtonElement) { - Breeding.callSimpleApiButtonAction(target, 'importDatasetData'); - } - - // noinspection JSUnusedGlobalSymbols, JSMethodCanBeStatic: called from HTML - /** - * Initiates the dataset metadata import by invoking the importDatasetMetadata method in the BreedingController - * @param {HTMLButtonElement} target - */ - public importDatasetMetadata(target: HTMLButtonElement) { - Breeding.callSimpleApiButtonAction(target, 'importDatasetMetadata'); - } - - // noinspection JSUnusedGlobalSymbols: called from HTML + // noinspection JSMethodCanBeStatic,JSUnusedGlobalSymbols /** * Entry point for the main polyfill. Renders the pregnancy grid (and possibly the details) and hooks up the browser * history management using the popstate event * @param {string} gridElementId * @param {string} detailElementId + * @param {string} subjects */ - public render(gridElementId: string, detailElementId: string) { + public render(gridElementId: string, detailElementId: string, subjects?: string) + { window.onpopstate = this.onPopState.bind(this, window.onpopstate); this.detailElementId = detailElementId; this.gridElementId = gridElementId; + Breeding.updateBrowserState('subjects', subjects); this.renderGrid(URI(document.location).query(true) as PregnancyState); } - // noinspection JSUnusedGlobalSymbols, JSMethodCanBeStatic: called from HTML + // noinspection JSUnusedGlobalSymbols /** * Entry point for the LabKey webpart. Renders the detail webpart, including the details panel and the child * record grids * @param {WebPartConfig} webpart */ - public renderDetail(webpart: WebPartConfig) { - if (webpart.taskId) { - // noinspection TypeScriptUnresolvedVariable, TypeScriptUnresolvedFunction - const defaultButtonBarConfig = { - buttonBar: { - items: [ - LABKEY.QueryWebPart.standardButtons.exportRows, - LABKEY.QueryWebPart.standardButtons.print, - { - text: 'insert new', - url: LABKEY.ActionURL.buildURL('ehr', 'dataEntryForm', LABKEY.ActionURL.getContainer(), { - formType: 'Breeding Encounter', - returnUrl: window.location, - taskid: webpart.taskId, - }), - }, - ], - }, - }; - // noinspection JSUnusedGlobalSymbols, TypeScriptUnresolvedVariable + public renderDetail(webpart: WebPartConfig) + { + if (webpart.objectId) + { const detailPanel = Ext4.create('WNPRC.ext4.ChildRecordsPanel', { - childRecords: Breeding.CHILD_RECORDS.map((c) => Ext4.apply(Ext4.apply({}, defaultButtonBarConfig), c)), + childRecords: Breeding.CHILD_RECORDS.map((c) => Ext4.apply(Ext4.apply({}, Breeding.createDefaultButtonBar(c.formName, webpart.objectId)), c)), renderTo: webpart.wrapperDivId, store: { - filterArray: [LABKEY.Filter.create('taskid', webpart.taskId, LABKEY.Filter.Types.EQUAL)], + filterArray: [LABKEY.Filter.create('objectid', webpart.objectId, LABKEY.Filter.Types.EQUAL)], queryName: 'PregnancyInfo', schemaName: 'study', viewName: '_details', @@ -201,8 +163,9 @@ export class Breeding { title: 'Pregnancy Detail', }); detailPanel.on('childLoad', this.attachDetailClickHandler, this, {single: true}); - detailPanel.on('childLoad', this.colorizePregnancyRows, this, {single: true}); - } else { + } + else + { $(`#${webpart.wrapperDivId}`).empty(); } } @@ -214,35 +177,23 @@ export class Breeding { /** * Overwrites the placeholder detail URI with a javascript:void(0) and attaches the detail click handler */ - private attachDetailClickHandler() { + private attachDetailClickHandler() + { $(`a[href*='${Breeding.DETAIL_PLACEHOLDER}']`).each((i, e) => { - const id = (URI($(e).attr('href')).query(true) as any).id; + const id = (URI($(e).attr('href')).query(true) as any).Id; $(e).attr('href', 'javascript:void(0)') .click(this.onDetailClick.bind(this, id)); }); } - /** - * Changes the background color for rows in the breeding/pregnancy history that indicate pregnancies - * rather than breeding encounters (based on a value being present in the estimated conception date - * and/or the outcome date) - */ - private colorizePregnancyRows(panel: any) { - const crp = panel.getEl(`.${Breeding.BREEDING_HISTORY_GRID_CLASS}`); - // noinspection TypeScriptUnresolvedFunction - const idx = $(Ext4.dom.Query.selectNode('td[column-name$="conceptiondate"]', crp.dom)).prevAll().length; - Ext4.dom.Query.select('tr.labkey-alternate-row, tr.labkey-row', crp.dom) - .filter(e => e.children[idx] && e.children[idx].children && (e.children[idx].children.length > 0)) - .forEach(e => $(e).toggleClass('labkey-warning-row')); - } - /** * Handler for clicking the detail links in the pregnancy grid - * @param {string | null} taskId + * @param {string | null} objectId */ - private onDetailClick(taskId: string | null) { - Breeding.updateBrowserState('taskId', taskId); - this.renderWebpart(taskId); + private onDetailClick(objectId: string | null) + { + Breeding.updateBrowserState('objectId', objectId); + this.renderWebpart(objectId); } /** @@ -250,10 +201,11 @@ export class Breeding { * @param {(PopStateEvent) => void} oldHandler * @param {PopStateEvent} evt */ - private onPopState(oldHandler: (PopStateEvent) => void, evt: PopStateEvent) { - this.renderGrid(evt.state); - this.renderWebpart(null); - if (oldHandler) { + private onPopState(oldHandler: (PopStateEvent) => void, evt: PopStateEvent) + { + this.renderGrid(evt.state || ({} as PregnancyState)); + if (oldHandler) + { oldHandler(evt); } } @@ -262,8 +214,19 @@ export class Breeding { * Renders the pregnancy grid view based on the passed state (viewName/breedingId) * @param {PregnancyState} state */ - private renderGrid(state: PregnancyState) { - // noinspection JSUnusedGlobalSymbols, TypeScriptUnresolvedFunction, TypeScriptUnresolvedVariable + private renderGrid(state: PregnancyState) + { + // set up the filters. if there are subjects passed in from the animal history report (or elsewhere) + // use those, otherwise leave it empty + const filters = []; + if (state.subjects != null && state.subjects !== '') + filters.push(LABKEY.Filter.create('Id', state.subjects, LABKEY.Filter.Types.IN)); + + // set up the view. if a view had been specified as part of the state, use that, otherwise check the + // subject filters. if there are subject filters, we probably want the full pregnancy history for those + // animals, otherwise leave it blank to get the current pregnancies + const view = state.viewName || ((state.subjects != null && state.subjects !== '') ? 'pregnancies_all' : ''); + const x = new LABKEY.QueryWebPart({ buttonBar: { items: [ @@ -275,14 +238,15 @@ export class Breeding { text: 'insert new', url: LABKEY.ActionURL.buildURL('ehr', 'dataEntryForm', LABKEY.ActionURL.getContainer(), { - formType: 'Breeding Encounter', - returnUrl: window.location, + formType: 'Pregnancies', + returnUrl: window.location }), }, ], }, - detailsURL: `/wnprc_ehr/${Breeding.DETAIL_PLACEHOLDER}\${taskid}`, + detailsURL: `/wnprc_ehr/${Breeding.DETAIL_PLACEHOLDER}\${objectid}`, failure: LABKEY.Utils.onError, + filterArray: filters, maxRows: 20, queryName: 'PregnancyInfo', schemaName: 'study', @@ -290,22 +254,22 @@ export class Breeding { success: (dr) => { Breeding.updateBrowserState('viewName', dr.viewName); this.attachDetailClickHandler(); - this.renderWebpart(state.taskId); + this.renderWebpart(state.objectId); }, title: 'Pregnancies', - viewName: state.viewName || '', + viewName: view, }); x.render(this.gridElementId); } /** * Renders the detail webpart for the passed breeding encounter id (or clears it) - * @param {string | null} taskId + * @param {string | null} objectId */ - private renderWebpart(taskId: string | null) { - // noinspection TypeScriptUnresolvedFunction + private renderWebpart(objectId: string | null) + { const x = new LABKEY.WebPart({ - partConfig: {taskId}, + partConfig: {objectId}, partName: 'Pregnancy Detail', renderTo: this.detailElementId, }); @@ -315,7 +279,7 @@ export class Breeding { // } -// noinspection JSUnusedGlobalSymbols: invoked in the browser +// noinspection JSUnusedGlobalSymbols export default new Breeding(); // @@ -323,10 +287,12 @@ export default new Breeding(); /** * Child record configuration to pass to the child records panel */ -interface ChildRecordConfiguration { +interface ChildRecordConfiguration +{ buttonBar?: { items: any[] }; cls?: string; detailsURL?: string; + formName?: string; filterArrayFactory?: (record: DataSetRecord) => any[]; parametersFactory?: (record: DataSetRecord) => any; queryName: string; @@ -339,23 +305,27 @@ interface ChildRecordConfiguration { /** * Single record returned from a data store */ -interface DataSetRecord { +interface DataSetRecord +{ get: (key: string) => any; } /** * Browser state/get query parameters for loading the pregnancy grid/detail */ -interface PregnancyState { - taskId: string | null; +interface PregnancyState +{ + objectId: string | null; viewName: string | null; + subjects: string | null; } /** * Configuration object passed from the webpart config for the pregnancy detail webpart */ -interface WebPartConfig { - taskId: string | null; +interface WebPartConfig +{ + objectId: string | null; wrapperDivId: string; } diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/aliases.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/aliases.tsv index 7d84b055d..50dca56ae 100644 --- a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/aliases.tsv +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/aliases.tsv @@ -1,3 +1,5 @@ -alias type affiliate tier_rate grantNumber investigatorName projectDescription contact_name contact_phone contact_email address city state zip comments po_number po_amount charge_grant_accounts_id uw_fund uw_account uw_udds uw_class_code budgetStartDate budgetEndDate grant_period_end order_cutoff successor_account predecessor_account active gencredits mds_number -acct100 internal campus 2 acct100 James Bond monkey 007 Eve Moneypenny 1-700-007-1111 moneypenny@bondworks.com MI6 Headquarters direct 100000 3000 135 acct100 A-XY-123 7777 1/1/1996 12/31/2099 12/31/2099 12/31/2099 1 0 -acct101 external campus 3 acct101 Jon Snow NHP White Walkers Sansa Stark 1-800-123-1234 bran_telepathy@got.com The Wall Direct bill WISDM 150000 3000 136 acct101 99-8888 8888 1/1/2010 12/31/2099 12/31/2099 12/31/2099 1 0 \ No newline at end of file +alias type affiliate tier_rate grantNumber investigatorName projectDescription contact_name contact_phone contact_email address city state zip comments po_number po_amount charge_grant_accounts_id uw_fund uw_account uw_udds uw_class_code budgetStartDate budgetEndDate grant_period_end order_cutoff successor_account predecessor_account gencredits mds_number +acct100 internal campus 2 acct100 James Bond monkey 007 Eve Moneypenny 1-700-007-1111 moneypenny@bondworks.com MI6 Headquarters direct 100000 3000 135 acct100 A-XY-123 7777 1/1/1996 12/31/2099 12/31/2099 12/31/2099 0 +acct101 external campus 3 acct101 Jon Snow NHP White Walkers Sansa Stark 1-800-123-1234 bran_telepathy@got.com The Wall Direct bill WISDM 150000 3000 136 acct101 99-8888 8888 1/1/2010 12/31/2099 12/31/2099 12/31/2099 0 +acct102 internal campus 1 acct102 Jon Snow NHP White Walkers Sansa Stark 1-800-123-1234 bran_telepathy@got.com The Wall Direct bill WISDM 150000 3000 136 acct102 99-8888 8888 1/1/2010 12/31/2099 12/31/2099 12/31/2099 0 +acct103 internal campus 1 acct103 Jon Snow NHP White Walkers Sansa Stark 1-800-123-1234 bran_telepathy@got.com The Wall Direct bill WISDM 150000 3000 136 acct103 99-8888 8888 1/1/2010 12/31/2099 12/31/2099 12/31/2099 1 \ No newline at end of file diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeUnits.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeUnits.tsv index 905864741..91e969043 100644 --- a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeUnits.tsv +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeUnits.tsv @@ -1,7 +1,7 @@ -serviceCenter chargeType active -5 Business Office 1 -14 Veterinary Services 1 -8 Immunology 1 -6 Scientific Protocol Implementation 1 -9 Clinical Pathology 1 -27 EHR Services 1 \ No newline at end of file +groupName active +Business Office 1 +Veterinary Services 1 +Immunology 1 +Scientific Protocol Implementation 1 +Clinical Pathology 1 +EHR Services 1 \ No newline at end of file diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRates.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRates.tsv index b229b58b0..e1376bd68 100644 --- a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRates.tsv +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRates.tsv @@ -1,10 +1,10 @@ -name departmentCode chargeableItemStartDate chargeableItemEndDate category serviceCode active comment unitCost genCredits chargeRateStartDate chargeRateEndDate allowBlankId -Blood draws Business Office 1/1/2005 12/31/2050 Blood Draws 45 true This is a comment 2 10.0 true 1/1/2009 12/31/2040 true -Blood draws - Additional Tubes Business Office 1/1/2005 12/31/2050 Blood Draws 20 true 0.5 true 1/1/2009 1/1/2045 true -Per diems Business Office 1/1/2005 12/31/2050 Animal Per Diem 21 true 20.0 true 1/1/2007 5/1/2045 false -Medicine A per dose Veterinary Services 1/1/2005 12/31/2050 Misc. Fees 46 true 20.75 true 1/1/2007 12/31/2045 false -Replacement Animal1 Business Office 1/1/2005 12/31/2050 Animal Replacement 2 true 30.50 true 1/1/2007 1/1/2045 false -Labor -Veterinarian Scientific Protocol Implementation 1/1/2005 12/31/2050 Clinical Lab Test 52 true This is another comment 55.25 true 1/1/2007 1/1/2045 true -vaccine supplies Clinical Pathology 1/1/2005 12/31/2050 Misc. Fees 45 true This is a comment 2 15.0 true 1/1/2007 1/1/2045 true -vaccine supplies Immunology 1/1/2005 12/31/2050 Misc. Fees 45 false 25.0 true 1/1/2005 12/31/2008 true -vaccine supplies Immunology 1/1/2005 12/31/2050 Misc. Fees 45 true 20.0 true 1/1/2009 5/25/2045 true \ No newline at end of file +name groupName chargeableItemStartDate chargeableItemEndDate category active comment unitCost genCredits chargeRateStartDate chargeRateEndDate allowBlankId +Blood draws Business Office 1/1/2005 12/31/2050 Blood Draws true This is a comment 2 10.0 true 1/1/2009 12/31/2040 true +Blood draws - Additional Tubes Business Office 1/1/2005 12/31/2050 Blood Draws true 0.5 true 1/1/2009 1/1/2045 true +Per diems Business Office 1/1/2005 12/31/2050 Animal Per Diem true 20.0 true 1/1/2007 5/1/2045 false +Medicine A per dose Veterinary Services 1/1/2005 12/31/2050 Misc. Fees true 20.75 true 1/1/2007 12/31/2045 false +Replacement Animal1 Business Office 1/1/2005 12/31/2050 Animal Replacement true 30.50 true 1/1/2007 1/1/2045 false +Labor -Veterinarian Scientific Protocol Implementation 1/1/2005 12/31/2050 Clinical Lab Test true This is another comment 55.25 true 1/1/2007 1/1/2045 true +vaccine supplies Clinical Pathology 1/1/2005 12/31/2050 Misc. Fees true This is a comment 2 15.0 true 1/1/2007 1/1/2045 true +vaccine supplies Immunology 1/1/2005 12/31/2050 Misc. Fees false 25.0 true 1/1/2005 12/31/2008 true +vaccine supplies Immunology 1/1/2005 12/31/2050 Misc. Fees true 20.0 true 1/1/2009 5/25/2045 true \ No newline at end of file diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesError.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesError.tsv index 5c30c9f26..5ca35c764 100644 --- a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesError.tsv +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesError.tsv @@ -1,3 +1,3 @@ -name departmentCode chargeableItemStartDate chargeableItemEndDate category serviceCode active comment unitCost genCredits chargeRateStartDate chargeRateEndDate allowBlankId -Per diems Veterinary Services 1/1/2050 12/31/2049 Animal Per Diem 21 false 20.0 true 1/1/2018 5/1/2018 false -Medicine A per dose Veterinary Services 1/1/2005 12/31/2050 Misc. Fees 46 true 20.75 true 5/5/2018 12/31/2019 false \ No newline at end of file +name groupName chargeableItemStartDate chargeableItemEndDate category active comment unitCost genCredits chargeRateStartDate chargeRateEndDate allowBlankId +Per diems Veterinary Services 1/1/2050 12/31/2049 Animal Per Diem false 20.0 true 1/1/2018 5/1/2018 false +Medicine A per dose Veterinary Services 1/1/2005 12/31/2050 Misc. Fees true 20.75 true 5/5/2018 12/31/2019 false \ No newline at end of file diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesGroupCategoryError.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesGroupCategoryError.tsv new file mode 100644 index 000000000..5f34015ae --- /dev/null +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesGroupCategoryError.tsv @@ -0,0 +1,3 @@ +name groupName chargeableItemStartDate chargeableItemEndDate category active comment unitCost genCredits chargeRateStartDate chargeRateEndDate allowBlankId +Labor charge Veterinarian Scientific Protocol Implementation 1/1/2005 12/31/2050 Surgery true This is another comment 55.25 true 1/1/2007 1/1/2045 true +needles Clinical Pathology 1/1/2005 12/31/2050 Surgery true This is a comment 2 15.0 true 1/1/2007 1/1/2045 true \ No newline at end of file diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesUpdate.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesUpdate.tsv index 0c513dd18..5b62f7a11 100644 --- a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesUpdate.tsv +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/chargeableItemsRatesUpdate.tsv @@ -1,4 +1,4 @@ -name departmentCode chargeableItemStartDate chargeableItemEndDate category serviceCode active comment unitCost genCredits chargeRateStartDate chargeRateEndDate allowBlankId -vaccine supplies Business Office 1/1/2005 12/31/2050 Misc. Fees 45 true 25.0 true 5/25/2007 01/01/2045 true -Medicine A per dose Scientific Protocol Implementation 1/1/2005 12/31/2050 Misc. Fees 46 true 20.75 true 1/1/2007 12/31/2050 false -Replacement Animal1 Scientific Protocol Implementation 1/1/2005 12/31/2050 Animal Replacement 2 true 30.50 true 1/1/2007 1/1/2045 false \ No newline at end of file +name groupName chargeableItemStartDate chargeableItemEndDate category active comment unitCost genCredits chargeRateStartDate chargeRateEndDate allowBlankId +vaccine supplies Business Office 1/1/2005 12/31/2050 Misc. Fees true 25.0 true 5/25/2007 01/01/2045 true +Medicine A per dose Scientific Protocol Implementation 1/1/2005 12/31/2050 Misc. Fees true 20.75 true 1/1/2007 12/31/2050 false +Replacement Animal1 Scientific Protocol Implementation 1/1/2005 12/31/2050 Animal Replacement true 30.50 true 1/1/2007 1/1/2045 false \ No newline at end of file diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/groupCategoryAssociations.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/groupCategoryAssociations.tsv new file mode 100644 index 000000000..9be0b4d96 --- /dev/null +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/groupCategoryAssociations.tsv @@ -0,0 +1,12 @@ +Category Group +Blood Draws Business Office +Misc. Fees Business Office +Animal Per Diem Business Office +Animal Per Diem Veterinary Services +Misc. Fees Veterinary Services +Animal Replacement Business Office +Clinical Lab Test Scientific Protocol Implementation +Misc. Fees Scientific Protocol Implementation +Animal Replacement Scientific Protocol Implementation +Misc. Fees Clinical Pathology +Misc. Fees Immunology \ No newline at end of file diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/tierRates.tsv b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/tierRates.tsv index e0bc6dcec..67fe080a7 100644 --- a/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/tierRates.tsv +++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/billing/tierRates.tsv @@ -1,5 +1,5 @@ -tierRateType tierRate startDate endDate isActive -1 1 1/1/2005 12/31/2050 TRUE -2 0.2 1/1/2005 12/31/2050 TRUE -2A 0.25 1/1/2005 12/31/2050 TRUE -3 0.3 1/1/2005 12/31/2050 TRUE \ No newline at end of file +tierRateType tierRate startDate endDate +1 1 1/1/2005 12/31/2050 +2 0.2 1/1/2005 12/31/2050 +2A 0.25 1/1/2005 12/31/2050 +3 0.3 1/1/2005 12/31/2050 \ No newline at end of file diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRCComplianceTrainingTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRCComplianceTrainingTest.java new file mode 100644 index 000000000..0d66f0a28 --- /dev/null +++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRCComplianceTrainingTest.java @@ -0,0 +1,108 @@ +package org.labkey.test.tests.wnprc_ehr; + +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.labkey.test.Locator; +import org.labkey.test.categories.CustomModules; +import org.labkey.test.categories.EHR; +import org.labkey.test.pages.list.EditListDefinitionPage; +import org.labkey.test.params.FieldDefinition; +import org.labkey.test.tests.ehr.ComplianceTrainingTest; +import org.labkey.test.util.DataRegionTable; +import org.labkey.test.util.Ext4Helper; +import org.labkey.test.util.PostgresOnlyTest; +import org.labkey.test.util.SchemaHelper; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@Category({CustomModules.class, EHR.class}) +public class WNPRCComplianceTrainingTest extends ComplianceTrainingTest implements PostgresOnlyTest +{ + @Override + protected void setUpTest() + { + super.setUpTest(); + _containerHelper.enableModule("WNPRC_EHR"); + + SchemaHelper schemaHelper = new SchemaHelper(this); + schemaHelper.createLinkedSchema(getProjectName(), null, "PublicSOPs", "/" + getProjectName(), null, "lists", null, null); + + goToSchemaBrowser(); + selectQuery("PublicSOPs", "SOPs"); + + waitForText(10000, "edit metadata"); + clickAndWait(Locator.linkWithText("edit metadata")); + clickButton("Edit Source", defaultWaitForPage); + _ext4Helper.clickExt4Tab("XML Metadata"); + setCodeEditorValue("metadataText", "\n" + + " \n" + + " \n" + + " \n" + + " true\n" + + " \n" + + " lists\n" + + " SOPs\n" + + " Id\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " lists\n" + + " SOPs\n" + + " Id\n" + + " \n" + + " \n" + + " \n" + + "
    \n" + + "
    "); + clickButton("Save", 0); + waitForElement(Locator.id("status").withText("Saved")); + } + + @Test + public void testSopSubmission() + { + beginAt("/ehr_compliancedb/" + getProjectName() + "/SOP_submission.view"); + reloadPage(); + + assertTrue("Submit button not disabled", isElementPresent(Locator.xpath("//button[@id='SOPsubmitButton' and @disabled]"))); + + DataRegionTable dr1 = DataRegionTable.findDataRegionWithinWebpart(this, "Unread SOPs (Less Than 10 Months Until Renewal)"); + DataRegionTable dr2 = DataRegionTable.findDataRegionWithinWebpart(this, "Dates SOPs Were Last Read"); + assertEquals("Incorrect row count found", 1, dr1.getDataRowCount()); + assertEquals("Incorrect row count found", 0, dr2.getDataRowCount()); + + dr1.checkAllOnPage(); + clickButton("Mark Read"); + reloadPage(); + + + dr1 = DataRegionTable.findDataRegionWithinWebpart(this, "Unread SOPs (Less Than 10 Months Until Renewal)"); + dr2 = DataRegionTable.findDataRegionWithinWebpart(this, "Dates SOPs Were Last Read"); + assertEquals("Incorrect row count found", 0, dr1.getDataRowCount()); + assertEquals("Incorrect row count found", 1, dr2.getDataRowCount()); + + assertFalse("Submit button is still disabled", isElementPresent(Locator.xpath("//button[@id='SOPsubmitButton' and @disabled]"))); + + dr2.checkAllOnPage(); + clickButton("Mark Reread"); + reloadPage(); + + waitForElement(Locator.xpath("//button[@id='SOPsubmitButton' and not(@disabled)]")); + click(Locator.id("SOPsubmitButton")); + assertAlert("You must check the box above the submit button to certify you have read your SOPs"); + + checkCheckbox(Locator.id("sopCheck")); + click(Locator.button("Submit")); + waitForElement(Ext4Helper.Locators.window("SOPs Complete")); + click(Ext4Helper.Locators.ext4Button("OK")); + } + + private void reloadPage() + { + waitForText("Mark Read"); + waitForText("Mark Reread"); + } +} diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java index 3b32ded45..f2b910b1c 100644 --- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java +++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java @@ -25,7 +25,10 @@ import org.labkey.remoteapi.query.Filter; import org.labkey.remoteapi.query.InsertRowsCommand; import org.labkey.remoteapi.query.SelectRowsCommand; +import org.labkey.remoteapi.query.UpdateRowsCommand; import org.labkey.remoteapi.query.SelectRowsResponse; +import org.labkey.remoteapi.query.TruncateTableCommand; +import org.labkey.remoteapi.query.SaveRowsResponse; import org.labkey.test.Locator; import org.labkey.test.ModulePropertyValue; import org.labkey.test.SortDirection; @@ -51,9 +54,9 @@ import org.labkey.test.util.TextSearcher; import org.labkey.test.util.ehr.EHRTestHelper; import org.labkey.test.util.ext4cmp.Ext4FieldRef; -import org.labkey.test.util.ext4cmp.Ext4FileFieldRef; import org.labkey.test.util.ext4cmp.Ext4GridRef; import org.labkey.test.util.external.labModules.LabModuleHelper; +import org.labkey.test.util.ext4cmp.Ext4ComboRef; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; @@ -66,7 +69,6 @@ import java.util.Arrays; import java.util.Date; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -74,7 +76,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.labkey.test.WebTestHelper.buildURL; -import static org.labkey.test.components.ext4.RadioButton.RadioButton; import static org.labkey.test.util.Ext4Helper.TextMatchTechnique.CONTAINS; /** @@ -98,10 +99,10 @@ public class WNPRC_EHRTest extends AbstractGenericEHRTest implements PostgresOnl protected static final String PROJECT_MEMBER_ID = "test2312318"; // PROJECT_ID's single participant private final File ALIASES_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/aliases.tsv"); - private static final int ALIASES_NUM_ROWS = 2; private final File CHARGEABLE_ITEMS_RATES_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/chargeableItemsRates.tsv"); private final File CHARGEABLE_ITEMS_RATES_ERROR_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/chargeableItemsRatesError.tsv"); + private final File CHARGEABLE_ITEMS_RATES_GROUP_CATEGORY_ERROR_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/chargeableItemsRatesGroupCategoryError.tsv"); private static final int CHARGE_RATES_NUM_ROWS = 9; private static final int CHARGEABLE_ITEMS_NUM_ROWS = 8; @@ -110,13 +111,12 @@ public class WNPRC_EHRTest extends AbstractGenericEHRTest implements PostgresOnl private static final int CHARGEABLE_ITEMS_NUM_UPDATE_ROWS = 11; private final File CHARGEABLE_ITEM_CATEGORIES_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/chargeableItemCategories.tsv"); - private static final int CHARGEABLE_ITEM_CATEGORIES_NUM_ROWS = 11; + + private final File GROUP_CATEGORY_ASSOCIATIONS_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/groupCategoryAssociations.tsv"); private final File TIER_RATES_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/tierRates.tsv"); - private static final int TIER_RATES_NUM_ROWS = 4; private final File CHARGE_UNITS_TSV = TestFileUtils.getSampleData("wnprc_ehr/billing/chargeUnits.tsv"); - private static final int CHARGE_UNITS_NUM_ROWS = 6; private static int BILLING_RUN_COUNT = 0; protected EHRTestHelper _helper = new EHRTestHelper(this); @@ -126,6 +126,11 @@ public class WNPRC_EHRTest extends AbstractGenericEHRTest implements PostgresOnl protected DateTimeFormatter _dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + public static final String NON_GEN_CREDIT_ACCOUNT_ID = "acct102"; + public static final String GEN_CREDIT_ACCT_ID = "acct103"; + + private Map aliasesMap = new HashMap<>(); + @Nullable @Override protected String getProjectName() @@ -175,6 +180,26 @@ public static void doSetup() throws Exception initTest.clickFolder("PI Portal"); initTest.addBillingPublicWebParts(); + + initTest.uploadBillingDataAndVerify(); + } + + private void uploadBillingDataAndVerify() throws Exception + { + log("Check Extensible table columns."); + checkExtensibleTablesCols(); + + log("Upload sample data."); + uploadData(); + + log("Add investigators."); + addInvestigators(); + + log("Provide Billing Data Access."); + provideBillingDataAccess(); + + log("Update new charge rates."); + updateChargeRates(); } @Override @@ -185,11 +210,11 @@ public void goToProjectHome() private void createFinanceManagementFolders() { - _containerHelper.createSubfolder(getProjectName(), getProjectName(), "WNPRC_Units", "Collaboration", null); - _containerHelper.createSubfolder(getProjectName(), "WNPRC_Units", "Operation_Services", "Collaboration", null); - _containerHelper.createSubfolder(getProjectName(), "Operation_Services", "Financial_Management", "Collaboration", null); - _containerHelper.createSubfolder(getProjectName(), "Financial_Management", "Private", "Collaboration", null); - _containerHelper.createSubfolder(getProjectName(), "Financial_Management", "PI Portal", "Collaboration", null); + _containerHelper.createSubfolder(getProjectName(), "WNPRC_Units", "Collaboration"); + _containerHelper.createSubfolder(getProjectName() + "/WNPRC_Units", "Operation_Services", "Collaboration"); + _containerHelper.createSubfolder(getProjectName() + "/WNPRC_Units/Operation_Services", "Financial_Management", "Collaboration"); + _containerHelper.createSubfolder(getProjectName() + "/WNPRC_Units/Operation_Services/Financial_Management", "Private", "Collaboration"); + _containerHelper.createSubfolder(getProjectName() + "/WNPRC_Units/Operation_Services/Financial_Management", "PI Portal", "Collaboration"); } private void loadBloodBilledByLookup() throws IOException, CommandException @@ -332,22 +357,19 @@ protected boolean doSetUserPasswords() } @Test - public void testBilling() throws IOException, CommandException + public void testBilling() { - log("Check Extensible table columns."); - checkExtensibleTablesCols(); - - log("Upload sample data."); - uploadData(); - - log("Update new charge rates."); - updateChargeRates(); - log("Enter misc charges via data entry form."); enterCharges(); - log("Perform Billing Run."); - performBillingPeriodRun(); + log("Perform Billing Run for period 10/01/2010-10/31/2010"); + performBillingRun("10/01/2010", "10/31/2010", ++BILLING_RUN_COUNT); + + log("Test Invoiced Items"); + testInvoicedItems(); + + log("Test Summary Reports"); + testSummaryReports(); log("View and download JET"); viewJET(); @@ -355,8 +377,8 @@ public void testBilling() throws IOException, CommandException log("View and download invoice PDF."); viewPDF("downloadPDF"); - log("View Estimated Charges By Project."); - viewEstimatedChargesByProject(); + log("View Billing Queries"); + viewBillingQueries(); log("Verify notification link"); testBillingNotification(); @@ -371,7 +393,8 @@ public void testBilling() throws IOException, CommandException testInvestigatorFacingLinks(); log("View Charges and adjustments Not Yet Billed"); - viewChargesAdjustmentsNotYetBilled(); + List expectedRowData = Arrays.asList("test2312318", "2011-09-15", "640991", " ", "vaccine supplies", "Misc. Fees", "Clinical Pathology", " ", "acct101", "10.0", "$15.00", "charge 2 with animal id"); + viewChargesAdjustmentsNotYetBilled(1, "comment", "charge 2 with animal id", expectedRowData); log("Download Multiple Invoices"); testDownloadMultipleInvoices(); @@ -380,6 +403,249 @@ public void testBilling() throws IOException, CommandException testDeleteInvoiceRuns(); } + @Test + public void testBulkEditChargesWithAnimalIds() + { + String comment = "Charges with Animal Ids added via bulk edit."; + String msg = "You are about to set values for 2 fields on 5 records. Do you want to do this?"; + + log ("Animals with Charge Ids - Bulk Edit via Add Batch"); + navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + clickAndWait(Locator.bodyLinkContainingText("Enter Charges with Animal Ids")); + Ext4GridRef miscChargesGrid = _helper.getExt4GridForFormSection("Misc. Charges"); + miscChargesGrid.clickTbarButton("Add Batch"); + waitForElement(Ext4Helper.Locators.window("Choose Animals")); + Ext4FieldRef.getForLabel(this, "Id(s)").setValue(StringUtils.join(MORE_ANIMAL_IDS, ";")); + Ext4FieldRef.getForLabel(this, "Bulk Edit Before Applying").setChecked(true); + waitAndClick(Ext4Helper.Locators.window("Choose Animals").append(Ext4Helper.Locators.ext4Button("Submit"))); + Locator.XPathLocator bulkEditWindow = Ext4Helper.Locators.window("Bulk Edit"); + fillBulkEditForm(bulkEditWindow, miscChargesGrid, true); + + assertEquals("Debit account derived in Bulk Edit does not match the Data Entry Grid:", "acct100", miscChargesGrid.getFieldValue(1, "debitedAccount")); + assertEquals("Total Cost calculated in Bulk Edit does not match the Data Entry Grid:", "50", miscChargesGrid.getFieldValue(1, "totalCost").toString()); + + assertEquals("Animals added via Add Batch and rows in Data Entry grid do not match:", miscChargesGrid.getRowCount(), MORE_ANIMAL_IDS.length); + + log ("Add comment via More Options --> Bulk Edit"); + addCommentViaBulkEdit(bulkEditWindow, miscChargesGrid, comment, MORE_ANIMAL_IDS.length, msg); + + log ("Submit " + comment); + submitForm(); + + log ("Verify entered charges in Misc Charges table"); + List expectedRowData = Arrays.asList("test1020148", LocalDateTime.now().format(_dateTimeFormatter), "795644", "Snow, Jon", "Blood draws", "Blood Draws", "Business Office", " ", "acct100", "5.0", "$10.00", comment); + viewChargesAdjustmentsNotYetBilled(MORE_ANIMAL_IDS.length, "comment", comment, expectedRowData); + } + + @Test + public void testDebitAccountFiltering() + { + log("Verify Debit Account drop down with list of account(s) active on the date of charge"); + + navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + clickAndWait(Locator.bodyLinkContainingText("Enter Charges without Animal Ids")); + + Ext4GridRef miscChargesGrid = _helper.getExt4GridForFormSection("Misc. Charges"); + _helper.addRecordToGrid(miscChargesGrid); + + miscChargesGrid.setGridCell(1, "date", "1997-05-16"); + Locator comboCol = miscChargesGrid.getCell(1, "debitedaccount"); + click(comboCol); + List options = _ext4Helper.getComboBoxOptions(Ext4Helper.Locators.formItemWithInputNamed("debitedaccount")); + assertEquals("There should be only one account listed in Debited Account drop down: ", 1, options.size()); + assertEquals("Account not found: ", ACCOUNT_ID_1, options.get(0)); + } + + @Test + public void testJETWithNonGenCreditAccount() + { + navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + clickAndWait(Locator.bodyLinkContainingText("Enter Charges without Animal Ids")); + + String startDate = LocalDateTime.now().minusDays(45).format(_dateTimeFormatter); + String endDate = LocalDateTime.now().minusDays(16).format(_dateTimeFormatter); + + Map mapWithDebitAcct = new LinkedHashMap<>(); + mapWithDebitAcct.put("date", startDate); + mapWithDebitAcct.put("debitedaccount", NON_GEN_CREDIT_ACCOUNT_ID); + mapWithDebitAcct.put("chargeGroup", "Business Office"); + mapWithDebitAcct.put("chargeId", "Blood draws - Additional Tubes"); + mapWithDebitAcct.put("quantity", "8"); + mapWithDebitAcct.put("chargetype", "Adjustment"); + mapWithDebitAcct.put("comment", "charge without non gen credit acct"); + + Map mapWithDebitAcct2 = new LinkedHashMap<>(); + mapWithDebitAcct2.put("date", startDate); + mapWithDebitAcct2.put("debitedaccount", GEN_CREDIT_ACCT_ID); + mapWithDebitAcct2.put("chargeGroup", "Clinical Pathology"); + mapWithDebitAcct2.put("chargeId", "vaccine supplies"); + mapWithDebitAcct2.put("quantity", "5"); + mapWithDebitAcct2.put("comment", "charge with gen credit acct"); + + log("Enter Misc. Charges with debit account " + NON_GEN_CREDIT_ACCOUNT_ID + " in grid row 1"); + enterChargesInGrid(1, mapWithDebitAcct); + + log("Enter Misc. Charges with debit account " + GEN_CREDIT_ACCT_ID + " in grid row 2"); + enterChargesInGrid(2, mapWithDebitAcct2); + + log("Submit the form"); + sleep(5000); + submitForm(); + + performBillingRun(startDate, endDate, ++BILLING_RUN_COUNT); + + navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + + DataRegionTable invoiceRunsDataRegionTable = getInvoiceRunsDataRegionTable(); + invoiceRunsDataRegionTable.link(0, "viewJETInvoice").click(); + + DataRegionTable jetRegionTable = new DataRegionTable("query", this); + assertEquals("Wrong jet item count: ", 1, jetRegionTable.getDataRowCount()); + + List expectedRowData = Arrays.asList(NON_GEN_CREDIT_ACCOUNT_ID, "$8.00"); + List actualRowData = jetRegionTable.getRowDataAsText(0, "Project", "Amount"); + assertEquals("Wrong row data for CSV to JET Preview report ", expectedRowData, actualRowData); + } + + private void addCommentViaBulkEdit(Locator.XPathLocator bulkEditWindow, Ext4GridRef grid, String comment, int numRows, String msg) + { + grid.clickTbarButton("Select All"); + openBulkEditWindowViaMoreActions(bulkEditWindow, grid); + _helper.toggleBulkEditField("Comment"); + _ext4Helper.queryOne("window field[fieldLabel=Comment]", Ext4ComboRef.class).setValue(comment); + waitAndClick(bulkEditWindow.append(Ext4Helper.Locators.ext4Button("Submit"))); + checkMessageWindow("Set Values", msg, "Yes"); + grid.waitForRowCount(numRows); + } + + private void openBulkEditWindowViaMoreActions(Locator.XPathLocator bulkEditWindow, Ext4GridRef grid) + { + grid.clickTbarButton("More Actions"); + click(Ext4Helper.Locators.menuItem("Bulk Edit")); + waitForElement(bulkEditWindow); + } + + private void fillBulkEditForm(Locator.XPathLocator bulkEditWindow, Ext4GridRef grid, boolean hasAnimalId) + { + waitForElement(bulkEditWindow); + + _helper.toggleBulkEditField("Date of Charge"); + if (Ext4FieldRef.getForLabel(this, "Date of Charge").getValue() == null) + { + Ext4FieldRef.getForLabel(this, "Date of Charge").setValue(LocalDateTime.now().format(_dateTimeFormatter)); + } + + log ("Toggle fields"); + if (hasAnimalId) + { + _helper.toggleBulkEditField("Project"); + } + else + { + _helper.toggleBulkEditField("Debit Account"); + } + + _helper.toggleBulkEditField("Investigator"); + _helper.toggleBulkEditField("Group"); + _helper.toggleBulkEditField("Charge Item"); + _helper.toggleBulkEditField("Quantity"); + _helper.toggleBulkEditField("Unit Cost"); + + log("Set and Reset fields"); + + if (hasAnimalId) + { + log("Set Project"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Project:"), Ext4Helper.TextMatchTechnique.CONTAINS, "640991"); + + log ("Set Investigator"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Investigator:"), "Stark, Sansa"); + + } + else + { + log ("Set Debit Account"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Debit Account:"), Ext4Helper.TextMatchTechnique.CONTAINS, "101"); + + log ("Set Investigator"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Investigator:"), Ext4Helper.TextMatchTechnique.CONTAINS, "Snow, Jon"); + + } + + if (hasAnimalId) + { + log ("Reset Project"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Project:"), Ext4Helper.TextMatchTechnique.CONTAINS, "795644"); + + log ("Reset Investigator"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Investigator:"), Ext4Helper.TextMatchTechnique.CONTAINS, "Snow, Jon"); + } + else + { + log ("Set Debit Account"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Debit Account:"), Ext4Helper.TextMatchTechnique.CONTAINS, "100"); + + log ("Set Investigator"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Investigator:"), Ext4Helper.TextMatchTechnique.CONTAINS, "Stark, Sansa"); + + } + + log ("Set Group"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Group:"), Ext4Helper.TextMatchTechnique.CONTAINS, "Clinical Pathology"); + + log ("Set Charge Item"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Charge Item:"), Ext4Helper.TextMatchTechnique.CONTAINS, "vaccine supplies"); + + log ("Reset Group"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Group:"), Ext4Helper.TextMatchTechnique.CONTAINS, "Business Office"); + + log ("Reset Charge Item"); + _ext4Helper.selectComboBoxItem( Ext4Helper.Locators.formItemWithLabelContaining("Charge Item:"), Ext4Helper.TextMatchTechnique.CONTAINS, "Blood draws"); + sleep(1000); + + String unitCost = Ext4FieldRef.getForLabel(this, "Unit Cost").getValue().toString(); + assertEquals("Unit cost mismatch:", unitCost, "10"); + + Ext4FieldRef.getForLabel(this, "Quantity").setValue(5); + + waitAndClick(bulkEditWindow.append(Ext4Helper.Locators.ext4Button("Submit"))); + } + + @Test + public void testBulkEditChargesWithoutAnimalIds() + { + String msg = "You are about to set values for 2 fields on 2 records. Do you want to do this?"; + String comment = "Charges without Animal Ids added via bulk edit."; + + log ("Animals without Charge Ids - Bulk Edit via More Options --> Bulk Edit"); + navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + clickAndWait(Locator.bodyLinkContainingText("Enter Charges without Animal Ids")); + Ext4GridRef miscChargesGrid = _helper.getExt4GridForFormSection("Misc. Charges"); + _helper.addRecordToGrid(miscChargesGrid); + _helper.addRecordToGrid(miscChargesGrid); + miscChargesGrid.clickTbarButton("Select All"); + Locator.XPathLocator bulkEditWindow = Ext4Helper.Locators.window("Bulk Edit"); + openBulkEditWindowViaMoreActions(bulkEditWindow, miscChargesGrid); + fillBulkEditForm(bulkEditWindow, miscChargesGrid, false); + + Window msgWindow = new Window.WindowFinder(this.getDriver()).withTitle("Set Values").waitFor(); + msgWindow.clickButton("Yes", 0); + + assertEquals("Total Cost calculated in Bulk Edit does not match the Data Entry Grid:", "50", miscChargesGrid.getFieldValue(1, "totalCost").toString()); + assertEquals("Animals added via More Actions --> Add Batch and rows in Data Entry grid do not match:", miscChargesGrid.getRowCount(), 2); + + log ("Add comment via More Options --> Bulk Edit"); + addCommentViaBulkEdit(bulkEditWindow, miscChargesGrid, comment, 2, msg); + + log ("Submit " + comment); + submitForm(); + + log ("Verify non-animal charges entered via Bulk Edit in Misc Charges table"); + List expectedRowData = Arrays.asList(" ", LocalDateTime.now().format(_dateTimeFormatter), " ", "Stark, Sansa", "Blood draws", "Blood Draws", "Business Office", " ", "acct100", "5.0", "$10.00", comment); + viewChargesAdjustmentsNotYetBilled(2, "comment", comment, expectedRowData); + + } + private void testBillingNotification() { log("Setup the LDK notification service for this container"); @@ -409,15 +675,8 @@ private void verifyChargeSummary(String category, int rowCount) popLocation(); } - private void testInvestigatorFacingLinks() throws IOException, CommandException + private void testInvestigatorFacingLinks() { - navigateToFolder(PROJECT_NAME, EHR_FOLDER); - log("Add investigator to ehr.investigators table."); - addInvestigators(); - - navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); - provideBillingDataAccess(); - navigateToFolder(PROJECT_NAME, PI_PORTAL); log("Give EHR Lab Read access to PI Portal folder."); _permissionsHelper.setPermissions("EHR Lab", "ReaderRole"); @@ -477,32 +736,17 @@ public int getUserId(String email) throws IOException, CommandException return userid; } - public int getInvestigatorId(int userId) throws IOException, CommandException + private void addInvestigators() throws IOException, CommandException { - Connection cn = WebTestHelper.getRemoteApiConnection(); + Map investigatorsMap = new HashMap<>(); - SelectRowsCommand sr = new SelectRowsCommand("ehr", "investigators"); - sr.addFilter(new Filter("userid", userId)); - SelectRowsResponse resp = sr.execute(cn, EHR_FOLDER_PATH); + log("Add investigators to ehr.investigators table."); - int investigatorId = -1; - List> rows = resp.getRows(); - if(rows.size() == 1) - { - for (Map row : rows) - { - return (int) row.get("rowid"); - } - } - return investigatorId; - } + navigateToFolder(PROJECT_NAME, EHR_FOLDER); - private void addInvestigators() throws IOException, CommandException - { Connection cn = WebTestHelper.getRemoteApiConnection(); log("Inserting Principal Investigator Jon Snow."); - InsertRowsCommand insertCmd = new InsertRowsCommand("ehr", "investigators"); Map rowMap = new HashMap<>(); rowMap.put("firstName", "Jon"); @@ -519,82 +763,111 @@ private void addInvestigators() throws IOException, CommandException rowMap.put("userid", getUserId(INVESTIGATOR.getEmail())); insertCmd.addRow(rowMap); - insertCmd.execute(cn, EHR_FOLDER_PATH); - + insertCmd.execute(cn, EHR_FOLDER_PATH).getRows().forEach(row -> investigatorsMap.put(row.get("emailAddress").toString(), row.get("rowid"))); log("Investigators inserted in to ehr.investigators table."); - } - private void provideBillingDataAccess() throws IOException, CommandException - { - Connection cn = WebTestHelper.getRemoteApiConnection(); + log("Update ehr_billing.aliases with investigators."); + UpdateRowsCommand cmdUpd = new UpdateRowsCommand("ehr_billing", "aliases"); + Map aliasesRowMap = new HashMap<>(); + aliasesRowMap.put("rowid", aliasesMap.get(ACCOUNT_ID_1)); + aliasesRowMap.put("investigatorId", investigatorsMap.get(INVESTIGATOR.getEmail())); + cmdUpd.addRow(aliasesRowMap); - log("Provide data access to Investigator Sansa Stark."); + aliasesRowMap = new HashMap<>(); + aliasesRowMap.put("rowid", aliasesMap.get(ACCOUNT_ID_2)); + aliasesRowMap.put("investigatorId", investigatorsMap.get(INVESTIGATOR_PRINCIPAL.getEmail())); + cmdUpd.addRow(aliasesRowMap); - InsertRowsCommand insertCmd = new InsertRowsCommand("ehr_billing", "dataAccess"); - Map rowMap = new HashMap<>(); + cmdUpd.execute(cn, PRIVATE_FOLDER_PATH); - int piUserId = getUserId(INVESTIGATOR_PRINCIPAL.getEmail()); - int userId = getUserId(INVESTIGATOR.getEmail()); - rowMap.put("userid", userId); - rowMap.put("investigatorId", getInvestigatorId(piUserId)); - rowMap.put("project", "640991"); + log("Update ehr_billing.project with investigators."); + cmdUpd = new UpdateRowsCommand("ehr", "project"); + Map projRowMap = new HashMap<>(); + projRowMap.put("project", Integer.valueOf(PROJECT_ID)); + projRowMap.put("investigatorId", investigatorsMap.get(INVESTIGATOR.getEmail())); + cmdUpd.addRow(projRowMap); - insertCmd.addRow(rowMap); + projRowMap = new HashMap<>(); + projRowMap.put("project", Integer.valueOf(PROTOCOL_PROJECT_ID)); + projRowMap.put("investigatorId", investigatorsMap.get(INVESTIGATOR_PRINCIPAL.getEmail())); + cmdUpd.addRow(projRowMap); + + cmdUpd.execute(cn, EHR_FOLDER_PATH); - insertCmd.execute(cn, PRIVATE_FOLDER_PATH); } - private void viewEstimatedChargesByProject() + private void provideBillingDataAccess() { navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + clickAndWait(Locator.bodyLinkContainingText("Access To Billing Data")); + DataRegionTable dataAccessTable = new DataRegionTable("query", getDriver()); + dataAccessTable.clickInsertNewRow(); + + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("User With Access:"), Ext4Helper.TextMatchTechnique.CONTAINS, _userHelper.getDisplayNameForEmail(INVESTIGATOR.getEmail())); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Investigator:"), Ext4Helper.TextMatchTechnique.CONTAINS, "Stark, Sansa"); + _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Project:"), Ext4Helper.TextMatchTechnique.CONTAINS, "640991"); + _ext4Helper.checkCheckbox("Access to all projects?:"); + clickButton("Submit",0); + checkMessageWindow("Error", "Must choose 'Project' or check 'Access to all projects' but not both.", "OK"); + _ext4Helper.uncheckCheckbox("Access to all projects?:"); + clickButton("Submit",0); - clickAndWait(Locator.bodyLinkContainingText("Estimated Charges By Project")); - _ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithLabelContaining("Center Project"), Ext4Helper.TextMatchTechnique.CONTAINS,"640991"); - - setFormElement(Locator.input("startDate"), "09/01/2011"); - setFormElement(Locator.input("endDate"), "09/30/2011"); - clickButtonContainingText("Submit", 0); + log("Verify row insert in ehr_billing.dataAccess."); + List actualRowData = dataAccessTable.getRowDataAsText(0, "investigatorid", "userId", "project", "alldata"); + List expectedRowData = Arrays.asList("Stark, Sansa", "investigator", "640991", "No"); + assertEquals("Data access row not inserted as expected: " , expectedRowData, actualRowData); + } - DataRegionTable perDiemFeeRatesTable = new DataRegionTable("perDiemFeeRatesQueryRegion", getDriver()); - List expectedRowData = Arrays.asList(PROJECT_MEMBER_ID, "2011-09-01 00:00", "640991", "acct101", "$26.00", "30.0", "0.3", "$780.00"); - List actualRowData = perDiemFeeRatesTable.getRowDataAsText(0, "Id", "date", "project", "debitedAccount", "unitCost", "quantity", "tierRate", "totalCost"); - assertEquals("Wrong row data for Per Diem Rates Table", expectedRowData, actualRowData); - assertEquals("One row should be displayed", perDiemFeeRatesTable.getDataRowCount(), 1); + private void viewBillingQueries() + { + String startDate="09%2F01%2F2011"; + String endDate="09%2F30%2F2011"; +// clickAndWait(Locator.bodyLinkContainingText("View Billing Queries"), WAIT_FOR_JAVASCRIPT); //firefox45 on teamcity does not load this page. + navigateToFolder(PROJECT_NAME, EHR_FOLDER); + log("Verify misc charges"); + beginAt(String.format("query/%s/executeQuery.view?schemaName=wnprc_billing&query.queryName=miscChargesFeeRates&query.param.StartDate=%s&query.param.EndDate=%s", getContainerPath(), startDate, endDate)); + DataRegionTable miscChargesFeeRates = new DataRegionTable("query", this); + List expectedRowData = Arrays.asList(PROJECT_MEMBER_ID, "2011-09-15", "640991", "acct101", "$19.50", "10.0", "$195.00", getDisplayName()); + List actualRowData = miscChargesFeeRates.getRowDataAsText(0, "Id", "date", "project", "debitedAccount", "unitCost", "quantity", "totalCost", "createdby"); + assertEquals("Wrong row data for Misc Charges: ", expectedRowData, actualRowData); + assertEquals("One row should be displayed", miscChargesFeeRates.getDataRowCount(), 1); - DataRegionTable procedureFeeRatesTable = new DataRegionTable("procedureFeeRatesQueryRegion", getDriver()); - expectedRowData = Arrays.asList(PROJECT_MEMBER_ID, "2011-09-27 09:30", "640991", "acct101", "$13.00", "1", "0.3", "$13.00"); - actualRowData = procedureFeeRatesTable.getRowDataAsText(0, "Id", "date", "project", "debitedAccount", "unitCost", "quantity", "tierRate", "totalCost"); - assertEquals("Wrong row data for Procedure Fee Rates Table", expectedRowData, actualRowData); - assertEquals("Two rows should be displayed", procedureFeeRatesTable.getDataRowCount(), 2); + navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + log("Verify per diems"); + beginAt(String.format("query%s/executeQuery.view?schemaName=wnprc_billing&query.queryName=perDiemFeeRates&query.param.StartDate=%s&query.param.EndDate=%s", PRIVATE_FOLDER_PATH, startDate, endDate)); + DataRegionTable perDiemFeeRates = new DataRegionTable("query", this); + expectedRowData = Arrays.asList(PROJECT_MEMBER_ID, "2011-09-01 00:00", "640991", "acct101", "$26.00", "30.0", "0.3", "$780.00"); + actualRowData = perDiemFeeRates.getRowDataAsText(0, "Id", "date", "project", "debitedAccount", "unitCost", "quantity", "tierRate", "totalCost"); + assertEquals("Wrong row data for Per Diems: ", expectedRowData, actualRowData); + assertEquals("One row should be displayed", perDiemFeeRates.getDataRowCount(), 1); - DataRegionTable miscChargesFeeRatesTable = new DataRegionTable("miscChargesFeeRatesQueryRegion", getDriver()); - expectedRowData = Arrays.asList(PROJECT_MEMBER_ID, "2011-09-15", "640991", "acct101", "$19.50", "10.0", "$195.00"); - actualRowData = miscChargesFeeRatesTable.getRowDataAsText(0, "Id", "date", "project", "debitedAccount", "unitCost", "quantity", "totalCost"); - assertEquals("Wrong row data for Per Diem Rates Table", expectedRowData, actualRowData); - assertEquals("One row should be displayed", miscChargesFeeRatesTable.getDataRowCount(), 1); + navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + log("Verify blood draws"); + beginAt(String.format("query%s/executeQuery.view?schemaName=wnprc_billing&query.queryName=procedureFeeRates&query.param.StartDate=%s&query.param.EndDate=%s", PRIVATE_FOLDER_PATH, startDate, endDate)); + DataRegionTable procedureFeeRates = new DataRegionTable("query", this); + expectedRowData = Arrays.asList(PROJECT_MEMBER_ID, "2011-09-27 09:30", "00640991", "acct101", "$13.00", "1", "0.3", "$13.00", " "); + actualRowData = procedureFeeRates.getRowDataAsText(0, "Id", "date", "project", "debitedAccount", "unitCost", "quantity", "tierRate", "totalCost", "performedby"); + assertEquals("Wrong row data for Procedure Fee Rates/Blood Draws: ", expectedRowData, actualRowData); + assertEquals("Two rows should be displayed", procedureFeeRates.getDataRowCount(), 2); } - private void viewChargesAdjustmentsNotYetBilled() + private void viewChargesAdjustmentsNotYetBilled(int numRows, String filterCol, String filterVal, List expectedRowData) { navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); clickAndWait(Locator.bodyLinkContainingText("View Charges and Adjustments Not Yet Billed")); - setFormElement(Locator.inputByNameContaining("StartDate"), "09/01/2011"); - setFormElement(Locator.inputByNameContaining("EndDate"), "09/30/2011"); + DataRegionTable notBilled = new DataRegionTable("query", getDriver()); + notBilled.setFilter(filterCol, "Equals", filterVal); + notBilled.setSort("Id", SortDirection.ASC); - clickButtonContainingText("Submit"); + DataRegionTable table = new DataRegionTable("query", getDriver()); - waitForText("Charges and Adjustments Not Yet Billed"); + List actualRowData = notBilled.getRowDataAsText(0, "Id", "date", "project", "investigator", "chargeId/name", "chargeId/chargeCategoryId/name", "chargeGroup", "chargetype", "debitedaccount", "quantity", "unitCost", "comment"); - DataRegionTable notBilled = new DataRegionTable("query", getDriver()); - assertEquals("Charge already billed: ", " ", notBilled.getDataAsText(0, "invoiceId"));//assertNull or using Null did not work, got "expected null, but was:< >" - assertEquals("Group Name not as expected: ", "Clinical Pathology", notBilled.getDataAsText(0, "groupName")); - assertEquals("Item not as expected: ", "vaccine supplies", notBilled.getDataAsText(0, "item")); - assertEquals("Quantity not as expected: ", "10.0", notBilled.getDataAsText(0, "quantity")); - assertEquals("Unit Cost not as expected: ", "$19.50", notBilled.getDataAsText(0, "unitCost")); - assertEquals("Total Cost not as expected: ", "$195.00", notBilled.getDataAsText(0, "totalcost")); + assertEquals("Wrong number of rows for misc charges not billed for '" + filterVal + "': ", numRows, notBilled.getDataRowCount()); + assertEquals("Wrong row data for misc charges not billed: ", expectedRowData, actualRowData); } private void viewJET() @@ -647,25 +920,25 @@ private void enterCharges() mapWithAnimalId.put("Id", PROJECT_MEMBER_ID); mapWithAnimalId.put("date", "2010-10-23"); mapWithAnimalId.put("project", PROJECT_ID); - mapWithAnimalId.put("chargetype", "Clinical Pathology"); + mapWithAnimalId.put("chargeGroup", "Clinical Pathology"); mapWithAnimalId.put("chargeId", "vaccine supplies"); mapWithAnimalId.put("quantity", "10"); - mapWithAnimalId.put("chargecategory", "Adjustment"); + mapWithAnimalId.put("chargetype", "Adjustment"); mapWithAnimalId.put("comment", "charge 1 with animal id"); Map mapWithDebitAcct = new LinkedHashMap<>(); - mapWithDebitAcct.put("debitedaccount", ACCOUNT_ID_1); mapWithDebitAcct.put("date", "2010-10-23"); - mapWithDebitAcct.put("chargetype", "Business Office"); + mapWithDebitAcct.put("debitedaccount", ACCOUNT_ID_1); + mapWithDebitAcct.put("chargeGroup", "Business Office"); mapWithDebitAcct.put("chargeId", "Blood draws - Additional Tubes"); mapWithDebitAcct.put("quantity", "8"); - mapWithDebitAcct.put("chargecategory", "Adjustment"); + mapWithDebitAcct.put("chargetype", "Adjustment"); mapWithDebitAcct.put("comment", "charge 1 without animal id"); Map mapWithDebitAcct2 = new LinkedHashMap<>(); - mapWithDebitAcct2.put("debitedaccount", ACCOUNT_ID_1); mapWithDebitAcct2.put("date", "2010-10-22"); - mapWithDebitAcct2.put("chargetype", "Clinical Pathology"); + mapWithDebitAcct2.put("debitedaccount", ACCOUNT_ID_1); + mapWithDebitAcct2.put("chargeGroup", "Clinical Pathology"); mapWithDebitAcct2.put("chargeId", "vaccine supplies"); mapWithDebitAcct2.put("quantity", "5"); mapWithDebitAcct2.put("comment", "charge 2 without animal id"); @@ -674,7 +947,7 @@ private void enterCharges() mapWithAnimalId2.put("Id", PROJECT_MEMBER_ID); mapWithAnimalId2.put("date", "2011-09-15"); mapWithAnimalId2.put("project", PROJECT_ID); - mapWithAnimalId2.put("chargetype", "Clinical Pathology"); + mapWithAnimalId2.put("chargeGroup", "Clinical Pathology"); mapWithAnimalId2.put("chargeId", "vaccine supplies"); mapWithAnimalId2.put("quantity", "10"); mapWithAnimalId2.put("comment", "charge 2 with animal id"); @@ -685,7 +958,7 @@ private void enterCharges() waitAndClickAndWait(Locator.bodyLinkContainingText("Enter Charges with Animal Ids")); enterChargesInGrid(1, mapWithAnimalId); - log("Submit the form"); + log("Submit Form"); sleep(5000); submitForm(); @@ -693,12 +966,12 @@ private void enterCharges() waitAndClickAndWait(Locator.bodyLinkContainingText("Enter Charges without Animal Ids")); enterChargesInGrid(1, mapWithDebitAcct); - log("Submit the form"); + log("Submit & Reload"); sleep(5000); - submitForm(); + submitAndReloadForm(); log("Enter another Misc. Charges with debit account"); - waitAndClickAndWait(Locator.bodyLinkContainingText("Enter Charges without Animal Ids")); + waitForElement(Locator.tagContainingText("label", "Assigned To")); enterChargesInGrid(1, mapWithDebitAcct2); log("Submit the form"); @@ -720,12 +993,10 @@ private void enterChargesInGrid(int rowIndex, Map items) Ext4GridRef miscChargesGrid = _helper.getExt4GridForFormSection("Misc. Charges"); _helper.addRecordToGrid(miscChargesGrid); - Iterator iterator = items.entrySet().iterator(); - while (iterator.hasNext()) + for (Map.Entry pair : items.entrySet()) { - Map.Entry pair = (Map.Entry) iterator.next(); - String colName = pair.getKey().toString(); - String colValue = pair.getValue().toString(); + String colName = pair.getKey(); + String colValue = pair.getValue(); if (colName.equals("Id") || colName.equals("date") || colName.equals("quantity") || colName.equals("comment")) miscChargesGrid.setGridCell(rowIndex, colName, colValue); else @@ -733,24 +1004,37 @@ private void enterChargesInGrid(int rowIndex, Map items) } } + private void submitAndReloadForm() + { + sleep(2000); + clickButton("Submit And Reload", 0); + _extHelper.waitForExtDialog("Finalize Form"); + click(Ext4Helper.Locators.ext4Button("Yes")); + waitForTextToDisappear("Saving Changes", 5000); + } + private void submitForm() { +// new WebDriverWait(getDriver(), 15).until(ExpectedConditions.elementToBeClickable(Locator.button("Submit"))); + sleep(2000); clickButton("Submit", 0); _extHelper.waitForExtDialog("Finalize Form"); click(Ext4Helper.Locators.ext4Button("Yes")); waitForTextToDisappear("Saving Changes", 5000); } + private void addComboBoxRecord(int rowIndex, String colName, String comboBoxSelectionValue, Ext4GridRef miscChargesGrid, @Nullable Ext4Helper.TextMatchTechnique matchTechnique) { - Locator chargetype = miscChargesGrid.getCell(rowIndex, colName); - click(chargetype); - Locator.XPathLocator chargetypeLocator = Ext4Helper.Locators.formItemWithInputNamed(colName); + Locator comboCol = miscChargesGrid.getCell(rowIndex, colName); + click(comboCol); + sleep(2000); + Locator.XPathLocator comboColLocator = Ext4Helper.Locators.formItemWithInputNamed(colName); if (matchTechnique != null) - _ext4Helper.selectComboBoxItem(chargetypeLocator, matchTechnique, comboBoxSelectionValue); + _ext4Helper.selectComboBoxItem(comboColLocator, matchTechnique, comboBoxSelectionValue); else - _ext4Helper.selectComboBoxItem(chargetypeLocator, comboBoxSelectionValue); + _ext4Helper.selectComboBoxItem(comboColLocator, comboBoxSelectionValue); } @@ -775,6 +1059,7 @@ private void checkGrantAccountsColumns(String linkText) "budgetEndDate", "affiliate", "investigatorName", + "investigatorId", "contact_name", "contact_phone", "contact_email", @@ -820,7 +1105,6 @@ private void checkChargeableItemsColumns(String linkText) "oldPk", "name", "chargeCategoryId", - "serviceCode", "departmentCode", "comment", "active", @@ -851,9 +1135,15 @@ private void updateChargeRates() importDataPage.setFile(CHARGEABLE_ITEMS_RATES_ERROR_TSV); importDataPage.submitExpectingError(); - assertTextPresent("ERROR: For charge Item Per diems: Charge item start date (2050-01-01) is after charge item end date (2049-12-31).", - "ERROR: For charge Item Medicine A per dose: Charge rate (2018-05-05 to 2019-12-31) overlaps a previous charge rate (2007-01-01 to 2045-12-31)."); + assertTextPresent("ERROR: For charge Item Per diems: Charge item start date (2050-01-01) is after charge item end date (2049-12-31)."); + assertTextPresent("ERROR: For charge Item Medicine A per dose: Charge rate (2018-05-05 to 2019-12-31) overlaps a previous charge rate (2007-01-01 to 2045-12-31)."); + refresh(); + + log("Test for Group-Category association during data upload"); + String error1 = "ERROR: 'Scientific Protocol Implementation, Surgery' is not a valid group and category association. If this is a new association, then add this association to ehr_billing.groupCategoryAssociations table by going to 'GROUP CATEGORY ASSOCIATIONS' link on the main Finance page."; + String error2 = "ERROR: 'Clinical Pathology, Surgery' is not a valid group and category association. If this is a new association, then add this association to ehr_billing.groupCategoryAssociations table by going to 'GROUP CATEGORY ASSOCIATIONS' link on the main Finance page."; + attemptUploadWithBadData(CHARGEABLE_ITEMS_RATES_GROUP_CATEGORY_ERROR_TSV, error1, error2); uploadChargeRates(CHARGEABLE_ITEMS_RATES_UPDATE_TSV, CHARGE_RATES_NUM_UPDATE_ROWS, CHARGEABLE_ITEMS_NUM_UPDATE_ROWS); navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); @@ -872,7 +1162,15 @@ private void updateChargeRates() assertTextPresent("Medicine A per dose", 2); assertTextPresent("vaccine supplies", 3); + } + private void attemptUploadWithBadData(File file, String... errors) + { + ImportDataPage importDataPage = new ImportDataPage(getDriver()); + importDataPage.setFile(file); + importDataPage.submitExpectingError(); + + assertTextPresent(errors); } private void uploadChargeRates(File file, int rateRows, int itemRows) @@ -897,64 +1195,69 @@ private void uploadChargeRates(File file, int rateRows, int itemRows) assertEquals(itemRows, drt.getDataRowCount()); } - private void uploadData() throws IOException, CommandException + private void truncateBillingTables(Connection connection) throws IOException, CommandException { - //upload Tier Rates - importBulkDataFromFile(TIER_RATES_TSV, "Tier Rates", TIER_RATES_NUM_ROWS); - testExpectedRowCount(TIER_RATES_NUM_ROWS); - - //upload Grant Accounts - importBulkDataFromFile(ALIASES_TSV, "Grant Accounts - ALL", ALIASES_NUM_ROWS); - testExpectedRowCount(ALIASES_NUM_ROWS); + truncateTable(connection, "wnprc_billing", "tierRates"); + truncateTable(connection, "ehr_billing", "aliases"); + truncateTable(connection, "ehr_billing", "chargeUnits"); + truncateTable(connection, "ehr_billing", "chargeRates"); + truncateTable(connection, "ehr_billing", "chargeableItems"); + truncateTable(connection, "ehr_billing", "chargeableItemCategories"); + truncateTable(connection, "wnprc_billing", "groupCategoryAssociations"); - //upload Chargeable Item Categories - importBulkDataFromFile(CHARGEABLE_ITEM_CATEGORIES_TSV, "Chargeable Item Categories", CHARGEABLE_ITEM_CATEGORIES_NUM_ROWS); - testExpectedRowCount(CHARGEABLE_ITEM_CATEGORIES_NUM_ROWS); - - //upload Chargeable Items and Charge Rates - uploadChargeRates(CHARGEABLE_ITEMS_RATES_TSV, CHARGE_RATES_NUM_ROWS, CHARGEABLE_ITEMS_NUM_ROWS); - - //upload Charge Units - importBulkDataFromFile(CHARGE_UNITS_TSV, "Charge Units", CHARGE_UNITS_NUM_ROWS); - testExpectedRowCount(CHARGE_UNITS_NUM_ROWS); } - private void testExpectedRowCount(int expectedNumRows) + private void uploadData() throws IOException, CommandException { - DataRegionTable results = new DataRegionTable("query", getDriver()); - assertEquals("Wrong row count", expectedNumRows, results.getDataRowCount()); - } + Connection connection = createDefaultConnection(true); + Map responseMap = new HashMap<>(); - private void importBulkDataFromFile(File file, String linkText, int numRows) - { - navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + truncateBillingTables(connection); - clickAndWait(Locator.bodyLinkContainingText(linkText)); + //upload Tier Rates + List> tsv = loadTsv(TIER_RATES_TSV); + insertTsvData(connection, "wnprc_billing", "tierrates", tsv) + .forEach(row -> responseMap.put(row.get("tierRateType").toString(),row.get("rowid"))); - DataRegionTable drt = new DataRegionTable("query", getDriver()); - drt.clickImportBulkData(); + //upload Grant Accounts + tsv = loadTsv(ALIASES_TSV); + insertTsvData(connection, "ehr_billing", "aliases", tsv) + .forEach(row -> aliasesMap.put(row.get("alias").toString(),row.get("rowid"))); - waitForText("Import Data"); + //upload Charge Units + tsv = loadTsv(CHARGE_UNITS_TSV); + insertTsvData(connection, "ehr_billing", "chargeUnits", tsv) + .forEach(row -> responseMap.put(row.get("groupName").toString(),row.get("active"))); - _ext4Helper.clickTabContainingText("Import Spreadsheet"); - waitForText("Upload From File"); - RadioButton().withLabel("Upload From File").find(this.getDriver()).check(); + //upload Chargeable Item Categories + tsv = loadTsv(CHARGEABLE_ITEM_CATEGORIES_TSV); + insertTsvData(connection, "ehr_billing", "chargeableItemCategories", tsv) + .forEach(row -> responseMap.put(row.get("name").toString(),row.get("rowId"))); - Ext4FileFieldRef fileField = Ext4FileFieldRef.create(this); - fileField.setToFile(file); + //upload Group-Category Associations + tsv = loadTsv(GROUP_CATEGORY_ASSOCIATIONS_TSV); + insertTsvData(connection, "wnprc_billing", "groupCategoryAssociations", tsv) + .forEach(row -> responseMap.put(row.get("chargeGroupName").toString(),row.get("rowid"))); - waitAndClick(Ext4Helper.Locators.ext4ButtonContainingText("Upload")); + //upload Chargeable Items and Charge Rates + uploadChargeRates(CHARGEABLE_ITEMS_RATES_TSV, CHARGE_RATES_NUM_ROWS, CHARGEABLE_ITEMS_NUM_ROWS); - checkMessageWindow("Success", "Success! " + numRows + " rows inserted.", "OK"); } - private void performBillingPeriodRun() + private List> insertTsvData(Connection connection, String schemaName, String queryName, List> tsv) throws IOException, CommandException { - navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); + log("Loading tsv data: " + schemaName + "." + queryName); + InsertRowsCommand command = new InsertRowsCommand(schemaName,queryName); + command.setRows(tsv); + SaveRowsResponse response = command.execute(connection, PRIVATE_FOLDER_PATH); + return response.getRows(); + } - performBillingRun("10/01/2010", "10/31/2010",++BILLING_RUN_COUNT); - testInvoicedItems(); - testSummaryReports(); + private void truncateTable(Connection connection, String schemaName, String queryName) throws IOException, CommandException + { + log("Truncating table: " + schemaName + "." + queryName); + TruncateTableCommand command = new TruncateTableCommand(schemaName, queryName); + command.execute(connection, PRIVATE_FOLDER_PATH); } private void performBillingRun(String startDate, String endDate, int billingRunCount) @@ -1014,10 +1317,10 @@ public void testDeleteInvoiceRuns() mapWithAnimalId.put("Id", PROJECT_MEMBER_ID); mapWithAnimalId.put("date", "2010-11-22"); mapWithAnimalId.put("project", PROJECT_ID); - mapWithAnimalId.put("chargetype", "Clinical Pathology"); + mapWithAnimalId.put("chargeGroup", "Clinical Pathology"); mapWithAnimalId.put("chargeId", "vaccine supplies"); mapWithAnimalId.put("quantity", "10"); - mapWithAnimalId.put("chargecategory", "Adjustment"); + mapWithAnimalId.put("chargetype", "Adjustment"); mapWithAnimalId.put("comment", "charge 1 with animal id"); navigateToFolder(PROJECT_NAME, PRIVATE_FOLDER); log("Enter Misc. Charges with animal Id."); @@ -1145,7 +1448,7 @@ public void testWeightDataEntry() waitForElement(Locator.xpath("//div[contains(@class, 'id-tasks-marker') and " + Locator.NOT_HIDDEN + "]//table"), WAIT_FOR_JAVASCRIPT); sleep(WAIT_FOR_JAVASCRIPT); //For the table to completely load - Teamcity error fix. assertEquals("Incorrect number of task rows.", 3, ((Locator) Locator.xpath("//div[contains(@class, 'id-tasks-marker') and " - + Locator.NOT_HIDDEN + "]//tr[@class='labkey-alternate-row' or @class='labkey-row']//a[.='Test weight task']")).findElements(getDriver()).size()); + + Locator.NOT_HIDDEN + "]//tr[contains(@class, 'labkey-alternate-row') or contains(@class, 'labkey-row')]//a[.='Test weight task']")).findElements(getDriver()).size()); sleep(1000); //Weird stopImpersonating(); @@ -1580,9 +1883,10 @@ public void testAnimalHistory() @Test public void testClinicalHistoryPanelOptions(){ + pauseJsErrorChecker(); beginAtAnimalHistoryTab(); openClinicalHistoryForAnimal("TEST1020148"); - List expectedLabels = new ArrayList( + List expectedLabels = new ArrayList<>( Arrays.asList( "Alert", "Antibiotic Sensitivity", @@ -1642,11 +1946,6 @@ private void setDoseConcFields() waitForElement(Locator.xpath("//div[@class='x-form-invalid-msg']"), WAIT_FOR_JAVASCRIPT); } - private void selectHistoryTab(String tab) - { - click(Locator.tagWithText("span", tab)); - } - private void testPaymentsReceived() { String date = LocalDateTime.now().format(_dateTimeFormatter); @@ -1656,15 +1955,13 @@ private void testPaymentsReceived() clickAndWait(Locator.bodyLinkContainingText("Invoice")); DataRegionTable invoice = new DataRegionTable("query", getDriver()); invoice.clickEditRow(0); - setFormElement(Locator.input("invoiceSentOn"), date); - setFormElement(Locator.input("paymentReceivedOn"), date); - setFormElement(Locator.input("paymentAmountReceived"), amount); + setFormElement(Locator.inputByNameContaining("invoiceSentOn"), date); + setFormElement(Locator.inputByNameContaining("paymentReceivedOn"), date); + setFormElement(Locator.inputByNameContaining("paymentAmountReceived"), amount); clickButton("Submit",0); - - Window msgWindow = new Window.WindowFinder(this.getDriver()).withTitle("Success").waitFor(); - assertEquals("Your upload was successful!", "Success", msgWindow.getTitle()); - msgWindow.clickButton("OK", 0); + waitForText("Your upload was successful!"); + clickButton("OK"); invoice = new DataRegionTable("query", getDriver()); String balance = invoice.getDataAsText(0,"balanceDue"); @@ -1679,8 +1976,8 @@ private void testPaymentsReceived() _customizeViewsHelper.applyCustomView(); DataRegionTable auditTable = new DataRegionTable("query", this); String auditLog = auditTable.getDataAsText(0,"DataChanges"); - assertTrue(auditLog.contains("paymentamountreceived: » 1028.95")); - assertTrue(auditLog.contains("balancedue: » 0.0")); + assertTrue("entry didn't contain \"paymentamountreceived: » 1028.95\"\n" + auditLog, auditLog.contains("paymentamountreceived: » 1028.95")); + assertTrue("entry didn't contain \"balancedue: » 0.0\"\n" + auditLog, auditLog.contains("balancedue: » 0.0")); } @Override diff --git a/WNPRC_EHR/tools/pg_testserver_change.sql b/WNPRC_EHR/tools/pg_testserver_change.sql index 472206e87..1fcfc17bf 100644 --- a/WNPRC_EHR/tools/pg_testserver_change.sql +++ b/WNPRC_EHR/tools/pg_testserver_change.sql @@ -72,6 +72,20 @@ WHERE (SELECT s.Category FROM prop.PropertySets s WHERE s.Set = p.Set) = 'wn AND p.Name = 'runIntervalInMinutes' ; +--disable kinship calculations +UPDATE prop.Properties p +SET Value = 'false' +WHERE (SELECT s.Category FROM prop.PropertySets s WHERE s.Set = p.Set) = 'org.labkey.ehr.geneticcalculations' + AND p.Name = 'enabled' +; + +--disable ldap sync +UPDATE prop.Properties p +SET Value = 'false' +WHERE (SELECT s.Category FROM prop.PropertySets s WHERE s.Set = p.Set) = 'ldk.ldapConfig' + AND p.Name = 'enabled' +; + UPDATE ehr.module_properties p SET stringvalue = 'test-ehr-do-not-reply@primate.wisc.edu' WHERE p.prop_name = 'site_email' @@ -141,6 +155,9 @@ WHERE (SELECT s.Category FROM prop.PropertySets s WHERE s.Set = p.Set) = 'Si DELETE FROM ehr.notificationrecipients WHERE (recipient <> 1975 OR recipient <> 1966); +--Delete +DELETE FROM googledrive.service_accounts WHERE id = '8c4a933c-2f8e-4094-9f43-46e80f14e163'; + INSERT INTO ehr.notificationrecipients (rowid, notificationtype, container, createdby, created, modifiedby, modified, recipient) VALUES diff --git a/WNPRC_EHR/tools/wnprc.modules b/WNPRC_EHR/tools/wnprc.modules index 3c5895dcb..8828beaf0 100644 --- a/WNPRC_EHR/tools/wnprc.modules +++ b/WNPRC_EHR/tools/wnprc.modules @@ -2,7 +2,7 @@ server/modules/* server/customModules/* server/optionalModules/* -externalModules/labModules/* -externalModules/onprcEHRModules/mergesync -externalModules/wnprcModules/webutils -externalModules/wnprcModules/dbutils \ No newline at end of file +server/modules/labModules/* +server/modules/onprcEHRModules/mergesync +server/modules/wnprcModules/webutils +server/modules/wnprcModules/dbutils \ No newline at end of file diff --git a/WNPRC_r24/build.gradle b/WNPRC_r24/build.gradle new file mode 100644 index 000000000..331444adc --- /dev/null +++ b/WNPRC_r24/build.gradle @@ -0,0 +1,10 @@ +apply plugin: 'java' +apply plugin: 'org.labkey.module' +compileJava { + options.compilerArgs << "-Xlint:unchecked" + +} + +dependencies { + compile project(":server:modules:wnprc-modules:WNPRC_EHR") +} \ No newline at end of file diff --git a/WNPRC_r24/module.properties b/WNPRC_r24/module.properties new file mode 100644 index 000000000..1d8136829 --- /dev/null +++ b/WNPRC_r24/module.properties @@ -0,0 +1,7 @@ +ModuleClass: org.labkey.wnprc_r24.wnprc_r24Module +Label: Marmoset WNPRC R24 module +License: Apache 2.0 +LicenseURL: http://www.apache.org/licenses/LICENSE-2.0 +ConsolidateScripts: true +ManageVersion: true +SupportedDatabases: pgsql \ No newline at end of file diff --git a/WNPRC_r24/resources/etls/WNPRC_demographics.xml b/WNPRC_r24/resources/etls/WNPRC_demographics.xml new file mode 100644 index 000000000..239921bed --- /dev/null +++ b/WNPRC_r24/resources/etls/WNPRC_demographics.xml @@ -0,0 +1,28 @@ + + + demographics + WNPRC Marmosets + + + Copy to target + + + + + + + + + + + + + + + + + + + diff --git a/WNPRC_r24/resources/etls/WNPRC_weights.xml b/WNPRC_r24/resources/etls/WNPRC_weights.xml new file mode 100644 index 000000000..0b1febe5b --- /dev/null +++ b/WNPRC_r24/resources/etls/WNPRC_weights.xml @@ -0,0 +1,20 @@ + + + WNPRC weights third component (update) + WNPRC weights third component (update) + + + Copy to target + + + + + + + + + + + + diff --git a/WNPRC_r24/resources/etls/WNPRC_weights_queued_update.xml b/WNPRC_r24/resources/etls/WNPRC_weights_queued_update.xml new file mode 100644 index 000000000..9f7500a5a --- /dev/null +++ b/WNPRC_r24/resources/etls/WNPRC_weights_queued_update.xml @@ -0,0 +1,47 @@ + + + WNPRC queued weights update + Queue up package related ETLs + + + + Copy weight rows to be deleted to local table + + + objectid + modified + + + + + + + Copy weights to local table + + + AnimalId + primateId + date + weight + objectid + modified + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/study/Demographics.query.xml b/WNPRC_r24/resources/queries/study/Demographics.query.xml new file mode 100644 index 000000000..7b274cd2b --- /dev/null +++ b/WNPRC_r24/resources/queries/study/Demographics.query.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + true + + + Gender + + + Species + + + MM-dd-yy + Date of Birth + + + MM-dd-yy + Date of Death + + + Status + + + Dam + + study + animal + id + + /query/executeQuery.view?schemaName=${schemaName}&query.queryName=Demographics&query.participantId~eq=${dam} + + + Sire + + study + animal + id + + /query/executeQuery.view?schemaName=${schemaName}&query.queryName=Demographics&query.participantId~eq=${sire} + + + true + + + true + + + true + + + true + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/study/Demographics/.qview.xml b/WNPRC_r24/resources/queries/study/Demographics/.qview.xml new file mode 100644 index 000000000..63d68f0f2 --- /dev/null +++ b/WNPRC_r24/resources/queries/study/Demographics/.qview.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/study/InVivoResults.query.xml b/WNPRC_r24/resources/queries/study/InVivoResults.query.xml new file mode 100644 index 000000000..0f7fdd460 --- /dev/null +++ b/WNPRC_r24/resources/queries/study/InVivoResults.query.xml @@ -0,0 +1,30 @@ + + + + + + + Animal Id + + + Creation Date + + + + wnprc_r24 + LookupAims + Value + + + + + wnprc_r24 + LookupDataTypes + Value + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/study/InVivoResultsPivot.sql b/WNPRC_r24/resources/queries/study/InVivoResultsPivot.sql new file mode 100644 index 000000000..35f692d22 --- /dev/null +++ b/WNPRC_r24/resources/queries/study/InVivoResultsPivot.sql @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +SELECT ivr.AnimalId, + ivr.Date, + ivr.Aim, + ivr.DataType, + group_concat(ivr.Value) as assay_value +FROM study.InVivoResults ivr +WHERE ivr.DataType IS NOT NULL +GROUP BY ivr.AnimalId, + ivr.Aim, + ivr.Date, + ivr.DataType +PIVOT assay_value BY DataType +order by Date desc, AnimalId asc, Aim asc diff --git a/WNPRC_r24/resources/queries/study/Weight/.qview.xml b/WNPRC_r24/resources/queries/study/Weight/.qview.xml new file mode 100644 index 000000000..c805594b5 --- /dev/null +++ b/WNPRC_r24/resources/queries/study/Weight/.qview.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/study/cohortsByGroup.query.xml b/WNPRC_r24/resources/queries/study/cohortsByGroup.query.xml new file mode 100644 index 000000000..c80c6ae73 --- /dev/null +++ b/WNPRC_r24/resources/queries/study/cohortsByGroup.query.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + Animal Id + + + Creation Date + + + Source Colony + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/study/cohortsByGroup.sql b/WNPRC_r24/resources/queries/study/cohortsByGroup.sql new file mode 100644 index 000000000..9fb675011 --- /dev/null +++ b/WNPRC_r24/resources/queries/study/cohortsByGroup.sql @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +select animalId, + Created as Date, + case when currentColony = 'SNPRC' then + case when sourceColony = 'SNPRC' then 'SNPRC' else 'S-NEPRC' end + else -- current colony = 'WNPRC' + case when sourceColony = 'WNPRC' then 'WNPRC' else 'W-NEPRC' end + end as sourceColony, + sequenceNum as sequenceNumMin +from study.demographics +where status = 'alive' + +union + +select animalId, + Created as Date, + 'Dead' as sourceColony, + sequenceNum as sequenceNumMin +from study.demographics +where status <> 'alive' \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/MHCHaplotypeConcatenated.query.xml b/WNPRC_r24/resources/queries/study/livingAnimalCohort.query.xml similarity index 52% rename from WNPRC_EHR/resources/queries/study/MHCHaplotypeConcatenated.query.xml rename to WNPRC_r24/resources/queries/study/livingAnimalCohort.query.xml index 405176089..aee731d26 100644 --- a/WNPRC_EHR/resources/queries/study/MHCHaplotypeConcatenated.query.xml +++ b/WNPRC_r24/resources/queries/study/livingAnimalCohort.query.xml @@ -1,19 +1,18 @@ - - + + - - Haplotypes +
    - - true + + Animal Id
    -
    +
    \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/MHCHaplotypeConcatenated.sql b/WNPRC_r24/resources/queries/study/livingAnimalCohort.sql similarity index 67% rename from WNPRC_EHR/resources/queries/study/MHCHaplotypeConcatenated.sql rename to WNPRC_r24/resources/queries/study/livingAnimalCohort.sql index 8860f7e49..81419dbac 100644 --- a/WNPRC_EHR/resources/queries/study/MHCHaplotypeConcatenated.sql +++ b/WNPRC_r24/resources/queries/study/livingAnimalCohort.sql @@ -1,20 +1,18 @@ -/* - * Copyright (c) 2014 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -SELECT -Haplotypes.id, -Haplotypes.mamuAHaplotype1 ||', '|| Haplotypes.mamuAHaplotype2 || ', '|| Haplotypes.mamuBHaplotype1||', '|| Haplotypes.mamuBHaplotype2 AS Haplotypes, -FROM study."MHCHaplotypes" AS Haplotypes \ No newline at end of file +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +select animalId +from study.demographics +where status = 'alive' \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/study/microbiotaPivot.sql b/WNPRC_r24/resources/queries/study/microbiotaPivot.sql new file mode 100644 index 000000000..181e3092a --- /dev/null +++ b/WNPRC_r24/resources/queries/study/microbiotaPivot.sql @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +SELECT d.AnimalId, + d.Date, + d.Barcode, + d.SpecimenId, + d.Otu, + group_concat(d.Value) as assay_value +FROM study.Microbiota d +WHERE d.Otu IS NOT NULL +GROUP BY d.AnimalId, + d.Date, + d.Barcode, + d.SpecimenId, + d.Otu +PIVOT assay_value BY Otu diff --git a/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers.js b/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers.js new file mode 100644 index 000000000..afb2d6dfd --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers.js @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +var console = require("console"); + +function init(event, errors) { + return; + console.log('init called'); +} + +function beforeInsert(row, errors){ + + + return; + // If we don't have the AnimalId for row, get it from the SampleInventory table + if (row.AnimalId === undefined || row.AnimalId == 'undefined') + { + console.log('beforeInsert called'); + LABKEY.Query.selectRows({ + schemaName: 'study', + queryName: 'SampleInventory', + columns: 'AnimalId', + scope: this, + filterArray: [ + LABKEY.Filter.create('SampleId', row.SampleId, LABKEY.Filter.Types.EQUAL) + ], + success: function (data) + { + if (data.rows && data.rows.length) + { + row.AnimalId = data.rows[0].AnimalId; + console.log('Found Animal Id for ' + row.SampleId + ': ' + row.AnimalId); + } + }, + failure: function (error) + { + console.log('Select rows error'); + console.log(error); + } + }); + } + } diff --git a/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers.query.xml b/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers.query.xml new file mode 100644 index 000000000..0e7e52b36 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers.query.xml @@ -0,0 +1,68 @@ + + + + + + + false + false + true + AnimalId + + wnprc_r24 + SampleInventory + SampleId + AnimalId + + + + false + false + true + Draw Date + + wnprc_r24 + SampleInventory + SampleId + Date + + + + Sample Id + + study + SampleInventory + SampleId + SampleId + + + + Lab + + wnprc_r24 + LookupLabs + Value + + + + Analyte + + wnprc_r24 + LookupAnalytes + Value + + + + Value + + + false + false + true + Lab + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers/.qview.xml new file mode 100644 index 000000000..e2ce3adc7 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/Biomarkers/.qview.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/Fit.query.xml b/WNPRC_r24/resources/queries/wnprc_r24/Fit.query.xml new file mode 100644 index 000000000..6b8ecff76 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/Fit.query.xml @@ -0,0 +1,37 @@ + + + + + + + Animal Id + + study + livingAnimalCohorts + animalId + + + + Start Date + + + Sample Id + + study + SampleInventory + SampleId + SampleId + + + + + wnprc_r24 + LookupAims + Value + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupAims.sql b/WNPRC_r24/resources/queries/wnprc_r24/LookupAims.sql new file mode 100644 index 000000000..538555a1d --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupAims.sql @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +select Value +from wnprc_r24.lookups +where SetName = 'Aims' \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupAims/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/LookupAims/.qview.xml new file mode 100644 index 000000000..b883ed82a --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupAims/.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupAnalytes.sql b/WNPRC_r24/resources/queries/wnprc_r24/LookupAnalytes.sql new file mode 100644 index 000000000..0d5008f9d --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupAnalytes.sql @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +select Value +from wnprc_r24.lookups +where SetName = 'Analytes' \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupAnalytes/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/LookupAnalytes/.qview.xml new file mode 100644 index 000000000..b883ed82a --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupAnalytes/.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupDataTypes.sql b/WNPRC_r24/resources/queries/wnprc_r24/LookupDataTypes.sql new file mode 100644 index 000000000..568b11c33 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupDataTypes.sql @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +select Value +from wnprc_r24.lookups +where SetName = 'DataTypes' \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupDataTypes/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/LookupDataTypes/.qview.xml new file mode 100644 index 000000000..b883ed82a --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupDataTypes/.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupLabs.sql b/WNPRC_r24/resources/queries/wnprc_r24/LookupLabs.sql new file mode 100644 index 000000000..ecd7a10cf --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupLabs.sql @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +select Value +from wnprc_r24.lookups +where SetName = 'Labs' \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupLabs/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/LookupLabs/.qview.xml new file mode 100644 index 000000000..b883ed82a --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupLabs/.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupSampleTypes.sql b/WNPRC_r24/resources/queries/wnprc_r24/LookupSampleTypes.sql new file mode 100644 index 000000000..0b6326429 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupSampleTypes.sql @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +select Value +from wnprc_r24.lookups +where SetName = 'SampleTypes' \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupSampleTypes/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/LookupSampleTypes/.qview.xml new file mode 100644 index 000000000..b883ed82a --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupSampleTypes/.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/LookupSets/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/LookupSets/.qview.xml new file mode 100644 index 000000000..85de2c586 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/LookupSets/.qview.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/Lookups.query.xml b/WNPRC_r24/resources/queries/wnprc_r24/Lookups.query.xml new file mode 100644 index 000000000..b490a9801 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/Lookups.query.xml @@ -0,0 +1,33 @@ + + + + + + + Set Name + + wnprc_r24 + LookupSets + SetName + + + + Value + + + Sort Order + + + Disable Date + + + false + false + true + ObjectId + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/Lookups/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/Lookups/.qview.xml new file mode 100644 index 000000000..07ec34cc2 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/Lookups/.qview.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/SampleInventory.query.xml b/WNPRC_r24/resources/queries/wnprc_r24/SampleInventory.query.xml new file mode 100644 index 000000000..09a933824 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/SampleInventory.query.xml @@ -0,0 +1,50 @@ + + + + + + + Animal Id + + study + Animal + id + + + + Collection Date + + + Sample Id + + + false + false + true + Lab + + + + wnprc_r24 + LookupAims + Value + + + + + wnprc_r24 + LookupSampleTypes + Value + + + + Sample Weight + + + Sample Amount + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/SampleInventory/.qview.xml b/WNPRC_r24/resources/queries/wnprc_r24/SampleInventory/.qview.xml new file mode 100644 index 000000000..f93d6be11 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/SampleInventory/.qview.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/biomarkersPivot.sql b/WNPRC_r24/resources/queries/wnprc_r24/biomarkersPivot.sql new file mode 100644 index 000000000..55b8142a5 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/biomarkersPivot.sql @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +SELECT si.AnimalId, + si.Date, + d.SampleId, + d.Lab, + d.Analyte, + group_concat(d.Value) as assay_value +FROM wnprc_r24.Biomarkers d + inner join wnprc_r24.SampleInventory as si on d.SampleId = si.SampleId +WHERE d.Analyte IS NOT NULL +GROUP BY si.AnimalId, + d.SampleId, + si.Date, + d.Lab, + d.Analyte +PIVOT assay_value BY Analyte \ No newline at end of file diff --git a/WNPRC_r24/resources/queries/wnprc_r24/lookup_sets.query.xml b/WNPRC_r24/resources/queries/wnprc_r24/lookup_sets.query.xml new file mode 100644 index 000000000..a57209d07 --- /dev/null +++ b/WNPRC_r24/resources/queries/wnprc_r24/lookup_sets.query.xml @@ -0,0 +1,22 @@ + + + + + + + Set Name + + + Label + + + false + false + true + ObjectId + + +
    +
    +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/referenceStudy/datasets/datasets_manifest.xml b/WNPRC_r24/resources/referenceStudy/datasets/datasets_manifest.xml new file mode 100644 index 000000000..f6495c403 --- /dev/null +++ b/WNPRC_r24/resources/referenceStudy/datasets/datasets_manifest.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/referenceStudy/datasets/datasets_metadata.xml b/WNPRC_r24/resources/referenceStudy/datasets/datasets_metadata.xml new file mode 100644 index 000000000..da99946e3 --- /dev/null +++ b/WNPRC_r24/resources/referenceStudy/datasets/datasets_metadata.xml @@ -0,0 +1,173 @@ + + + + Contains up to one row of demographics data for each Animal Id. + + + varchar + Animal Id + Subject identifier + http://cpas.labkey.com/Study#ParticipantId + false + + ptid + + 32 + + + varchar + NEPRC Id + http://www.w3.org/2001/XMLSchema#string + 32 + + + timestamp + Date + http://cpas.labkey.com/Study#VisitDate + http://cpas.labkey.com/Study#VisitDate + false + Date + + + timestamp + DOB + http://www.w3.org/2001/XMLSchema#dateTime + + + timestamp + DOD + http://www.w3.org/2001/XMLSchema#dateTime + + + varchar + Status + http://www.w3.org/2001/XMLSchema#string + 4000 + + + varchar + Object Id + http://www.w3.org/2001/XMLSchema#string + 4000 + + + varchar + Species + http://www.w3.org/2001/XMLSchema#string + 4000 + + + varchar + Source Colony + http://www.w3.org/2001/XMLSchema#string + 4000 + + + varchar + Current Colony + http://www.w3.org/2001/XMLSchema#string + 4000 + + + varchar + Sex + http://www.w3.org/2001/XMLSchema#string + 4000 + + + varchar + Dam + http://cpas.labkey.com/Study#ParticipantId + http://www.w3.org/2001/XMLSchema#string + false + 4000 + + + varchar + Sire + http://cpas.labkey.com/Study#ParticipantId + http://www.w3.org/2001/XMLSchema#string + false + 4000 + + + Demographics +
    + + Contains up to one row of weight data for each Animal Id/Date/objectid combination. + + + varchar + Animal Id + Subject identifier + http://cpas.labkey.com/Study#ParticipantId + false + + ptid + + 32 + + + timestamp + Date + http://cpas.labkey.com/Study#VisitDate + http://cpas.labkey.com/Study#VisitDate + false + Date + + + double + Weight (kg) + http://www.w3.org/2001/XMLSchema#double + + + varchar + Object Id + http://www.w3.org/2001/XMLSchema#string + 4000 + true + + + Weight +
    + + + Contains one row of sample data data for each Animal Id/Date/DataType. + + + varchar + Animal Id + Subject identifier + http://cpas.labkey.com/Study#ParticipantId + false + + ptid + + 32 + + + timestamp + Date + http://cpas.labkey.com/Study#VisitDate + http://cpas.labkey.com/Study#VisitDate + false + Date + + + varchar + Aim + + + varchar + Data Type + true + 32 + + + double + Value + + + In Vivo Results +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/referenceStudy/datasets/wnprc_r24.dataset b/WNPRC_r24/resources/referenceStudy/datasets/wnprc_r24.dataset new file mode 100644 index 000000000..667aa4358 --- /dev/null +++ b/WNPRC_r24/resources/referenceStudy/datasets/wnprc_r24.dataset @@ -0,0 +1,19 @@ + # default group can be used to avoid repeating definitions for each dataset +# +# action=[REPLACE,APPEND,DELETE] (default:REPLACE) +# deleteAfterImport=[TRUE|FALSE] (default:FALSE) + +default.action=REPLACE +default.deleteAfterImport=FALSE + +# map a source tsv column (right side) to a property name or full propertyURI (left) +# predefined properties: ParticipantId, SiteId, VisitId, Created +default.property.ParticipantId=ptid +default.property.Created=dfcreate + +# use to map from filename->datasetid +# NOTE: if there are NO explicit import definitions, we will try to import all files matching pattern +# NOTE: if there are ANY explicit mapping, we will only import listed datasets + +default.filePattern=dataset(\\d*).tsv +default.importAllMatches=TRUE diff --git a/WNPRC_r24/resources/referenceStudy/study.xml b/WNPRC_r24/resources/referenceStudy/study.xml new file mode 100644 index 000000000..abc6696c0 --- /dev/null +++ b/WNPRC_r24/resources/referenceStudy/study.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-0.00-17.10.sql b/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-0.00-17.10.sql new file mode 100644 index 000000000..8bd1b1bd7 --- /dev/null +++ b/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-0.00-17.10.sql @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +-- Create schema, tables, indexes, and constraints used for wnprc_r24 module here +-- All SQL VIEW definitions should be created in wnprc_r24-create.sql and dropped in wnprc_r24-drop.sql +-- Modify by Daniel Nicolalde to Postgres 07/26/2019 +CREATE SCHEMA wnprc_r24; + + +CREATE TABLE wnprc_R24.Biomarkers( + RowId SERIAL NOT NULL, + SampleId VARCHAR(32) NOT NULL, + Lab VARCHAR(128) NULL, + Analyte VARCHAR(128) NOT NULL, + ObjectId VARCHAR(128), + Value NUMERIC(6,2), + Created TIMESTAMP NULL, + CreatedBy USERID NULL, + Modified TIMESTAMP NULL, + ModifiedBy USERID NULL, + DiCreated TIMESTAMP NULL, + DiModified TIMESTAMP NULL, + DiCreatedBy USERID NULL, + DiModifiedBy USERID NULL, + Container entityId NOT NULL, + + + CONSTRAINT PK_wnprc_r24_Biomarkers PRIMARY KEY (SampleId, Analyte), + CONSTRAINT FK_wnprc_r24_Biomarkers_container FOREIGN KEY (Container) REFERENCES core.Containers (EntityId) + ); + + +ALTER TABLE wnprc_r24.Biomarkers ALTER ObjectId SET DEFAULT (ehr.uuid()); diff --git a/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-17.10-17.20.sql b/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-17.10-17.20.sql new file mode 100644 index 000000000..1dabe5602 --- /dev/null +++ b/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-17.10-17.20.sql @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +CREATE TABLE wnprc_r24.SampleInventory( + RowId SERIAL NOT NULL, + AnimalId VARCHAR(32) NOT NULL, + Date TIMESTAMP NOT NULL, + SampleId VARCHAR(32) NOT NULL, + Aim VARCHAR(128) NULL, + SampleType VARCHAR(128) NOT NULL, + ObjectId VARCHAR(128) NULL, + Created TIMESTAMP NULL, + CreatedBy USERID NULL, + Modified TIMESTAMP NULL, + ModifiedBy USERID NULL, + DiCreated TIMESTAMP NULL, + DiModified TIMESTAMP NULL, + DiCreatedBy USERID NULL, + DiModifiedBy USERID NULL, + Container entityId NOT NULL, + + CONSTRAINT pk_wnprc_r24_sampleinventory PRIMARY KEY (SampleId), + CONSTRAINT fk_wnprc_r24_sampleinventory_container FOREIGN KEY (Container) REFERENCES core.Containers (EntityId) +); + + +ALTER TABLE wnprc_r24.SampleInventory ALTER ObjectId SET DEFAULT (ehr.uuid()); + + +CREATE TABLE wnprc_r24.lookupSets( + RowId SERIAL NOT NULL, + SetName VARCHAR(32) NOT NULL, + Label VARCHAR(32) NOT NULL, + ObjectId VARCHAR(128) NULL, + Created TIMESTAMP NULL, + CreatedBy USERID NULL, + Modified TIMESTAMP NULL, + ModifiedBy USERID NULL, + DiCreated TIMESTAMP NULL, + DiModified TIMESTAMP NULL, + DiCreatedBy USERID NULL, + DiModifiedBy USERID NULL, + Container entityId NOT NULL, + + CONSTRAINT pk_wnprc_r24_lookupsets PRIMARY KEY ( RowId ), + CONSTRAINT fk_wnprc_r24_lookupsets_container FOREIGN KEY (Container) REFERENCES core.Containers (EntityId) + ); + + +CREATE UNIQUE INDEX idx_wnprc_r24_lookupSets_setname ON wnprc_r24.lookupSets ( SetName ); + + +ALTER TABLE wnprc_r24.LookupSets ALTER ObjectId SET DEFAULT (ehr.uuid()); + + +CREATE TABLE wnprc_r24.lookups( + RowId SERIAL NOT NULL, + SetName VARCHAR(32) NOT NULL, + Value VARCHAR(128) NOT NULL, + SortOrder INTEGER NULL, + DateDisabled TIMESTAMP NULL, + ObjectId VARCHAR(128) NULL, + Created TIMESTAMP NULL, + CreatedBy USERID NULL, + Modified TIMESTAMP NULL, + ModifiedBy USERID NULL, + DiCreated TIMESTAMP NULL, + DiModified TIMESTAMP NULL, + DiCreatedBy USERID NULL, + DiModifiedBy USERID NULL, + Container entityId NOT NULL, + + CONSTRAINT pk_wnprc_r24_lookups PRIMARY KEY ( RowId ), + CONSTRAINT fk_wnprc_r24_lookups_SetName FOREIGN KEY (SetName) REFERENCES wnprc_r24.LookupSets (SetName), + CONSTRAINT fk_wnprc_r24_lookups_container FOREIGN KEY (Container) REFERENCES core.Containers (EntityId) +); + + +CREATE UNIQUE INDEX idx_wnprc_r24_lookups_setname ON wnprc_r24.lookups ( SetName , VALUE ); + + +ALTER TABLE wnprc_r24.Lookups ALTER ObjectId SET DEFAULT (ehr.uuid()); diff --git a/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-18.10-18.20.sql b/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-18.10-18.20.sql new file mode 100644 index 000000000..cd401b4cc --- /dev/null +++ b/WNPRC_r24/resources/schemas/dbscripts/postgresql/wnprc_r24-18.10-18.20.sql @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +ALTER TABLE wnprc_r24.SampleInventory ADD SampleWeight NUMERIC(7,2) NULL; +ALTER TABLE wnprc_r24.SampleInventory ADD SampleAmount NUMERIC(7,2) NULL; + +CREATE TABLE wnprc_r24.RowsToDelete( + ObjectId EntityId NOT NULL, + Modified TIMESTAMP NOT NULL, + CONSTRAINT pk_wnprc_r24_RowsToDelete PRIMARY KEY ( ObjectId ) +); + +CREATE TABLE wnprc_r24.WeightStaging ( + AnimalId VARCHAR(32) NOT NULL, + PrimateId VARCHAR(10) NOT NULL, + Date TIMESTAMP NOT NULL, + Weight NUMERIC(7,4) NOT NULL, + ObjectId EntityId NOT NULL, + Created TIMESTAMP NULL, + CreatedBy USERID NULL, + Modified TIMESTAMP NULL, + ModifiedBy USERID NULL, + WeightMVIndicator VARCHAR(32) NULL, + + CONSTRAINT pk_wnprc_r24_weight_staging PRIMARY KEY (ObjectId ) +); + diff --git a/WNPRC_r24/resources/schemas/wnprc_r24.xml b/WNPRC_r24/resources/schemas/wnprc_r24.xml new file mode 100644 index 000000000..888e0d77d --- /dev/null +++ b/WNPRC_r24/resources/schemas/wnprc_r24.xml @@ -0,0 +1,362 @@ + + + + + DETAILED + Contains one row of sample data data for each Animal Id/Date/SampleId combination. + RowId + + + false + true + + + varchar + Sample Id + true + 32 + + wnprc_r24 + SampleInventory + SampleId + + + + Lab + true + + + varchar + Analyte + true + 128 + + + double + Value + + + true + + + + + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + + + Biomarkers +
    + + DETAILED + Contains one row of sample data data for each Animal Id/Date/SampleId combination. + RowId + + + false + true + + + varchar + Animal Id + Subject identifier + http://cpas.labkey.com/Study#ParticipantId + false + + ptid + + + study + AnimalId + AnimalId + + 32 + + + timestamp + Date + http://cpas.labkey.com/Study#VisitDate + http://cpas.labkey.com/Study#VisitDate + false + Date + + + varchar + Sample Id + true + 32 + + + varchar + Aim + true + 128 + + + varchar + Sample Type + 128 + + + numeric + Sample Weight + + + numeric + Sample Amount + + + true + + + + + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + + + SampleInventory +
    + + DETAILED + Provides lookup values. + RowId + + + false + true + + + varchar + Set Name + false + 32 + + + varchar + 32 + true + + + true + + + + + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + + + LookupSets +
    + + DETAILED + Provides lookup values. + RowId + + + false + true + + + varchar + Set Name + false + 32 + + + varchar + false + 128 + + + integer + Sort Order + true + + + timestamp + Date + true + Date + + + true + + + + + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + true + + core + Users + UserId + + + + false + true + true + + + false + true + + + Lookups +
    + + + + + + RowsToDelete +
    + + Table to stage remote ETLs into. + + + + + + + + + + + + +
    +
    \ No newline at end of file diff --git a/WNPRC_r24/resources/transform/MANIFEST.MF b/WNPRC_r24/resources/transform/MANIFEST.MF new file mode 100644 index 000000000..2d26b1b89 --- /dev/null +++ b/WNPRC_r24/resources/transform/MANIFEST.MF @@ -0,0 +1,2 @@ +Main-Class: com.simontuffs.onejar.Boot +One-Jar-Main-Class: MicrobiomeTransform diff --git a/WNPRC_r24/resources/transform/META-INF/MANIFEST.MF b/WNPRC_r24/resources/transform/META-INF/MANIFEST.MF new file mode 100644 index 000000000..f75bf1fd8 --- /dev/null +++ b/WNPRC_r24/resources/transform/META-INF/MANIFEST.MF @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Ant-Version: Apache Ant 1.7.0 +Created-By: 1.4.2_04-b05 (Sun Microsystems Inc.) + diff --git a/WNPRC_r24/resources/transform/src/AbstractAssayValidator.java b/WNPRC_r24/resources/transform/src/AbstractAssayValidator.java new file mode 100644 index 000000000..efbbb35b0 --- /dev/null +++ b/WNPRC_r24/resources/transform/src/AbstractAssayValidator.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2016-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.*; +import java.util.*; + +/** + * User: klum + * Date: May 29, 2009 + */ +public abstract class AbstractAssayValidator +{ + private String _email; + private String _password; + private File _errorFile; + private Map _runProperties = new HashMap<>(); + private Map _transformFile = new HashMap<>(); + private List _errors = new ArrayList<>(); + private String _host; + private String ERROR_FILE = "c:\\temp\\Labkey\\error.txt"; + + public enum Props { + assayId, // the assay id from the run properties field + runComments, // run properties comments + containerPath, + assayType, // assay definition name : general, nab, elispot etc. + assayName, // assay instance name + userName, // user email + workingDir, // temp directory that the script will be executed from + protocolId, // protocol row id + protocolLsid, + protocolDescription, + runDataFile, + runDataUploadedFile, + errorsFile, + transformedRunPropertiesFile, + } + + public String getEmail() { + return _email; + } + + public String getPassword() { + return _password; + } + + public File getErrorFile() { + return _errorFile; + } + + public void setErrorFile(File errorFile) { + _errorFile = errorFile; + } + + public Map getRunProperties() { + return _runProperties; + } + + public String getRunProperty(String prop) { + return getRunProperties().get(prop); + } + + public String getRunProperty(Props prop) { + return getRunProperty(prop.name()); + } + + public File getWorkingDir() { + return new File(getRunProperty(Props.workingDir)); + } + + public List getErrors() { + return _errors; + } + + public void setEmail(String email) { + _email = email; + } + + public void setPassword(String password) { + _password = password; + } + + public void setHost(String host) { + _host = host; + } + + public String getHost() { + return _host; + } + + public Map getTransformFile() { + return _transformFile; + } + + protected void writeError(String message, String prop) throws IOException + { + if (_errorFile == null) + setErrorFile(new File(ERROR_FILE)); + + if (_errorFile != null) + { + _errors.add(message); + + StringBuilder sb = new StringBuilder(); + sb.append("error\t"); + sb.append(prop); + sb.append('\t'); + sb.append(message); + sb.append('\n'); + + try (PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(_errorFile, true)))) + { + pw.write(sb.toString().replaceAll("\\\\", "\\\\\\\\")); + } + } + else + throw new RuntimeException("Errors file does not exist"); + } + + protected void parseRunProperties(File runProperties) + { + try (BufferedReader br = new BufferedReader(new FileReader(runProperties))) + { + String l; + while ((l = br.readLine()) != null) + { + //System.out.println(l); + String[] parts = l.split("\t"); + _runProperties.put(parts[0], parts[1]); + + + if (Props.runDataFile.name().equals(parts[0]) && parts.length >= 4) + { + _transformFile.put(parts[1], parts[3]); + } + } + if (_runProperties.containsKey(Props.errorsFile.name())) + setErrorFile(new File(_runProperties.get(Props.errorsFile.name()))); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + private int _runErrorLevel = 0; + + protected void setMaxSeverity(int level) + { + // 0:NONE, 1:WARN, 2:ERROR + int value = 0; + + // Don't display warnings if severityLevel set to ERROR + if(level == 2) + { + value = 2; + } + else if(!"ERROR".equals(getRunProperty("severityLevel")) && level > _runErrorLevel) + { + value = level; + } + + _runErrorLevel = value; + } + + protected void writeWarnings() throws IOException + { + if(_runErrorLevel > 0) + { + try (PrintWriter fileConn = new PrintWriter(new BufferedWriter(new FileWriter(new File(getRunProperty(Props.transformedRunPropertiesFile)))))) + { + if (_runErrorLevel == 1) + { + fileConn.append("maximumSeverity\tWARN"); + } + else + { + fileConn.append("maximumSeverity\tERROR"); + } + } + + // This file gets read and displayed directly as warnings or errors, depending on maximumSeverity level. + try (PrintWriter errors = new PrintWriter(new BufferedWriter(new FileWriter(new File(getWorkingDir(), "errors.html"))))) + { + errors.println("Inline warning from Java transform.
    Warning link"); + } + + // These two files are just to verify files are available to be downloaded and reviewed + try (PrintWriter errors = new PrintWriter(new BufferedWriter(new FileWriter(new File(getWorkingDir(), "test1.txt"))))) + { + errors.println("This is test file 1 (Java)."); + } + try (PrintWriter errors = new PrintWriter(new BufferedWriter(new FileWriter(new File(getWorkingDir(), "test2.tsv"))))) + { + errors.println("This is test file 2 (Java)."); + } + + // System output should appear in import + System.out.println("System.out warning"); + System.err.println("System.err warning"); + } + } + /** + * Parse the tab-delimitted input data file + */ + protected List> parseRunData(File data) + { + BufferedReader br = null; + Map columnMap = new LinkedHashMap<>(); + List> dataMap = new ArrayList<>(); + + try { + br = new BufferedReader(new FileReader(data)); + String l; + boolean isHeader = true; + while ((l = br.readLine()) != null) + { + if (isHeader) + { + int i=0; + for (String col : l.split("\t")) + columnMap.put(i++, col.toLowerCase()); + isHeader = false; + } + dataMap.add(parseDataRow(l, columnMap)); + } + return dataMap; + } + catch (Exception e) + { + throw new RuntimeException(e.getMessage()); + } + finally + { + if (br != null) + try {br.close();} catch(IOException ioe) {} + } + } + + protected Map parseDataRow(String row, Map columnMap) + { + Map props = new LinkedHashMap<>(); + int i=0; + for (String col : row.split("\t")) + { + props.put(columnMap.get(i), col); + i++; + } + return props; + } +} diff --git a/WNPRC_r24/resources/transform/src/MicrobiomeTransform.java b/WNPRC_r24/resources/transform/src/MicrobiomeTransform.java new file mode 100644 index 000000000..45364c2ca --- /dev/null +++ b/WNPRC_r24/resources/transform/src/MicrobiomeTransform.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2016-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.*; +import java.util.*; + + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.ss.usermodel.DateUtil; + +import com.google.common.collect.*; + +public class MicrobiomeTransform extends AbstractAssayValidator +{ + private File _errorFile; + private Map _runProperties = new HashMap<>(); + private Map _colMap = new HashMap<>(); + private Map _dictionary = new HashMap<>(); + private final int numHeaderCols = 4; + + public static void main(String[] args) + { + + if (args.length < 1) + throw new IllegalArgumentException("Run properties file not passed in."); + + File runProperties = new File(args[0]); + if (runProperties.exists()) + { + + MicrobiomeTransform transform = new MicrobiomeTransform(); + transform.runTransform(runProperties); + + } + else + throw new IllegalArgumentException("Input data file does not exist"); + + } + + private String getValue(Cell cell) + { + StringBuilder value = new StringBuilder(); + + if(null != cell) + { + switch (cell.getCellType()) + { + case STRING: + value.append(cell.getStringCellValue()); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) + { + value.append(cell.getDateCellValue()); + } + else + { + value.append(((Double)cell.getNumericCellValue()).intValue()); + } + break; + case BOOLEAN: + value.append(cell.getBooleanCellValue()); + break; + } + } + + return value.toString(); + } + + private String getColumns(Row row) + { + Iterator cellIter = row.iterator(); + StringBuilder sb = new StringBuilder(); + + int col = 0; + int i = 0; + Cell cell; + String s; + + // column header lookup HashMap + _dictionary.put("Sample Id", "SampleId\t"); + _dictionary.put("Marmoset ID", "ParticipantId\t"); + _dictionary.put("Sample Date", "Date\t"); + //_dictionary.put("UI ID", "UiId\t"); + _dictionary.put("Barcode", "Barcode\t"); + + try + { + + // Populate column map + while (cellIter.hasNext()) + { + + cell = cellIter.next(); + _colMap.put(col++, getValue(cell)); + + // Get header columns + if (i < numHeaderCols) + { + s = _dictionary.get(getValue(cell)); + if (s != null) + { + sb.append(s); + } + else + { + writeError("Encountered Invalid column header: " + getValue(cell) + " " + sb.toString(), ""); + //throw new IllegalArgumentException("Encountered Invalid column header: " + getValue(cell) + "\n"); + } + + } + i++; + + } + } + catch (IOException e) + { + throw new RuntimeException(e); + } + + //i++; + + sb.append("OTU\tValue\n"); + + return sb.toString(); + } + + + // Can add more checking here + private boolean isValid(String common) + { + return !common.isEmpty() && common.trim().length() > 0; + } + + + private String processRow(Row row) + { + StringBuilder rows = new StringBuilder(); + StringBuilder common = new StringBuilder(); + StringBuilder notes = new StringBuilder(); + int note = 0, col; + Cell cell; + + int i = 0; + Integer rowNum = 0; + + for (Map.Entry entry : _colMap.entrySet()) + { + // get columns that will be used as common values for each unpivoted row + if (i < numHeaderCols) + { + i++; + col = entry.getKey(); + cell = row.getCell(col); + try + { + if (cell != null) + { + common.append(getValue(cell)); + common.append('\t'); + } + else + { + rowNum = row.getRowNum(); + writeError("Missing row identifyer informaion on row: " + rowNum.toString(), ""); + } + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + else + { + // Get OTUs + col = entry.getKey(); + String value = getValue(row.getCell(col)); + try + { + // only store rows with valued > 0 10/31/2017 tjh + int intValue = Integer.parseInt(value); + // is an integer! + + if (intValue > 0) + { + rows.append(common); + rows.append(entry.getValue() + "\t"); + rows.append(value); + rows.append('\n'); + } + } catch (NumberFormatException e) { + // not an integer! + } + } + } + return rows.toString(); + } + + public void runTransform(File inputFile) + { + + + + parseRunProperties(inputFile); + + try + { + + + //writeError("runfile name: " + inputFile, ""); + + if (getRunProperties().containsKey(Props.runDataFile.name())) + { + + File inputDataFile = new File(getRunProperty(Props.runDataUploadedFile)); + File transformFile = new File(getTransformFile().get(getRunProperty(Props.runDataFile))); + + try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(transformFile)))) + { + try { + //writeError("inputDataFile " + inputDataFile.getName() , ""); + FileInputStream stream = new FileInputStream(inputDataFile); + + Workbook workbook = new XSSFWorkbook(stream); + + Sheet firstSheet = workbook.getSheetAt(0); + + Iterator rowIter = firstSheet.iterator(); + + boolean first = true; + StringBuilder sb; + + while (rowIter.hasNext()) + { + Row nextRow = rowIter.next(); + Iterator cellIter = nextRow.iterator(); + + sb = new StringBuilder(); + if(first) + { + + sb.append(getColumns(nextRow)); + System.out.println(sb.toString()); + first = false; + + } + else + { + sb.append(processRow(nextRow)); + } + + writer.print(sb.toString()); + } + + } + catch (Exception e) + { + writeError("Error opening Excel workbook: " + inputDataFile, ""); + } + } + } + + else + writeError("Unable to locate the runDataFile", "runDataFile"); + } + + catch (IOException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/WNPRC_r24/resources/views/welcome.html b/WNPRC_r24/resources/views/welcome.html new file mode 100644 index 000000000..a8052619a --- /dev/null +++ b/WNPRC_r24/resources/views/welcome.html @@ -0,0 +1 @@ +

    Welcome to the r24 module

    \ No newline at end of file diff --git a/WNPRC_r24/resources/views/welcome.view.xml b/WNPRC_r24/resources/views/welcome.view.xml new file mode 100644 index 000000000..82fd93e60 --- /dev/null +++ b/WNPRC_r24/resources/views/welcome.view.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/WNPRC_r24/resources/views/welcome.webpart.xml b/WNPRC_r24/resources/views/welcome.webpart.xml new file mode 100644 index 000000000..10d5ec1e2 --- /dev/null +++ b/WNPRC_r24/resources/views/welcome.webpart.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/WNPRC_r24/src/org/labkey/wnprc_r24/view/hello.jsp b/WNPRC_r24/src/org/labkey/wnprc_r24/view/hello.jsp new file mode 100644 index 000000000..504c78427 --- /dev/null +++ b/WNPRC_r24/src/org/labkey/wnprc_r24/view/hello.jsp @@ -0,0 +1,25 @@ +<% +/* + * Copyright (c) 2016-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +%> +<%@ page import="org.labkey.api.data.Container" %> +<%@ page import="org.labkey.api.security.User" %> +<%@ page extends="org.labkey.api.jsp.JspBase" %> +<% + Container c = getContainer(); + User user = getUser(); +%> +Hello, and welcome to the wnprc_r24 module. \ No newline at end of file diff --git a/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24ContainerListener.java b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24ContainerListener.java new file mode 100644 index 000000000..00633b1f6 --- /dev/null +++ b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24ContainerListener.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.wnprc_r24; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager.ContainerListener; +import org.labkey.api.security.User; +import java.util.Collections; +import java.util.Collection; + +import java.beans.PropertyChangeEvent; + +public class wnprc_r24ContainerListener implements ContainerListener +{ + @Override + public void containerCreated(Container c, User user) + { + } + + @Override + public void containerDeleted(Container c, User user) + { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + } + + @Override + public void containerMoved(Container c, Container oldParent, User user) + { + } + + @NotNull @Override + public Collection canMove(Container c, Container newParent, User user) + { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Controller.java b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Controller.java new file mode 100644 index 000000000..de6d5fa6b --- /dev/null +++ b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Controller.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.wnprc_r24; + +import org.labkey.api.action.SimpleViewAction; +import org.labkey.api.action.SpringActionController; +import org.labkey.api.security.RequiresPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.view.JspView; +import org.labkey.api.view.NavTree; +import org.springframework.validation.BindException; +import org.springframework.web.servlet.ModelAndView; + +public class wnprc_r24Controller extends SpringActionController +{ + private static final DefaultActionResolver _actionResolver = new DefaultActionResolver(wnprc_r24Controller.class); + public static final String NAME = "wnprc_r24"; + + public wnprc_r24Controller() + { + setActionResolver(_actionResolver); + } + + @RequiresPermission(ReadPermission.class) + public class BeginAction extends SimpleViewAction + { + public ModelAndView getView(Object o, BindException errors) throws Exception + { + return new JspView("/org/labkey/wnprc_r24/view/hello.jsp"); + } + + public NavTree appendNavTrail(NavTree root) + { + return root; + } + } +} \ No newline at end of file diff --git a/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Manager.java b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Manager.java new file mode 100644 index 000000000..977068e53 --- /dev/null +++ b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Manager.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.wnprc_r24; + +public class wnprc_r24Manager +{ + private static final wnprc_r24Manager _instance = new wnprc_r24Manager(); + + private wnprc_r24Manager() + { + // prevent external construction with a private default constructor + } + + public static wnprc_r24Manager get() + { + return _instance; + } +} \ No newline at end of file diff --git a/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Module.java b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Module.java new file mode 100644 index 000000000..5f1dd239f --- /dev/null +++ b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Module.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.wnprc_r24; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.data.DbSchema; +import org.labkey.api.data.DbSchemaType; +import org.labkey.api.module.DefaultModule; +import org.labkey.api.module.Module; +import org.labkey.api.module.ModuleContext; +import org.labkey.api.query.DefaultSchema; +import org.labkey.api.query.QuerySchema; +import org.labkey.api.query.QueryService; +import org.labkey.api.view.WebPartFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public class wnprc_r24Module extends DefaultModule +{ + public static final String NAME = "wnprc_r24"; + + @Override + public String getName() + { + return NAME; + } + + @Override + public Double getSchemaVersion() + { + return 20.000; + } + + @Override + public boolean hasScripts() + { + return true; + } + + @Override + @NotNull + protected Collection createWebPartFactories() + { + return Collections.emptyList(); + } + + @Override + protected void init() + { + addController(wnprc_r24Controller.NAME, wnprc_r24Controller.class); + } + + @Override + public void doStartup(ModuleContext moduleContext) + { + // add a container listener so we'll know when our container is deleted: + ContainerManager.addContainerListener(new wnprc_r24ContainerListener()); + + for (final String schemaName : getSchemaNames()) + { + final DbSchema dbSchema = DbSchema.get(schemaName, DbSchemaType.Module); + DefaultSchema.registerProvider(dbSchema.getQuerySchemaName(), new DefaultSchema.SchemaProvider(this) + { + public QuerySchema createSchema(final DefaultSchema schema, Module module) + { + DbSchema dbSchema = DbSchema.get(schemaName, DbSchemaType.Module); + return QueryService.get().createSimpleUserSchema(dbSchema.getQuerySchemaName(), null, schema.getUser(), schema.getContainer(), dbSchema); + } + }); + } + } + + + @Override + @NotNull + public Collection getSummary(Container c) + { + return Collections.emptyList(); + } + + @Override + @NotNull + public Set getSchemaNames() + { + return Collections.singleton(wnprc_r24Schema.NAME); + } +} \ No newline at end of file diff --git a/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Schema.java b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Schema.java new file mode 100644 index 000000000..260b335c8 --- /dev/null +++ b/WNPRC_r24/src/org/labkey/wnprc_r24/wnprc_r24Schema.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.labkey.wnprc_r24; + +import org.labkey.api.data.DbSchema; +import org.labkey.api.data.DbSchemaType; +import org.labkey.api.data.dialect.SqlDialect; + +public class wnprc_r24Schema +{ + private static final wnprc_r24Schema _instance = new wnprc_r24Schema(); + public static final String NAME = "wnprc_r24"; + + public static wnprc_r24Schema getInstance() + { + return _instance; + } + + private wnprc_r24Schema() + { + // private constructor to prevent instantiation from + // outside this class: this singleton should only be + // accessed via org.labkey.wnprc_r24.wnprc_r24Schema.getInstance() + } + + public DbSchema getSchema() + { + return DbSchema.get(NAME, DbSchemaType.Module); + } + + public SqlDialect getSqlDialect() + { + return getSchema().getSqlDialect(); + } +} diff --git a/WebUtils/resources/queries/lists/WNPRC Colony Records Project Number Request Form.js b/WebUtils/resources/queries/lists/WNPRC Colony Records Project Number Request Form.js new file mode 100644 index 000000000..e2ae42652 --- /dev/null +++ b/WebUtils/resources/queries/lists/WNPRC Colony Records Project Number Request Form.js @@ -0,0 +1,15 @@ +var console = require("console"); +var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; +var LABKEY = require("labkey"); + +function afterInsert (row, errors){ + var key = row.key; + var hostName = 'https://' + LABKEY.serverName; + WNPRC.Utils.getJavaHelper().sendProjectNotification(key, hostName); +} + +function beforeUpdate(row, oldRow, errors){ + var key = row.key; + var hostName = 'https://' + LABKEY.serverName; + WNPRC.Utils.getJavaHelper().sendProjectNotification(key, hostName); +} \ No newline at end of file diff --git a/WebUtils/resources/queries/lists/vl_sample_queue.js b/WebUtils/resources/queries/lists/vl_sample_queue.js new file mode 100644 index 000000000..2f81b5d91 --- /dev/null +++ b/WebUtils/resources/queries/lists/vl_sample_queue.js @@ -0,0 +1,27 @@ +var console = require("console"); +var WNPRC = require("wnprc_ehr/WNPRC").WNPRC; +var LABKEY = require("labkey"); + +var rowids = []; +var hostName = 'https://' + LABKEY.serverName; +var status = 0; +var experimentNumber = 0; +var completedStatus = 8; + +function beforeUpdate(row){ + if (typeof row.experimentNumber == 'undefined' && row.Status == completedStatus){ + throw 'Cannot complete a record without an experiment number'; + } +} + +function afterUpdate(row, oldRow, errors){ + if (typeof row.experimentNumber != 'undefined') { + experimentNumber = row.experimentNumber + } + status = row.Status; + rowids.push(row.Key); +} + +function complete() { + WNPRC.Utils.getJavaHelper().sendViralLoadQueueNotification(rowids, status, hostName, experimentNumber); +} diff --git a/WebUtils/resources/web/webutils/lib/bootstrap/bootstrap.lib.xml b/WebUtils/resources/web/webutils/lib/bootstrap/bootstrap.lib.xml new file mode 100644 index 000000000..d8b99aeca --- /dev/null +++ b/WebUtils/resources/web/webutils/lib/bootstrap/bootstrap.lib.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/wnprc_billing/resources/views/customDataAccessUpsertPage.view.xml b/wnprc_billing/resources/views/customDataAccessUpsertPage.view.xml new file mode 100644 index 000000000..fad481a6e --- /dev/null +++ b/wnprc_billing/resources/views/customDataAccessUpsertPage.view.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/wnprc_billing/resources/views/financeDataEntry.html b/wnprc_billing/resources/views/financeDataEntry.html new file mode 100644 index 000000000..80648d547 --- /dev/null +++ b/wnprc_billing/resources/views/financeDataEntry.html @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/wnprc_billing/resources/views/financeDataEntry.view.xml b/wnprc_billing/resources/views/financeDataEntry.view.xml new file mode 100644 index 000000000..51c5252b7 --- /dev/null +++ b/wnprc_billing/resources/views/financeDataEntry.view.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/wnprc_billing/resources/views/financeDataEntry.webpart.xml b/wnprc_billing/resources/views/financeDataEntry.webpart.xml new file mode 100644 index 000000000..df516521d --- /dev/null +++ b/wnprc_billing/resources/views/financeDataEntry.webpart.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/wnprc_billing/resources/views/financeManagement.html b/wnprc_billing/resources/views/financeManagement.html index ca2f9f6a5..f371a8b80 100644 --- a/wnprc_billing/resources/views/financeManagement.html +++ b/wnprc_billing/resources/views/financeManagement.html @@ -36,8 +36,8 @@ header: 'Current Billing Period / Adjustments', items: [ {name: 'Billing Period Summary / Discrepancy Report', url: LABKEY.ActionURL.buildURL('ldk', 'runNotification', ctx.EHRStudyContainer, {key: 'org.labkey.ehr_billing.notification.BillingNotification'})}, - {name: 'Estimated Charges By Project', url: LABKEY.ActionURL.buildURL('wnprc_billing', 'invoiceEstimate', null)}, - {name: 'View Charges and Adjustments Not Yet Billed', url: LABKEY.ActionURL.buildURL('query', 'executeQuery', ctx.EHRStudyContainer, {schemaName: 'wnprc_billing', 'query.queryName': 'miscChargesNotBilledUpdate'})}, + {name: 'View Billing Queries', url: LABKEY.ActionURL.buildURL('wnprc_billing', 'viewBillingQuery', null)}, + {name: 'View Charges and Adjustments Not Yet Billed', url: LABKEY.ActionURL.buildURL('query', 'executeQuery', ctx.EHRStudyContainer, {schemaName: 'ehr_billing', 'query.queryName': 'miscCharges', 'query.viewName': 'Charges Not Billed'})}, {name: 'Perform Billing Run', url: LABKEY.ActionURL.buildURL('ehr_billing', 'billingPipeline', null)}, {name: 'Invoice Runs', url: LABKEY.ActionURL.buildURL('query', 'executeQuery', null, {schemaName: 'ehr_billing', 'query.queryName': 'invoiceRuns'})}, {name: 'Invoice External - Latest Run', url: LABKEY.ActionURL.buildURL('query', 'executeQuery', null, {schemaName: 'ehr_billing', 'query.queryName': 'invoiceExternalLastRun'})}, @@ -73,8 +73,9 @@ },{ header: 'Charge Category and Rates', items: [ - {name: 'Charge Units', url: LABKEY.ActionURL.buildURL(queryController, queryAction, null, {schemaName: 'ehr_billing', 'query.queryName': 'chargeUnits', showImport: true})}, + {name: 'Groups', url: LABKEY.ActionURL.buildURL(queryController, queryAction, null, {schemaName: 'ehr_billing', 'query.queryName': 'chargeUnits', showImport: true})}, {name: 'Chargeable Item Categories', url: LABKEY.ActionURL.buildURL(queryController, queryAction, null, {schemaName: 'ehr_billing', 'query.queryName': 'chargeableItemCategories', showImport: true})}, + {name: 'Group Category Associations', url: LABKEY.ActionURL.buildURL(queryController, queryAction, null, {schemaName: 'wnprc_billing', 'query.queryName': 'groupCategoryAssociations', showImport: true})}, {name: 'Chargeable Items', url: LABKEY.ActionURL.buildURL('query', 'executeQuery', null, {schemaName: 'ehr_billing', 'query.queryName': 'chargeableItems', showImport: true})}, {name: 'Standard Rates', url: LABKEY.ActionURL.buildURL("query", "executeQuery", null, {schemaName: 'ehr_billing', 'query.queryName': 'chargeRates', showImport: true})}, {name: 'Tier Rates', url: LABKEY.ActionURL.buildURL(queryController, queryAction, null, {schemaName: 'wnprc_billing', 'query.queryName': 'tierRates', showImport: true})}, @@ -82,8 +83,7 @@ },{ header: 'Other', items: [ - {name: 'Access To Billing Data', url: LABKEY.ActionURL.buildURL('query', 'executeQuery', null, {schemaName: 'ehr_billing', 'query.queryName': 'dataAccess'})}, - {name: 'Import Historical Misc. Charges', url: LABKEY.ActionURL.buildURL(queryController, queryAction, ctx.EHRStudyContainer, {schemaName: 'ehr_billing', 'query.queryName': 'miscCharges', showImport: true})} + {name: 'Access To Billing Data', url: LABKEY.ActionURL.buildURL('query', 'executeQuery', null, {schemaName: 'ehr_billing', 'query.queryName': 'dataAccess'})} ] }] }] diff --git a/wnprc_billing/resources/views/invoiceEstimate.html b/wnprc_billing/resources/views/invoiceEstimate.html deleted file mode 100644 index 38dafdb66..000000000 --- a/wnprc_billing/resources/views/invoiceEstimate.html +++ /dev/null @@ -1,225 +0,0 @@ - \ No newline at end of file diff --git a/wnprc_billing/resources/views/viewBillingQuery.html b/wnprc_billing/resources/views/viewBillingQuery.html new file mode 100644 index 000000000..914f9fa3f --- /dev/null +++ b/wnprc_billing/resources/views/viewBillingQuery.html @@ -0,0 +1,153 @@ +

    + Preview the billing cost query for a given start and end date period. + You can optionally select how to aggregate the data or filter for a specific project. +

    +
    +
    +
    + + \ No newline at end of file diff --git a/wnprc_billing/resources/views/invoiceEstimate.view.xml b/wnprc_billing/resources/views/viewBillingQuery.view.xml similarity index 58% rename from wnprc_billing/resources/views/invoiceEstimate.view.xml rename to wnprc_billing/resources/views/viewBillingQuery.view.xml index 5eaafe9d6..f4a83f494 100644 --- a/wnprc_billing/resources/views/invoiceEstimate.view.xml +++ b/wnprc_billing/resources/views/viewBillingQuery.view.xml @@ -1,4 +1,4 @@ - + diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeGroupField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeGroupField.js new file mode 100644 index 000000000..65dfe8e2c --- /dev/null +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeGroupField.js @@ -0,0 +1,42 @@ +Ext4.define('WNPRC_Billing.form.field.ChargeGroupEntryField', { + extend: 'Ext.form.field.ComboBox', + alias: 'widget.wnprc_billing-chargegroupentryfield', + initComponent: function(){ + + this.addListener({ + scope:this, + select: function (combo, recs) { + + //on chargeGroup (labeled as Group) change, reset chargeId (labeled as Charge Item) and unitCost. + //for bulk edit window + if (this.up("form") && this.up("form").getForm()) { + + var chargeIdField = this.up("form").getForm().findField("chargeId"); + if (chargeIdField) { + chargeIdField.disabled = false; + chargeIdField.setValue(null); + } + + var unitCostField = this.up("form").getForm().findField("unitCost"); + if (unitCostField) { + unitCostField.disabled = false; + unitCostField.setValue(null); + } + var totalCostField = this.up("form").getForm().findField("totalCost"); + if (totalCostField) { + totalCostField.disabled = false; + totalCostField.setValue(null); + } + } + //for data entry grid + else { + EHR.DataEntryUtils.setSiblingFields(combo, { + chargeId: null, + unitCost: null, + totalCost: null + }); + } + }}); + this.callParent(); + } +}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeItemField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeItemField.js index 3cf6fa002..64a51a2f0 100644 --- a/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeItemField.js +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeItemField.js @@ -1,36 +1,118 @@ Ext4.define('WNPRC_Billing.form.field.ChargeItemField', { - extend: 'EHR_Billing.form.field.EHRBillingRowObserverEntryField', + extend: 'Ext.form.field.ComboBox', alias: 'widget.wnprc_billing-chargeitemfield', + valueField: 'rowid', + displayField: 'name', initComponent: function(){ - this.addListener( - { - scope:this, - select: function (combo, recs) { + this.addListener({ + scope: this, + focus: function() { + //for data entry grid + if (this.up("grid")) { + var chargeGroupVal = EHR.DataEntryUtils.getSiblingValue(this, "chargeGroup"); + if (chargeGroupVal) { + var filter = LABKEY.Filter.create('departmentCode', chargeGroupVal, LABKEY.Filter.Types.EQUAL); + this.store.filterArray = [filter]; + this.store.load(); + } + } - var chargeDate = EHR.DataEntryUtils.getSiblingValue(combo, 'date'); // get date value from data entry form - var chargeId = recs[0].get('rowId'); + //for bulk edit window + var form = this.up("form") ? this.up("form").getForm() : undefined; + if (form) { + //filter charge items based on chargeGroup selection + var chargeGroupField = form.findField("chargeGroup"); + + if (chargeGroupField) { + var filter = LABKEY.Filter.create('departmentCode', chargeGroupField.value, LABKEY.Filter.Types.EQUAL); + this.store.filterArray = [filter]; + this.store.load(); + } + } + }, + beforerender: function (field) { + + //for bulk edit window + var form = field.up("form") ? field.up("form").getForm() : undefined; + if (form) { + //filter charge items based on chargeGroup selection + var chargeGroupField = form.findField("chargeGroup"); + + if (chargeGroupField) { + var filter = LABKEY.Filter.create('departmentCode', chargeGroupField.value, LABKEY.Filter.Types.EQUAL); + field.store.filterArray = [filter]; + field.store.load(); + } + } + }, + select: function (combo, recs) { + + if (recs && recs[0] && recs[0].data) { + + var chargeId = recs[0].data.rowid; + var chargeDateValue = undefined; + + var form = this.up("form") ? this.up("form").getForm() : undefined; + + if (form) { + chargeDateValue = form.findField("date").value; + } + else { + chargeDateValue = EHR.DataEntryUtils.getSiblingValue(combo, "date"); + } LABKEY.Query.selectRows({ schemaName: 'ehr_billing_public', queryName: 'chargeRates', filterArray: [ LABKEY.Filter.create('chargeId', chargeId, LABKEY.Filter.Types.EQUAL), - LABKEY.Filter.create('startDate', chargeDate.format("Y-m-d"), LABKEY.Filter.Types.DATE_LESS_THAN_OR_EQUAL), - LABKEY.Filter.create('endDate', chargeDate.format("Y-m-d"), LABKEY.Filter.Types.DATE_GREATER_THAN_OR_EQUAL) + LABKEY.Filter.create('startDate', chargeDateValue.format("Y-m-d"), LABKEY.Filter.Types.DATE_LESS_THAN_OR_EQUAL), + LABKEY.Filter.create('endDate', chargeDateValue.format("Y-m-d"), LABKEY.Filter.Types.DATE_GREATER_THAN_OR_EQUAL) ], columns: 'chargeId, unitCost', failure: LDK.Utils.getErrorCallback(), scope: this, - success: function(results){ - EHR.DataEntryUtils.setSiblingFields(combo, { - unitCost: (results.rows[0] != null ? results.rows[0].unitCost : null) - }); + success: function (results) { + + var unitCost = results.rows[0].unitCost; + // for bulk edit window + if (form) { + var unitCostField = this.up("form").getForm().findField("unitCost"); + if (unitCostField) + { + unitCostField.disabled = false; + unitCostField.setValue(results.rows[0] != null ? unitCost : null); + } + var quantity = this.up("form").getForm().findField("quantity"); + if (quantity && quantity.getValue()) + { + var totalCostField = this.up("form").getForm().findField("totalCost"); + if (totalCostField) + { + var val = results.rows[0] != null ? (quantity.getValue() * unitCost) : null; + totalCostField.disabled = false; + totalCostField.setValue(val); + } + } + + + } + //for data entry grid + else { + var quantity = EHR.DataEntryUtils.getSiblingValue(this, "quantity"); + EHR.DataEntryUtils.setSiblingFields(combo, { + unitCost: (results.rows[0] != null ? unitCost : null), + totalCost: (results.rows[0] != null && quantity != null ? unitCost * quantity : null) + }); + } } - }); - }}); + }); + } + } + }); this.callParent(); } }); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeTypeField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeTypeField.js deleted file mode 100644 index 1f5c9e445..000000000 --- a/wnprc_billing/resources/web/wnprc_billing/form/field/ChargeTypeField.js +++ /dev/null @@ -1,18 +0,0 @@ -Ext4.define('WNPRC_Billing.form.field.ChargeTypeEntryField', { - extend: 'Ext.form.field.ComboBox', - alias: 'widget.wnprc_billing-chargetypeentryfield', - initComponent: function(){ - - this.addListener({ - scope:this, - select: function (combo, recs) { - - //if chargetype (labeled as Charge Unit) is changed, reset its coupled column chargeId (labeled as Charge Item), and unitCost (which is coupled with chargeId). - EHR.DataEntryUtils.setSiblingFields(combo, { - chargeId: null, - unitCost: null - }); - }}); - this.callParent(); - } -}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/InvestigatorField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/InvestigatorField.js index 117a20771..58ae68b75 100644 --- a/wnprc_billing/resources/web/wnprc_billing/form/field/InvestigatorField.js +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/InvestigatorField.js @@ -7,12 +7,50 @@ * This field is used to display WNPRC Investigator. */ Ext4.define('WNPRC_BILLING.form.field.InvestigatorField', { - extend: 'EHR_Billing.form.field.EHRBillingRowObserverEntryField', + extend: 'Ext.form.field.ComboBox', alias: 'widget.wnprc_billing-investigatorfield', containerPath: LABKEY.moduleContext.ehr['EHRStudyContainer'], + displayField: 'investigatorName', + valueField: 'investigatorName', + initComponent: function() { this.callParent(arguments); - } + this.addListener({ + scope: this, + focus: function() { + + var filter = undefined; + + //for data entry grid + if (this.up("grid")) { + var projectVal = EHR.DataEntryUtils.getSiblingValue(this, "project"); + if (projectVal) { + filter = LABKEY.Filter.create('project', projectVal, LABKEY.Filter.Types.EQUAL) + } + } + + //for bulk edit window + var form = this.up("form") ? this.up("form").getForm() : undefined; + if (form) { + //for charges form with animal Ids, get investigator based on project selection + var projectField = form.findField("project"); + + if (projectField) { + filter = LABKEY.Filter.create('project', projectField.value, LABKEY.Filter.Types.EQUAL); + } + } + + var array = []; + if (filter) { + array.push(filter); + } + + this.store.filterArray = array; + this.store.load(); + } + }); + this.callParent(); + } }); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/InvestigatorFieldFromAlias.js b/wnprc_billing/resources/web/wnprc_billing/form/field/InvestigatorFieldFromAlias.js new file mode 100644 index 000000000..90eae289d --- /dev/null +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/InvestigatorFieldFromAlias.js @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +/** + * This field is used to display WNPRC Investigator. + */ +Ext4.define('WNPRC_BILLING.form.field.InvestigatorFieldFromAlias', { + extend: 'Ext.form.field.ComboBox', + alias: 'widget.wnprc_billing-investigatorfieldfromalias', + containerPath: LABKEY.moduleContext.ehr['EHRStudyContainer'], + + displayField: 'investigatorName', + valueField: 'investigatorName', + + initComponent: function() { + this.callParent(arguments); + this.addListener({ + scope: this, + focus: function() { + + var filter = undefined; + + //for data entry grid + if (this.up("grid")) { + + var debitedAcctVal = EHR.DataEntryUtils.getSiblingValue(this, "debitedaccount"); + if (debitedAcctVal) { + filter = LABKEY.Filter.create('alias', debitedAcctVal, LABKEY.Filter.Types.EQUAL); + } + } + + //for bulk edit window + var form = this.up("form") ? this.up("form").getForm() : undefined; + if (form) { + + var debitedAcctField = form.findField("debitedaccount"); + + //for charges form without animal Ids, get investigator based on debited account selection + if (debitedAcctField) { + filter = LABKEY.Filter.create('alias', debitedAcctField.value, LABKEY.Filter.Types.EQUAL); + } + } + + this.store.filterArray = [filter]; + this.store.load(); + } + }); + this.callParent(); + } +}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDateField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDateField.js index e1c3ede8a..fd03243ef 100644 --- a/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDateField.js +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDateField.js @@ -6,14 +6,60 @@ Ext4.define('WNPRC_Billing.form.field.MiscChargesDateField', { this.addListener({ scope:this, - change: function (combo, val) { - - //if date is changed, reset below values since unitCost is retrieved from ehr_billing.chargeRates based on the date entered along with its coupled selections (chargetype (labeled as Charge Unit), which is coupled with chargeId (labeled as Charge Item)) - EHR.DataEntryUtils.setSiblingFields(combo, { - chargetype: null, - chargeId: null, - unitCost: null - }); + render: function (field, newVal) { + //for bulk edit window + if (this.up("form") && this.up("form").getForm()) { + if (!field.getValue()) { + field.setValue(Ext4.Date.format(new Date(), 'Y-m-d')); + } + //Non-Animal Charges bulk edit doesn't like the above date setting + if (!field.getValue()) { + field.setValue(new Date()); + } + } + }, + change: function (field, newVal) { + + //for bulk edit window + if (this.up("form") && this.up("form").getForm()) { + + var unitCostField = this.up("form").getForm().findField("unitCost"); + if (unitCostField) { + unitCostField.setValue(null); + } + + var chargeIdField = this.up("form").getForm().findField("chargeId"); + if (chargeIdField) { + chargeIdField.setValue(null); + } + + var chargeGroupField = this.up("form").getForm().findField("chargeGroup"); + if (chargeGroupField) { + chargeGroupField.setValue(null); + } + + var projectField = this.up("form").getForm().findField("project"); + if (projectField) { + projectField.setValue(null); + } + + var debitedAccount = this.up("form").getForm().findField("debitedAccount"); + if (debitedAccount) { + debitedAccount.setValue(null); + } + + } + //for data entry grid + else { + //if date is changed, reset below values since unitCost is retrieved from ehr_billing.chargeRates based on the date entered along with its coupled selections (chargeGroup (labeled as Group), which is coupled with chargeId (labeled as Charge Item)) + EHR.DataEntryUtils.setSiblingFields(field, { + chargeGroup: null, + chargeId: null, + unitCost: null, + project: null, + debitedAccount: null + }); + } }}); this.callParent(); } diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDebitAcctEntryField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDebitAcctEntryField.js deleted file mode 100644 index b35cbafa5..000000000 --- a/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDebitAcctEntryField.js +++ /dev/null @@ -1,22 +0,0 @@ -Ext4.define('WNPRC_Billing.form.field.MiscChargesDebitAcctEntryField', { - extend: 'Ext.form.field.ComboBox', - alias: 'widget.wnprc_billing-miscchargesdebitacctentryfield', - - schemaName: 'ehr_billing', - queryName: 'aliases', - - initComponent: function() { - - this.addListener({ - scope:this, - select: function (combo, recs) { - - //clear the investigator field if alias (labeled as 'Debited Account' on data entry form) value is changed - EHR.DataEntryUtils.setSiblingFields(combo, { - investigator: null - }); - } - }); - this.callParent(arguments); - } -}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDebitAcctField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDebitAcctField.js new file mode 100644 index 000000000..cc0be8b7f --- /dev/null +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/MiscChargesDebitAcctField.js @@ -0,0 +1,5 @@ +Ext4.define('WNPRC_Billing.form.field.MiscChargesDebitAcctField', { + extend: 'Ext.form.field.Text', + alias: 'widget.wnprc_billing-miscchargesdebitacctfield', + readOnly: true +}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/NonAnimalChargesDebitAcctField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/NonAnimalChargesDebitAcctField.js new file mode 100644 index 000000000..825e6c250 --- /dev/null +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/NonAnimalChargesDebitAcctField.js @@ -0,0 +1,55 @@ +Ext4.define('WNPRC_Billing.form.field.NonAnimalChargesDebitAcctField', { + extend: 'Ext.form.field.ComboBox', + alias: 'widget.wnprc_billing-nonanimalchargesdebitacctfield', + + initComponent: function() { + + this.addListener({ + scope:this, + select: function(field, newValue) { + //on alias (labeled as 'Debited Account') change, reset investigator + //for bulk edit window + if (this.up("form") && this.up("form").getForm()) { + + var invesField = this.up("form").getForm().findField("investigator"); + if (invesField) { + invesField.disabled = false; + invesField.setValue(null); + } + } + else { + //for data entry grid + EHR.DataEntryUtils.setSiblingFields(this, { + investigator: null + }); + } + }, + + focus: function() { + + var dateEntered = undefined; + //for bulk edit window + if (this.up("form") && this.up("form").getForm()) { + var dateFieldVal = this.up("form").getForm().findField("date"); + + if (dateFieldVal && dateFieldVal.getValue()) { + dateEntered = dateFieldVal.getValue(); + } + } + else { + if (this.up("grid")) { + dateEntered = EHR.DataEntryUtils.getSiblingValue(this, "date"); + } + } + + //filter debitedAccount based on alias.budgetStartDate and alias.budgetEndDate w.r.t the date entered + if (dateEntered) { + this.store.filterArray = [LABKEY.Filter.create('budgetStartDate', Ext4.Date.format(dateEntered, 'Y-m-d'), LABKEY.Filter.Types.DATE_LESS_THAN_OR_EQUAL), + LABKEY.Filter.create('budgetEndDate', Ext4.Date.format(dateEntered, 'Y-m-d'), LABKEY.Filter.Types.DATE_GREATER_THAN_OR_EQUAL)]; + this.store.load(); + } + } + }); + this.callParent(arguments); + } +}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/QuantityField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/QuantityField.js new file mode 100644 index 000000000..8f1fb28a6 --- /dev/null +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/QuantityField.js @@ -0,0 +1,35 @@ +Ext4.define('WNPRC_Billing.form.field.QuantityField', { + extend: 'Ext.form.field.Number', + alias: 'widget.wnprc_billing-quantityfield', + initComponent: function() { + + this.addListener({ + scope:this, + change: function (field, val) { + + //for bulk edit window + if (this.up("form") && this.up("form").getForm()) { + + var unitCost = this.up("form").getForm().findField("unitCost"); + var totalCost = this.up("form").getForm().findField("totalCost"); + totalCost.disabled = false; + if (unitCost && unitCost.getValue()) { + totalCost.setValue(val * unitCost.getValue()); + } + else { + totalCost.setValue(null); + } + } + //for data entry grid + else { + if (this.up("grid")) { + var unitCost = EHR.DataEntryUtils.getSiblingValue(this, "unitCost"); + EHR.DataEntryUtils.setSiblingFields(field, { + totalCost: unitCost ? (val * unitCost) : null + }); + } + } + }}); + this.callParent(); + } +}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/TotalCostField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/TotalCostField.js new file mode 100644 index 000000000..4ed355385 --- /dev/null +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/TotalCostField.js @@ -0,0 +1,8 @@ +Ext4.define('WNPRC_Billing.form.field.TotalCostField', { + extend: 'Ext.form.field.Number', + alias: 'widget.wnprc_billing-totalcostfield', + editable: false, + hideTrigger: true, + keyNavEnabled: false, + mouseWheelEnabled: false +}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/UnitCostField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/UnitCostField.js new file mode 100644 index 000000000..f781973cc --- /dev/null +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/UnitCostField.js @@ -0,0 +1,35 @@ +Ext4.define('WNPRC_Billing.form.field.UnitCostField', { + extend: 'Ext.form.field.Number', + alias: 'widget.wnprc_billing-unitcostfield', + initComponent: function() { + + this.addListener({ + scope:this, + change: function (field, val) { + + //for bulk edit window + if (this.up("form") && this.up("form").getForm()) { + + var quantity = this.up("form").getForm().findField("quantity"); + var totalCost = this.up("form").getForm().findField("totalCost"); + totalCost.disabled = false; + if (quantity && quantity.getValue()) { + totalCost.setValue(val * quantity.getValue()); + } + else { + totalCost.setValue(null); + } + } + //for data entry grid + else { + if (this.up("grid")) { + var quantity = EHR.DataEntryUtils.getSiblingValue(this, "quantity"); + EHR.DataEntryUtils.setSiblingFields(field, { + totalCost: quantity ? (val * quantity) : null + }); + } + } + }}); + this.callParent(); + } +}); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/form/field/WNPRC_BillingProjectEntryField.js b/wnprc_billing/resources/web/wnprc_billing/form/field/WNPRC_BillingProjectEntryField.js index a44602241..e67b21140 100644 --- a/wnprc_billing/resources/web/wnprc_billing/form/field/WNPRC_BillingProjectEntryField.js +++ b/wnprc_billing/resources/web/wnprc_billing/form/field/WNPRC_BillingProjectEntryField.js @@ -5,12 +5,42 @@ Ext4.define('WNPRC_Billing.form.field.ProjectEntryField', { initComponent: function(){ - this.addListener({scope:this, select: function (combo, recs) { - //clear the investigator field if the project is changed - EHR.DataEntryUtils.setSiblingFields(combo, { - investigator: null - }); - }}); + this.addListener({ + scope:this, + select: function (field, val) { + + //get debit acct value + var projectRec = field.store.getAt(field.store.find('project', field.getValue())); + var acct = null; + if(projectRec) { + acct = projectRec.get('account'); + } + + //on project change, reset investigator + //for bulk edit window + if (field.up("form") && field.up("form").getForm()) { + var invesField = field.up("form").getForm().findField("investigator"); + if (invesField) { + invesField.disabled = false; + invesField.setValue(null); + } + + var debitedacct = field.up("form").getForm().findField("debitedaccount"); + if (debitedacct) { + debitedacct.disabled = false; + debitedacct.setValue(acct); + } + } + //for data entry grid + else { + + EHR.DataEntryUtils.setSiblingFields(field, { + investigator: null, + debitedaccount: acct + }); + } + } + }); this.callParent(); } }); \ No newline at end of file diff --git a/wnprc_billing/resources/web/wnprc_billing/model/sources/MiscCharges.js b/wnprc_billing/resources/web/wnprc_billing/model/sources/MiscCharges.js index fe548ca3b..1c8242ef4 100644 --- a/wnprc_billing/resources/web/wnprc_billing/model/sources/MiscCharges.js +++ b/wnprc_billing/resources/web/wnprc_billing/model/sources/MiscCharges.js @@ -3,6 +3,7 @@ * * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 */ + EHR.model.DataModelManager.registerMetadata('Charges', { byQuery: { 'ehr_billing.miscCharges': { @@ -22,29 +23,23 @@ EHR.model.DataModelManager.registerMetadata('Charges', { } }, debitedaccount: { - hidden: true + hidden: false, + xtype: 'wnprc_billing-miscchargesdebitacctfield', + userEditable: false }, investigator: { xtype: 'wnprc_billing-investigatorfield', hidden: false, userEditable: true, columnConfig: { - width: 150 - }, - editorConfig: { - caseSensitive: false, - id: 'wnprc_billing-Charges-investigator', - valueField: 'inves', - displayField: 'inves', - observedField: 'project', - observerLookupField: 'project' + width: 200 }, lookup: { schemaName: 'ehr', - queryName: 'project', - keyColumn: 'inves', - displayColumn: 'inves', - columns: 'inves' + queryName: 'projectsWithInvestigators', + keyColumn: 'investigatorWithName', + columns: 'project, investigatorId, investigatorWithName', + displayColumn: 'investigatorWithName' } }, chargeId: { @@ -55,16 +50,8 @@ EHR.model.DataModelManager.registerMetadata('Charges', { width: 200 }, lookup: { - columns: 'rowId, name, chargeCategoryId, departmentCode, startDate, endDate' + columns: 'rowid, name, chargeCategoryId, departmentCode, startDate, endDate' }, - editorConfig: { - caseSensitive: false, - id: 'ehr_billing-Misc-charges-chargeId', - valueField: 'rowId', - displayField: 'name', - observedField: 'chargetype', - observerLookupField: 'departmentCode' - } }, date: { hidden: false, @@ -73,9 +60,9 @@ EHR.model.DataModelManager.registerMetadata('Charges', { width: 125 } }, - chargetype: { + chargeGroup: { hidden: false, - xtype: 'wnprc_billing-chargetypeentryfield', + xtype: 'wnprc_billing-chargegroupentryfield', columnConfig: { width: 175 } @@ -86,14 +73,27 @@ EHR.model.DataModelManager.registerMetadata('Charges', { anchor: '50%', height: 20, columnConfig: { - width: 200 + width: 300 } }, - chargeCategory: { + chargetype: { hidden: false, columnConfig: { width: 125 } + }, + chargeCategory: { + hidden: true + }, + quantity: { + xtype: 'wnprc_billing-quantityfield' + }, + unitCost: { + xtype: 'wnprc_billing-unitcostfield' + }, + totalCost: { + userEditable: false, + xtype: 'wnprc_billing-totalcostfield' } } } diff --git a/wnprc_billing/resources/web/wnprc_billing/model/sources/NonAnimalCharges.js b/wnprc_billing/resources/web/wnprc_billing/model/sources/NonAnimalCharges.js index c3a40bab2..29bf563d9 100644 --- a/wnprc_billing/resources/web/wnprc_billing/model/sources/NonAnimalCharges.js +++ b/wnprc_billing/resources/web/wnprc_billing/model/sources/NonAnimalCharges.js @@ -16,11 +16,9 @@ EHR.model.DataModelManager.registerMetadata('NonAnimalCharges', { }, debitedaccount: { hidden: false, - xtype: 'wnprc_billing-miscchargesdebitacctentryfield', + xtype: 'wnprc_billing-nonanimalchargesdebitacctfield', lookup: { - schemaName: 'ehr_billing', - queryName: 'aliases', - filterArray: [LABKEY.Filter.create('isAcceptingCharges', 'N', LABKEY.Filter.Types.NEQ_OR_NULL)] + columns:"alias,budgetStartDate,budgetEndDate" }, columnConfig: { width: 125 @@ -31,21 +29,13 @@ EHR.model.DataModelManager.registerMetadata('NonAnimalCharges', { columnConfig: { width: 250 }, - xtype: 'ehr_billingRowObserverEntryField', + xtype: 'wnprc_billing-investigatorfieldfromalias', lookup: { - schemaName: 'ehr_billing', - queryName: 'aliases', - keyColumn: 'investigatorName', - displayColumn: 'investigatorName', - columns: 'alias, investigatorName' - }, - editorConfig: { - caseSensitive: false, - id: 'wnprc_billing-debitAcct-investigator', - valueField: 'investigatorName', - displayField: 'investigatorName', - observedField: 'debitedaccount', - observerLookupField: 'alias' + schemaName: 'ehr', + queryName: 'aliasesWithInvestigators', + keyColumn: 'investigatorWithName', + columns: 'investigatorWithName', + displayColumn: 'investigatorWithName' } }, chargeId: { @@ -57,14 +47,6 @@ EHR.model.DataModelManager.registerMetadata('NonAnimalCharges', { }, lookup: { columns: 'rowId, name, chargeCategoryId, departmentCode, startDate, endDate' - }, - editorConfig: { - caseSensitive: false, - id: 'ehr_billing-nonAnimalCharges-chargeId', - valueField: 'rowId', - displayField: 'name', - observedField: 'chargetype', - observerLookupField: 'departmentCode' } }, date: { @@ -74,9 +56,9 @@ EHR.model.DataModelManager.registerMetadata('NonAnimalCharges', { width: 125 } }, - chargetype: { + chargeGroup: { hidden: false, - xtype: 'wnprc_billing-chargetypeentryfield', + xtype: 'wnprc_billing-chargegroupentryfield', columnConfig: { width: 175 } @@ -90,13 +72,25 @@ EHR.model.DataModelManager.registerMetadata('NonAnimalCharges', { width: 200 } }, - chargeCategory: { + chargetype: { hidden: false, columnConfig: { width: 125 } }, - + chargeCategory: { + hidden: true + }, + quantity: { + xtype: 'wnprc_billing-quantityfield' + }, + unitCost: { + xtype: 'wnprc_billing-unitcostfield' + }, + totalCost: { + userEditable: false, + xtype: 'wnprc_billing-totalcostfield' + } } } }); \ No newline at end of file diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingContainerListener.java b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingContainerListener.java index ab203ffef..27078ce19 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingContainerListener.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingContainerListener.java @@ -46,7 +46,15 @@ public void containerDeleted(Container c, User user) { TableInfo tierRatesTable = WNPRC_BillingSchema.getInstance().getTierRates(); if (tierRatesTable.getTableType() == DatabaseTableType.TABLE) + { Table.delete(tierRatesTable, containerFilter); + } + + TableInfo groupCategoryAssociations = WNPRC_BillingSchema.getInstance().getGroupCategoryAssociations(); + if (groupCategoryAssociations.getTableType() == DatabaseTableType.TABLE) + { + Table.delete(groupCategoryAssociations, containerFilter); + } transaction.commit(); } diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingController.java b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingController.java index 9f26116ce..6d70caeaa 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingController.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingController.java @@ -32,6 +32,7 @@ import org.labkey.api.pipeline.PipelineJobException; import org.labkey.api.query.FieldKey; import org.labkey.api.query.QueryService; +import org.labkey.api.query.SimpleUserSchema; import org.labkey.api.query.UserSchema; import org.labkey.api.security.RequiresPermission; import org.labkey.api.security.permissions.ReadPermission; @@ -46,6 +47,7 @@ import org.labkey.wnprc_billing.domain.*; import org.labkey.wnprc_billing.invoice.InvoicePDF; import org.labkey.wnprc_billing.invoice.SummaryPDF; +import org.labkey.wnprc_billing.query.WNPRC_BillingUserSchema; import org.springframework.validation.BindException; import javax.servlet.http.HttpServletResponse; @@ -58,6 +60,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Collections; import java.util.List; import java.util.Map; @@ -83,7 +86,7 @@ private List getInvoicedItems(String invoiceNumber) TableInfo tableInfo = getEhrBillingSchema().getTable(WNPRC_BillingSchema.TABLE_INVOICED_ITEMS_FOR_PDF); SimpleFilter filter = new SimpleFilter(FieldKey.fromParts("invoiceNumber"), invoiceNumber); - TableSelector tableSelector = new TableSelector(tableInfo, filter,new Sort( "date,serviceCenter,id")); + TableSelector tableSelector = new TableSelector(tableInfo, filter,new Sort("date,groupName,id")); return tableSelector.getArrayList(InvoicedItem.class); } @@ -100,7 +103,9 @@ private Invoice getInvoice(String invoiceNumber) private TierRate getTierRate(String tierRateType) { - TableInfo tableInfo = WNPRC_BillingSchema.getSchema().getTable(WNPRC_BillingSchema.TABLE_TIER_RATES); + + UserSchema userSchema = QueryService.get().getUserSchema(getUser(), getContainer(), WNPRC_BillingSchema.NAME); + TableInfo tableInfo = userSchema.getTable(WNPRC_BillingSchema.TABLE_TIER_RATES); SimpleFilter filter = new SimpleFilter(FieldKey.fromParts("tierRateType"), tierRateType); filter.addCondition(FieldKey.fromString("isActive"), true, CompareType.EQUAL); @@ -535,6 +540,42 @@ public void export(InvoicePdfForm invoicePdfForm, HttpServletResponse response, } } + @RequiresPermission(ReadPermission.class) + public class DownloadSummaryInvoicesAction extends ExportAction + { + @Override + public void export(InvoicePdfForm invoicePdfForm, HttpServletResponse response, BindException errors) throws Exception + { + Set selectedInvoices = DataRegionSelection.getSelected(HttpView.currentContext(), null, true); + + String currentDate = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime()); + String headerString = "attachment; filename=Invoices "+ currentDate+ ".zip"; + + response.reset(); + response.setContentType("application/zip"); + response.setHeader("Content-Disposition", headerString); + + try(ZipOutputStream zout = new ZipOutputStream(response.getOutputStream())) + { + selectedInvoices.forEach(invoiceNumber-> { + try + { + PDFFile pdfFile = getInvoicePDF(invoiceNumber, "Download Summary Invoices"); + ZipEntry entry = new ZipEntry(pdfFile.getFileName()); + zout.putNextEntry(entry); + pdfFile.getInvoicePDF().output(zout); + zout.closeEntry(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + }); + } + + } + } + @RequiresPermission(ReadPermission.class) public class PDFExportAction extends ExportAction { diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingModule.java b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingModule.java index aef8904e8..163efc039 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingModule.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingModule.java @@ -126,4 +126,4 @@ public Set getSchemaNames() { return Collections.singleton(WNPRC_BillingSchema.NAME); } -} \ No newline at end of file +} diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingSchema.java b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingSchema.java index 65a739b5c..47f55b3c2 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingSchema.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/WNPRC_BillingSchema.java @@ -31,6 +31,7 @@ public class WNPRC_BillingSchema public static final String TABLE_INVOICE = "Invoice"; public static final String TABLE_INVOICE_RUNS = "InvoiceRuns"; public static final String TABLE_TIER_RATES = "tierrates"; + public static final String TABLE_GROUP_CATEGORY_ASSOCIATIONS = "groupCategoryAssociations"; public static final String TABLE_JET_INVOICE_ITEMS = "JetInvoiceItems"; public static final String TABLE_ALIASES = "Aliases"; public static final String TABLE_SUMMARIZED_ITEMS = "summarizedInvoicedItemsByCategory"; @@ -61,4 +62,9 @@ public TableInfo getTierRates() { return getSchema().getTable(TABLE_TIER_RATES); } + + public TableInfo getGroupCategoryAssociations() + { + return getSchema().getTable(TABLE_GROUP_CATEGORY_ASSOCIATIONS); + } } diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/AbstractMiscChargesFormType.java b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/AbstractMiscChargesFormType.java index e501ae25c..457722b63 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/AbstractMiscChargesFormType.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/AbstractMiscChargesFormType.java @@ -3,7 +3,7 @@ import org.labkey.api.ehr.dataentry.DataEntryFormContext; import org.labkey.api.ehr.dataentry.FormSection; import org.labkey.api.ehr.dataentry.TaskForm; -import org.labkey.api.ehr_billing.security.EHR_BillingAdminPermission; +import org.labkey.api.ehr.security.EHR_BillingAdminPermission; import org.labkey.api.module.Module; import org.labkey.api.view.template.ClientDependency; @@ -27,11 +27,15 @@ public AbstractMiscChargesFormType(DataEntryFormContext ctx, Module owner, Strin addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/WNPRC_BillingProjectEntryField.js")); addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/ChargeItemField.js")); addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/InvestigatorField.js")); + addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/InvestigatorFieldFromAlias.js")); addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/MiscChargesDateField.js")); - addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/ChargeTypeField.js")); + addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/ChargeGroupField.js")); addClientDependency(ClientDependency.supplierFromPath("ehr_billing/data/sources/EHR_BillingDefault.js")); - addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/MiscChargesDebitAcctEntryField.js")); - + addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/NonAnimalChargesDebitAcctField.js")); + addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/MiscChargesDebitAcctField.js")); + addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/QuantityField.js")); + addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/UnitCostField.js")); + addClientDependency(ClientDependency.supplierFromPath("wnprc_billing/form/field/TotalCostField.js")); } @Override @@ -45,6 +49,7 @@ protected List getButtonConfigs() { List defaultButtons = new ArrayList(); defaultButtons.add("FINANCESUBMIT"); + defaultButtons.add("SUBMITANDRELOAD"); return defaultButtons; } @@ -72,4 +77,4 @@ public boolean canRead() return super.canRead(); } -} \ No newline at end of file +} diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormSection.java b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormSection.java index f1c80ec55..226c64126 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormSection.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormSection.java @@ -38,12 +38,4 @@ public List getTbarButtons() return defaultButtons; } - - @Override - public List getTbarMoreActionButtons() - { - List defaultMoreActionButtons = super.getTbarMoreActionButtons(); - defaultMoreActionButtons.remove("BULKEDIT"); - return defaultMoreActionButtons; - } -} \ No newline at end of file +} diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormType.java b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormType.java index d8f6abc86..91ed239f5 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormType.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/ChargesFormType.java @@ -1,18 +1,11 @@ package org.labkey.wnprc_billing.dataentry; -import org.labkey.api.ehr.dataentry.AnimalDetailsFormSection; import org.labkey.api.ehr.dataentry.DataEntryFormContext; import org.labkey.api.ehr.dataentry.FormSection; -import org.labkey.api.ehr.dataentry.TaskForm; import org.labkey.api.ehr.dataentry.TaskFormSection; import org.labkey.api.module.Module; -import org.labkey.api.view.template.ClientDependency; -import org.labkey.api.ehr_billing.security.EHR_BillingAdminPermission; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; /** * Data entry form setup to administer three sections/Ext4JS components - Task, Animal Details, and Misc Charges. diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormSection.java b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormSection.java index f8c7a92e5..bf1591b01 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormSection.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormSection.java @@ -44,7 +44,6 @@ public List getTbarButtons() public List getTbarMoreActionButtons() { List defaultMoreActionButtons = super.getTbarMoreActionButtons(); - defaultMoreActionButtons.remove("BULKEDIT"); defaultMoreActionButtons.remove("GUESSPROJECT"); defaultMoreActionButtons.remove("COPY_IDS"); return defaultMoreActionButtons; diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormType.java b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormType.java index 67bab57c8..218f01e92 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormType.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/dataentry/NonAnimalChargesFormType.java @@ -2,16 +2,10 @@ import org.labkey.api.ehr.dataentry.DataEntryFormContext; import org.labkey.api.ehr.dataentry.FormSection; -import org.labkey.api.ehr.dataentry.TaskForm; import org.labkey.api.ehr.dataentry.TaskFormSection; -import org.labkey.api.ehr_billing.security.EHR_BillingAdminPermission; import org.labkey.api.module.Module; -import org.labkey.api.view.template.ClientDependency; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; public class NonAnimalChargesFormType extends AbstractMiscChargesFormType { diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/domain/Alias.java b/wnprc_billing/src/org/labkey/wnprc_billing/domain/Alias.java index d486e83d3..5811c8b9a 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/domain/Alias.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/domain/Alias.java @@ -7,7 +7,13 @@ public class Alias String _alias; String _type; String _po_number; + String _investigatorName; + String _institution; String _address; + String _city; + String _state; + String _zip; + String _billing_contact_info; String _contact_email; private String _grantNumber; private String _uw_account; @@ -48,6 +54,26 @@ public void setPo_number(String po_number) _po_number = po_number; } + public String getInvestigatorName() + { + return _investigatorName; + } + + public void setInvestigatorName(String investigatorName) + { + _investigatorName = investigatorName; + } + + public String getInstitution() + { + return _institution; + } + + public void setInstitution(String institution) + { + _institution = institution; + } + public String getAddress() { return _address; @@ -58,6 +84,46 @@ public void setAddress(String address) _address = address; } + public String getCity() + { + return _city; + } + + public void setCity(String city) + { + _city = city; + } + + public String getState() + { + return _state; + } + + public void setState(String state) + { + _state = state; + } + + public String getZip() + { + return _zip; + } + + public void setZip(String zip) + { + _zip = zip; + } + + public String getBilling_contact_info() + { + return _billing_contact_info; + } + + public void setBilling_contact_info(String billing_contact_info) + { + _billing_contact_info = billing_contact_info; + } + public String getContact_email() { return _contact_email; diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/domain/InvoicedItem.java b/wnprc_billing/src/org/labkey/wnprc_billing/domain/InvoicedItem.java index 140a826bf..870b439b4 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/domain/InvoicedItem.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/domain/InvoicedItem.java @@ -18,7 +18,6 @@ public class InvoicedItem Date _date; TimeStamp _invoiceDate; private String _category; - private String _servicecenter; public int getRowId() { @@ -130,16 +129,6 @@ public void setCategory(String category) _category = category; } - public String getServicecenter() - { - return _servicecenter; - } - - public void setServicecenter(String servicecenter) - { - _servicecenter = servicecenter; - } - public String getGroupName() { return _groupName; diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/invoice/InvoicePDF.java b/wnprc_billing/src/org/labkey/wnprc_billing/invoice/InvoicePDF.java index 3390ab1cc..dbce9a04a 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/invoice/InvoicePDF.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/invoice/InvoicePDF.java @@ -73,8 +73,8 @@ public void createLineItems(List invoicedItems, boolean includeSub List items = new ArrayList<>(); Calendar calendarCurrent = Calendar.getInstance(); Calendar calendarItem = Calendar.getInstance(); - boolean isFirstItem =true; - String currentServiceCenter=null; + boolean isFirstItem = true; + String currentGroup = null; float subTotal = 0; for (InvoicedItem invoicedItem : invoicedItems) @@ -83,16 +83,16 @@ public void createLineItems(List invoicedItems, boolean includeSub calendarItem.setTime(invoicedItem.getDate()); boolean isDateChange = isFirstItem || calendarCurrent.get(Calendar.DAY_OF_MONTH) != calendarItem.get(Calendar.DAY_OF_MONTH); - boolean isServiceCenterChange = false; - if(invoicedItem.getServicecenter()== null){ - isServiceCenterChange = currentServiceCenter != null; + boolean isGroupChange = false; + if(invoicedItem.getGroupName()== null){ + isGroupChange = currentGroup != null; } else { - isServiceCenterChange = !invoicedItem.getServicecenter().equals(currentServiceCenter); + isGroupChange = !invoicedItem.getGroupName().equals(currentGroup); } if(includeSubtotal) { - if((isDateChange || isServiceCenterChange) && !isFirstItem ){ + if((isDateChange || isGroupChange) && !isFirstItem ){ items.add(new FormattedLineItem(null,"Sub total:", null, null, subTotal, true)); subTotal = 0; } @@ -100,14 +100,14 @@ public void createLineItems(List invoicedItems, boolean includeSub if (isDateChange){ items.add(new FormattedLineItem(invoicedItem.getDate(), groupHeader, null, null, null, true)); - currentServiceCenter = invoicedItem.getServicecenter(); + currentGroup = invoicedItem.getGroupName(); calendarCurrent.setTime(invoicedItem.getDate()); isFirstItem = false; } - if (!isDateChange && isServiceCenterChange){ + if (!isDateChange && isGroupChange){ items.add(new FormattedLineItem(null, groupHeader, null, null, null, true)); - currentServiceCenter = invoicedItem.getServicecenter(); + currentGroup = invoicedItem.getGroupName(); } subTotal += invoicedItem.getTotalCost(); @@ -128,37 +128,76 @@ protected List getLineItemsFromInvoicedItem(InvoicedItem invo boolean showDetailsWithItem = invoicedItem.getComment() == null; String participantId = invoicedItem.getId() == null? "": " - " + invoicedItem.getId(); - FormattedLineItem itemLine = null; - FormattedLineItem commentLine = null; - - if(invoicedItem.getItem() != null || showDetailsWithItem){ - itemLine = new FormattedLineItem(); - itemLine._description = indent + invoicedItem.getItem() + participantId; - participantId = "";//don't duplicate on the comment line + List itemLines = new ArrayList<>(); + List commentLines = new ArrayList<>(); + + if (invoicedItem.getItem() != null || showDetailsWithItem) { + if (invoicedItem.getItem() != null && invoicedItem.getItem().length() > 60) { + FormattedLineItem itemLine = new FormattedLineItem(); + itemLine._description = indent + invoicedItem.getItem().substring(0, 60); + itemLines.add(itemLine); + for (int i = 60; i < invoicedItem.getItem().length(); i+= 60) { + itemLine = new FormattedLineItem(); + if (i + 60 >= invoicedItem.getItem().length()) { + itemLine._description = indent + invoicedItem.getItem().substring(i) + participantId; + } else { + itemLine._description = indent + invoicedItem.getItem().substring(i, i + 60); + } + itemLines.add(itemLine); + } + } else { + FormattedLineItem itemLine = new FormattedLineItem(); + itemLine._description = indent + invoicedItem.getItem() + participantId; + participantId = "";//don't duplicate on the comment line + itemLines.add(itemLine); + } indent += " "; } - if(invoicedItem.getComment() != null){ - commentLine = new FormattedLineItem(); - if (invoicedItem.getComment().length() > 60) - commentLine._description = indent + invoicedItem.getComment().substring(0, 59) + participantId; - else + if (invoicedItem.getComment() != null) { + if (invoicedItem.getComment().length() > 60) { + //break the comment up into multiple lines of 60 characters (or less) each + //and indent any line after the first + //TODO consider making line breaks at word boundaries instead of 60 characters + FormattedLineItem commentLine = new FormattedLineItem(); + commentLine._description = indent + invoicedItem.getComment().substring(0, 60); + commentLines.add(commentLine); + for (int i = 60; i < invoicedItem.getComment().length(); i+= 58) { + commentLine = new FormattedLineItem(); + //only add participantId to the last line of the comment + if (i + 58 >= invoicedItem.getComment().length()) { + commentLine._description = indent + indent + invoicedItem.getComment().substring(i) + participantId; + } else { + commentLine._description = indent + indent + invoicedItem.getComment().substring(i, i + 58); + } + commentLines.add(commentLine); + } + } else { + FormattedLineItem commentLine = new FormattedLineItem(); commentLine._description = indent + invoicedItem.getComment() + participantId; + commentLines.add(commentLine); + } } - if(showDetailsWithItem){ - addDetailsToLineItem(itemLine, invoicedItem); - } - else{ - addDetailsToLineItem(commentLine,invoicedItem); + if (showDetailsWithItem) { + //only add details to the first line of the item so they're not duplicated for each line + addDetailsToLineItem(itemLines.get(0), invoicedItem); + } else { + //only add details to the first line of the comment so they're not duplicated for each line + addDetailsToLineItem(commentLines.get(0), invoicedItem); } - if(itemLine != null){ - formattedLineItems.add(itemLine); + + if (itemLines.size() > 0) { + for (FormattedLineItem itemLine : itemLines) { + formattedLineItems.add(itemLine); + } } - if(commentLine != null){ - formattedLineItems.add(commentLine); + if (commentLines.size() > 0) { + for (FormattedLineItem commentLine : commentLines) { + formattedLineItems.add(commentLine); + } } return formattedLineItems; } @@ -340,7 +379,7 @@ public void Header() addChargeLine(); addCreditLine(); addPaymentInfo(); - addAccountContact(StringUtils.isNotBlank(alias.getContact_email()) ? alias.getContact_email() : "Contact Email Not Specified"); + addAccountContact(StringUtils.isNotBlank(alias.getBilling_contact_info()) ? alias.getBilling_contact_info() : "Billing Contact Email Not Specified"); addBillingDate(invoiceRun.getBillingPeriodStart(), invoiceRun.getBillingPeriodEnd()); addCols(this.getHeaders()); @@ -476,7 +515,8 @@ private void addGrantAddress() throws IOException x = right_x; setXY(x, y); setFont("Arial", Collections.emptySet(), 10); - MultiCell(76, 3, alias.getAddress()); + String address = formatAddess(alias); + MultiCell(76, 3, address); String req_text; @@ -611,6 +651,10 @@ private void addInvoiceNo() throws IOException setFont(font, Collections.singleton(FontStyle.BOLD), 11); String invoiceNo = "INVOICE NO. "; invoiceNo += invoice.getInvoiceNumber(); + if (!alias.getType().toLowerCase().contains("internal")) + { + invoiceNo += "\nMake check payable to: Wisconsin National Primate Research Center"; + } MultiCell(0, 4, invoiceNo, null, Alignment.LEFT, false); } @@ -639,7 +683,6 @@ private void addCreditLine() throws IOException } - private String addItem(String item) { if(item != null){ @@ -648,7 +691,6 @@ private String addItem(String item) return ""; } - // payment info private void addPaymentInfo() throws IOException { @@ -707,7 +749,6 @@ private void addTotals() throws IOException Cell(17, 4, moneyFormat.format(grandTotal + (grandTotal * tier_rate)), Alignment.RIGHT); //grandtotal plus overhead assessment } - private void addCols(List headers) throws IOException { setFont("Helvetica", Collections.singleton(FontStyle.BOLD), 10); @@ -777,4 +818,28 @@ public float addLine (float line, FormattedLineItem lineItem, boolean bold) thro return line + 2; } + private String formatAddess(Alias alias) + { + //check for pi name before appending (only show on internal invoices) + //check for institution before appending + //always assume address will be present + //check for city/state/zip before appending + StringBuilder address = new StringBuilder(); + if (alias.getType().toLowerCase().contains("internal") && StringUtils.isNotBlank(alias.getInvestigatorName())) + { + address.append(alias.getInvestigatorName()).append("\n"); + } + if (StringUtils.isNotBlank(alias.getInstitution())) + { + address.append(alias.getInstitution()).append("\n"); + } + address.append(alias.getAddress()); + if (StringUtils.isNotBlank(alias.getCity()) && StringUtils.isNotBlank(alias.getState()) && StringUtils.isNotBlank(alias.getZip())) + { + address.append("\n").append(alias.getCity()).append(", ").append(alias.getState()).append(" ").append(alias.getZip()); + } + + return address.toString(); + } + } diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/notification/WNPRCBillingNotificationProvider.java b/wnprc_billing/src/org/labkey/wnprc_billing/notification/WNPRCBillingNotificationProvider.java index 783642e7f..6c03506dd 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/notification/WNPRCBillingNotificationProvider.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/notification/WNPRCBillingNotificationProvider.java @@ -97,7 +97,7 @@ public List getFieldDescriptor() fields.add(new FieldDescriptor("isExpiredAccount", true, "Expired/Invalid Account", true)); fields.add(new FieldDescriptor("isAcceptingCharges", true, "Account Not Accepting Charges", true)); fields.add(new FieldDescriptor("lacksRate", true, "Lacks Rate", true)); - fields.add(new FieldDescriptor("investigatorLastName", false, "Missing Investigator", true)); + fields.add(new FieldDescriptor("investigator", false, "Missing Investigator", true)); fields.add(new FieldDescriptor("matchesProject", true, "Project Does Not Match Assignment", false)); fields.add(new FieldDescriptor("isAdjustment", true, "Adjustment/Reversal", false)); fields.add(new FieldDescriptor("isOldCharge", true, "Over 45 Days Old", false)); diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/pipeline/InvoicedItemsProcessingServiceImpl.java b/wnprc_billing/src/org/labkey/wnprc_billing/pipeline/InvoicedItemsProcessingServiceImpl.java index 55e6719c3..b92203af0 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/pipeline/InvoicedItemsProcessingServiceImpl.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/pipeline/InvoicedItemsProcessingServiceImpl.java @@ -72,7 +72,7 @@ private Map getPerDiemColMap() colMap.put("chargeId", "chargeId"); colMap.put("item", "item"); colMap.put("category", "category"); - colMap.put("serviceCenter", "serviceCenter"); + colMap.put("groupName", "groupName"); return colMap; } @@ -93,7 +93,7 @@ private Map getProceduresColMap() colMap.put("chargeId", "chargeId"); colMap.put("item", "item"); colMap.put("category", "category"); - colMap.put("serviceCenter", "serviceCenter"); + colMap.put("groupName", "groupName"); return colMap; } @@ -114,7 +114,7 @@ private Map getMisChargesColMap() colMap.put("chargeId", "chargeId"); colMap.put("item", "item"); colMap.put("category", "category"); - colMap.put("serviceCenter", "serviceCenter"); + colMap.put("groupName", "groupName"); colMap.put("creditedAccount", "creditedAccount"); return colMap; } diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/query/WNPRC_BillingUserSchema.java b/wnprc_billing/src/org/labkey/wnprc_billing/query/WNPRC_BillingUserSchema.java index a04483af4..3c63e2b0f 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/query/WNPRC_BillingUserSchema.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/query/WNPRC_BillingUserSchema.java @@ -13,7 +13,7 @@ import org.labkey.api.security.permissions.InsertPermission; import org.labkey.api.security.permissions.ReadPermission; import org.labkey.api.security.permissions.UpdatePermission; -import org.labkey.api.ehr_billing.security.EHR_BillingAdminPermission; +import org.labkey.api.ehr.security.EHR_BillingAdminPermission; /** * Created by Binal on 10/31/2017. diff --git a/wnprc_billing/src/org/labkey/wnprc_billing/table/WNPRC_BillingCustomizer.java b/wnprc_billing/src/org/labkey/wnprc_billing/table/WNPRC_BillingCustomizer.java index 79dd08e8a..7081c3190 100644 --- a/wnprc_billing/src/org/labkey/wnprc_billing/table/WNPRC_BillingCustomizer.java +++ b/wnprc_billing/src/org/labkey/wnprc_billing/table/WNPRC_BillingCustomizer.java @@ -12,6 +12,9 @@ import org.labkey.api.query.QueryService; import org.labkey.api.query.UserSchema; import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.query.ExprColumn; +import org.labkey.api.data.JdbcType; +import org.labkey.api.data.SQLFragment; public class WNPRC_BillingCustomizer extends AbstractTableCustomizer { @@ -38,6 +41,37 @@ public void customize(TableInfo table) { customizeMiscCharges((AbstractTableInfo) table); } + else if (matches(table, "wnprc_billing", "tierRates")) + { + customizeTierRates((AbstractTableInfo) table); + } + } + } + + private SQLFragment getIsActiveSql(AbstractTableInfo ti) + { + return new SQLFragment("(CASE " + + // when the start is in the future, using whole-day increments, it is not active + " WHEN (CAST(" + ExprColumn.STR_TABLE_ALIAS + ".startDate as DATE) > {fn curdate()}) THEN " + ti.getSqlDialect().getBooleanFALSE() + "\n" + + // when enddate is null, it is active + " WHEN (" + ExprColumn.STR_TABLE_ALIAS + ".endDate IS NULL) THEN " + ti.getSqlDialect().getBooleanTRUE() + "\n" + + // if enddate is in the future (whole-day increments), then it is active + " WHEN (CAST(" + ExprColumn.STR_TABLE_ALIAS + ".endDate AS DATE) >= {fn curdate()}) THEN " + ti.getSqlDialect().getBooleanTRUE() + "\n" + + " ELSE " + ti.getSqlDialect().getBooleanFALSE() + "\n" + + " END)"); + } + + private void customizeTierRates(AbstractTableInfo ti) + { + String name = "isActive"; + if (ti.getColumn(name) == null) + { + SQLFragment sql = getIsActiveSql(ti); + ExprColumn col = new ExprColumn(ti, name, sql, JdbcType.BOOLEAN, ti.getColumn("startDate"), ti.getColumn("endDate")); + col.setLabel("Is Active?"); + col.setUserEditable(false); + col.setFormat("Y;N;"); + ti.addColumn(col); } } @@ -48,15 +82,14 @@ private void customizeMiscCharges(AbstractTableInfo table) { return; } - - var chargeType = table.getMutableColumn("chargeType"); - if (chargeType != null) - { - chargeType.setFk(QueryForeignKey.from(us, table.getContainerFilter()) - .container(us.getContainer()) - .table("chargeUnits") - .key("chargeType") - .raw(true)); + var chargeType = table.getMutableColumn("chargeGroup"); + if (chargeType != null) + { + chargeType.setFk(QueryForeignKey.from(us, table.getContainerFilter()) + .container(us.getContainer()) + .table("chargeUnits") + .key("groupName") + .raw(true)); } var debitedAcct = table.getMutableColumn("debitedAccount"); @@ -78,15 +111,6 @@ private void customizeMiscCharges(AbstractTableInfo table) .key("rowid") .raw(true)); } - -// UserSchema wnprcBillingUS = getBillingUserSchema(table, "wnprc_billing"); - -// ColumnInfo chargeCategory = table.getColumn("chargeCategory"); -// if (chargeCategory != null) -// { -// chargeCategory.setFk(new QueryForeignKey(wnprcBillingUS, wnprcBillingUS.getContainer(), "miscChargesType", -// "category", null, true)); -// } } private UserSchema getBillingUserSchema(AbstractTableInfo table, String schemaName) @@ -107,16 +131,6 @@ private UserSchema getBillingUserSchema(AbstractTableInfo table, String schemaNa return us; } } - -// //then a linked schema -// UserSchema us = QueryService.get().getUserSchema(table.getUserSchema().getUser(), -// table.getUserSchema().getContainer(), "wnprc_billing_public"); -// if (us != null) -// { -// _billingUserSchema = us; -// return us; -// } - return null; } } diff --git a/wnprc_billingpublic/resources/queries/ehr_billing_public/aliases.query.xml b/wnprc_billingpublic/resources/queries/ehr_billing_public/aliases.query.xml index 5b6bd0721..71a8b5a23 100644 --- a/wnprc_billingpublic/resources/queries/ehr_billing_public/aliases.query.xml +++ b/wnprc_billingpublic/resources/queries/ehr_billing_public/aliases.query.xml @@ -16,7 +16,7 @@ wnprc_billingLinked - tierRates + activeTierRates tierRateType tierRate @@ -34,8 +34,9 @@ ehr - investigators + investigatorsWithName rowid + investigatorWithName diff --git a/wnprc_billingpublic/resources/queries/ehr_billing_public/chargeRates/.qview.xml b/wnprc_billingpublic/resources/queries/ehr_billing_public/chargeRates/.qview.xml index c60d38094..8b033eff8 100644 --- a/wnprc_billingpublic/resources/queries/ehr_billing_public/chargeRates/.qview.xml +++ b/wnprc_billingpublic/resources/queries/ehr_billing_public/chargeRates/.qview.xml @@ -4,13 +4,11 @@ - - \ No newline at end of file